Annotation of src/usr.bin/rsh/rsh.c, Revision 1.18
1.18 ! itojun 1: /* $OpenBSD: rsh.c,v 1.17 1998/03/25 19:53:21 art 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.18 ! itojun 44: static char rcsid[] = "$OpenBSD: rsh.c,v 1.17 1998/03/25 19:53:21 art 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.15 mickey 62: #ifdef __STDC__
1.7 tholo 63: #include <stdarg.h>
64: #else
1.1 deraadt 65: #include <varargs.h>
1.7 tholo 66: #endif
1.1 deraadt 67: #include "pathnames.h"
68:
69: #ifdef KERBEROS
1.14 provos 70: #include <des.h>
1.1 deraadt 71: #include <kerberosIV/krb.h>
72:
73: CREDENTIALS cred;
74: Key_schedule schedule;
75: int use_kerberos = 1, doencrypt;
76: char dst_realm_buf[REALM_SZ], *dest_realm;
1.7 tholo 77:
78: void warning __P((const char *, ...));
1.17 art 79: void desrw_set_key __P((des_cblock *, des_key_schedule *));
80: int des_read __P((int, char *, int));
81: int des_write __P((int, char *, int));
82:
83: int krcmd __P((char **, u_short, char *, char *, int *, char *));
84: int krcmd_mutual __P((char **, u_short, char *, char *, int *, char *,
85: CREDENTIALS *, Key_schedule));
1.1 deraadt 86: #endif
87:
1.17 art 88: void usage __P((void));
89:
90: void talk __P((int, int, int, register int));
91:
1.1 deraadt 92: /*
93: * rsh - remote shell
94: */
95: extern int errno;
96: int rfd2;
97:
1.17 art 98: int
1.1 deraadt 99: main(argc, argv)
100: int argc;
101: char **argv;
102: {
103: extern char *optarg;
104: extern int optind;
105: struct passwd *pw;
106: struct servent *sp;
1.13 deraadt 107: int omask;
1.17 art 108: int argoff, asrsh, ch, dflag, nflag, one, pid = 0, rem, uid;
1.1 deraadt 109: register char *p;
110: char *args, *host, *user, *copyargs();
111: void sendsig();
112:
113: argoff = asrsh = dflag = nflag = 0;
114: one = 1;
115: host = user = NULL;
116:
117: /* if called as something other than "rsh", use it as the host name */
1.17 art 118: if ((p = strrchr(argv[0], '/')))
1.1 deraadt 119: ++p;
120: else
121: p = argv[0];
122: if (strcmp(p, "rsh"))
123: host = p;
124: else
125: asrsh = 1;
126:
127: /* handle "rsh host flags" */
128: if (!host && argc > 2 && argv[1][0] != '-') {
129: host = argv[1];
130: argoff = 1;
131: }
132:
133: #ifdef KERBEROS
134: #define OPTIONS "8KLdek:l:nwx"
135: #else
136: #define OPTIONS "8KLdel:nw"
137: #endif
1.11 millert 138: while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
1.1 deraadt 139: switch(ch) {
140: case 'K':
141: #ifdef KERBEROS
142: use_kerberos = 0;
143: #endif
144: break;
145: case 'L': /* -8Lew are ignored to allow rlogin aliases */
146: case 'e':
147: case 'w':
148: case '8':
149: break;
150: case 'd':
151: dflag = 1;
152: break;
153: case 'l':
154: user = optarg;
155: break;
156: #ifdef KERBEROS
157: case 'k':
158: dest_realm = dst_realm_buf;
159: strncpy(dest_realm, optarg, REALM_SZ);
160: break;
161: #endif
162: case 'n':
163: nflag = 1;
164: break;
165: #ifdef KERBEROS
166: case 'x':
167: doencrypt = 1;
1.17 art 168: desrw_set_key(&cred.session, &schedule);
1.1 deraadt 169: break;
170: #endif
171: case '?':
172: default:
173: usage();
174: }
175: optind += argoff;
176:
177: /* if haven't gotten a host yet, do so */
178: if (!host && !(host = argv[optind++]))
179: usage();
180:
181: /* if no further arguments, must have been called as rlogin. */
182: if (!argv[optind]) {
183: if (asrsh)
184: *argv = "rlogin";
1.10 tholo 185: seteuid(getuid());
1.6 deraadt 186: setuid(getuid());
1.1 deraadt 187: execv(_PATH_RLOGIN, argv);
188: (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN);
189: exit(1);
190: }
191:
192: argc -= optind;
193: argv += optind;
194:
1.8 millert 195: if (geteuid()) {
196: (void)fprintf(stderr, "rsh: must be setuid root.\n");
197: exit(1);
198: }
1.1 deraadt 199: if (!(pw = getpwuid(uid = getuid()))) {
200: (void)fprintf(stderr, "rsh: unknown user id.\n");
201: exit(1);
202: }
203: if (!user)
204: user = pw->pw_name;
205:
206: #ifdef KERBEROS
207: /* -x turns off -n */
208: if (doencrypt)
209: nflag = 0;
210: #endif
211:
212: args = copyargs(argv);
213:
214: sp = NULL;
215: #ifdef KERBEROS
216: if (use_kerberos) {
217: sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
218: if (sp == NULL) {
219: use_kerberos = 0;
220: warning("can't get entry for %s/tcp service",
221: doencrypt ? "ekshell" : "kshell");
222: }
223: }
224: #endif
225: if (sp == NULL)
226: sp = getservbyname("shell", "tcp");
227: if (sp == NULL) {
228: (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
229: exit(1);
230: }
1.9 millert 231:
232: (void) unsetenv("RSH"); /* no tricks with rcmd(3) */
1.1 deraadt 233:
234: #ifdef KERBEROS
235: try_connect:
236: if (use_kerberos) {
237: rem = KSUCCESS;
238: errno = 0;
239: if (dest_realm == NULL)
240: dest_realm = krb_realmofhost(host);
241:
242: if (doencrypt)
243: rem = krcmd_mutual(&host, sp->s_port, user, args,
244: &rfd2, dest_realm, &cred, schedule);
245: else
246: rem = krcmd(&host, sp->s_port, user, args, &rfd2,
247: dest_realm);
248: if (rem < 0) {
249: use_kerberos = 0;
250: sp = getservbyname("shell", "tcp");
251: if (sp == NULL) {
252: (void)fprintf(stderr,
253: "rsh: unknown service shell/tcp.\n");
254: exit(1);
255: }
256: if (errno == ECONNREFUSED)
257: warning("remote host doesn't support Kerberos");
258: if (errno == ENOENT)
259: warning("can't provide Kerberos auth data");
260: goto try_connect;
261: }
262: } else {
263: if (doencrypt) {
264: (void)fprintf(stderr,
265: "rsh: the -x flag requires Kerberos authentication.\n");
266: exit(1);
267: }
1.18 ! itojun 268: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args,
! 269: &rfd2, PF_UNSPEC);
1.1 deraadt 270: }
271: #else
1.18 ! itojun 272: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
! 273: PF_UNSPEC);
1.1 deraadt 274: #endif
275:
276: if (rem < 0)
277: exit(1);
278:
279: if (rfd2 < 0) {
280: (void)fprintf(stderr, "rsh: can't establish stderr.\n");
281: exit(1);
282: }
283: if (dflag) {
284: if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
285: sizeof(one)) < 0)
286: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
287: strerror(errno));
288: if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
289: sizeof(one)) < 0)
290: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
291: strerror(errno));
292: }
293:
1.10 tholo 294: (void)seteuid(uid);
1.1 deraadt 295: (void)setuid(uid);
296: omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
297: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
298: (void)signal(SIGINT, sendsig);
299: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
300: (void)signal(SIGQUIT, sendsig);
301: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
302: (void)signal(SIGTERM, sendsig);
303:
304: if (!nflag) {
305: pid = fork();
306: if (pid < 0) {
307: (void)fprintf(stderr,
308: "rsh: fork: %s.\n", strerror(errno));
309: exit(1);
310: }
311: }
312:
313: #ifdef KERBEROS
314: if (!doencrypt)
315: #endif
316: {
317: (void)ioctl(rfd2, FIONBIO, &one);
318: (void)ioctl(rem, FIONBIO, &one);
319: }
320:
321: talk(nflag, omask, pid, rem);
322:
323: if (!nflag)
324: (void)kill(pid, SIGKILL);
1.17 art 325:
326: return 0;
1.1 deraadt 327: }
328:
1.17 art 329: void
1.1 deraadt 330: talk(nflag, omask, pid, rem)
331: int nflag, pid;
1.13 deraadt 332: int omask;
1.1 deraadt 333: register int rem;
334: {
335: register int cc, wc;
336: register char *bp;
1.17 art 337: fd_set readfrom, ready, rembits;
1.1 deraadt 338: char buf[BUFSIZ];
339:
340: if (!nflag && pid == 0) {
341: (void)close(rfd2);
342:
343: reread: errno = 0;
344: if ((cc = read(0, buf, sizeof buf)) <= 0)
345: goto done;
346: bp = buf;
347:
1.17 art 348: rewrite: FD_ZERO(&rembits);
349: FD_SET(rem, &rembits);
1.12 deraadt 350: if (select(rem + 1, 0, &rembits, 0, 0) < 0) {
1.1 deraadt 351: if (errno != EINTR) {
352: (void)fprintf(stderr,
353: "rsh: select: %s.\n", strerror(errno));
354: exit(1);
355: }
356: goto rewrite;
357: }
1.17 art 358: if (!FD_ISSET(rem, &rembits))
1.1 deraadt 359: goto rewrite;
360: #ifdef KERBEROS
361: if (doencrypt)
362: wc = des_write(rem, bp, cc);
363: else
364: #endif
365: wc = write(rem, bp, cc);
366: if (wc < 0) {
367: if (errno == EWOULDBLOCK)
368: goto rewrite;
369: goto done;
370: }
371: bp += wc;
372: cc -= wc;
373: if (cc == 0)
374: goto reread;
375: goto rewrite;
376: done:
377: (void)shutdown(rem, 1);
378: exit(0);
379: }
380:
381: (void)sigsetmask(omask);
1.17 art 382: FD_ZERO(&readfrom);
383: FD_SET(rfd2, &readfrom);
384: FD_SET(rem, &readfrom);
1.1 deraadt 385: do {
1.17 art 386: FD_COPY(&readfrom, &ready);
1.12 deraadt 387: if (select(MAX(rfd2, rem) + 1, &ready, 0, 0, 0) < 0) {
1.1 deraadt 388: if (errno != EINTR) {
389: (void)fprintf(stderr,
390: "rsh: select: %s.\n", strerror(errno));
391: exit(1);
392: }
393: continue;
394: }
1.17 art 395: if (FD_ISSET(rfd2, &ready)) {
1.1 deraadt 396: errno = 0;
397: #ifdef KERBEROS
398: if (doencrypt)
399: cc = des_read(rfd2, buf, sizeof buf);
400: else
401: #endif
402: cc = read(rfd2, buf, sizeof buf);
403: if (cc <= 0) {
404: if (errno != EWOULDBLOCK)
1.17 art 405: FD_CLR(rfd2, &readfrom);
1.1 deraadt 406: } else
407: (void)write(2, buf, cc);
408: }
1.17 art 409: if (FD_ISSET(rem, &ready)) {
1.1 deraadt 410: errno = 0;
411: #ifdef KERBEROS
412: if (doencrypt)
413: cc = des_read(rem, buf, sizeof buf);
414: else
415: #endif
416: cc = read(rem, buf, sizeof buf);
417: if (cc <= 0) {
418: if (errno != EWOULDBLOCK)
1.17 art 419: FD_CLR(rem, &readfrom);
1.1 deraadt 420: } else
421: (void)write(1, buf, cc);
422: }
1.17 art 423: } while (FD_ISSET(rem, &readfrom) || FD_ISSET(rfd2, &readfrom));
1.1 deraadt 424: }
425:
426: void
427: sendsig(signo)
428: char signo;
429: {
1.16 deraadt 430: int save_errno = errno;
431:
1.1 deraadt 432: #ifdef KERBEROS
433: if (doencrypt)
434: (void)des_write(rfd2, &signo, 1);
435: else
436: #endif
437: (void)write(rfd2, &signo, 1);
1.16 deraadt 438: errno = save_errno;
1.1 deraadt 439: }
440:
441: #ifdef KERBEROS
442: /* VARARGS */
1.7 tholo 443: void
1.15 mickey 444: #ifdef __STDC__
1.7 tholo 445: warning(const char *fmt, ...)
446: #else
1.1 deraadt 447: warning(va_alist)
448: va_dcl
1.7 tholo 449: #endif
1.1 deraadt 450: {
451: va_list ap;
1.15 mickey 452: #ifndef __STDC__
1.1 deraadt 453: char *fmt;
1.7 tholo 454: #endif
455: char myrealm[REALM_SZ];
1.1 deraadt 456:
1.7 tholo 457: if (krb_get_lrealm(myrealm, 0) != KSUCCESS)
458: return;
1.1 deraadt 459: (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
1.15 mickey 460: #ifdef __STDC__
1.7 tholo 461: va_start(ap, fmt);
462: #else
1.1 deraadt 463: va_start(ap);
464: fmt = va_arg(ap, char *);
1.7 tholo 465: #endif
1.1 deraadt 466: vfprintf(stderr, fmt, ap);
467: va_end(ap);
468: (void)fprintf(stderr, ".\n");
469: }
470: #endif
471:
472: char *
473: copyargs(argv)
474: char **argv;
475: {
476: register int cc;
477: register char **ap, *p;
478: char *args, *malloc();
479:
480: cc = 0;
481: for (ap = argv; *ap; ++ap)
482: cc += strlen(*ap) + 1;
483: if (!(args = malloc((u_int)cc))) {
484: (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
485: exit(1);
486: }
487: for (p = args, ap = argv; *ap; ++ap) {
488: (void)strcpy(p, *ap);
489: for (p = strcpy(p, *ap); *p; ++p);
490: if (ap[1])
491: *p++ = ' ';
492: }
493: return(args);
494: }
495:
1.17 art 496: void
497: usage(void)
1.1 deraadt 498: {
499: (void)fprintf(stderr,
500: "usage: rsh [-nd%s]%s[-l login] host [command]\n",
501: #ifdef KERBEROS
502: "x", " [-k realm] ");
503: #else
504: "", " ");
505: #endif
506: exit(1);
507: }