Annotation of src/usr.bin/rsh/rsh.c, Revision 1.25
1.25 ! millert 1: /* $OpenBSD: rsh.c,v 1.24 2002/02/17 19:42:31 millert Exp $ */
1.4 deraadt 2:
1.1 deraadt 3: /*-
4: * Copyright (c) 1983, 1990 The Regents of the University of California.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #ifndef lint
37: char copyright[] =
38: "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
39: All rights reserved.\n";
40: #endif /* not lint */
41:
42: #ifndef lint
43: /*static char sccsid[] = "from: @(#)rsh.c 5.24 (Berkeley) 7/1/91";*/
1.25 ! millert 44: static char rcsid[] = "$OpenBSD: rsh.c,v 1.24 2002/02/17 19:42:31 millert Exp $";
1.1 deraadt 45: #endif /* not lint */
46:
47: #include <sys/types.h>
48: #include <sys/socket.h>
49: #include <sys/ioctl.h>
50: #include <sys/file.h>
51:
52: #include <netinet/in.h>
53: #include <netdb.h>
54:
55: #include <pwd.h>
56: #include <signal.h>
57: #include <stdio.h>
1.17 art 58: #include <stdlib.h>
59: #include <unistd.h>
1.1 deraadt 60: #include <errno.h>
61: #include <string.h>
1.7 tholo 62: #include <stdarg.h>
1.1 deraadt 63: #include "pathnames.h"
64:
65: #ifdef KERBEROS
1.14 provos 66: #include <des.h>
1.1 deraadt 67: #include <kerberosIV/krb.h>
68:
69: CREDENTIALS cred;
70: Key_schedule schedule;
71: int use_kerberos = 1, doencrypt;
72: char dst_realm_buf[REALM_SZ], *dest_realm;
1.7 tholo 73:
1.23 millert 74: void warning(const char *, ...);
75: void desrw_set_key(des_cblock *, des_key_schedule *);
76: int des_read(int, char *, int);
77: int des_write(int, char *, int);
1.17 art 78:
1.23 millert 79: int krcmd(char **, u_short, char *, char *, int *, char *);
1.24 millert 80: int krcmd_mutual(char **, u_short, char *, char *, int *, char *,
81: CREDENTIALS *, Key_schedule);
1.1 deraadt 82: #endif
83:
1.23 millert 84: void usage(void);
1.17 art 85:
1.23 millert 86: void talk(int, sigset_t *, int, int);
1.17 art 87:
1.1 deraadt 88: /*
89: * rsh - remote shell
90: */
91: int rfd2;
92:
1.17 art 93: int
1.1 deraadt 94: main(argc, argv)
95: int argc;
96: char **argv;
97: {
98: extern char *optarg;
99: extern int optind;
100: struct passwd *pw;
101: struct servent *sp;
1.20 millert 102: sigset_t mask, omask;
1.17 art 103: int argoff, asrsh, ch, dflag, nflag, one, pid = 0, rem, uid;
1.22 mpech 104: char *p;
1.1 deraadt 105: char *args, *host, *user, *copyargs();
106: void sendsig();
107:
108: argoff = asrsh = dflag = nflag = 0;
109: one = 1;
110: host = user = NULL;
111:
112: /* if called as something other than "rsh", use it as the host name */
1.17 art 113: if ((p = strrchr(argv[0], '/')))
1.1 deraadt 114: ++p;
115: else
116: p = argv[0];
117: if (strcmp(p, "rsh"))
118: host = p;
119: else
120: asrsh = 1;
121:
122: /* handle "rsh host flags" */
123: if (!host && argc > 2 && argv[1][0] != '-') {
124: host = argv[1];
125: argoff = 1;
126: }
127:
128: #ifdef KERBEROS
129: #define OPTIONS "8KLdek:l:nwx"
130: #else
131: #define OPTIONS "8KLdel:nw"
132: #endif
1.11 millert 133: while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
1.1 deraadt 134: switch(ch) {
135: case 'K':
136: #ifdef KERBEROS
137: use_kerberos = 0;
138: #endif
139: break;
140: case 'L': /* -8Lew are ignored to allow rlogin aliases */
141: case 'e':
142: case 'w':
143: case '8':
144: break;
145: case 'd':
146: dflag = 1;
147: break;
148: case 'l':
149: user = optarg;
150: break;
151: #ifdef KERBEROS
152: case 'k':
153: dest_realm = dst_realm_buf;
154: strncpy(dest_realm, optarg, REALM_SZ);
155: break;
156: #endif
157: case 'n':
158: nflag = 1;
159: break;
160: #ifdef KERBEROS
161: case 'x':
162: doencrypt = 1;
1.17 art 163: desrw_set_key(&cred.session, &schedule);
1.1 deraadt 164: break;
165: #endif
166: case '?':
167: default:
168: usage();
169: }
170: optind += argoff;
171:
172: /* if haven't gotten a host yet, do so */
173: if (!host && !(host = argv[optind++]))
174: usage();
175:
176: /* if no further arguments, must have been called as rlogin. */
177: if (!argv[optind]) {
178: if (asrsh)
179: *argv = "rlogin";
1.10 tholo 180: seteuid(getuid());
1.6 deraadt 181: setuid(getuid());
1.1 deraadt 182: execv(_PATH_RLOGIN, argv);
183: (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN);
184: exit(1);
185: }
186:
187: argc -= optind;
188: argv += optind;
189:
1.8 millert 190: if (geteuid()) {
191: (void)fprintf(stderr, "rsh: must be setuid root.\n");
192: exit(1);
193: }
1.1 deraadt 194: if (!(pw = getpwuid(uid = getuid()))) {
195: (void)fprintf(stderr, "rsh: unknown user id.\n");
196: exit(1);
197: }
198: if (!user)
199: user = pw->pw_name;
200:
201: #ifdef KERBEROS
202: /* -x turns off -n */
203: if (doencrypt)
204: nflag = 0;
205: #endif
206:
207: args = copyargs(argv);
208:
209: sp = NULL;
210: #ifdef KERBEROS
211: if (use_kerberos) {
212: sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
213: if (sp == NULL) {
214: use_kerberos = 0;
215: warning("can't get entry for %s/tcp service",
216: doencrypt ? "ekshell" : "kshell");
217: }
218: }
219: #endif
220: if (sp == NULL)
221: sp = getservbyname("shell", "tcp");
222: if (sp == NULL) {
223: (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
224: exit(1);
225: }
1.9 millert 226:
227: (void) unsetenv("RSH"); /* no tricks with rcmd(3) */
1.1 deraadt 228:
229: #ifdef KERBEROS
230: try_connect:
231: if (use_kerberos) {
232: rem = KSUCCESS;
233: errno = 0;
234: if (dest_realm == NULL)
235: dest_realm = krb_realmofhost(host);
236:
237: if (doencrypt)
238: rem = krcmd_mutual(&host, sp->s_port, user, args,
239: &rfd2, dest_realm, &cred, schedule);
240: else
241: rem = krcmd(&host, sp->s_port, user, args, &rfd2,
242: dest_realm);
243: if (rem < 0) {
244: use_kerberos = 0;
245: sp = getservbyname("shell", "tcp");
246: if (sp == NULL) {
247: (void)fprintf(stderr,
248: "rsh: unknown service shell/tcp.\n");
249: exit(1);
250: }
251: if (errno == ECONNREFUSED)
252: warning("remote host doesn't support Kerberos");
253: if (errno == ENOENT)
254: warning("can't provide Kerberos auth data");
255: goto try_connect;
256: }
257: } else {
258: if (doencrypt) {
259: (void)fprintf(stderr,
260: "rsh: the -x flag requires Kerberos authentication.\n");
261: exit(1);
262: }
1.18 itojun 263: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args,
264: &rfd2, PF_UNSPEC);
1.1 deraadt 265: }
266: #else
1.18 itojun 267: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
268: PF_UNSPEC);
1.1 deraadt 269: #endif
270:
271: if (rem < 0)
272: exit(1);
273:
274: if (rfd2 < 0) {
275: (void)fprintf(stderr, "rsh: can't establish stderr.\n");
276: exit(1);
277: }
278: if (dflag) {
279: if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
280: sizeof(one)) < 0)
281: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
282: strerror(errno));
283: if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
284: sizeof(one)) < 0)
285: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
286: strerror(errno));
287: }
288:
1.10 tholo 289: (void)seteuid(uid);
1.1 deraadt 290: (void)setuid(uid);
1.20 millert 291: sigemptyset(&mask);
292: sigaddset(&mask, SIGINT);
293: sigaddset(&mask, SIGQUIT);
294: sigaddset(&mask, SIGTERM);
295: sigprocmask(SIG_BLOCK, &mask, &omask);
1.1 deraadt 296: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
297: (void)signal(SIGINT, sendsig);
298: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
299: (void)signal(SIGQUIT, sendsig);
300: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
301: (void)signal(SIGTERM, sendsig);
302:
303: if (!nflag) {
304: pid = fork();
305: if (pid < 0) {
306: (void)fprintf(stderr,
307: "rsh: fork: %s.\n", strerror(errno));
308: exit(1);
309: }
310: }
311:
312: #ifdef KERBEROS
313: if (!doencrypt)
314: #endif
315: {
316: (void)ioctl(rfd2, FIONBIO, &one);
317: (void)ioctl(rem, FIONBIO, &one);
318: }
319:
1.20 millert 320: talk(nflag, &omask, pid, rem);
1.1 deraadt 321:
322: if (!nflag)
323: (void)kill(pid, SIGKILL);
1.17 art 324:
325: return 0;
1.1 deraadt 326: }
327:
1.17 art 328: void
1.1 deraadt 329: talk(nflag, omask, pid, rem)
330: int nflag, pid;
1.20 millert 331: sigset_t *omask;
1.22 mpech 332: int rem;
1.1 deraadt 333: {
1.22 mpech 334: int cc, wc;
335: char *bp;
1.17 art 336: fd_set readfrom, ready, rembits;
1.1 deraadt 337: char buf[BUFSIZ];
338:
339: if (!nflag && pid == 0) {
340: (void)close(rfd2);
341:
342: reread: errno = 0;
343: if ((cc = read(0, buf, sizeof buf)) <= 0)
344: goto done;
345: bp = buf;
346:
1.17 art 347: rewrite: FD_ZERO(&rembits);
348: FD_SET(rem, &rembits);
1.12 deraadt 349: if (select(rem + 1, 0, &rembits, 0, 0) < 0) {
1.1 deraadt 350: if (errno != EINTR) {
351: (void)fprintf(stderr,
352: "rsh: select: %s.\n", strerror(errno));
353: exit(1);
354: }
355: goto rewrite;
356: }
1.17 art 357: if (!FD_ISSET(rem, &rembits))
1.1 deraadt 358: goto rewrite;
359: #ifdef KERBEROS
360: if (doencrypt)
361: wc = des_write(rem, bp, cc);
362: else
363: #endif
364: wc = write(rem, bp, cc);
365: if (wc < 0) {
366: if (errno == EWOULDBLOCK)
367: goto rewrite;
368: goto done;
369: }
370: bp += wc;
371: cc -= wc;
372: if (cc == 0)
373: goto reread;
374: goto rewrite;
375: done:
376: (void)shutdown(rem, 1);
377: exit(0);
378: }
379:
1.21 deraadt 380: sigprocmask(SIG_SETMASK, omask, NULL);
1.17 art 381: FD_ZERO(&readfrom);
382: FD_SET(rfd2, &readfrom);
383: FD_SET(rem, &readfrom);
1.1 deraadt 384: do {
1.17 art 385: FD_COPY(&readfrom, &ready);
1.12 deraadt 386: if (select(MAX(rfd2, rem) + 1, &ready, 0, 0, 0) < 0) {
1.1 deraadt 387: if (errno != EINTR) {
388: (void)fprintf(stderr,
389: "rsh: select: %s.\n", strerror(errno));
390: exit(1);
391: }
392: continue;
393: }
1.17 art 394: if (FD_ISSET(rfd2, &ready)) {
1.1 deraadt 395: errno = 0;
396: #ifdef KERBEROS
397: if (doencrypt)
398: cc = des_read(rfd2, buf, sizeof buf);
399: else
400: #endif
401: cc = read(rfd2, buf, sizeof buf);
402: if (cc <= 0) {
403: if (errno != EWOULDBLOCK)
1.17 art 404: FD_CLR(rfd2, &readfrom);
1.1 deraadt 405: } else
406: (void)write(2, buf, cc);
407: }
1.17 art 408: if (FD_ISSET(rem, &ready)) {
1.1 deraadt 409: errno = 0;
410: #ifdef KERBEROS
411: if (doencrypt)
412: cc = des_read(rem, buf, sizeof buf);
413: else
414: #endif
415: cc = read(rem, buf, sizeof buf);
416: if (cc <= 0) {
417: if (errno != EWOULDBLOCK)
1.17 art 418: FD_CLR(rem, &readfrom);
1.1 deraadt 419: } else
420: (void)write(1, buf, cc);
421: }
1.17 art 422: } while (FD_ISSET(rem, &readfrom) || FD_ISSET(rfd2, &readfrom));
1.1 deraadt 423: }
424:
425: void
426: sendsig(signo)
427: char signo;
428: {
1.16 deraadt 429: int save_errno = errno;
430:
1.1 deraadt 431: #ifdef KERBEROS
432: if (doencrypt)
433: (void)des_write(rfd2, &signo, 1);
434: else
435: #endif
436: (void)write(rfd2, &signo, 1);
1.16 deraadt 437: errno = save_errno;
1.1 deraadt 438: }
439:
440: #ifdef KERBEROS
441: /* VARARGS */
1.7 tholo 442: void
443: warning(const char *fmt, ...)
1.1 deraadt 444: {
445: va_list ap;
1.7 tholo 446: char myrealm[REALM_SZ];
1.1 deraadt 447:
1.7 tholo 448: if (krb_get_lrealm(myrealm, 0) != KSUCCESS)
449: return;
1.1 deraadt 450: (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
1.7 tholo 451: va_start(ap, fmt);
1.1 deraadt 452: vfprintf(stderr, fmt, ap);
453: va_end(ap);
454: (void)fprintf(stderr, ".\n");
455: }
456: #endif
457:
458: char *
459: copyargs(argv)
460: char **argv;
461: {
1.22 mpech 462: int cc;
463: char **ap, *p;
1.1 deraadt 464: char *args, *malloc();
465:
466: cc = 0;
467: for (ap = argv; *ap; ++ap)
468: cc += strlen(*ap) + 1;
469: if (!(args = malloc((u_int)cc))) {
470: (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
471: exit(1);
472: }
473: for (p = args, ap = argv; *ap; ++ap) {
474: (void)strcpy(p, *ap);
475: for (p = strcpy(p, *ap); *p; ++p);
476: if (ap[1])
477: *p++ = ' ';
478: }
479: return(args);
480: }
481:
1.17 art 482: void
483: usage(void)
1.1 deraadt 484: {
485: (void)fprintf(stderr,
486: "usage: rsh [-nd%s]%s[-l login] host [command]\n",
487: #ifdef KERBEROS
488: "x", " [-k realm] ");
489: #else
490: "", " ");
491: #endif
492: exit(1);
493: }