xref: /original-bsd/usr.bin/rsh/rsh.c (revision 7cab520e)
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) 09/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 /*
42  * rsh - remote shell
43  */
44 /* VARARGS */
45 int	error();
46 char	*index(), *rindex(), *malloc(), *getpass(), *strcpy();
47 
48 struct	passwd *getpwuid();
49 
50 int	errno;
51 int	options;
52 int	rfd2;
53 int	nflag;
54 int	sendsig();
55 
56 #define	mask(s)	(1 << ((s) - 1))
57 
58 main(argc, argv0)
59 	int argc;
60 	char **argv0;
61 {
62 	int rem, pid;
63 	char *host, *cp, **ap, buf[BUFSIZ], *args, **argv = argv0, *user = 0;
64 	register int cc;
65 	int asrsh = 0;
66 	struct passwd *pwd;
67 	int readfrom, ready;
68 	int one = 1;
69 	struct servent *sp;
70 	int omask;
71 
72 	host = rindex(argv[0], '/');
73 	if (host)
74 		host++;
75 	else
76 		host = argv[0];
77 	argv++, --argc;
78 	if (!strcmp(host, "rsh")) {
79 		host = *argv++, --argc;
80 		asrsh = 1;
81 	}
82 another:
83 	if (argc > 0 && !strcmp(*argv, "-l")) {
84 		argv++, argc--;
85 		if (argc > 0)
86 			user = *argv++, argc--;
87 		goto another;
88 	}
89 	if (argc > 0 && !strcmp(*argv, "-n")) {
90 		argv++, argc--;
91 		nflag++;
92 		goto another;
93 	}
94 	if (argc > 0 && !strcmp(*argv, "-d")) {
95 		argv++, argc--;
96 		options |= SO_DEBUG;
97 		goto another;
98 	}
99 	/*
100 	 * Ignore the -L, -w, -e and -8 flags to allow aliases with rlogin
101 	 * to work
102 	 *
103 	 * There must be a better way to do this! -jmb
104 	 */
105 	if (argc > 0 && !strncmp(*argv, "-L", 2)) {
106 		argv++, argc--;
107 		goto another;
108 	}
109 	if (argc > 0 && !strncmp(*argv, "-w", 2)) {
110 		argv++, argc--;
111 		goto another;
112 	}
113 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
114 		argv++, argc--;
115 		goto another;
116 	}
117 	if (argc > 0 && !strncmp(*argv, "-8", 2)) {
118 		argv++, argc--;
119 		goto another;
120 	}
121 	if (host == 0)
122 		goto usage;
123 	if (argv[0] == 0) {
124 		if (asrsh)
125 			*argv0 = "rlogin";
126 		execv("/usr/ucb/rlogin", argv0);
127 		perror("/usr/ucb/rlogin");
128 		exit(1);
129 	}
130 	pwd = getpwuid(getuid());
131 	if (pwd == 0) {
132 		fprintf(stderr, "who are you?\n");
133 		exit(1);
134 	}
135 	cc = 0;
136 	for (ap = argv; *ap; ap++)
137 		cc += strlen(*ap) + 1;
138 	cp = args = malloc(cc);
139 	for (ap = argv; *ap; ap++) {
140 		(void) strcpy(cp, *ap);
141 		while (*cp)
142 			cp++;
143 		if (ap[1])
144 			*cp++ = ' ';
145 	}
146 	sp = getservbyname("shell", "tcp");
147 	if (sp == 0) {
148 		fprintf(stderr, "rsh: shell/tcp: unknown service\n");
149 		exit(1);
150 	}
151         rem = rcmd(&host, sp->s_port, pwd->pw_name,
152 	    user ? user : pwd->pw_name, args, &rfd2);
153         if (rem < 0)
154                 exit(1);
155 	if (rfd2 < 0) {
156 		fprintf(stderr, "rsh: can't establish stderr\n");
157 		exit(2);
158 	}
159 	if (options & SO_DEBUG) {
160 		if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof (one)) < 0)
161 			perror("setsockopt (stdin)");
162 		if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, sizeof (one)) < 0)
163 			perror("setsockopt (stderr)");
164 	}
165 	(void) setuid(getuid());
166 	omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
167 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
168 		signal(SIGINT, sendsig);
169 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
170 		signal(SIGQUIT, sendsig);
171 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
172 		signal(SIGTERM, sendsig);
173 	if (nflag == 0) {
174 		pid = fork();
175 		if (pid < 0) {
176 			perror("fork");
177 			exit(1);
178 		}
179 	}
180 	ioctl(rfd2, FIONBIO, &one);
181 	ioctl(rem, FIONBIO, &one);
182         if (nflag == 0 && pid == 0) {
183 		char *bp; int rembits, wc;
184 		(void) close(rfd2);
185 	reread:
186 		errno = 0;
187 		cc = read(0, buf, sizeof buf);
188 		if (cc <= 0)
189 			goto done;
190 		bp = buf;
191 	rewrite:
192 		rembits = 1<<rem;
193 		if (select(16, 0, &rembits, 0, 0) < 0) {
194 			if (errno != EINTR) {
195 				perror("select");
196 				exit(1);
197 			}
198 			goto rewrite;
199 		}
200 		if ((rembits & (1<<rem)) == 0)
201 			goto rewrite;
202 		wc = write(rem, bp, cc);
203 		if (wc < 0) {
204 			if (errno == EWOULDBLOCK)
205 				goto rewrite;
206 			goto done;
207 		}
208 		cc -= wc; bp += wc;
209 		if (cc == 0)
210 			goto reread;
211 		goto rewrite;
212 	done:
213 		(void) shutdown(rem, 1);
214 		exit(0);
215 	}
216 	sigsetmask(omask);
217 	readfrom = (1<<rfd2) | (1<<rem);
218 	do {
219 		ready = readfrom;
220 		if (select(16, &ready, 0, 0, 0) < 0) {
221 			if (errno != EINTR) {
222 				perror("select");
223 				exit(1);
224 			}
225 			continue;
226 		}
227 		if (ready & (1<<rfd2)) {
228 			errno = 0;
229 			cc = read(rfd2, buf, sizeof buf);
230 			if (cc <= 0) {
231 				if (errno != EWOULDBLOCK)
232 					readfrom &= ~(1<<rfd2);
233 			} else
234 				(void) write(2, buf, cc);
235 		}
236 		if (ready & (1<<rem)) {
237 			errno = 0;
238 			cc = read(rem, buf, sizeof buf);
239 			if (cc <= 0) {
240 				if (errno != EWOULDBLOCK)
241 					readfrom &= ~(1<<rem);
242 			} else
243 				(void) write(1, buf, cc);
244 		}
245         } while (readfrom);
246 	if (nflag == 0)
247 		(void) kill(pid, SIGKILL);
248 	exit(0);
249 usage:
250 	fprintf(stderr,
251 	    "usage: rsh host [ -l login ] [ -n ] command\n");
252 	exit(1);
253 }
254 
255 sendsig(signo)
256 	char signo;
257 {
258 
259 	(void) write(rfd2, &signo, 1);
260 }
261