Annotation of src/usr.bin/rsh/rsh.c, Revision 1.1.1.1
1.1 deraadt 1: /*-
2: * Copyright (c) 1983, 1990 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
34: #ifndef lint
35: char copyright[] =
36: "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
37: All rights reserved.\n";
38: #endif /* not lint */
39:
40: #ifndef lint
41: /*static char sccsid[] = "from: @(#)rsh.c 5.24 (Berkeley) 7/1/91";*/
42: static char rcsid[] = "$Id: rsh.c,v 1.3 1995/06/27 00:31:00 jtc Exp $";
43: #endif /* not lint */
44:
45: /*
46: * $Source: /a/cvsroot/src/usr.bin/rsh/rsh.c,v $
47: * $Header: /a/cvsroot/src/usr.bin/rsh/rsh.c,v 1.3 1995/06/27 00:31:00 jtc Exp $
48: */
49:
50: #include <sys/types.h>
51: #include <sys/socket.h>
52: #include <sys/ioctl.h>
53: #include <sys/file.h>
54:
55: #include <netinet/in.h>
56: #include <netdb.h>
57:
58: #include <pwd.h>
59: #include <signal.h>
60: #include <stdio.h>
61: #include <errno.h>
62: #include <string.h>
63: #include <varargs.h>
64: #include "pathnames.h"
65:
66: #ifdef KERBEROS
67: #include <kerberosIV/des.h>
68: #include <kerberosIV/krb.h>
69:
70: CREDENTIALS cred;
71: Key_schedule schedule;
72: int use_kerberos = 1, doencrypt;
73: char dst_realm_buf[REALM_SZ], *dest_realm;
74: extern char *krb_realmofhost();
75: #endif
76:
77: /*
78: * rsh - remote shell
79: */
80: extern int errno;
81: int rfd2;
82:
83: main(argc, argv)
84: int argc;
85: char **argv;
86: {
87: extern char *optarg;
88: extern int optind;
89: struct passwd *pw;
90: struct servent *sp;
91: long omask;
92: int argoff, asrsh, ch, dflag, nflag, one, pid, rem, uid;
93: register char *p;
94: char *args, *host, *user, *copyargs();
95: void sendsig();
96:
97: argoff = asrsh = dflag = nflag = 0;
98: one = 1;
99: host = user = NULL;
100:
101: /* if called as something other than "rsh", use it as the host name */
102: if (p = rindex(argv[0], '/'))
103: ++p;
104: else
105: p = argv[0];
106: if (strcmp(p, "rsh"))
107: host = p;
108: else
109: asrsh = 1;
110:
111: /* handle "rsh host flags" */
112: if (!host && argc > 2 && argv[1][0] != '-') {
113: host = argv[1];
114: argoff = 1;
115: }
116:
117: #ifdef KERBEROS
118: #ifdef CRYPT
119: #define OPTIONS "8KLdek:l:nwx"
120: #else
121: #define OPTIONS "8KLdek:l:nw"
122: #endif
123: #else
124: #define OPTIONS "8KLdel:nw"
125: #endif
126: while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
127: switch(ch) {
128: case 'K':
129: #ifdef KERBEROS
130: use_kerberos = 0;
131: #endif
132: break;
133: case 'L': /* -8Lew are ignored to allow rlogin aliases */
134: case 'e':
135: case 'w':
136: case '8':
137: break;
138: case 'd':
139: dflag = 1;
140: break;
141: case 'l':
142: user = optarg;
143: break;
144: #ifdef KERBEROS
145: case 'k':
146: dest_realm = dst_realm_buf;
147: strncpy(dest_realm, optarg, REALM_SZ);
148: break;
149: #endif
150: case 'n':
151: nflag = 1;
152: break;
153: #ifdef KERBEROS
154: #ifdef CRYPT
155: case 'x':
156: doencrypt = 1;
157: des_set_key(cred.session, schedule);
158: break;
159: #endif
160: #endif
161: case '?':
162: default:
163: usage();
164: }
165: optind += argoff;
166:
167: /* if haven't gotten a host yet, do so */
168: if (!host && !(host = argv[optind++]))
169: usage();
170:
171: /* if no further arguments, must have been called as rlogin. */
172: if (!argv[optind]) {
173: if (asrsh)
174: *argv = "rlogin";
175: execv(_PATH_RLOGIN, argv);
176: (void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN);
177: exit(1);
178: }
179:
180: argc -= optind;
181: argv += optind;
182:
183: if (!(pw = getpwuid(uid = getuid()))) {
184: (void)fprintf(stderr, "rsh: unknown user id.\n");
185: exit(1);
186: }
187: if (!user)
188: user = pw->pw_name;
189:
190: #ifdef KERBEROS
191: #ifdef CRYPT
192: /* -x turns off -n */
193: if (doencrypt)
194: nflag = 0;
195: #endif
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: }
217:
218: #ifdef KERBEROS
219: try_connect:
220: if (use_kerberos) {
221: rem = KSUCCESS;
222: errno = 0;
223: if (dest_realm == NULL)
224: dest_realm = krb_realmofhost(host);
225:
226: #ifdef CRYPT
227: if (doencrypt)
228: rem = krcmd_mutual(&host, sp->s_port, user, args,
229: &rfd2, dest_realm, &cred, schedule);
230: else
231: #endif
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:
278: (void)setuid(uid);
279: omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
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) {
288: pid = fork();
289: if (pid < 0) {
290: (void)fprintf(stderr,
291: "rsh: fork: %s.\n", strerror(errno));
292: exit(1);
293: }
294: }
295:
296: #ifdef KERBEROS
297: #ifdef CRYPT
298: if (!doencrypt)
299: #endif
300: #endif
301: {
302: (void)ioctl(rfd2, FIONBIO, &one);
303: (void)ioctl(rem, FIONBIO, &one);
304: }
305:
306: talk(nflag, omask, pid, rem);
307:
308: if (!nflag)
309: (void)kill(pid, SIGKILL);
310: exit(0);
311: }
312:
313: talk(nflag, omask, pid, rem)
314: int nflag, pid;
315: long omask;
316: register int rem;
317: {
318: register int cc, wc;
319: register char *bp;
320: int readfrom, ready, rembits;
321: char buf[BUFSIZ];
322:
323: if (!nflag && pid == 0) {
324: (void)close(rfd2);
325:
326: reread: errno = 0;
327: if ((cc = read(0, buf, sizeof buf)) <= 0)
328: goto done;
329: bp = buf;
330:
331: rewrite: rembits = 1 << rem;
332: if (select(16, 0, &rembits, 0, 0) < 0) {
333: if (errno != EINTR) {
334: (void)fprintf(stderr,
335: "rsh: select: %s.\n", strerror(errno));
336: exit(1);
337: }
338: goto rewrite;
339: }
340: if ((rembits & (1 << rem)) == 0)
341: goto rewrite;
342: #ifdef KERBEROS
343: #ifdef CRYPT
344: if (doencrypt)
345: wc = des_write(rem, bp, cc);
346: else
347: #endif
348: #endif
349: wc = write(rem, bp, cc);
350: if (wc < 0) {
351: if (errno == EWOULDBLOCK)
352: goto rewrite;
353: goto done;
354: }
355: bp += wc;
356: cc -= wc;
357: if (cc == 0)
358: goto reread;
359: goto rewrite;
360: done:
361: (void)shutdown(rem, 1);
362: exit(0);
363: }
364:
365: (void)sigsetmask(omask);
366: readfrom = (1 << rfd2) | (1 << rem);
367: do {
368: ready = readfrom;
369: if (select(16, &ready, 0, 0, 0) < 0) {
370: if (errno != EINTR) {
371: (void)fprintf(stderr,
372: "rsh: select: %s.\n", strerror(errno));
373: exit(1);
374: }
375: continue;
376: }
377: if (ready & (1 << rfd2)) {
378: errno = 0;
379: #ifdef KERBEROS
380: #ifdef CRYPT
381: if (doencrypt)
382: cc = des_read(rfd2, buf, sizeof buf);
383: else
384: #endif
385: #endif
386: cc = read(rfd2, buf, sizeof buf);
387: if (cc <= 0) {
388: if (errno != EWOULDBLOCK)
389: readfrom &= ~(1 << rfd2);
390: } else
391: (void)write(2, buf, cc);
392: }
393: if (ready & (1 << rem)) {
394: errno = 0;
395: #ifdef KERBEROS
396: #ifdef CRYPT
397: if (doencrypt)
398: cc = des_read(rem, buf, sizeof buf);
399: else
400: #endif
401: #endif
402: cc = read(rem, buf, sizeof buf);
403: if (cc <= 0) {
404: if (errno != EWOULDBLOCK)
405: readfrom &= ~(1 << rem);
406: } else
407: (void)write(1, buf, cc);
408: }
409: } while (readfrom);
410: }
411:
412: void
413: sendsig(signo)
414: char signo;
415: {
416: #ifdef KERBEROS
417: #ifdef CRYPT
418: if (doencrypt)
419: (void)des_write(rfd2, &signo, 1);
420: else
421: #endif
422: #endif
423: (void)write(rfd2, &signo, 1);
424: }
425:
426: #ifdef KERBEROS
427: /* VARARGS */
428: warning(va_alist)
429: va_dcl
430: {
431: va_list ap;
432: char *fmt;
433:
434: (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
435: va_start(ap);
436: fmt = va_arg(ap, char *);
437: vfprintf(stderr, fmt, ap);
438: va_end(ap);
439: (void)fprintf(stderr, ".\n");
440: }
441: #endif
442:
443: char *
444: copyargs(argv)
445: char **argv;
446: {
447: register int cc;
448: register char **ap, *p;
449: char *args, *malloc();
450:
451: cc = 0;
452: for (ap = argv; *ap; ++ap)
453: cc += strlen(*ap) + 1;
454: if (!(args = malloc((u_int)cc))) {
455: (void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
456: exit(1);
457: }
458: for (p = args, ap = argv; *ap; ++ap) {
459: (void)strcpy(p, *ap);
460: for (p = strcpy(p, *ap); *p; ++p);
461: if (ap[1])
462: *p++ = ' ';
463: }
464: return(args);
465: }
466:
467: usage()
468: {
469: (void)fprintf(stderr,
470: "usage: rsh [-nd%s]%s[-l login] host [command]\n",
471: #ifdef KERBEROS
472: #ifdef CRYPT
473: "x", " [-k realm] ");
474: #else
475: "", " [-k realm] ");
476: #endif
477: #else
478: "", " ");
479: #endif
480: exit(1);
481: }