xref: /original-bsd/usr.bin/rsh/rsh.c (revision a76afa45)
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 MERCHANTIBILITY 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.7 (Berkeley) 9/20/88";
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 
41 #ifdef	KERBEROS
42 #include <kerberos/krb.h>
43 char	krb_realm[REALM_SZ];
44 int	use_kerberos = 1, encrypt = 0;
45 CREDENTIALS	cred;
46 Key_schedule	schedule;
47 #endif	/* KERBEROS */
48 
49 /*
50  * rsh - remote shell
51  */
52 /* VARARGS */
53 int	error();
54 char	*index(), *rindex(), *malloc(), *getpass(), *strcpy();
55 
56 struct	passwd *getpwuid();
57 
58 int	errno;
59 int	options;
60 int	rfd2;
61 int	nflag;
62 int	sendsig();
63 
64 #define	mask(s)	(1 << ((s) - 1))
65 
66 main(argc, argv0)
67 	int argc;
68 	char **argv0;
69 {
70 	int rem, pid;
71 	char *host, *cp, **ap, buf[BUFSIZ], *args, **argv = argv0, *user = 0;
72 	register int cc;
73 	int asrsh = 0;
74 	struct passwd *pwd;
75 	int readfrom, ready;
76 	int one = 1;
77 	struct servent *sp;
78 	int omask;
79 
80 	host = rindex(argv[0], '/');
81 	if (host)
82 		host++;
83 	else
84 		host = argv[0];
85 	argv++, --argc;
86 	if (!strcmp(host, "rsh")) {
87 		host = *argv++, --argc;
88 		asrsh = 1;
89 	}
90 another:
91 	if (argc > 0 && !strcmp(*argv, "-l")) {
92 		argv++, argc--;
93 		if (argc > 0)
94 			user = *argv++, argc--;
95 		goto another;
96 	}
97 	if (argc > 0 && !strcmp(*argv, "-n")) {
98 		argv++, argc--;
99 		nflag++;
100 		goto another;
101 	}
102 	if (argc > 0 && !strcmp(*argv, "-d")) {
103 		argv++, argc--;
104 		options |= SO_DEBUG;
105 		goto another;
106 	}
107 	/*
108 	 * Ignore the -L, -w, -e and -8 flags to allow aliases with rlogin
109 	 * to work
110 	 *
111 	 * There must be a better way to do this! -jmb
112 	 */
113 	if (argc > 0 && !strncmp(*argv, "-L", 2)) {
114 		argv++, argc--;
115 		goto another;
116 	}
117 	if (argc > 0 && !strncmp(*argv, "-w", 2)) {
118 		argv++, argc--;
119 		goto another;
120 	}
121 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
122 		argv++, argc--;
123 		goto another;
124 	}
125 	if (argc > 0 && !strncmp(*argv, "-8", 2)) {
126 		argv++, argc--;
127 		goto another;
128 	}
129 
130 #ifdef	KERBEROS
131 	if(argc > 0 && !strncmp(*argv, "-x", 2)) {
132 		encrypt = 1;
133 		des_set_key(cred.session, schedule);
134 		argv++, argc--;
135 		goto another;
136 	}
137 
138 	if(argc > 0 && !strcmp(*argv, "-k")) {
139 		argv++, argc--;
140 		if(argc <= 0 || (**argv == '-')) {
141 			fprintf(stderr, "-k option requires an argument\n");
142 			exit(1);
143 		}
144 		strncpy(krb_realm, *argv, REALM_SZ);
145 		argv++, argc--;
146 		goto another;
147 	}
148 #endif
149 
150 	if (host == 0)
151 		goto usage;
152 	if (argv[0] == 0) {
153 		if (asrsh)
154 			*argv0 = "rlogin";
155 		execv("/usr/ucb/rlogin", argv0);
156 		perror("/usr/ucb/rlogin");
157 		exit(1);
158 	}
159 	pwd = getpwuid(getuid());
160 	if (pwd == 0) {
161 		fprintf(stderr, "who are you?\n");
162 		exit(1);
163 	}
164 	cc = 0;
165 	for (ap = argv; *ap; ap++)
166 		cc += strlen(*ap) + 1;
167 	cp = args = malloc(cc);
168 	for (ap = argv; *ap; ap++) {
169 		(void) strcpy(cp, *ap);
170 		while (*cp)
171 			cp++;
172 		if (ap[1])
173 			*cp++ = ' ';
174 	}
175 #ifdef	KERBEROS
176 	sp = getservbyname("kshell", "tcp");
177 	if (sp == NULL) {
178 		use_kerberos = 0;
179 		old_warning("kshell service unknown");
180 		sp = getservbyname("shell", "tcp");
181 	}
182 #else
183 	sp = getservbyname("shell", "tcp");
184 #endif
185 
186 	if (sp == 0) {
187 		fprintf(stderr, "rsh: shell/tcp: unknown service\n");
188 		exit(1);
189 	}
190 
191 #ifdef	KERBEROS
192 try_connect:
193 	if(use_kerberos) {
194 		rem = KSUCCESS;
195 		if(krb_realm[0] == '\0') {
196 			rem = krb_get_lrealm(krb_realm, 1);
197 		}
198 
199 		if(rem == KSUCCESS) {
200 			if(encrypt) {
201 				rem = krcmd_mutual(
202 					&host, sp->s_port,
203 					user ? user : pwd->pw_name,
204 					args,
205 					&rfd2,
206 					krb_realm,
207 					&cred, schedule);
208 			} else {
209 				rem = krcmd(
210 					&host,
211 					sp->s_port,
212 					user ? user : pwd->pw_name,
213 					args,
214 					&rfd2,
215 					krb_realm
216 				);
217 			}
218 		} else {
219 			fprintf(stderr,
220 			    "%s: error getting local realm\n",
221 			    argv0[0]);
222 			exit(1);
223 		}
224 		if((rem < 0) && errno == ECONNREFUSED) {
225 			use_kerberos = 0;
226 			sp = getservbyname("shell", "tcp");
227 			if(sp == NULL) {
228 				fprintf(stderr, "unknown service shell/tcp\n");
229 				exit(1);
230 			}
231 			old_warning("remote host doesn't support Kerberos");
232 			goto try_connect;
233 		}
234 	} else {
235 		if(encrypt) {
236 			fprintf(stderr,"The -x flag requires Kerberos authentication\n");
237 			exit(1);
238 		}
239         	rem = rcmd(&host, sp->s_port, pwd->pw_name,
240 	    		user ? user : pwd->pw_name, args, &rfd2);
241 	}
242 
243 #else
244 
245         rem = rcmd(&host, sp->s_port, pwd->pw_name,
246 		user ? user : pwd->pw_name, args, &rfd2);
247 #endif
248 
249         if (rem < 0)
250                 exit(1);
251 
252 	if (rfd2 < 0) {
253 		fprintf(stderr, "rsh: can't establish stderr\n");
254 		exit(2);
255 	}
256 	if (options & SO_DEBUG) {
257 		if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof (one)) < 0)
258 			perror("setsockopt (stdin)");
259 		if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, sizeof (one)) < 0)
260 			perror("setsockopt (stderr)");
261 	}
262 	(void) setuid(getuid());
263 	omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
264 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
265 		signal(SIGINT, sendsig);
266 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
267 		signal(SIGQUIT, sendsig);
268 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
269 		signal(SIGTERM, sendsig);
270 	if (nflag == 0) {
271 		pid = fork();
272 		if (pid < 0) {
273 			perror("fork");
274 			exit(1);
275 		}
276 	}
277 	ioctl(rfd2, FIONBIO, &one);
278 	ioctl(rem, FIONBIO, &one);
279         if (nflag == 0 && pid == 0) {
280 		char *bp; int rembits, wc;
281 		(void) close(rfd2);
282 	reread:
283 		errno = 0;
284 		cc = read(0, buf, sizeof buf);
285 		if (cc <= 0)
286 			goto done;
287 		bp = buf;
288 	rewrite:
289 		rembits = 1<<rem;
290 		if (select(16, 0, &rembits, 0, 0) < 0) {
291 			if (errno != EINTR) {
292 				perror("select");
293 				exit(1);
294 			}
295 			goto rewrite;
296 		}
297 		if ((rembits & (1<<rem)) == 0)
298 			goto rewrite;
299 		wc = write(rem, bp, cc);
300 		if (wc < 0) {
301 			if (errno == EWOULDBLOCK)
302 				goto rewrite;
303 			goto done;
304 		}
305 		cc -= wc; bp += wc;
306 		if (cc == 0)
307 			goto reread;
308 		goto rewrite;
309 	done:
310 		(void) shutdown(rem, 1);
311 		exit(0);
312 	}
313 	sigsetmask(omask);
314 	readfrom = (1<<rfd2) | (1<<rem);
315 	do {
316 		ready = readfrom;
317 		if (select(16, &ready, 0, 0, 0) < 0) {
318 			if (errno != EINTR) {
319 				perror("select");
320 				exit(1);
321 			}
322 			continue;
323 		}
324 		if (ready & (1<<rfd2)) {
325 			errno = 0;
326 			cc = read(rfd2, buf, sizeof buf);
327 			if (cc <= 0) {
328 				if (errno != EWOULDBLOCK)
329 					readfrom &= ~(1<<rfd2);
330 			} else
331 				(void) write(2, buf, cc);
332 		}
333 		if (ready & (1<<rem)) {
334 			errno = 0;
335 			cc = read(rem, buf, sizeof buf);
336 			if (cc <= 0) {
337 				if (errno != EWOULDBLOCK)
338 					readfrom &= ~(1<<rem);
339 			} else
340 				(void) write(1, buf, cc);
341 		}
342         } while (readfrom);
343 	if (nflag == 0)
344 		(void) kill(pid, SIGKILL);
345 	exit(0);
346 usage:
347 	fprintf(stderr,
348 #ifdef	KERBEROS
349 	    "usage: rsh host [ -l login ] [ -n ] [ -k realm ] command\n");
350 #else
351 	    "usage: rsh host [ -l login ] [ -n ] command\n");
352 #endif
353 	exit(1);
354 }
355 
356 sendsig(signo)
357 	char signo;
358 {
359 
360 	(void) write(rfd2, &signo, 1);
361 }
362 
363 #ifdef	KERBEROS
364 int
365 old_warning(str)
366 	char	*str;
367 {
368 	fprintf(stderr,"Warning: %s, using standard rsh\n", str);
369 }
370 #endif
371