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