Annotation of src/usr.bin/rsh/rsh.c, Revision 1.13
1.13 ! deraadt 1: /* $OpenBSD: rsh.c,v 1.12 1997/03/26 19:41:59 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.13 ! deraadt 44: static char rcsid[] = "$OpenBSD: rsh.c,v 1.12 1997/03/26 19:41:59 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>
58: #include <errno.h>
59: #include <string.h>
1.7 tholo 60: #if __STDC__
61: #include <stdarg.h>
62: #else
1.1 deraadt 63: #include <varargs.h>
1.7 tholo 64: #endif
1.1 deraadt 65: #include "pathnames.h"
66:
67: #ifdef KERBEROS
68: #include <kerberosIV/des.h>
69: #include <kerberosIV/krb.h>
70:
71: CREDENTIALS cred;
72: Key_schedule schedule;
73: int use_kerberos = 1, doencrypt;
74: char dst_realm_buf[REALM_SZ], *dest_realm;
1.7 tholo 75:
76: void warning __P((const char *, ...));
1.1 deraadt 77: #endif
78:
79: /*
80: * rsh - remote shell
81: */
82: extern int errno;
83: int rfd2;
84:
85: main(argc, argv)
86: int argc;
87: char **argv;
88: {
89: extern char *optarg;
90: extern int optind;
91: struct passwd *pw;
92: struct servent *sp;
1.13 ! deraadt 93: int omask;
1.1 deraadt 94: int argoff, asrsh, ch, dflag, nflag, one, pid, rem, uid;
95: register char *p;
96: char *args, *host, *user, *copyargs();
97: void sendsig();
98:
99: argoff = asrsh = dflag = nflag = 0;
100: one = 1;
101: host = user = NULL;
102:
103: /* if called as something other than "rsh", use it as the host name */
1.8 millert 104: if (p = strrchr(argv[0], '/'))
1.1 deraadt 105: ++p;
106: else
107: p = argv[0];
108: if (strcmp(p, "rsh"))
109: host = p;
110: else
111: asrsh = 1;
112:
113: /* handle "rsh host flags" */
114: if (!host && argc > 2 && argv[1][0] != '-') {
115: host = argv[1];
116: argoff = 1;
117: }
118:
119: #ifdef KERBEROS
120: #define OPTIONS "8KLdek:l:nwx"
121: #else
122: #define OPTIONS "8KLdel:nw"
123: #endif
1.11 millert 124: while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
1.1 deraadt 125: switch(ch) {
126: case 'K':
127: #ifdef KERBEROS
128: use_kerberos = 0;
129: #endif
130: break;
131: case 'L': /* -8Lew are ignored to allow rlogin aliases */
132: case 'e':
133: case 'w':
134: case '8':
135: break;
136: case 'd':
137: dflag = 1;
138: break;
139: case 'l':
140: user = optarg;
141: break;
142: #ifdef KERBEROS
143: case 'k':
144: dest_realm = dst_realm_buf;
145: strncpy(dest_realm, optarg, REALM_SZ);
146: break;
147: #endif
148: case 'n':
149: nflag = 1;
150: break;
151: #ifdef KERBEROS
152: case 'x':
153: doencrypt = 1;
1.3 tholo 154: desrw_set_key(&cred.session, schedule);
1.1 deraadt 155: break;
156: #endif
157: case '?':
158: default:
159: usage();
160: }
161: optind += argoff;
162:
163: /* if haven't gotten a host yet, do so */
164: if (!host && !(host = argv[optind++]))
165: usage();
166:
167: /* if no further arguments, must have been called as rlogin. */
168: if (!argv[optind]) {
169: if (asrsh)
170: *argv = "rlogin";
1.10 tholo 171: seteuid(getuid());
1.6 deraadt 172: setuid(getuid());
1.1 deraadt 173: execv(_PATH_RLOGIN, argv);
174: (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN);
175: exit(1);
176: }
177:
178: argc -= optind;
179: argv += optind;
180:
1.8 millert 181: if (geteuid()) {
182: (void)fprintf(stderr, "rsh: must be setuid root.\n");
183: exit(1);
184: }
1.1 deraadt 185: if (!(pw = getpwuid(uid = getuid()))) {
186: (void)fprintf(stderr, "rsh: unknown user id.\n");
187: exit(1);
188: }
189: if (!user)
190: user = pw->pw_name;
191:
192: #ifdef KERBEROS
193: /* -x turns off -n */
194: if (doencrypt)
195: nflag = 0;
196: #endif
197:
198: args = copyargs(argv);
199:
200: sp = NULL;
201: #ifdef KERBEROS
202: if (use_kerberos) {
203: sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
204: if (sp == NULL) {
205: use_kerberos = 0;
206: warning("can't get entry for %s/tcp service",
207: doencrypt ? "ekshell" : "kshell");
208: }
209: }
210: #endif
211: if (sp == NULL)
212: sp = getservbyname("shell", "tcp");
213: if (sp == NULL) {
214: (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
215: exit(1);
216: }
1.9 millert 217:
218: (void) unsetenv("RSH"); /* no tricks with rcmd(3) */
1.1 deraadt 219:
220: #ifdef KERBEROS
221: try_connect:
222: if (use_kerberos) {
223: rem = KSUCCESS;
224: errno = 0;
225: if (dest_realm == NULL)
226: dest_realm = krb_realmofhost(host);
227:
228: if (doencrypt)
229: rem = krcmd_mutual(&host, sp->s_port, user, args,
230: &rfd2, dest_realm, &cred, schedule);
231: else
232: rem = krcmd(&host, sp->s_port, user, args, &rfd2,
233: dest_realm);
234: if (rem < 0) {
235: use_kerberos = 0;
236: sp = getservbyname("shell", "tcp");
237: if (sp == NULL) {
238: (void)fprintf(stderr,
239: "rsh: unknown service shell/tcp.\n");
240: exit(1);
241: }
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 {
249: if (doencrypt) {
250: (void)fprintf(stderr,
251: "rsh: the -x flag requires Kerberos authentication.\n");
252: exit(1);
253: }
254: rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
255: }
256: #else
257: rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
258: #endif
259:
260: if (rem < 0)
261: exit(1);
262:
263: if (rfd2 < 0) {
264: (void)fprintf(stderr, "rsh: can't establish stderr.\n");
265: exit(1);
266: }
267: if (dflag) {
268: if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
269: sizeof(one)) < 0)
270: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
271: strerror(errno));
272: if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
273: sizeof(one)) < 0)
274: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
275: strerror(errno));
276: }
277:
1.10 tholo 278: (void)seteuid(uid);
1.1 deraadt 279: (void)setuid(uid);
280: omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
281: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
282: (void)signal(SIGINT, sendsig);
283: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
284: (void)signal(SIGQUIT, sendsig);
285: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
286: (void)signal(SIGTERM, sendsig);
287:
288: if (!nflag) {
289: pid = fork();
290: if (pid < 0) {
291: (void)fprintf(stderr,
292: "rsh: fork: %s.\n", strerror(errno));
293: exit(1);
294: }
295: }
296:
297: #ifdef KERBEROS
298: if (!doencrypt)
299: #endif
300: {
301: (void)ioctl(rfd2, FIONBIO, &one);
302: (void)ioctl(rem, FIONBIO, &one);
303: }
304:
305: talk(nflag, omask, pid, rem);
306:
307: if (!nflag)
308: (void)kill(pid, SIGKILL);
309: exit(0);
310: }
311:
312: talk(nflag, omask, pid, rem)
313: int nflag, pid;
1.13 ! deraadt 314: int omask;
1.1 deraadt 315: register int rem;
316: {
317: register int cc, wc;
318: register char *bp;
319: int readfrom, ready, rembits;
320: char buf[BUFSIZ];
321:
322: if (!nflag && pid == 0) {
323: (void)close(rfd2);
324:
325: reread: errno = 0;
326: if ((cc = read(0, buf, sizeof buf)) <= 0)
327: goto done;
328: bp = buf;
329:
330: rewrite: rembits = 1 << rem;
1.12 deraadt 331: if (select(rem + 1, 0, &rembits, 0, 0) < 0) {
1.1 deraadt 332: if (errno != EINTR) {
333: (void)fprintf(stderr,
334: "rsh: select: %s.\n", strerror(errno));
335: exit(1);
336: }
337: goto rewrite;
338: }
339: if ((rembits & (1 << rem)) == 0)
340: goto rewrite;
341: #ifdef KERBEROS
342: if (doencrypt)
343: wc = des_write(rem, bp, cc);
344: else
345: #endif
346: wc = write(rem, bp, cc);
347: if (wc < 0) {
348: if (errno == EWOULDBLOCK)
349: goto rewrite;
350: goto done;
351: }
352: bp += wc;
353: cc -= wc;
354: if (cc == 0)
355: goto reread;
356: goto rewrite;
357: done:
358: (void)shutdown(rem, 1);
359: exit(0);
360: }
361:
362: (void)sigsetmask(omask);
363: readfrom = (1 << rfd2) | (1 << rem);
364: do {
365: ready = readfrom;
1.12 deraadt 366: if (select(MAX(rfd2, rem) + 1, &ready, 0, 0, 0) < 0) {
1.1 deraadt 367: if (errno != EINTR) {
368: (void)fprintf(stderr,
369: "rsh: select: %s.\n", strerror(errno));
370: exit(1);
371: }
372: continue;
373: }
374: if (ready & (1 << rfd2)) {
375: errno = 0;
376: #ifdef KERBEROS
377: if (doencrypt)
378: cc = des_read(rfd2, buf, sizeof buf);
379: else
380: #endif
381: cc = read(rfd2, buf, sizeof buf);
382: if (cc <= 0) {
383: if (errno != EWOULDBLOCK)
384: readfrom &= ~(1 << rfd2);
385: } else
386: (void)write(2, buf, cc);
387: }
388: if (ready & (1 << rem)) {
389: errno = 0;
390: #ifdef KERBEROS
391: if (doencrypt)
392: cc = des_read(rem, buf, sizeof buf);
393: else
394: #endif
395: cc = read(rem, buf, sizeof buf);
396: if (cc <= 0) {
397: if (errno != EWOULDBLOCK)
398: readfrom &= ~(1 << rem);
399: } else
400: (void)write(1, buf, cc);
401: }
402: } while (readfrom);
403: }
404:
405: void
406: sendsig(signo)
407: char signo;
408: {
409: #ifdef KERBEROS
410: if (doencrypt)
411: (void)des_write(rfd2, &signo, 1);
412: else
413: #endif
414: (void)write(rfd2, &signo, 1);
415: }
416:
417: #ifdef KERBEROS
418: /* VARARGS */
1.7 tholo 419: void
420: #if __STDC__
421: warning(const char *fmt, ...)
422: #else
1.1 deraadt 423: warning(va_alist)
424: va_dcl
1.7 tholo 425: #endif
1.1 deraadt 426: {
427: va_list ap;
1.7 tholo 428: #if !__STDC__
1.1 deraadt 429: char *fmt;
1.7 tholo 430: #endif
431: char myrealm[REALM_SZ];
1.1 deraadt 432:
1.7 tholo 433: if (krb_get_lrealm(myrealm, 0) != KSUCCESS)
434: return;
1.1 deraadt 435: (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
1.7 tholo 436: #if __STDC__
437: va_start(ap, fmt);
438: #else
1.1 deraadt 439: va_start(ap);
440: fmt = va_arg(ap, char *);
1.7 tholo 441: #endif
1.1 deraadt 442: vfprintf(stderr, fmt, ap);
443: va_end(ap);
444: (void)fprintf(stderr, ".\n");
445: }
446: #endif
447:
448: char *
449: copyargs(argv)
450: char **argv;
451: {
452: register int cc;
453: register char **ap, *p;
454: char *args, *malloc();
455:
456: cc = 0;
457: for (ap = argv; *ap; ++ap)
458: cc += strlen(*ap) + 1;
459: if (!(args = malloc((u_int)cc))) {
460: (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
461: exit(1);
462: }
463: for (p = args, ap = argv; *ap; ++ap) {
464: (void)strcpy(p, *ap);
465: for (p = strcpy(p, *ap); *p; ++p);
466: if (ap[1])
467: *p++ = ' ';
468: }
469: return(args);
470: }
471:
472: usage()
473: {
474: (void)fprintf(stderr,
475: "usage: rsh [-nd%s]%s[-l login] host [command]\n",
476: #ifdef KERBEROS
477: "x", " [-k realm] ");
478: #else
479: "", " ");
480: #endif
481: exit(1);
482: }