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