Annotation of src/usr.bin/rsh/rsh.c, Revision 1.19
1.19 ! deraadt 1: /* $OpenBSD: rsh.c,v 1.18 2000/01/27 05:27:42 itojun 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.19 ! deraadt 44: static char rcsid[] = "$OpenBSD: rsh.c,v 1.18 2000/01/27 05:27:42 itojun 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: int rfd2;
96:
1.17 art 97: int
1.1 deraadt 98: main(argc, argv)
99: int argc;
100: char **argv;
101: {
102: extern char *optarg;
103: extern int optind;
104: struct passwd *pw;
105: struct servent *sp;
1.13 deraadt 106: int omask;
1.17 art 107: int argoff, asrsh, ch, dflag, nflag, one, pid = 0, rem, uid;
1.1 deraadt 108: register char *p;
109: char *args, *host, *user, *copyargs();
110: void sendsig();
111:
112: argoff = asrsh = dflag = nflag = 0;
113: one = 1;
114: host = user = NULL;
115:
116: /* if called as something other than "rsh", use it as the host name */
1.17 art 117: if ((p = strrchr(argv[0], '/')))
1.1 deraadt 118: ++p;
119: else
120: p = argv[0];
121: if (strcmp(p, "rsh"))
122: host = p;
123: else
124: asrsh = 1;
125:
126: /* handle "rsh host flags" */
127: if (!host && argc > 2 && argv[1][0] != '-') {
128: host = argv[1];
129: argoff = 1;
130: }
131:
132: #ifdef KERBEROS
133: #define OPTIONS "8KLdek:l:nwx"
134: #else
135: #define OPTIONS "8KLdel:nw"
136: #endif
1.11 millert 137: while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
1.1 deraadt 138: switch(ch) {
139: case 'K':
140: #ifdef KERBEROS
141: use_kerberos = 0;
142: #endif
143: break;
144: case 'L': /* -8Lew are ignored to allow rlogin aliases */
145: case 'e':
146: case 'w':
147: case '8':
148: break;
149: case 'd':
150: dflag = 1;
151: break;
152: case 'l':
153: user = optarg;
154: break;
155: #ifdef KERBEROS
156: case 'k':
157: dest_realm = dst_realm_buf;
158: strncpy(dest_realm, optarg, REALM_SZ);
159: break;
160: #endif
161: case 'n':
162: nflag = 1;
163: break;
164: #ifdef KERBEROS
165: case 'x':
166: doencrypt = 1;
1.17 art 167: desrw_set_key(&cred.session, &schedule);
1.1 deraadt 168: break;
169: #endif
170: case '?':
171: default:
172: usage();
173: }
174: optind += argoff;
175:
176: /* if haven't gotten a host yet, do so */
177: if (!host && !(host = argv[optind++]))
178: usage();
179:
180: /* if no further arguments, must have been called as rlogin. */
181: if (!argv[optind]) {
182: if (asrsh)
183: *argv = "rlogin";
1.10 tholo 184: seteuid(getuid());
1.6 deraadt 185: setuid(getuid());
1.1 deraadt 186: execv(_PATH_RLOGIN, argv);
187: (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN);
188: exit(1);
189: }
190:
191: argc -= optind;
192: argv += optind;
193:
1.8 millert 194: if (geteuid()) {
195: (void)fprintf(stderr, "rsh: must be setuid root.\n");
196: exit(1);
197: }
1.1 deraadt 198: if (!(pw = getpwuid(uid = getuid()))) {
199: (void)fprintf(stderr, "rsh: unknown user id.\n");
200: exit(1);
201: }
202: if (!user)
203: user = pw->pw_name;
204:
205: #ifdef KERBEROS
206: /* -x turns off -n */
207: if (doencrypt)
208: nflag = 0;
209: #endif
210:
211: args = copyargs(argv);
212:
213: sp = NULL;
214: #ifdef KERBEROS
215: if (use_kerberos) {
216: sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
217: if (sp == NULL) {
218: use_kerberos = 0;
219: warning("can't get entry for %s/tcp service",
220: doencrypt ? "ekshell" : "kshell");
221: }
222: }
223: #endif
224: if (sp == NULL)
225: sp = getservbyname("shell", "tcp");
226: if (sp == NULL) {
227: (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
228: exit(1);
229: }
1.9 millert 230:
231: (void) unsetenv("RSH"); /* no tricks with rcmd(3) */
1.1 deraadt 232:
233: #ifdef KERBEROS
234: try_connect:
235: if (use_kerberos) {
236: rem = KSUCCESS;
237: errno = 0;
238: if (dest_realm == NULL)
239: dest_realm = krb_realmofhost(host);
240:
241: if (doencrypt)
242: rem = krcmd_mutual(&host, sp->s_port, user, args,
243: &rfd2, dest_realm, &cred, schedule);
244: else
245: rem = krcmd(&host, sp->s_port, user, args, &rfd2,
246: dest_realm);
247: if (rem < 0) {
248: use_kerberos = 0;
249: sp = getservbyname("shell", "tcp");
250: if (sp == NULL) {
251: (void)fprintf(stderr,
252: "rsh: unknown service shell/tcp.\n");
253: exit(1);
254: }
255: if (errno == ECONNREFUSED)
256: warning("remote host doesn't support Kerberos");
257: if (errno == ENOENT)
258: warning("can't provide Kerberos auth data");
259: goto try_connect;
260: }
261: } else {
262: if (doencrypt) {
263: (void)fprintf(stderr,
264: "rsh: the -x flag requires Kerberos authentication.\n");
265: exit(1);
266: }
1.18 itojun 267: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args,
268: &rfd2, PF_UNSPEC);
1.1 deraadt 269: }
270: #else
1.18 itojun 271: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
272: PF_UNSPEC);
1.1 deraadt 273: #endif
274:
275: if (rem < 0)
276: exit(1);
277:
278: if (rfd2 < 0) {
279: (void)fprintf(stderr, "rsh: can't establish stderr.\n");
280: exit(1);
281: }
282: if (dflag) {
283: if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
284: sizeof(one)) < 0)
285: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
286: strerror(errno));
287: if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
288: sizeof(one)) < 0)
289: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
290: strerror(errno));
291: }
292:
1.10 tholo 293: (void)seteuid(uid);
1.1 deraadt 294: (void)setuid(uid);
295: omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
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:
320: talk(nflag, omask, pid, rem);
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.13 deraadt 331: int omask;
1.1 deraadt 332: register int rem;
333: {
334: register int cc, wc;
335: register 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:
380: (void)sigsetmask(omask);
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
1.15 mickey 443: #ifdef __STDC__
1.7 tholo 444: warning(const char *fmt, ...)
445: #else
1.1 deraadt 446: warning(va_alist)
447: va_dcl
1.7 tholo 448: #endif
1.1 deraadt 449: {
450: va_list ap;
1.15 mickey 451: #ifndef __STDC__
1.1 deraadt 452: char *fmt;
1.7 tholo 453: #endif
454: char myrealm[REALM_SZ];
1.1 deraadt 455:
1.7 tholo 456: if (krb_get_lrealm(myrealm, 0) != KSUCCESS)
457: return;
1.1 deraadt 458: (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
1.15 mickey 459: #ifdef __STDC__
1.7 tholo 460: va_start(ap, fmt);
461: #else
1.1 deraadt 462: va_start(ap);
463: fmt = va_arg(ap, char *);
1.7 tholo 464: #endif
1.1 deraadt 465: vfprintf(stderr, fmt, ap);
466: va_end(ap);
467: (void)fprintf(stderr, ".\n");
468: }
469: #endif
470:
471: char *
472: copyargs(argv)
473: char **argv;
474: {
475: register int cc;
476: register char **ap, *p;
477: char *args, *malloc();
478:
479: cc = 0;
480: for (ap = argv; *ap; ++ap)
481: cc += strlen(*ap) + 1;
482: if (!(args = malloc((u_int)cc))) {
483: (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
484: exit(1);
485: }
486: for (p = args, ap = argv; *ap; ++ap) {
487: (void)strcpy(p, *ap);
488: for (p = strcpy(p, *ap); *p; ++p);
489: if (ap[1])
490: *p++ = ' ';
491: }
492: return(args);
493: }
494:
1.17 art 495: void
496: usage(void)
1.1 deraadt 497: {
498: (void)fprintf(stderr,
499: "usage: rsh [-nd%s]%s[-l login] host [command]\n",
500: #ifdef KERBEROS
501: "x", " [-k realm] ");
502: #else
503: "", " ");
504: #endif
505: exit(1);
506: }