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