xref: /original-bsd/usr.bin/rsh/rsh.c (revision 0842ddeb)
1 /*-
2  * Copyright (c) 1983, 1990, 1993, 1994
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, 1994\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.4 (Berkeley) 04/29/95";
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 <err.h>
33 #include <errno.h>
34 #include <pwd.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <varargs.h>
41 
42 #include "pathnames.h"
43 
44 #ifdef KERBEROS
45 #include <kerberosIV/des.h>
46 #include <kerberosIV/krb.h>
47 
48 CREDENTIALS cred;
49 Key_schedule schedule;
50 int use_kerberos = 1, doencrypt;
51 char dst_realm_buf[REALM_SZ], *dest_realm;
52 extern char *krb_realmofhost();
53 #endif
54 
55 /*
56  * rsh - remote shell
57  */
58 int	rfd2;
59 
60 char   *copyargs __P((char **));
61 void	sendsig __P((int));
62 void	talk __P((int, long, pid_t, int));
63 void	usage __P((void));
64 void	warning __P(());
65 
66 int
67 main(argc, argv)
68 	int argc;
69 	char **argv;
70 {
71 	struct passwd *pw;
72 	struct servent *sp;
73 	long omask;
74 	int argoff, asrsh, ch, dflag, nflag, one, rem;
75 	pid_t pid;
76 	uid_t uid;
77 	char *args, *host, *p, *user;
78 
79 	argoff = asrsh = dflag = nflag = 0;
80 	one = 1;
81 	host = user = NULL;
82 
83 	/* if called as something other than "rsh", use it as the host name */
84 	if (p = strrchr(argv[0], '/'))
85 		++p;
86 	else
87 		p = argv[0];
88 	if (strcmp(p, "rsh"))
89 		host = p;
90 	else
91 		asrsh = 1;
92 
93 	/* handle "rsh host flags" */
94 	if (!host && argc > 2 && argv[1][0] != '-') {
95 		host = argv[1];
96 		argoff = 1;
97 	}
98 
99 #ifdef KERBEROS
100 #ifdef CRYPT
101 #define	OPTIONS	"8KLdek:l:nwx"
102 #else
103 #define	OPTIONS	"8KLdek:l:nw"
104 #endif
105 #else
106 #define	OPTIONS	"8KLdel:nw"
107 #endif
108 	while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
109 		switch(ch) {
110 		case 'K':
111 #ifdef KERBEROS
112 			use_kerberos = 0;
113 #endif
114 			break;
115 		case 'L':	/* -8Lew are ignored to allow rlogin aliases */
116 		case 'e':
117 		case 'w':
118 		case '8':
119 			break;
120 		case 'd':
121 			dflag = 1;
122 			break;
123 		case 'l':
124 			user = optarg;
125 			break;
126 #ifdef KERBEROS
127 		case 'k':
128 			dest_realm = dst_realm_buf;
129 			strncpy(dest_realm, optarg, REALM_SZ);
130 			break;
131 #endif
132 		case 'n':
133 			nflag = 1;
134 			break;
135 #ifdef KERBEROS
136 #ifdef CRYPT
137 		case 'x':
138 			doencrypt = 1;
139 			des_set_key(cred.session, schedule);
140 			break;
141 #endif
142 #endif
143 		case '?':
144 		default:
145 			usage();
146 		}
147 	optind += argoff;
148 
149 	/* if haven't gotten a host yet, do so */
150 	if (!host && !(host = argv[optind++]))
151 		usage();
152 
153 	/* if no further arguments, must have been called as rlogin. */
154 	if (!argv[optind]) {
155 		if (asrsh)
156 			*argv = "rlogin";
157 		execv(_PATH_RLOGIN, argv);
158 		err(1, "can't exec %s", _PATH_RLOGIN);
159 	}
160 
161 	argc -= optind;
162 	argv += optind;
163 
164 	if (!(pw = getpwuid(uid = getuid())))
165 		errx(1, "unknown user id");
166 	/* Accept user1@host format, though "-l user2" overrides user1 */
167 	p = strchr(host, '@');
168 	if (p) {
169 		*p = '\0';
170 		if (!user && p > host)
171 			user = host;
172 		host = p + 1;
173 		if (*host == '\0')
174 			usage();
175 	}
176 	if (!user)
177 		user = pw->pw_name;
178 
179 #ifdef KERBEROS
180 #ifdef CRYPT
181 	/* -x turns off -n */
182 	if (doencrypt)
183 		nflag = 0;
184 #endif
185 #endif
186 
187 	args = copyargs(argv);
188 
189 	sp = NULL;
190 #ifdef KERBEROS
191 	if (use_kerberos) {
192 		sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
193 		if (sp == NULL) {
194 			use_kerberos = 0;
195 			warning("can't get entry for %s/tcp service",
196 			    doencrypt ? "ekshell" : "kshell");
197 		}
198 	}
199 #endif
200 	if (sp == NULL)
201 		sp = getservbyname("shell", "tcp");
202 	if (sp == NULL)
203 		errx(1, "shell/tcp: unknown service");
204 
205 #ifdef KERBEROS
206 try_connect:
207 	if (use_kerberos) {
208 		struct hostent *hp;
209 
210 		/* fully qualify hostname (needed for krb_realmofhost) */
211 		hp = gethostbyname(host);
212 		if (hp != NULL && !(host = strdup(hp->h_name)))
213 			err(1, NULL);
214 
215 		rem = KSUCCESS;
216 		errno = 0;
217 		if (dest_realm == NULL)
218 			dest_realm = krb_realmofhost(host);
219 
220 #ifdef CRYPT
221 		if (doencrypt)
222 			rem = krcmd_mutual(&host, sp->s_port, user, args,
223 			    &rfd2, dest_realm, &cred, schedule);
224 		else
225 #endif
226 			rem = krcmd(&host, sp->s_port, user, args, &rfd2,
227 			    dest_realm);
228 		if (rem < 0) {
229 			use_kerberos = 0;
230 			sp = getservbyname("shell", "tcp");
231 			if (sp == NULL)
232 				errx(1, "shell/tcp: unknown service");
233 			if (errno == ECONNREFUSED)
234 				warning("remote host doesn't support Kerberos");
235 			if (errno == ENOENT)
236 				warning("can't provide Kerberos auth data");
237 			goto try_connect;
238 		}
239 	} else {
240 		if (doencrypt)
241 			errx(1, "the -x flag requires Kerberos authentication");
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 		errx(1, "can't establish stderr");
253 	if (dflag) {
254 		if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
255 		    sizeof(one)) < 0)
256 			warn("setsockopt");
257 		if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
258 		    sizeof(one)) < 0)
259 			warn("setsockopt");
260 	}
261 
262 	(void)setuid(uid);
263 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
264 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
265 		(void)signal(SIGINT, sendsig);
266 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
267 		(void)signal(SIGQUIT, sendsig);
268 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
269 		(void)signal(SIGTERM, sendsig);
270 
271 	if (!nflag) {
272 		pid = fork();
273 		if (pid < 0)
274 			err(1, "fork");
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 void
295 talk(nflag, omask, pid, rem)
296 	int nflag;
297 	long omask;
298 	pid_t pid;
299 	int rem;
300 {
301 	int cc, wc;
302 	fd_set readfrom, ready, rembits;
303 	char *bp, buf[BUFSIZ];
304 
305 	if (!nflag && pid == 0) {
306 		(void)close(rfd2);
307 
308 reread:		errno = 0;
309 		if ((cc = read(0, buf, sizeof buf)) <= 0)
310 			goto done;
311 		bp = buf;
312 
313 rewrite:
314 		FD_ZERO(&rembits);
315 		FD_SET(rem, &rembits);
316 		if (select(16, 0, &rembits, 0, 0) < 0) {
317 			if (errno != EINTR)
318 				err(1, "select");
319 			goto rewrite;
320 		}
321 		if (!FD_ISSET(rem, &rembits))
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 	FD_ZERO(&readfrom);
348 	FD_SET(rfd2, &readfrom);
349 	FD_SET(rem, &readfrom);
350 	do {
351 		ready = readfrom;
352 		if (select(16, &ready, 0, 0, 0) < 0) {
353 			if (errno != EINTR)
354 				err(1, "select");
355 			continue;
356 		}
357 		if (FD_ISSET(rfd2, &ready)) {
358 			errno = 0;
359 #ifdef KERBEROS
360 #ifdef CRYPT
361 			if (doencrypt)
362 				cc = des_read(rfd2, buf, sizeof buf);
363 			else
364 #endif
365 #endif
366 				cc = read(rfd2, buf, sizeof buf);
367 			if (cc <= 0) {
368 				if (errno != EWOULDBLOCK)
369 					FD_CLR(rfd2, &readfrom);
370 			} else
371 				(void)write(2, buf, cc);
372 		}
373 		if (FD_ISSET(rem, &ready)) {
374 			errno = 0;
375 #ifdef KERBEROS
376 #ifdef CRYPT
377 			if (doencrypt)
378 				cc = des_read(rem, buf, sizeof buf);
379 			else
380 #endif
381 #endif
382 				cc = read(rem, buf, sizeof buf);
383 			if (cc <= 0) {
384 				if (errno != EWOULDBLOCK)
385 					FD_CLR(rem, &readfrom);
386 			} else
387 				(void)write(1, buf, cc);
388 		}
389 	} while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
390 }
391 
392 void
393 sendsig(sig)
394 	int sig;
395 {
396 	char signo;
397 
398 	signo = sig;
399 #ifdef KERBEROS
400 #ifdef CRYPT
401 	if (doencrypt)
402 		(void)des_write(rfd2, &signo, 1);
403 	else
404 #endif
405 #endif
406 		(void)write(rfd2, &signo, 1);
407 }
408 
409 #ifdef KERBEROS
410 /* VARARGS */
411 void
412 warning(va_alist)
413 va_dcl
414 {
415 	va_list ap;
416 	char *fmt;
417 
418 	(void)fprintf(stderr, "rsh: warning, using standard rsh: ");
419 	va_start(ap);
420 	fmt = va_arg(ap, char *);
421 	vfprintf(stderr, fmt, ap);
422 	va_end(ap);
423 	(void)fprintf(stderr, ".\n");
424 }
425 #endif
426 
427 char *
428 copyargs(argv)
429 	char **argv;
430 {
431 	int cc;
432 	char **ap, *args, *p;
433 
434 	cc = 0;
435 	for (ap = argv; *ap; ++ap)
436 		cc += strlen(*ap) + 1;
437 	if (!(args = malloc((u_int)cc)))
438 		err(1, NULL);
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 void
449 usage()
450 {
451 
452 	(void)fprintf(stderr,
453 	    "usage: rsh [-nd%s]%s[-l login] [login@]host [command]\n",
454 #ifdef KERBEROS
455 #ifdef CRYPT
456 	    "x", " [-k realm] ");
457 #else
458 	    "", " [-k realm] ");
459 #endif
460 #else
461 	    "", " ");
462 #endif
463 	exit(1);
464 }
465