Annotation of src/usr.bin/rsh/rsh.c, Revision 1.32
1.32 ! millert 1: /* $OpenBSD: rsh.c,v 1.31 2003/04/08 22:11:56 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.
1.32 ! millert 15: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: #ifndef lint
33: char copyright[] =
34: "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
35: All rights reserved.\n";
36: #endif /* not lint */
37:
38: #ifndef lint
39: /*static char sccsid[] = "from: @(#)rsh.c 5.24 (Berkeley) 7/1/91";*/
1.32 ! millert 40: static char rcsid[] = "$OpenBSD: rsh.c,v 1.31 2003/04/08 22:11:56 millert Exp $";
1.1 deraadt 41: #endif /* not lint */
42:
43: #include <sys/types.h>
44: #include <sys/socket.h>
45: #include <sys/ioctl.h>
46: #include <sys/file.h>
47:
48: #include <netinet/in.h>
49: #include <netdb.h>
50:
51: #include <pwd.h>
52: #include <signal.h>
53: #include <stdio.h>
1.17 art 54: #include <stdlib.h>
55: #include <unistd.h>
1.1 deraadt 56: #include <errno.h>
1.31 millert 57: #include <err.h>
1.1 deraadt 58: #include <string.h>
1.7 tholo 59: #include <stdarg.h>
1.1 deraadt 60: #include "pathnames.h"
61:
62: #ifdef KERBEROS
1.14 provos 63: #include <des.h>
1.1 deraadt 64: #include <kerberosIV/krb.h>
65:
66: CREDENTIALS cred;
67: Key_schedule schedule;
68: int use_kerberos = 1, doencrypt;
69: char dst_realm_buf[REALM_SZ], *dest_realm;
1.7 tholo 70:
1.23 millert 71: void warning(const char *, ...);
72: void desrw_set_key(des_cblock *, des_key_schedule *);
73: int des_read(int, char *, int);
1.29 deraadt 74: int des_write(int, void *, int);
1.17 art 75:
1.23 millert 76: int krcmd(char **, u_short, char *, char *, int *, char *);
1.24 millert 77: int krcmd_mutual(char **, u_short, char *, char *, int *, char *,
78: CREDENTIALS *, Key_schedule);
1.1 deraadt 79: #endif
80:
1.23 millert 81: void usage(void);
1.29 deraadt 82: void sendsig(int);
83: char *copyargs(char **argv);
1.17 art 84:
1.23 millert 85: void talk(int, sigset_t *, int, int);
1.17 art 86:
1.1 deraadt 87: /*
88: * rsh - remote shell
89: */
90: int rfd2;
91:
1.17 art 92: int
1.29 deraadt 93: main(int argc, char *argv[])
1.1 deraadt 94: {
95: extern char *optarg;
96: extern int optind;
97: struct passwd *pw;
98: struct servent *sp;
1.20 millert 99: sigset_t mask, omask;
1.28 mpech 100: int argoff, asrsh, ch, dflag, nflag, one, rem, uid;
1.29 deraadt 101: char *args, *host, *user, *p;
1.28 mpech 102: pid_t pid = 0;
1.1 deraadt 103:
104: argoff = asrsh = dflag = nflag = 0;
105: one = 1;
106: host = user = NULL;
107:
108: /* if called as something other than "rsh", use it as the host name */
1.17 art 109: if ((p = strrchr(argv[0], '/')))
1.1 deraadt 110: ++p;
111: else
112: p = argv[0];
113: if (strcmp(p, "rsh"))
114: host = p;
115: else
116: asrsh = 1;
117:
118: /* handle "rsh host flags" */
119: if (!host && argc > 2 && argv[1][0] != '-') {
120: host = argv[1];
121: argoff = 1;
122: }
123:
124: #ifdef KERBEROS
125: #define OPTIONS "8KLdek:l:nwx"
126: #else
127: #define OPTIONS "8KLdel:nw"
128: #endif
1.11 millert 129: while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
1.1 deraadt 130: switch(ch) {
131: case 'K':
132: #ifdef KERBEROS
133: use_kerberos = 0;
134: #endif
135: break;
136: case 'L': /* -8Lew are ignored to allow rlogin aliases */
137: case 'e':
138: case 'w':
139: case '8':
140: break;
141: case 'd':
142: dflag = 1;
143: break;
144: case 'l':
145: user = optarg;
146: break;
147: #ifdef KERBEROS
148: case 'k':
149: dest_realm = dst_realm_buf;
150: strncpy(dest_realm, optarg, REALM_SZ);
151: break;
152: #endif
153: case 'n':
154: nflag = 1;
155: break;
156: #ifdef KERBEROS
157: case 'x':
158: doencrypt = 1;
1.17 art 159: desrw_set_key(&cred.session, &schedule);
1.1 deraadt 160: break;
161: #endif
162: case '?':
163: default:
164: usage();
165: }
166: optind += argoff;
167:
168: /* if haven't gotten a host yet, do so */
169: if (!host && !(host = argv[optind++]))
170: usage();
171:
1.26 millert 172: /* if no command, login to remote host via rlogin or telnet. */
1.1 deraadt 173: if (!argv[optind]) {
1.26 millert 174: seteuid(getuid());
175: setuid(getuid());
1.1 deraadt 176: if (asrsh)
177: *argv = "rlogin";
178: execv(_PATH_RLOGIN, argv);
1.26 millert 179: if (errno == ENOENT) {
180: if (asrsh)
181: *argv = "telnet";
182: execv(_PATH_TELNET, argv);
183: }
184: (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_TELNET);
1.1 deraadt 185: exit(1);
186: }
187:
188: argc -= optind;
189: argv += optind;
190:
1.8 millert 191: if (geteuid()) {
192: (void)fprintf(stderr, "rsh: must be setuid root.\n");
193: exit(1);
194: }
1.1 deraadt 195: if (!(pw = getpwuid(uid = getuid()))) {
196: (void)fprintf(stderr, "rsh: unknown user id.\n");
197: exit(1);
198: }
199: if (!user)
200: user = pw->pw_name;
201:
202: #ifdef KERBEROS
203: /* -x turns off -n */
204: if (doencrypt)
205: nflag = 0;
206: #endif
207:
208: args = copyargs(argv);
209:
210: sp = NULL;
211: #ifdef KERBEROS
212: if (use_kerberos) {
213: sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
214: if (sp == NULL) {
215: use_kerberos = 0;
216: warning("can't get entry for %s/tcp service",
217: doencrypt ? "ekshell" : "kshell");
218: }
219: }
220: #endif
221: if (sp == NULL)
222: sp = getservbyname("shell", "tcp");
223: if (sp == NULL) {
224: (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
225: exit(1);
226: }
1.9 millert 227:
228: (void) unsetenv("RSH"); /* no tricks with rcmd(3) */
1.1 deraadt 229:
230: #ifdef KERBEROS
231: try_connect:
232: if (use_kerberos) {
233: rem = KSUCCESS;
234: errno = 0;
235: if (dest_realm == NULL)
236: dest_realm = krb_realmofhost(host);
237:
238: if (doencrypt)
239: rem = krcmd_mutual(&host, sp->s_port, user, args,
240: &rfd2, dest_realm, &cred, schedule);
241: else
242: rem = krcmd(&host, sp->s_port, user, args, &rfd2,
243: dest_realm);
244: if (rem < 0) {
245: use_kerberos = 0;
246: sp = getservbyname("shell", "tcp");
247: if (sp == NULL) {
248: (void)fprintf(stderr,
249: "rsh: unknown service shell/tcp.\n");
250: exit(1);
251: }
252: if (errno == ECONNREFUSED)
253: warning("remote host doesn't support Kerberos");
254: if (errno == ENOENT)
255: warning("can't provide Kerberos auth data");
256: goto try_connect;
257: }
258: } else {
259: if (doencrypt) {
260: (void)fprintf(stderr,
261: "rsh: the -x flag requires Kerberos authentication.\n");
262: exit(1);
263: }
1.18 itojun 264: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args,
265: &rfd2, PF_UNSPEC);
1.1 deraadt 266: }
267: #else
1.18 itojun 268: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
269: PF_UNSPEC);
1.1 deraadt 270: #endif
271:
272: if (rem < 0)
273: exit(1);
274:
275: if (rfd2 < 0) {
276: (void)fprintf(stderr, "rsh: can't establish stderr.\n");
277: exit(1);
278: }
279: if (dflag) {
280: if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
281: sizeof(one)) < 0)
282: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
283: strerror(errno));
284: if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
285: sizeof(one)) < 0)
286: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
287: strerror(errno));
288: }
289:
1.10 tholo 290: (void)seteuid(uid);
1.1 deraadt 291: (void)setuid(uid);
1.20 millert 292: sigemptyset(&mask);
293: sigaddset(&mask, SIGINT);
294: sigaddset(&mask, SIGQUIT);
295: sigaddset(&mask, SIGTERM);
296: sigprocmask(SIG_BLOCK, &mask, &omask);
1.1 deraadt 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:
1.20 millert 321: talk(nflag, &omask, pid, rem);
1.1 deraadt 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.29 deraadt 330: talk(int nflag, sigset_t *omask, pid_t pid, int rem)
1.1 deraadt 331: {
1.22 mpech 332: int cc, wc;
333: char *bp;
1.17 art 334: fd_set readfrom, ready, rembits;
1.1 deraadt 335: char buf[BUFSIZ];
336:
337: if (!nflag && pid == 0) {
338: (void)close(rfd2);
339:
340: reread: errno = 0;
341: if ((cc = read(0, buf, sizeof buf)) <= 0)
342: goto done;
343: bp = buf;
344:
1.17 art 345: rewrite: FD_ZERO(&rembits);
1.30 itojun 346: if (rem >= FD_SETSIZE)
347: errx(1, "descriptor too large");
1.17 art 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);
1.30 itojun 382: if (rfd2 >= FD_SETSIZE)
383: errx(1, "descriptor too large");
1.17 art 384: FD_SET(rfd2, &readfrom);
1.30 itojun 385: if (rem >= FD_SETSIZE)
386: errx(1, "descriptor too large");
1.17 art 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
1.29 deraadt 430: sendsig(int signo)
1.1 deraadt 431: {
1.16 deraadt 432: int save_errno = errno;
433:
1.1 deraadt 434: #ifdef KERBEROS
435: if (doencrypt)
436: (void)des_write(rfd2, &signo, 1);
437: else
438: #endif
439: (void)write(rfd2, &signo, 1);
1.16 deraadt 440: errno = save_errno;
1.1 deraadt 441: }
442:
443: #ifdef KERBEROS
444: /* VARARGS */
1.7 tholo 445: void
446: warning(const char *fmt, ...)
1.1 deraadt 447: {
448: va_list ap;
1.7 tholo 449: char myrealm[REALM_SZ];
1.1 deraadt 450:
1.7 tholo 451: if (krb_get_lrealm(myrealm, 0) != KSUCCESS)
452: return;
1.1 deraadt 453: (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
1.7 tholo 454: va_start(ap, fmt);
1.1 deraadt 455: vfprintf(stderr, fmt, ap);
456: va_end(ap);
457: (void)fprintf(stderr, ".\n");
458: }
459: #endif
460:
461: char *
1.29 deraadt 462: copyargs(char **argv)
1.1 deraadt 463: {
1.29 deraadt 464: char **ap, *p, *args;
1.31 millert 465: size_t cc, len;
1.1 deraadt 466:
467: cc = 0;
468: for (ap = argv; *ap; ++ap)
469: cc += strlen(*ap) + 1;
1.31 millert 470: if ((args = malloc(cc)) == NULL)
471: err(1, NULL);
1.1 deraadt 472: for (p = args, ap = argv; *ap; ++ap) {
1.31 millert 473: len = strlcpy(p, *ap, cc);
474: if (len >= cc)
475: errx(1, "copyargs overflow");
476: p += len;
477: cc -= len;
478: if (ap[1]) {
1.1 deraadt 479: *p++ = ' ';
1.31 millert 480: cc--;
481: }
1.1 deraadt 482: }
483: return(args);
484: }
485:
1.17 art 486: void
487: usage(void)
1.1 deraadt 488: {
489: (void)fprintf(stderr,
1.27 hin 490: "usage: rsh [-Kdn%s]%s[-l username] hostname [command]\n",
1.1 deraadt 491: #ifdef KERBEROS
492: "x", " [-k realm] ");
493: #else
494: "", " ");
495: #endif
496: exit(1);
497: }