Annotation of src/usr.bin/rsh/rsh.c, Revision 1.33
1.33 ! millert 1: /* $OpenBSD: rsh.c,v 1.32 2003/06/03 02:56:15 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
1.33 ! millert 33: static const char copyright[] =
1.1 deraadt 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
1.33 ! millert 39: /*static const char sccsid[] = "from: @(#)rsh.c 5.24 (Berkeley) 7/1/91";*/
! 40: static const char rcsid[] = "$OpenBSD: rsh.c,v 1.32 2003/06/03 02:56:15 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: }
1.33 ! millert 184: errx(1, "can't exec %s", _PATH_TELNET);
1.1 deraadt 185: }
186:
187: argc -= optind;
188: argv += optind;
189:
1.33 ! millert 190: if (geteuid() != 0)
! 191: errx(1, "must be setuid root");
! 192: if (!(pw = getpwuid(uid = getuid())))
! 193: errx(1, "unknown user ID %u", uid);
1.1 deraadt 194: if (!user)
195: user = pw->pw_name;
196:
197: #ifdef KERBEROS
198: /* -x turns off -n */
199: if (doencrypt)
200: nflag = 0;
201: #endif
202:
203: args = copyargs(argv);
204:
205: sp = NULL;
206: #ifdef KERBEROS
207: if (use_kerberos) {
208: sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
209: if (sp == NULL) {
210: use_kerberos = 0;
211: warning("can't get entry for %s/tcp service",
212: doencrypt ? "ekshell" : "kshell");
213: }
214: }
215: #endif
216: if (sp == NULL)
217: sp = getservbyname("shell", "tcp");
1.33 ! millert 218: if (sp == NULL)
! 219: errx(1, "shell/tcp: unknown service");
1.9 millert 220:
221: (void) unsetenv("RSH"); /* no tricks with rcmd(3) */
1.1 deraadt 222:
223: #ifdef KERBEROS
224: try_connect:
225: if (use_kerberos) {
226: rem = KSUCCESS;
227: errno = 0;
228: if (dest_realm == NULL)
229: dest_realm = krb_realmofhost(host);
230:
231: if (doencrypt)
232: rem = krcmd_mutual(&host, sp->s_port, user, args,
233: &rfd2, dest_realm, &cred, schedule);
234: else
235: rem = krcmd(&host, sp->s_port, user, args, &rfd2,
236: dest_realm);
237: if (rem < 0) {
238: use_kerberos = 0;
239: sp = getservbyname("shell", "tcp");
1.33 ! millert 240: if (sp == NULL)
! 241: errx(1, "unknown service shell/tcp");
1.1 deraadt 242: if (errno == ECONNREFUSED)
243: warning("remote host doesn't support Kerberos");
244: if (errno == ENOENT)
245: warning("can't provide Kerberos auth data");
246: goto try_connect;
247: }
248: } else {
1.33 ! millert 249: if (doencrypt)
! 250: errx("the -x flag requires Kerberos authentication");
1.18 itojun 251: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args,
252: &rfd2, PF_UNSPEC);
1.1 deraadt 253: }
254: #else
1.18 itojun 255: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
256: PF_UNSPEC);
1.1 deraadt 257: #endif
258:
259: if (rem < 0)
260: exit(1);
261:
1.33 ! millert 262: if (rfd2 < 0)
! 263: errx(1, "can't establish stderr");
1.1 deraadt 264: if (dflag) {
265: if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
266: sizeof(one)) < 0)
1.33 ! millert 267: warn("setsockopt");
1.1 deraadt 268: if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
269: sizeof(one)) < 0)
1.33 ! millert 270: warn("setsockopt");
1.1 deraadt 271: }
272:
1.10 tholo 273: (void)seteuid(uid);
1.1 deraadt 274: (void)setuid(uid);
1.20 millert 275: sigemptyset(&mask);
276: sigaddset(&mask, SIGINT);
277: sigaddset(&mask, SIGQUIT);
278: sigaddset(&mask, SIGTERM);
279: sigprocmask(SIG_BLOCK, &mask, &omask);
1.1 deraadt 280: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
281: (void)signal(SIGINT, sendsig);
282: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
283: (void)signal(SIGQUIT, sendsig);
284: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
285: (void)signal(SIGTERM, sendsig);
286:
287: if (!nflag) {
1.33 ! millert 288: if ((pid = fork()) < 0)
! 289: err(1, "fork");
1.1 deraadt 290: }
291:
292: #ifdef KERBEROS
293: if (!doencrypt)
294: #endif
295: {
296: (void)ioctl(rfd2, FIONBIO, &one);
297: (void)ioctl(rem, FIONBIO, &one);
298: }
299:
1.20 millert 300: talk(nflag, &omask, pid, rem);
1.1 deraadt 301:
302: if (!nflag)
303: (void)kill(pid, SIGKILL);
1.17 art 304:
305: return 0;
1.1 deraadt 306: }
307:
1.17 art 308: void
1.29 deraadt 309: talk(int nflag, sigset_t *omask, pid_t pid, int rem)
1.1 deraadt 310: {
1.22 mpech 311: int cc, wc;
312: char *bp;
1.17 art 313: fd_set readfrom, ready, rembits;
1.1 deraadt 314: char buf[BUFSIZ];
315:
316: if (!nflag && pid == 0) {
317: (void)close(rfd2);
318:
319: reread: errno = 0;
320: if ((cc = read(0, buf, sizeof buf)) <= 0)
321: goto done;
322: bp = buf;
323:
1.17 art 324: rewrite: FD_ZERO(&rembits);
1.30 itojun 325: if (rem >= FD_SETSIZE)
326: errx(1, "descriptor too large");
1.17 art 327: FD_SET(rem, &rembits);
1.12 deraadt 328: if (select(rem + 1, 0, &rembits, 0, 0) < 0) {
1.33 ! millert 329: if (errno != EINTR)
! 330: err(1, "select");
1.1 deraadt 331: goto rewrite;
332: }
1.17 art 333: if (!FD_ISSET(rem, &rembits))
1.1 deraadt 334: goto rewrite;
335: #ifdef KERBEROS
336: if (doencrypt)
337: wc = des_write(rem, bp, cc);
338: else
339: #endif
340: wc = write(rem, bp, cc);
341: if (wc < 0) {
342: if (errno == EWOULDBLOCK)
343: goto rewrite;
344: goto done;
345: }
346: bp += wc;
347: cc -= wc;
348: if (cc == 0)
349: goto reread;
350: goto rewrite;
351: done:
352: (void)shutdown(rem, 1);
353: exit(0);
354: }
355:
1.21 deraadt 356: sigprocmask(SIG_SETMASK, omask, NULL);
1.17 art 357: FD_ZERO(&readfrom);
1.30 itojun 358: if (rfd2 >= FD_SETSIZE)
359: errx(1, "descriptor too large");
1.17 art 360: FD_SET(rfd2, &readfrom);
1.30 itojun 361: if (rem >= FD_SETSIZE)
362: errx(1, "descriptor too large");
1.17 art 363: FD_SET(rem, &readfrom);
1.1 deraadt 364: do {
1.17 art 365: FD_COPY(&readfrom, &ready);
1.12 deraadt 366: if (select(MAX(rfd2, rem) + 1, &ready, 0, 0, 0) < 0) {
1.33 ! millert 367: if (errno != EINTR)
! 368: err(1, "select");
1.1 deraadt 369: continue;
370: }
1.17 art 371: if (FD_ISSET(rfd2, &ready)) {
1.1 deraadt 372: errno = 0;
373: #ifdef KERBEROS
374: if (doencrypt)
375: cc = des_read(rfd2, buf, sizeof buf);
376: else
377: #endif
378: cc = read(rfd2, buf, sizeof buf);
379: if (cc <= 0) {
380: if (errno != EWOULDBLOCK)
1.17 art 381: FD_CLR(rfd2, &readfrom);
1.1 deraadt 382: } else
383: (void)write(2, buf, cc);
384: }
1.17 art 385: if (FD_ISSET(rem, &ready)) {
1.1 deraadt 386: errno = 0;
387: #ifdef KERBEROS
388: if (doencrypt)
389: cc = des_read(rem, buf, sizeof buf);
390: else
391: #endif
392: cc = read(rem, buf, sizeof buf);
393: if (cc <= 0) {
394: if (errno != EWOULDBLOCK)
1.17 art 395: FD_CLR(rem, &readfrom);
1.1 deraadt 396: } else
397: (void)write(1, buf, cc);
398: }
1.17 art 399: } while (FD_ISSET(rem, &readfrom) || FD_ISSET(rfd2, &readfrom));
1.1 deraadt 400: }
401:
402: void
1.29 deraadt 403: sendsig(int signo)
1.1 deraadt 404: {
1.16 deraadt 405: int save_errno = errno;
406:
1.1 deraadt 407: #ifdef KERBEROS
408: if (doencrypt)
409: (void)des_write(rfd2, &signo, 1);
410: else
411: #endif
412: (void)write(rfd2, &signo, 1);
1.16 deraadt 413: errno = save_errno;
1.1 deraadt 414: }
415:
416: #ifdef KERBEROS
417: /* VARARGS */
1.7 tholo 418: void
419: warning(const char *fmt, ...)
1.1 deraadt 420: {
421: va_list ap;
1.7 tholo 422: char myrealm[REALM_SZ];
1.1 deraadt 423:
1.7 tholo 424: if (krb_get_lrealm(myrealm, 0) != KSUCCESS)
425: return;
1.1 deraadt 426: (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
1.7 tholo 427: va_start(ap, fmt);
1.1 deraadt 428: vfprintf(stderr, fmt, ap);
429: va_end(ap);
430: (void)fprintf(stderr, ".\n");
431: }
432: #endif
433:
434: char *
1.29 deraadt 435: copyargs(char **argv)
1.1 deraadt 436: {
1.29 deraadt 437: char **ap, *p, *args;
1.31 millert 438: size_t cc, len;
1.1 deraadt 439:
440: cc = 0;
441: for (ap = argv; *ap; ++ap)
442: cc += strlen(*ap) + 1;
1.31 millert 443: if ((args = malloc(cc)) == NULL)
444: err(1, NULL);
1.1 deraadt 445: for (p = args, ap = argv; *ap; ++ap) {
1.31 millert 446: len = strlcpy(p, *ap, cc);
447: if (len >= cc)
448: errx(1, "copyargs overflow");
449: p += len;
450: cc -= len;
451: if (ap[1]) {
1.1 deraadt 452: *p++ = ' ';
1.31 millert 453: cc--;
454: }
1.1 deraadt 455: }
456: return(args);
457: }
458:
1.17 art 459: void
460: usage(void)
1.1 deraadt 461: {
462: (void)fprintf(stderr,
1.27 hin 463: "usage: rsh [-Kdn%s]%s[-l username] hostname [command]\n",
1.1 deraadt 464: #ifdef KERBEROS
465: "x", " [-k realm] ");
466: #else
467: "", " ");
468: #endif
469: exit(1);
470: }