xref: /original-bsd/usr.bin/rsh/rsh.c (revision e58c8952)
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.3 (Berkeley) 04/06/94";
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 	if (!user)
167 		user = pw->pw_name;
168 
169 #ifdef KERBEROS
170 #ifdef CRYPT
171 	/* -x turns off -n */
172 	if (doencrypt)
173 		nflag = 0;
174 #endif
175 #endif
176 
177 	args = copyargs(argv);
178 
179 	sp = NULL;
180 #ifdef KERBEROS
181 	if (use_kerberos) {
182 		sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
183 		if (sp == NULL) {
184 			use_kerberos = 0;
185 			warning("can't get entry for %s/tcp service",
186 			    doencrypt ? "ekshell" : "kshell");
187 		}
188 	}
189 #endif
190 	if (sp == NULL)
191 		sp = getservbyname("shell", "tcp");
192 	if (sp == NULL)
193 		errx(1, "shell/tcp: unknown service");
194 
195 #ifdef KERBEROS
196 try_connect:
197 	if (use_kerberos) {
198 		struct hostent *hp;
199 
200 		/* fully qualify hostname (needed for krb_realmofhost) */
201 		hp = gethostbyname(host);
202 		if (hp != NULL && !(host = strdup(hp->h_name)))
203 			err(1, NULL);
204 
205 		rem = KSUCCESS;
206 		errno = 0;
207 		if (dest_realm == NULL)
208 			dest_realm = krb_realmofhost(host);
209 
210 #ifdef CRYPT
211 		if (doencrypt)
212 			rem = krcmd_mutual(&host, sp->s_port, user, args,
213 			    &rfd2, dest_realm, &cred, schedule);
214 		else
215 #endif
216 			rem = krcmd(&host, sp->s_port, user, args, &rfd2,
217 			    dest_realm);
218 		if (rem < 0) {
219 			use_kerberos = 0;
220 			sp = getservbyname("shell", "tcp");
221 			if (sp == NULL)
222 				errx(1, "shell/tcp: unknown service");
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 			errx(1, "the -x flag requires Kerberos authentication");
232 		rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
233 	}
234 #else
235 	rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
236 #endif
237 
238 	if (rem < 0)
239 		exit(1);
240 
241 	if (rfd2 < 0)
242 		errx(1, "can't establish stderr");
243 	if (dflag) {
244 		if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
245 		    sizeof(one)) < 0)
246 			warn("setsockopt");
247 		if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
248 		    sizeof(one)) < 0)
249 			warn("setsockopt");
250 	}
251 
252 	(void)setuid(uid);
253 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
254 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
255 		(void)signal(SIGINT, sendsig);
256 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
257 		(void)signal(SIGQUIT, sendsig);
258 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
259 		(void)signal(SIGTERM, sendsig);
260 
261 	if (!nflag) {
262 		pid = fork();
263 		if (pid < 0)
264 			err(1, "fork");
265 	}
266 
267 #ifdef KERBEROS
268 #ifdef CRYPT
269 	if (!doencrypt)
270 #endif
271 #endif
272 	{
273 		(void)ioctl(rfd2, FIONBIO, &one);
274 		(void)ioctl(rem, FIONBIO, &one);
275 	}
276 
277 	talk(nflag, omask, pid, rem);
278 
279 	if (!nflag)
280 		(void)kill(pid, SIGKILL);
281 	exit(0);
282 }
283 
284 void
285 talk(nflag, omask, pid, rem)
286 	int nflag;
287 	long omask;
288 	pid_t pid;
289 	int rem;
290 {
291 	int cc, wc;
292 	fd_set readfrom, ready, rembits;
293 	char *bp, buf[BUFSIZ];
294 
295 	if (!nflag && pid == 0) {
296 		(void)close(rfd2);
297 
298 reread:		errno = 0;
299 		if ((cc = read(0, buf, sizeof buf)) <= 0)
300 			goto done;
301 		bp = buf;
302 
303 rewrite:
304 		FD_ZERO(&rembits);
305 		FD_SET(rem, &rembits);
306 		if (select(16, 0, &rembits, 0, 0) < 0) {
307 			if (errno != EINTR)
308 				err(1, "select");
309 			goto rewrite;
310 		}
311 		if (!FD_ISSET(rem, &rembits))
312 			goto rewrite;
313 #ifdef KERBEROS
314 #ifdef CRYPT
315 		if (doencrypt)
316 			wc = des_write(rem, bp, cc);
317 		else
318 #endif
319 #endif
320 			wc = write(rem, bp, cc);
321 		if (wc < 0) {
322 			if (errno == EWOULDBLOCK)
323 				goto rewrite;
324 			goto done;
325 		}
326 		bp += wc;
327 		cc -= wc;
328 		if (cc == 0)
329 			goto reread;
330 		goto rewrite;
331 done:
332 		(void)shutdown(rem, 1);
333 		exit(0);
334 	}
335 
336 	(void)sigsetmask(omask);
337 	FD_ZERO(&readfrom);
338 	FD_SET(rfd2, &readfrom);
339 	FD_SET(rem, &readfrom);
340 	do {
341 		ready = readfrom;
342 		if (select(16, &ready, 0, 0, 0) < 0) {
343 			if (errno != EINTR)
344 				err(1, "select");
345 			continue;
346 		}
347 		if (FD_ISSET(rfd2, &ready)) {
348 			errno = 0;
349 #ifdef KERBEROS
350 #ifdef CRYPT
351 			if (doencrypt)
352 				cc = des_read(rfd2, buf, sizeof buf);
353 			else
354 #endif
355 #endif
356 				cc = read(rfd2, buf, sizeof buf);
357 			if (cc <= 0) {
358 				if (errno != EWOULDBLOCK)
359 					FD_CLR(rfd2, &readfrom);
360 			} else
361 				(void)write(2, buf, cc);
362 		}
363 		if (FD_ISSET(rem, &ready)) {
364 			errno = 0;
365 #ifdef KERBEROS
366 #ifdef CRYPT
367 			if (doencrypt)
368 				cc = des_read(rem, buf, sizeof buf);
369 			else
370 #endif
371 #endif
372 				cc = read(rem, buf, sizeof buf);
373 			if (cc <= 0) {
374 				if (errno != EWOULDBLOCK)
375 					FD_CLR(rem, &readfrom);
376 			} else
377 				(void)write(1, buf, cc);
378 		}
379 	} while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
380 }
381 
382 void
383 sendsig(sig)
384 	int sig;
385 {
386 	char signo;
387 
388 	signo = sig;
389 #ifdef KERBEROS
390 #ifdef CRYPT
391 	if (doencrypt)
392 		(void)des_write(rfd2, &signo, 1);
393 	else
394 #endif
395 #endif
396 		(void)write(rfd2, &signo, 1);
397 }
398 
399 #ifdef KERBEROS
400 /* VARARGS */
401 void
402 warning(va_alist)
403 va_dcl
404 {
405 	va_list ap;
406 	char *fmt;
407 
408 	(void)fprintf(stderr, "rsh: warning, using standard rsh: ");
409 	va_start(ap);
410 	fmt = va_arg(ap, char *);
411 	vfprintf(stderr, fmt, ap);
412 	va_end(ap);
413 	(void)fprintf(stderr, ".\n");
414 }
415 #endif
416 
417 char *
418 copyargs(argv)
419 	char **argv;
420 {
421 	int cc;
422 	char **ap, *args, *p;
423 
424 	cc = 0;
425 	for (ap = argv; *ap; ++ap)
426 		cc += strlen(*ap) + 1;
427 	if (!(args = malloc((u_int)cc)))
428 		err(1, NULL);
429 	for (p = args, ap = argv; *ap; ++ap) {
430 		(void)strcpy(p, *ap);
431 		for (p = strcpy(p, *ap); *p; ++p);
432 		if (ap[1])
433 			*p++ = ' ';
434 	}
435 	return (args);
436 }
437 
438 void
439 usage()
440 {
441 
442 	(void)fprintf(stderr,
443 	    "usage: rsh [-nd%s]%s[-l login] host [command]\n",
444 #ifdef KERBEROS
445 #ifdef CRYPT
446 	    "x", " [-k realm] ");
447 #else
448 	    "", " [-k realm] ");
449 #endif
450 #else
451 	    "", " ");
452 #endif
453 	exit(1);
454 }
455