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