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