xref: /original-bsd/usr.bin/rsh/rsh.c (revision b5ed8b48)
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.24.1.1 (Berkeley) 08/20/91";
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 	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:nw"
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 #endif
124 		case '?':
125 		default:
126 			usage();
127 		}
128 	optind += argoff;
129 
130 	/* if haven't gotten a host yet, do so */
131 	if (!host && !(host = argv[optind++]))
132 		usage();
133 
134 	/* if no further arguments, must have been called as rlogin. */
135 	if (!argv[optind]) {
136 		if (asrsh)
137 			*argv = "rlogin";
138 		execv(_PATH_RLOGIN, argv);
139 		(void)fprintf(stderr, "rsh: can't exec %s.\n", _PATH_RLOGIN);
140 		exit(1);
141 	}
142 
143 	argc -= optind;
144 	argv += optind;
145 
146 	if (!(pw = getpwuid(uid = getuid()))) {
147 		(void)fprintf(stderr, "rsh: unknown user id.\n");
148 		exit(1);
149 	}
150 	if (!user)
151 		user = pw->pw_name;
152 
153 #ifdef KERBEROS
154 #endif
155 
156 	args = copyargs(argv);
157 
158 	sp = NULL;
159 #ifdef KERBEROS
160 	if (use_kerberos) {
161 		sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
162 		if (sp == NULL) {
163 			use_kerberos = 0;
164 			warning("can't get entry for %s/tcp service",
165 			    doencrypt ? "ekshell" : "kshell");
166 		}
167 	}
168 #endif
169 	if (sp == NULL)
170 		sp = getservbyname("shell", "tcp");
171 	if (sp == NULL) {
172 		(void)fprintf(stderr, "rsh: shell/tcp: unknown service.\n");
173 		exit(1);
174 	}
175 
176 #ifdef KERBEROS
177 try_connect:
178 	if (use_kerberos) {
179 		rem = KSUCCESS;
180 		errno = 0;
181 		if (dest_realm == NULL)
182 			dest_realm = krb_realmofhost(host);
183 
184 			rem = krcmd(&host, sp->s_port, user, args, &rfd2,
185 			    dest_realm);
186 		if (rem < 0) {
187 			use_kerberos = 0;
188 			sp = getservbyname("shell", "tcp");
189 			if (sp == NULL) {
190 				(void)fprintf(stderr,
191 				    "rsh: unknown service shell/tcp.\n");
192 				exit(1);
193 			}
194 			if (errno == ECONNREFUSED)
195 				warning("remote host doesn't support Kerberos");
196 			if (errno == ENOENT)
197 				warning("can't provide Kerberos auth data");
198 			goto try_connect;
199 		}
200 	} else {
201 		if (doencrypt) {
202 			(void)fprintf(stderr,
203 			    "rsh: the -x flag requires Kerberos authentication.\n");
204 			exit(1);
205 		}
206 		rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
207 	}
208 #else
209 	rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
210 #endif
211 
212 	if (rem < 0)
213 		exit(1);
214 
215 	if (rfd2 < 0) {
216 		(void)fprintf(stderr, "rsh: can't establish stderr.\n");
217 		exit(1);
218 	}
219 	if (dflag) {
220 		if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
221 		    sizeof(one)) < 0)
222 			(void)fprintf(stderr, "rsh: setsockopt: %s.\n",
223 			    strerror(errno));
224 		if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
225 		    sizeof(one)) < 0)
226 			(void)fprintf(stderr, "rsh: setsockopt: %s.\n",
227 			    strerror(errno));
228 	}
229 
230 	(void)setuid(uid);
231 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
232 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
233 		(void)signal(SIGINT, sendsig);
234 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
235 		(void)signal(SIGQUIT, sendsig);
236 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
237 		(void)signal(SIGTERM, sendsig);
238 
239 	if (!nflag) {
240 		pid = fork();
241 		if (pid < 0) {
242 			(void)fprintf(stderr,
243 			    "rsh: fork: %s.\n", strerror(errno));
244 			exit(1);
245 		}
246 	}
247 
248 #ifdef KERBEROS
249 #endif
250 	{
251 		(void)ioctl(rfd2, FIONBIO, &one);
252 		(void)ioctl(rem, FIONBIO, &one);
253 	}
254 
255 	talk(nflag, omask, pid, rem);
256 
257 	if (!nflag)
258 		(void)kill(pid, SIGKILL);
259 	exit(0);
260 }
261 
262 talk(nflag, omask, pid, rem)
263 	int nflag, pid;
264 	long omask;
265 	register int rem;
266 {
267 	register int cc, wc;
268 	register char *bp;
269 	int readfrom, ready, rembits;
270 	char buf[BUFSIZ];
271 
272 	if (!nflag && pid == 0) {
273 		(void)close(rfd2);
274 
275 reread:		errno = 0;
276 		if ((cc = read(0, buf, sizeof buf)) <= 0)
277 			goto done;
278 		bp = buf;
279 
280 rewrite:	rembits = 1 << rem;
281 		if (select(16, 0, &rembits, 0, 0) < 0) {
282 			if (errno != EINTR) {
283 				(void)fprintf(stderr,
284 				    "rsh: select: %s.\n", strerror(errno));
285 				exit(1);
286 			}
287 			goto rewrite;
288 		}
289 		if ((rembits & (1 << rem)) == 0)
290 			goto rewrite;
291 #ifdef KERBEROS
292 #endif
293 			wc = write(rem, bp, cc);
294 		if (wc < 0) {
295 			if (errno == EWOULDBLOCK)
296 				goto rewrite;
297 			goto done;
298 		}
299 		bp += wc;
300 		cc -= wc;
301 		if (cc == 0)
302 			goto reread;
303 		goto rewrite;
304 done:
305 		(void)shutdown(rem, 1);
306 		exit(0);
307 	}
308 
309 	(void)sigsetmask(omask);
310 	readfrom = (1 << rfd2) | (1 << rem);
311 	do {
312 		ready = readfrom;
313 		if (select(16, &ready, 0, 0, 0) < 0) {
314 			if (errno != EINTR) {
315 				(void)fprintf(stderr,
316 				    "rsh: select: %s.\n", strerror(errno));
317 				exit(1);
318 			}
319 			continue;
320 		}
321 		if (ready & (1 << rfd2)) {
322 			errno = 0;
323 #ifdef KERBEROS
324 #endif
325 				cc = read(rfd2, buf, sizeof buf);
326 			if (cc <= 0) {
327 				if (errno != EWOULDBLOCK)
328 					readfrom &= ~(1 << rfd2);
329 			} else
330 				(void)write(2, buf, cc);
331 		}
332 		if (ready & (1 << rem)) {
333 			errno = 0;
334 #ifdef KERBEROS
335 #endif
336 				cc = read(rem, buf, sizeof buf);
337 			if (cc <= 0) {
338 				if (errno != EWOULDBLOCK)
339 					readfrom &= ~(1 << rem);
340 			} else
341 				(void)write(1, buf, cc);
342 		}
343 	} while (readfrom);
344 }
345 
346 void
347 sendsig(signo)
348 	char signo;
349 {
350 #ifdef KERBEROS
351 #endif
352 		(void)write(rfd2, &signo, 1);
353 }
354 
355 #ifdef KERBEROS
356 /* VARARGS */
357 warning(va_alist)
358 va_dcl
359 {
360 	va_list ap;
361 	char *fmt;
362 
363 	(void)fprintf(stderr, "rsh: warning, using standard rsh: ");
364 	va_start(ap);
365 	fmt = va_arg(ap, char *);
366 	vfprintf(stderr, fmt, ap);
367 	va_end(ap);
368 	(void)fprintf(stderr, ".\n");
369 }
370 #endif
371 
372 char *
373 copyargs(argv)
374 	char **argv;
375 {
376 	register int cc;
377 	register char **ap, *p;
378 	char *args, *malloc();
379 
380 	cc = 0;
381 	for (ap = argv; *ap; ++ap)
382 		cc += strlen(*ap) + 1;
383 	if (!(args = malloc((u_int)cc))) {
384 		(void)fprintf(stderr, "rsh: %s.\n", strerror(ENOMEM));
385 		exit(1);
386 	}
387 	for (p = args, ap = argv; *ap; ++ap) {
388 		(void)strcpy(p, *ap);
389 		for (p = strcpy(p, *ap); *p; ++p);
390 		if (ap[1])
391 			*p++ = ' ';
392 	}
393 	return(args);
394 }
395 
396 usage()
397 {
398 	(void)fprintf(stderr,
399 	    "usage: rsh [-nd%s]%s[-l login] host [command]\n",
400 #ifdef KERBEROS
401 	    "", " [-k realm] ");
402 #else
403 	    "", " ");
404 #endif
405 	exit(1);
406 }
407