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