Annotation of src/usr.bin/rsh/rsh.c, Revision 1.20
1.20 ! millert 1: /* $OpenBSD: rsh.c,v 1.19 2000/02/01 03:23:37 deraadt 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.20 ! millert 44: static char rcsid[] = "$OpenBSD: rsh.c,v 1.19 2000/02/01 03:23:37 deraadt 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:
1.20 ! millert 90: void talk __P((int, sigset_t *, int, register int));
1.17 art 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.20 ! millert 106: sigset_t mask, 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);
1.20 ! millert 295: sigemptyset(&mask);
! 296: sigaddset(&mask, SIGINT);
! 297: sigaddset(&mask, SIGQUIT);
! 298: sigaddset(&mask, SIGTERM);
! 299: sigprocmask(SIG_BLOCK, &mask, &omask);
1.1 deraadt 300: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
301: (void)signal(SIGINT, sendsig);
302: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
303: (void)signal(SIGQUIT, sendsig);
304: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
305: (void)signal(SIGTERM, sendsig);
306:
307: if (!nflag) {
308: pid = fork();
309: if (pid < 0) {
310: (void)fprintf(stderr,
311: "rsh: fork: %s.\n", strerror(errno));
312: exit(1);
313: }
314: }
315:
316: #ifdef KERBEROS
317: if (!doencrypt)
318: #endif
319: {
320: (void)ioctl(rfd2, FIONBIO, &one);
321: (void)ioctl(rem, FIONBIO, &one);
322: }
323:
1.20 ! millert 324: talk(nflag, &omask, pid, rem);
1.1 deraadt 325:
326: if (!nflag)
327: (void)kill(pid, SIGKILL);
1.17 art 328:
329: return 0;
1.1 deraadt 330: }
331:
1.17 art 332: void
1.1 deraadt 333: talk(nflag, omask, pid, rem)
334: int nflag, pid;
1.20 ! millert 335: sigset_t *omask;
1.1 deraadt 336: register int rem;
337: {
338: register int cc, wc;
339: register char *bp;
1.17 art 340: fd_set readfrom, ready, rembits;
1.1 deraadt 341: char buf[BUFSIZ];
342:
343: if (!nflag && pid == 0) {
344: (void)close(rfd2);
345:
346: reread: errno = 0;
347: if ((cc = read(0, buf, sizeof buf)) <= 0)
348: goto done;
349: bp = buf;
350:
1.17 art 351: rewrite: FD_ZERO(&rembits);
352: FD_SET(rem, &rembits);
1.12 deraadt 353: if (select(rem + 1, 0, &rembits, 0, 0) < 0) {
1.1 deraadt 354: if (errno != EINTR) {
355: (void)fprintf(stderr,
356: "rsh: select: %s.\n", strerror(errno));
357: exit(1);
358: }
359: goto rewrite;
360: }
1.17 art 361: if (!FD_ISSET(rem, &rembits))
1.1 deraadt 362: goto rewrite;
363: #ifdef KERBEROS
364: if (doencrypt)
365: wc = des_write(rem, bp, cc);
366: else
367: #endif
368: wc = write(rem, bp, cc);
369: if (wc < 0) {
370: if (errno == EWOULDBLOCK)
371: goto rewrite;
372: goto done;
373: }
374: bp += wc;
375: cc -= wc;
376: if (cc == 0)
377: goto reread;
378: goto rewrite;
379: done:
380: (void)shutdown(rem, 1);
381: exit(0);
382: }
383:
1.20 ! millert 384: sigprocmask(SIG_SETMASK, &omask, NULL);
1.17 art 385: FD_ZERO(&readfrom);
386: FD_SET(rfd2, &readfrom);
387: FD_SET(rem, &readfrom);
1.1 deraadt 388: do {
1.17 art 389: FD_COPY(&readfrom, &ready);
1.12 deraadt 390: if (select(MAX(rfd2, rem) + 1, &ready, 0, 0, 0) < 0) {
1.1 deraadt 391: if (errno != EINTR) {
392: (void)fprintf(stderr,
393: "rsh: select: %s.\n", strerror(errno));
394: exit(1);
395: }
396: continue;
397: }
1.17 art 398: if (FD_ISSET(rfd2, &ready)) {
1.1 deraadt 399: errno = 0;
400: #ifdef KERBEROS
401: if (doencrypt)
402: cc = des_read(rfd2, buf, sizeof buf);
403: else
404: #endif
405: cc = read(rfd2, buf, sizeof buf);
406: if (cc <= 0) {
407: if (errno != EWOULDBLOCK)
1.17 art 408: FD_CLR(rfd2, &readfrom);
1.1 deraadt 409: } else
410: (void)write(2, buf, cc);
411: }
1.17 art 412: if (FD_ISSET(rem, &ready)) {
1.1 deraadt 413: errno = 0;
414: #ifdef KERBEROS
415: if (doencrypt)
416: cc = des_read(rem, buf, sizeof buf);
417: else
418: #endif
419: cc = read(rem, buf, sizeof buf);
420: if (cc <= 0) {
421: if (errno != EWOULDBLOCK)
1.17 art 422: FD_CLR(rem, &readfrom);
1.1 deraadt 423: } else
424: (void)write(1, buf, cc);
425: }
1.17 art 426: } while (FD_ISSET(rem, &readfrom) || FD_ISSET(rfd2, &readfrom));
1.1 deraadt 427: }
428:
429: void
430: sendsig(signo)
431: char signo;
432: {
1.16 deraadt 433: int save_errno = errno;
434:
1.1 deraadt 435: #ifdef KERBEROS
436: if (doencrypt)
437: (void)des_write(rfd2, &signo, 1);
438: else
439: #endif
440: (void)write(rfd2, &signo, 1);
1.16 deraadt 441: errno = save_errno;
1.1 deraadt 442: }
443:
444: #ifdef KERBEROS
445: /* VARARGS */
1.7 tholo 446: void
1.15 mickey 447: #ifdef __STDC__
1.7 tholo 448: warning(const char *fmt, ...)
449: #else
1.1 deraadt 450: warning(va_alist)
451: va_dcl
1.7 tholo 452: #endif
1.1 deraadt 453: {
454: va_list ap;
1.15 mickey 455: #ifndef __STDC__
1.1 deraadt 456: char *fmt;
1.7 tholo 457: #endif
458: char myrealm[REALM_SZ];
1.1 deraadt 459:
1.7 tholo 460: if (krb_get_lrealm(myrealm, 0) != KSUCCESS)
461: return;
1.1 deraadt 462: (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
1.15 mickey 463: #ifdef __STDC__
1.7 tholo 464: va_start(ap, fmt);
465: #else
1.1 deraadt 466: va_start(ap);
467: fmt = va_arg(ap, char *);
1.7 tholo 468: #endif
1.1 deraadt 469: vfprintf(stderr, fmt, ap);
470: va_end(ap);
471: (void)fprintf(stderr, ".\n");
472: }
473: #endif
474:
475: char *
476: copyargs(argv)
477: char **argv;
478: {
479: register int cc;
480: register char **ap, *p;
481: char *args, *malloc();
482:
483: cc = 0;
484: for (ap = argv; *ap; ++ap)
485: cc += strlen(*ap) + 1;
486: if (!(args = malloc((u_int)cc))) {
487: (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
488: exit(1);
489: }
490: for (p = args, ap = argv; *ap; ++ap) {
491: (void)strcpy(p, *ap);
492: for (p = strcpy(p, *ap); *p; ++p);
493: if (ap[1])
494: *p++ = ' ';
495: }
496: return(args);
497: }
498:
1.17 art 499: void
500: usage(void)
1.1 deraadt 501: {
502: (void)fprintf(stderr,
503: "usage: rsh [-nd%s]%s[-l login] host [command]\n",
504: #ifdef KERBEROS
505: "x", " [-k realm] ");
506: #else
507: "", " ");
508: #endif
509: exit(1);
510: }