]>
Commit | Line | Data |
---|---|---|
b7080c8e A |
1 | /*- |
2 | * Copyright (c) 1983, 1990, 1993, 1994 | |
3 | * The Regents of the University of California. All rights reserved. | |
ac2f15b3 A |
4 | * Copyright (c) 2002 Networks Associates Technology, Inc. |
5 | * All rights reserved. | |
6 | * | |
7 | * Portions of this software were developed for the FreeBSD Project by | |
8 | * ThinkSec AS and NAI Labs, the Security Research Division of Network | |
9 | * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 | |
10 | * ("CBOSS"), as part of the DARPA CHATS research program. | |
b7080c8e A |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | |
15 | * 1. Redistributions of source code must retain the above copyright | |
16 | * notice, this list of conditions and the following disclaimer. | |
17 | * 2. Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * 3. All advertising materials mentioning features or use of this software | |
21 | * must display the following acknowledgement: | |
22 | * This product includes software developed by the University of | |
23 | * California, Berkeley and its contributors. | |
24 | * 4. Neither the name of the University nor the names of its contributors | |
25 | * may be used to endorse or promote products derived from this software | |
26 | * without specific prior written permission. | |
27 | * | |
28 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
29 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
31 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
32 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
36 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
37 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
38 | * SUCH DAMAGE. | |
39 | */ | |
40 | ||
ac2f15b3 A |
41 | #ifndef lint |
42 | static const char copyright[] = | |
43 | "@(#) Copyright (c) 1983, 1990, 1993, 1994\n\ | |
44 | The Regents of the University of California. All rights reserved.\n"; | |
45 | #endif /* not lint */ | |
b7080c8e | 46 | |
ac2f15b3 A |
47 | #ifndef lint |
48 | static const char sccsid[] = "From: @(#)rsh.c 8.3 (Berkeley) 4/6/94"; | |
49 | #endif /* not lint */ | |
50 | ||
51 | #include <sys/cdefs.h> | |
b7080c8e | 52 | |
ac2f15b3 | 53 | #include <sys/param.h> |
b7080c8e A |
54 | #include <sys/signal.h> |
55 | #include <sys/socket.h> | |
56 | #include <sys/ioctl.h> | |
57 | #include <sys/file.h> | |
ac2f15b3 | 58 | #include <sys/time.h> |
b7080c8e A |
59 | |
60 | #include <netinet/in.h> | |
61 | #include <netdb.h> | |
62 | ||
63 | #include <err.h> | |
64 | #include <errno.h> | |
ac2f15b3 | 65 | #include <paths.h> |
b7080c8e A |
66 | #include <pwd.h> |
67 | #include <signal.h> | |
68 | #include <stdio.h> | |
69 | #include <stdlib.h> | |
70 | #include <string.h> | |
71 | #include <unistd.h> | |
ac2f15b3 | 72 | #include <err.h> |
b7080c8e A |
73 | |
74 | /* | |
75 | * rsh - remote shell | |
76 | */ | |
77 | int rfd2; | |
78 | ||
ac2f15b3 A |
79 | int family = PF_UNSPEC; |
80 | char rlogin[] = "rlogin"; | |
81 | ||
82 | void connect_timeout(int); | |
83 | char *copyargs(char * const *); | |
84 | void sendsig(int); | |
85 | void talk(int, long, pid_t, int, int); | |
86 | void usage(void); | |
b7080c8e A |
87 | |
88 | int | |
ac2f15b3 | 89 | main(int argc, char *argv[]) |
b7080c8e | 90 | { |
ac2f15b3 A |
91 | struct passwd const *pw; |
92 | struct servent const *sp; | |
b7080c8e A |
93 | long omask; |
94 | int argoff, asrsh, ch, dflag, nflag, one, rem; | |
ac2f15b3 | 95 | pid_t pid = 0; |
b7080c8e A |
96 | uid_t uid; |
97 | char *args, *host, *p, *user; | |
ac2f15b3 | 98 | int timeout = 0; |
b7080c8e A |
99 | |
100 | argoff = asrsh = dflag = nflag = 0; | |
101 | one = 1; | |
102 | host = user = NULL; | |
103 | ||
104 | /* if called as something other than "rsh", use it as the host name */ | |
ac2f15b3 | 105 | if ((p = strrchr(argv[0], '/'))) |
b7080c8e A |
106 | ++p; |
107 | else | |
108 | p = argv[0]; | |
109 | if (strcmp(p, "rsh")) | |
110 | host = p; | |
111 | else | |
112 | asrsh = 1; | |
113 | ||
114 | /* handle "rsh host flags" */ | |
115 | if (!host && argc > 2 && argv[1][0] != '-') { | |
116 | host = argv[1]; | |
117 | argoff = 1; | |
118 | } | |
119 | ||
ac2f15b3 A |
120 | #define OPTIONS "468KLde:l:nt:w" |
121 | while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) | |
b7080c8e | 122 | switch(ch) { |
ac2f15b3 A |
123 | case '4': |
124 | family = PF_INET; | |
125 | break; | |
126 | ||
127 | case '6': | |
128 | family = PF_INET6; | |
b7080c8e | 129 | break; |
ac2f15b3 | 130 | |
b7080c8e A |
131 | case 'L': /* -8Lew are ignored to allow rlogin aliases */ |
132 | case 'e': | |
133 | case 'w': | |
134 | case '8': | |
135 | break; | |
136 | case 'd': | |
137 | dflag = 1; | |
138 | break; | |
139 | case 'l': | |
140 | user = optarg; | |
141 | break; | |
b7080c8e A |
142 | case 'n': |
143 | nflag = 1; | |
144 | break; | |
ac2f15b3 A |
145 | case 't': |
146 | timeout = atoi(optarg); | |
b7080c8e | 147 | break; |
b7080c8e A |
148 | case '?': |
149 | default: | |
150 | usage(); | |
151 | } | |
152 | optind += argoff; | |
153 | ||
154 | /* if haven't gotten a host yet, do so */ | |
155 | if (!host && !(host = argv[optind++])) | |
156 | usage(); | |
157 | ||
158 | /* if no further arguments, must have been called as rlogin. */ | |
159 | if (!argv[optind]) { | |
160 | if (asrsh) | |
ac2f15b3 | 161 | *argv = rlogin; |
b7080c8e A |
162 | execv(_PATH_RLOGIN, argv); |
163 | err(1, "can't exec %s", _PATH_RLOGIN); | |
164 | } | |
165 | ||
166 | argc -= optind; | |
167 | argv += optind; | |
168 | ||
169 | if (!(pw = getpwuid(uid = getuid()))) | |
170 | errx(1, "unknown user id"); | |
b7080c8e A |
171 | if (!user) |
172 | user = pw->pw_name; | |
173 | ||
b7080c8e A |
174 | args = copyargs(argv); |
175 | ||
176 | sp = NULL; | |
b7080c8e A |
177 | if (sp == NULL) |
178 | sp = getservbyname("shell", "tcp"); | |
179 | if (sp == NULL) | |
180 | errx(1, "shell/tcp: unknown service"); | |
181 | ||
ac2f15b3 A |
182 | if (timeout) { |
183 | signal(SIGALRM, connect_timeout); | |
184 | alarm(timeout); | |
185 | } | |
186 | rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2, | |
187 | family); | |
188 | if (timeout) { | |
189 | signal(SIGALRM, SIG_DFL); | |
190 | alarm(0); | |
b7080c8e | 191 | } |
b7080c8e A |
192 | |
193 | if (rem < 0) | |
194 | exit(1); | |
195 | ||
196 | if (rfd2 < 0) | |
197 | errx(1, "can't establish stderr"); | |
198 | if (dflag) { | |
199 | if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, | |
200 | sizeof(one)) < 0) | |
201 | warn("setsockopt"); | |
202 | if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, | |
203 | sizeof(one)) < 0) | |
204 | warn("setsockopt"); | |
205 | } | |
206 | ||
207 | (void)setuid(uid); | |
208 | omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); | |
209 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) | |
210 | (void)signal(SIGINT, sendsig); | |
211 | if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) | |
212 | (void)signal(SIGQUIT, sendsig); | |
213 | if (signal(SIGTERM, SIG_IGN) != SIG_IGN) | |
214 | (void)signal(SIGTERM, sendsig); | |
215 | ||
216 | if (!nflag) { | |
217 | pid = fork(); | |
218 | if (pid < 0) | |
219 | err(1, "fork"); | |
220 | } | |
ac2f15b3 A |
221 | else |
222 | (void)shutdown(rem, 1); | |
b7080c8e | 223 | |
ac2f15b3 A |
224 | (void)ioctl(rfd2, FIONBIO, &one); |
225 | (void)ioctl(rem, FIONBIO, &one); | |
b7080c8e | 226 | |
ac2f15b3 | 227 | talk(nflag, omask, pid, rem, timeout); |
b7080c8e A |
228 | |
229 | if (!nflag) | |
230 | (void)kill(pid, SIGKILL); | |
231 | exit(0); | |
232 | } | |
233 | ||
234 | void | |
ac2f15b3 | 235 | talk(int nflag, long omask, pid_t pid, int rem, int timeout) |
b7080c8e A |
236 | { |
237 | int cc, wc; | |
238 | fd_set readfrom, ready, rembits; | |
ac2f15b3 A |
239 | char buf[BUFSIZ]; |
240 | const char *bp; | |
241 | struct timeval tvtimeout; | |
242 | int nfds, srval; | |
b7080c8e A |
243 | |
244 | if (!nflag && pid == 0) { | |
245 | (void)close(rfd2); | |
246 | ||
247 | reread: errno = 0; | |
248 | if ((cc = read(0, buf, sizeof buf)) <= 0) | |
249 | goto done; | |
250 | bp = buf; | |
251 | ||
ac2f15b3 A |
252 | rewrite: |
253 | if (rem >= FD_SETSIZE) | |
254 | errx(1, "descriptor too big"); | |
b7080c8e A |
255 | FD_ZERO(&rembits); |
256 | FD_SET(rem, &rembits); | |
ac2f15b3 A |
257 | nfds = rem + 1; |
258 | if (select(nfds, 0, &rembits, 0, 0) < 0) { | |
b7080c8e A |
259 | if (errno != EINTR) |
260 | err(1, "select"); | |
261 | goto rewrite; | |
262 | } | |
263 | if (!FD_ISSET(rem, &rembits)) | |
264 | goto rewrite; | |
ac2f15b3 | 265 | wc = write(rem, bp, cc); |
b7080c8e A |
266 | if (wc < 0) { |
267 | if (errno == EWOULDBLOCK) | |
268 | goto rewrite; | |
269 | goto done; | |
270 | } | |
271 | bp += wc; | |
272 | cc -= wc; | |
273 | if (cc == 0) | |
274 | goto reread; | |
275 | goto rewrite; | |
276 | done: | |
277 | (void)shutdown(rem, 1); | |
278 | exit(0); | |
279 | } | |
280 | ||
ac2f15b3 A |
281 | tvtimeout.tv_sec = timeout; |
282 | tvtimeout.tv_usec = 0; | |
283 | ||
b7080c8e | 284 | (void)sigsetmask(omask); |
ac2f15b3 A |
285 | if (rfd2 >= FD_SETSIZE || rem >= FD_SETSIZE) |
286 | errx(1, "descriptor too big"); | |
b7080c8e A |
287 | FD_ZERO(&readfrom); |
288 | FD_SET(rfd2, &readfrom); | |
289 | FD_SET(rem, &readfrom); | |
ac2f15b3 | 290 | nfds = MAX(rfd2+1, rem+1); |
b7080c8e A |
291 | do { |
292 | ready = readfrom; | |
ac2f15b3 A |
293 | if (timeout) { |
294 | srval = select(nfds, &ready, 0, 0, &tvtimeout); | |
295 | } else { | |
296 | srval = select(nfds, &ready, 0, 0, 0); | |
297 | } | |
298 | ||
299 | if (srval < 0) { | |
b7080c8e A |
300 | if (errno != EINTR) |
301 | err(1, "select"); | |
302 | continue; | |
303 | } | |
ac2f15b3 A |
304 | if (srval == 0) |
305 | errx(1, "timeout reached (%d seconds)\n", timeout); | |
b7080c8e A |
306 | if (FD_ISSET(rfd2, &ready)) { |
307 | errno = 0; | |
ac2f15b3 | 308 | cc = read(rfd2, buf, sizeof buf); |
b7080c8e A |
309 | if (cc <= 0) { |
310 | if (errno != EWOULDBLOCK) | |
311 | FD_CLR(rfd2, &readfrom); | |
312 | } else | |
ac2f15b3 | 313 | (void)write(STDERR_FILENO, buf, cc); |
b7080c8e A |
314 | } |
315 | if (FD_ISSET(rem, &ready)) { | |
316 | errno = 0; | |
ac2f15b3 | 317 | cc = read(rem, buf, sizeof buf); |
b7080c8e A |
318 | if (cc <= 0) { |
319 | if (errno != EWOULDBLOCK) | |
320 | FD_CLR(rem, &readfrom); | |
321 | } else | |
ac2f15b3 | 322 | (void)write(STDOUT_FILENO, buf, cc); |
b7080c8e A |
323 | } |
324 | } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom)); | |
325 | } | |
326 | ||
327 | void | |
ac2f15b3 | 328 | connect_timeout(int sig) |
b7080c8e | 329 | { |
ac2f15b3 | 330 | char message[] = "timeout reached before connection completed.\n"; |
b7080c8e | 331 | |
ac2f15b3 A |
332 | write(STDERR_FILENO, message, sizeof(message) - 1); |
333 | _exit(1); | |
b7080c8e A |
334 | } |
335 | ||
b7080c8e | 336 | void |
ac2f15b3 | 337 | sendsig(int sig) |
b7080c8e | 338 | { |
ac2f15b3 A |
339 | char signo; |
340 | ||
341 | signo = sig; | |
342 | (void)write(rfd2, &signo, 1); | |
b7080c8e | 343 | } |
b7080c8e A |
344 | |
345 | char * | |
ac2f15b3 | 346 | copyargs(char * const *argv) |
b7080c8e A |
347 | { |
348 | int cc; | |
ac2f15b3 A |
349 | char *args, *p; |
350 | char * const *ap; | |
b7080c8e A |
351 | |
352 | cc = 0; | |
353 | for (ap = argv; *ap; ++ap) | |
354 | cc += strlen(*ap) + 1; | |
355 | if (!(args = malloc((u_int)cc))) | |
356 | err(1, NULL); | |
357 | for (p = args, ap = argv; *ap; ++ap) { | |
358 | (void)strcpy(p, *ap); | |
359 | for (p = strcpy(p, *ap); *p; ++p); | |
360 | if (ap[1]) | |
361 | *p++ = ' '; | |
362 | } | |
363 | return (args); | |
364 | } | |
365 | ||
366 | void | |
ac2f15b3 | 367 | usage(void) |
b7080c8e A |
368 | { |
369 | ||
370 | (void)fprintf(stderr, | |
ac2f15b3 | 371 | "usage: rsh [-46] [-nd] [-l login] [-t timeout] host [command]\n"); |
b7080c8e A |
372 | exit(1); |
373 | } |