xref: /original-bsd/usr.bin/rsh/rsh.c (revision c47935e1)
1 /*
2  * Copyright (c) 1983 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)rsh.c	5.12 (Berkeley) 05/11/89";
26 #endif /* not lint */
27 
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
31 #include <sys/file.h>
32 
33 #include <netinet/in.h>
34 
35 #include <stdio.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include <pwd.h>
39 #include <netdb.h>
40 #include "pathnames.h"
41 
42 #ifdef	KERBEROS
43 #include <kerberos/krb.h>
44 char	krb_realm[REALM_SZ];
45 int	use_kerberos = 1, encrypt = 0;
46 CREDENTIALS	cred;
47 Key_schedule	schedule;
48 #endif	/* KERBEROS */
49 
50 /*
51  * rsh - remote shell
52  */
53 /* VARARGS */
54 int	error();
55 char	*index(), *rindex(), *malloc(), *getpass(), *strcpy();
56 
57 struct	passwd *getpwuid();
58 
59 int	errno;
60 int	options;
61 int	rfd2;
62 int	nflag;
63 int	sendsig();
64 
65 #define	mask(s)	(1 << ((s) - 1))
66 
67 main(argc, argv0)
68 	int argc;
69 	char **argv0;
70 {
71 	int rem, pid;
72 	char *host, *cp, **ap, buf[BUFSIZ], *args, **argv = argv0, *user = 0;
73 	register int cc;
74 	int asrsh = 0;
75 	struct passwd *pwd;
76 	int readfrom, ready;
77 	int one = 1;
78 	struct servent *sp;
79 	int omask;
80 
81 	host = rindex(argv[0], '/');
82 	if (host)
83 		host++;
84 	else
85 		host = argv[0];
86 	argv++, --argc;
87 	if (!strcmp(host, "rsh")) {
88 		host = *argv++, --argc;
89 		asrsh = 1;
90 	}
91 another:
92 	if (argc > 0 && !strcmp(*argv, "-l")) {
93 		argv++, argc--;
94 		if (argc > 0)
95 			user = *argv++, argc--;
96 		goto another;
97 	}
98 	if (argc > 0 && !strcmp(*argv, "-n")) {
99 		argv++, argc--;
100 		nflag++;
101 		goto another;
102 	}
103 	if (argc > 0 && !strcmp(*argv, "-d")) {
104 		argv++, argc--;
105 		options |= SO_DEBUG;
106 		goto another;
107 	}
108 	/*
109 	 * Ignore the -L, -w, -e and -8 flags to allow aliases with rlogin
110 	 * to work
111 	 *
112 	 * There must be a better way to do this! -jmb
113 	 */
114 	if (argc > 0 && !strncmp(*argv, "-L", 2)) {
115 		argv++, argc--;
116 		goto another;
117 	}
118 	if (argc > 0 && !strncmp(*argv, "-w", 2)) {
119 		argv++, argc--;
120 		goto another;
121 	}
122 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
123 		argv++, argc--;
124 		goto another;
125 	}
126 	if (argc > 0 && !strncmp(*argv, "-8", 2)) {
127 		argv++, argc--;
128 		goto another;
129 	}
130 
131 #ifdef	KERBEROS
132 	if(argc > 0 && !strncmp(*argv, "-x", 2)) {
133 		encrypt = 1;
134 		des_set_key(cred.session, schedule);
135 		argv++, argc--;
136 		goto another;
137 	}
138 
139 	if(argc > 0 && !strcmp(*argv, "-k")) {
140 		argv++, argc--;
141 		if(argc <= 0 || (**argv == '-')) {
142 			fprintf(stderr, "-k option requires an argument\n");
143 			exit(1);
144 		}
145 		strncpy(krb_realm, *argv, REALM_SZ);
146 		argv++, argc--;
147 		goto another;
148 	}
149 #endif
150 
151 	if (host == 0)
152 		goto usage;
153 	if (argv[0] == 0) {
154 		if (asrsh)
155 			*argv0 = "rlogin";
156 		execv(_PATH_RLOGIN, argv0);
157 		perror(_PATH_RLOGIN);
158 		exit(1);
159 	}
160 	pwd = getpwuid(getuid());
161 	if (pwd == 0) {
162 		fprintf(stderr, "who are you?\n");
163 		exit(1);
164 	}
165 	cc = 0;
166 	for (ap = argv; *ap; ap++)
167 		cc += strlen(*ap) + 1;
168 	cp = args = malloc(cc);
169 	for (ap = argv; *ap; ap++) {
170 		(void) strcpy(cp, *ap);
171 		while (*cp)
172 			cp++;
173 		if (ap[1])
174 			*cp++ = ' ';
175 	}
176 #ifdef	KERBEROS
177 	sp = getservbyname("kshell", "tcp");
178 	if (sp == NULL) {
179 		use_kerberos = 0;
180 		old_warning("kshell service unknown");
181 		sp = getservbyname("shell", "tcp");
182 	}
183 #else
184 	sp = getservbyname("shell", "tcp");
185 #endif
186 
187 	if (sp == 0) {
188 		fprintf(stderr, "rsh: shell/tcp: unknown service\n");
189 		exit(1);
190 	}
191 
192 #ifdef	KERBEROS
193 try_connect:
194 	if(use_kerberos) {
195 		rem = KSUCCESS;
196 		if(krb_realm[0] == '\0') {
197 			rem = krb_get_lrealm(krb_realm, 1);
198 		}
199 
200 		if(rem == KSUCCESS) {
201 			if(encrypt) {
202 				rem = krcmd_mutual(
203 					&host, sp->s_port,
204 					user ? user : pwd->pw_name,
205 					args,
206 					&rfd2,
207 					krb_realm,
208 					&cred, schedule);
209 			} else {
210 				rem = krcmd(
211 					&host,
212 					sp->s_port,
213 					user ? user : pwd->pw_name,
214 					args,
215 					&rfd2,
216 					krb_realm
217 				);
218 			}
219 		} else {
220 			fprintf(stderr,
221 			    "%s: error getting local realm\n",
222 			    argv0[0]);
223 			exit(1);
224 		}
225 		if((rem < 0) && errno == ECONNREFUSED) {
226 			use_kerberos = 0;
227 			sp = getservbyname("shell", "tcp");
228 			if(sp == NULL) {
229 				fprintf(stderr, "unknown service shell/tcp\n");
230 				exit(1);
231 			}
232 			old_warning("remote host doesn't support Kerberos");
233 			goto try_connect;
234 		}
235 	} else {
236 		if(encrypt) {
237 			fprintf(stderr,"The -x flag requires Kerberos authentication\n");
238 			exit(1);
239 		}
240         	rem = rcmd(&host, sp->s_port, pwd->pw_name,
241 	    		user ? user : pwd->pw_name, args, &rfd2);
242 	}
243 
244 #else
245 
246         rem = rcmd(&host, sp->s_port, pwd->pw_name,
247 		user ? user : pwd->pw_name, args, &rfd2);
248 #endif
249 
250         if (rem < 0)
251                 exit(1);
252 
253 	if (rfd2 < 0) {
254 		fprintf(stderr, "rsh: can't establish stderr\n");
255 		exit(2);
256 	}
257 	if (options & SO_DEBUG) {
258 		if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof (one)) < 0)
259 			perror("setsockopt (stdin)");
260 		if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, sizeof (one)) < 0)
261 			perror("setsockopt (stderr)");
262 	}
263 	(void) setuid(getuid());
264 	omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
265 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
266 		signal(SIGINT, sendsig);
267 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
268 		signal(SIGQUIT, sendsig);
269 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
270 		signal(SIGTERM, sendsig);
271 	if (nflag == 0) {
272 		pid = fork();
273 		if (pid < 0) {
274 			perror("fork");
275 			exit(1);
276 		}
277 	}
278 	ioctl(rfd2, FIONBIO, &one);
279 	ioctl(rem, FIONBIO, &one);
280         if (nflag == 0 && pid == 0) {
281 		char *bp; int rembits, wc;
282 		(void) close(rfd2);
283 	reread:
284 		errno = 0;
285 		cc = read(0, buf, sizeof buf);
286 		if (cc <= 0)
287 			goto done;
288 		bp = buf;
289 	rewrite:
290 		rembits = 1<<rem;
291 		if (select(16, 0, &rembits, 0, 0) < 0) {
292 			if (errno != EINTR) {
293 				perror("select");
294 				exit(1);
295 			}
296 			goto rewrite;
297 		}
298 		if ((rembits & (1<<rem)) == 0)
299 			goto rewrite;
300 		wc = write(rem, bp, cc);
301 		if (wc < 0) {
302 			if (errno == EWOULDBLOCK)
303 				goto rewrite;
304 			goto done;
305 		}
306 		cc -= wc; bp += wc;
307 		if (cc == 0)
308 			goto reread;
309 		goto rewrite;
310 	done:
311 		(void) shutdown(rem, 1);
312 		exit(0);
313 	}
314 	sigsetmask(omask);
315 	readfrom = (1<<rfd2) | (1<<rem);
316 	do {
317 		ready = readfrom;
318 		if (select(16, &ready, 0, 0, 0) < 0) {
319 			if (errno != EINTR) {
320 				perror("select");
321 				exit(1);
322 			}
323 			continue;
324 		}
325 		if (ready & (1<<rfd2)) {
326 			errno = 0;
327 			cc = read(rfd2, buf, sizeof buf);
328 			if (cc <= 0) {
329 				if (errno != EWOULDBLOCK)
330 					readfrom &= ~(1<<rfd2);
331 			} else
332 				(void) write(2, buf, cc);
333 		}
334 		if (ready & (1<<rem)) {
335 			errno = 0;
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 	if (nflag == 0)
345 		(void) kill(pid, SIGKILL);
346 	exit(0);
347 usage:
348 	fprintf(stderr,
349 #ifdef	KERBEROS
350 	    "usage: rsh host [ -l login ] [ -n ] [ -k realm ] command\n");
351 #else
352 	    "usage: rsh host [ -l login ] [ -n ] command\n");
353 #endif
354 	exit(1);
355 }
356 
357 sendsig(signo)
358 	char signo;
359 {
360 
361 	(void) write(rfd2, &signo, 1);
362 }
363 
364 #ifdef	KERBEROS
365 int
366 old_warning(str)
367 	char	*str;
368 {
369 	fprintf(stderr,"Warning: %s, using standard rsh\n", str);
370 }
371 #endif
372