Annotation of src/usr.bin/rsh/rsh.c, Revision 1.28
1.28 ! mpech 1: /* $OpenBSD: rsh.c,v 1.27 2002/06/09 05:50:33 hin 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.28 ! mpech 44: static char rcsid[] = "$OpenBSD: rsh.c,v 1.27 2002/06/09 05:50:33 hin 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.28 ! mpech 103: int argoff, asrsh, ch, dflag, nflag, one, rem, uid;
1.22 mpech 104: char *p;
1.1 deraadt 105: char *args, *host, *user, *copyargs();
1.28 ! mpech 106: pid_t pid = 0;
1.1 deraadt 107: void sendsig();
108:
109: argoff = asrsh = dflag = nflag = 0;
110: one = 1;
111: host = user = NULL;
112:
113: /* if called as something other than "rsh", use it as the host name */
1.17 art 114: if ((p = strrchr(argv[0], '/')))
1.1 deraadt 115: ++p;
116: else
117: p = argv[0];
118: if (strcmp(p, "rsh"))
119: host = p;
120: else
121: asrsh = 1;
122:
123: /* handle "rsh host flags" */
124: if (!host && argc > 2 && argv[1][0] != '-') {
125: host = argv[1];
126: argoff = 1;
127: }
128:
129: #ifdef KERBEROS
130: #define OPTIONS "8KLdek:l:nwx"
131: #else
132: #define OPTIONS "8KLdel:nw"
133: #endif
1.11 millert 134: while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
1.1 deraadt 135: switch(ch) {
136: case 'K':
137: #ifdef KERBEROS
138: use_kerberos = 0;
139: #endif
140: break;
141: case 'L': /* -8Lew are ignored to allow rlogin aliases */
142: case 'e':
143: case 'w':
144: case '8':
145: break;
146: case 'd':
147: dflag = 1;
148: break;
149: case 'l':
150: user = optarg;
151: break;
152: #ifdef KERBEROS
153: case 'k':
154: dest_realm = dst_realm_buf;
155: strncpy(dest_realm, optarg, REALM_SZ);
156: break;
157: #endif
158: case 'n':
159: nflag = 1;
160: break;
161: #ifdef KERBEROS
162: case 'x':
163: doencrypt = 1;
1.17 art 164: desrw_set_key(&cred.session, &schedule);
1.1 deraadt 165: break;
166: #endif
167: case '?':
168: default:
169: usage();
170: }
171: optind += argoff;
172:
173: /* if haven't gotten a host yet, do so */
174: if (!host && !(host = argv[optind++]))
175: usage();
176:
1.26 millert 177: /* if no command, login to remote host via rlogin or telnet. */
1.1 deraadt 178: if (!argv[optind]) {
1.26 millert 179: seteuid(getuid());
180: setuid(getuid());
1.1 deraadt 181: if (asrsh)
182: *argv = "rlogin";
183: execv(_PATH_RLOGIN, argv);
1.26 millert 184: if (errno == ENOENT) {
185: if (asrsh)
186: *argv = "telnet";
187: execv(_PATH_TELNET, argv);
188: }
189: (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_TELNET);
1.1 deraadt 190: exit(1);
191: }
192:
193: argc -= optind;
194: argv += optind;
195:
1.8 millert 196: if (geteuid()) {
197: (void)fprintf(stderr, "rsh: must be setuid root.\n");
198: exit(1);
199: }
1.1 deraadt 200: if (!(pw = getpwuid(uid = getuid()))) {
201: (void)fprintf(stderr, "rsh: unknown user id.\n");
202: exit(1);
203: }
204: if (!user)
205: user = pw->pw_name;
206:
207: #ifdef KERBEROS
208: /* -x turns off -n */
209: if (doencrypt)
210: nflag = 0;
211: #endif
212:
213: args = copyargs(argv);
214:
215: sp = NULL;
216: #ifdef KERBEROS
217: if (use_kerberos) {
218: sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
219: if (sp == NULL) {
220: use_kerberos = 0;
221: warning("can't get entry for %s/tcp service",
222: doencrypt ? "ekshell" : "kshell");
223: }
224: }
225: #endif
226: if (sp == NULL)
227: sp = getservbyname("shell", "tcp");
228: if (sp == NULL) {
229: (void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
230: exit(1);
231: }
1.9 millert 232:
233: (void) unsetenv("RSH"); /* no tricks with rcmd(3) */
1.1 deraadt 234:
235: #ifdef KERBEROS
236: try_connect:
237: if (use_kerberos) {
238: rem = KSUCCESS;
239: errno = 0;
240: if (dest_realm == NULL)
241: dest_realm = krb_realmofhost(host);
242:
243: if (doencrypt)
244: rem = krcmd_mutual(&host, sp->s_port, user, args,
245: &rfd2, dest_realm, &cred, schedule);
246: else
247: rem = krcmd(&host, sp->s_port, user, args, &rfd2,
248: dest_realm);
249: if (rem < 0) {
250: use_kerberos = 0;
251: sp = getservbyname("shell", "tcp");
252: if (sp == NULL) {
253: (void)fprintf(stderr,
254: "rsh: unknown service shell/tcp.\n");
255: exit(1);
256: }
257: if (errno == ECONNREFUSED)
258: warning("remote host doesn't support Kerberos");
259: if (errno == ENOENT)
260: warning("can't provide Kerberos auth data");
261: goto try_connect;
262: }
263: } else {
264: if (doencrypt) {
265: (void)fprintf(stderr,
266: "rsh: the -x flag requires Kerberos authentication.\n");
267: exit(1);
268: }
1.18 itojun 269: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args,
270: &rfd2, PF_UNSPEC);
1.1 deraadt 271: }
272: #else
1.18 itojun 273: rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
274: PF_UNSPEC);
1.1 deraadt 275: #endif
276:
277: if (rem < 0)
278: exit(1);
279:
280: if (rfd2 < 0) {
281: (void)fprintf(stderr, "rsh: can't establish stderr.\n");
282: exit(1);
283: }
284: if (dflag) {
285: if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
286: sizeof(one)) < 0)
287: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
288: strerror(errno));
289: if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
290: sizeof(one)) < 0)
291: (void)fprintf(stderr, "rsh: setsockopt: %s.\n",
292: strerror(errno));
293: }
294:
1.10 tholo 295: (void)seteuid(uid);
1.1 deraadt 296: (void)setuid(uid);
1.20 millert 297: sigemptyset(&mask);
298: sigaddset(&mask, SIGINT);
299: sigaddset(&mask, SIGQUIT);
300: sigaddset(&mask, SIGTERM);
301: sigprocmask(SIG_BLOCK, &mask, &omask);
1.1 deraadt 302: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
303: (void)signal(SIGINT, sendsig);
304: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
305: (void)signal(SIGQUIT, sendsig);
306: if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
307: (void)signal(SIGTERM, sendsig);
308:
309: if (!nflag) {
310: pid = fork();
311: if (pid < 0) {
312: (void)fprintf(stderr,
313: "rsh: fork: %s.\n", strerror(errno));
314: exit(1);
315: }
316: }
317:
318: #ifdef KERBEROS
319: if (!doencrypt)
320: #endif
321: {
322: (void)ioctl(rfd2, FIONBIO, &one);
323: (void)ioctl(rem, FIONBIO, &one);
324: }
325:
1.20 millert 326: talk(nflag, &omask, pid, rem);
1.1 deraadt 327:
328: if (!nflag)
329: (void)kill(pid, SIGKILL);
1.17 art 330:
331: return 0;
1.1 deraadt 332: }
333:
1.17 art 334: void
1.1 deraadt 335: talk(nflag, omask, pid, rem)
1.28 ! mpech 336: int nflag;
1.20 millert 337: sigset_t *omask;
1.28 ! mpech 338: pid_t pid;
1.22 mpech 339: int rem;
1.1 deraadt 340: {
1.22 mpech 341: int cc, wc;
342: char *bp;
1.17 art 343: fd_set readfrom, ready, rembits;
1.1 deraadt 344: char buf[BUFSIZ];
345:
346: if (!nflag && pid == 0) {
347: (void)close(rfd2);
348:
349: reread: errno = 0;
350: if ((cc = read(0, buf, sizeof buf)) <= 0)
351: goto done;
352: bp = buf;
353:
1.17 art 354: rewrite: FD_ZERO(&rembits);
355: FD_SET(rem, &rembits);
1.12 deraadt 356: if (select(rem + 1, 0, &rembits, 0, 0) < 0) {
1.1 deraadt 357: if (errno != EINTR) {
358: (void)fprintf(stderr,
359: "rsh: select: %s.\n", strerror(errno));
360: exit(1);
361: }
362: goto rewrite;
363: }
1.17 art 364: if (!FD_ISSET(rem, &rembits))
1.1 deraadt 365: goto rewrite;
366: #ifdef KERBEROS
367: if (doencrypt)
368: wc = des_write(rem, bp, cc);
369: else
370: #endif
371: wc = write(rem, bp, cc);
372: if (wc < 0) {
373: if (errno == EWOULDBLOCK)
374: goto rewrite;
375: goto done;
376: }
377: bp += wc;
378: cc -= wc;
379: if (cc == 0)
380: goto reread;
381: goto rewrite;
382: done:
383: (void)shutdown(rem, 1);
384: exit(0);
385: }
386:
1.21 deraadt 387: sigprocmask(SIG_SETMASK, omask, NULL);
1.17 art 388: FD_ZERO(&readfrom);
389: FD_SET(rfd2, &readfrom);
390: FD_SET(rem, &readfrom);
1.1 deraadt 391: do {
1.17 art 392: FD_COPY(&readfrom, &ready);
1.12 deraadt 393: if (select(MAX(rfd2, rem) + 1, &ready, 0, 0, 0) < 0) {
1.1 deraadt 394: if (errno != EINTR) {
395: (void)fprintf(stderr,
396: "rsh: select: %s.\n", strerror(errno));
397: exit(1);
398: }
399: continue;
400: }
1.17 art 401: if (FD_ISSET(rfd2, &ready)) {
1.1 deraadt 402: errno = 0;
403: #ifdef KERBEROS
404: if (doencrypt)
405: cc = des_read(rfd2, buf, sizeof buf);
406: else
407: #endif
408: cc = read(rfd2, buf, sizeof buf);
409: if (cc <= 0) {
410: if (errno != EWOULDBLOCK)
1.17 art 411: FD_CLR(rfd2, &readfrom);
1.1 deraadt 412: } else
413: (void)write(2, buf, cc);
414: }
1.17 art 415: if (FD_ISSET(rem, &ready)) {
1.1 deraadt 416: errno = 0;
417: #ifdef KERBEROS
418: if (doencrypt)
419: cc = des_read(rem, buf, sizeof buf);
420: else
421: #endif
422: cc = read(rem, buf, sizeof buf);
423: if (cc <= 0) {
424: if (errno != EWOULDBLOCK)
1.17 art 425: FD_CLR(rem, &readfrom);
1.1 deraadt 426: } else
427: (void)write(1, buf, cc);
428: }
1.17 art 429: } while (FD_ISSET(rem, &readfrom) || FD_ISSET(rfd2, &readfrom));
1.1 deraadt 430: }
431:
432: void
433: sendsig(signo)
434: char signo;
435: {
1.16 deraadt 436: int save_errno = errno;
437:
1.1 deraadt 438: #ifdef KERBEROS
439: if (doencrypt)
440: (void)des_write(rfd2, &signo, 1);
441: else
442: #endif
443: (void)write(rfd2, &signo, 1);
1.16 deraadt 444: errno = save_errno;
1.1 deraadt 445: }
446:
447: #ifdef KERBEROS
448: /* VARARGS */
1.7 tholo 449: void
450: warning(const char *fmt, ...)
1.1 deraadt 451: {
452: va_list ap;
1.7 tholo 453: char myrealm[REALM_SZ];
1.1 deraadt 454:
1.7 tholo 455: if (krb_get_lrealm(myrealm, 0) != KSUCCESS)
456: return;
1.1 deraadt 457: (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
1.7 tholo 458: va_start(ap, fmt);
1.1 deraadt 459: vfprintf(stderr, fmt, ap);
460: va_end(ap);
461: (void)fprintf(stderr, ".\n");
462: }
463: #endif
464:
465: char *
466: copyargs(argv)
467: char **argv;
468: {
1.22 mpech 469: int cc;
470: char **ap, *p;
1.1 deraadt 471: char *args, *malloc();
472:
473: cc = 0;
474: for (ap = argv; *ap; ++ap)
475: cc += strlen(*ap) + 1;
476: if (!(args = malloc((u_int)cc))) {
477: (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
478: exit(1);
479: }
480: for (p = args, ap = argv; *ap; ++ap) {
481: (void)strcpy(p, *ap);
482: for (p = strcpy(p, *ap); *p; ++p);
483: if (ap[1])
484: *p++ = ' ';
485: }
486: return(args);
487: }
488:
1.17 art 489: void
490: usage(void)
1.1 deraadt 491: {
492: (void)fprintf(stderr,
1.27 hin 493: "usage: rsh [-Kdn%s]%s[-l username] hostname [command]\n",
1.1 deraadt 494: #ifdef KERBEROS
495: "x", " [-k realm] ");
496: #else
497: "", " ");
498: #endif
499: exit(1);
500: }