]> git.saurik.com Git - apple/network_cmds.git/blame - rsh.tproj/rsh.c
network_cmds-176.tar.gz
[apple/network_cmds.git] / rsh.tproj / rsh.c
CommitLineData
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
42static 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
48static 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 */
77int rfd2;
78
ac2f15b3
A
79int family = PF_UNSPEC;
80char rlogin[] = "rlogin";
81
82void connect_timeout(int);
83char *copyargs(char * const *);
84void sendsig(int);
85void talk(int, long, pid_t, int, int);
86void usage(void);
b7080c8e
A
87
88int
ac2f15b3 89main(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
234void
ac2f15b3 235talk(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
247reread: errno = 0;
248 if ((cc = read(0, buf, sizeof buf)) <= 0)
249 goto done;
250 bp = buf;
251
ac2f15b3
A
252rewrite:
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;
276done:
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
327void
ac2f15b3 328connect_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 336void
ac2f15b3 337sendsig(int sig)
b7080c8e 338{
ac2f15b3
A
339 char signo;
340
341 signo = sig;
342 (void)write(rfd2, &signo, 1);
b7080c8e 343}
b7080c8e
A
344
345char *
ac2f15b3 346copyargs(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
366void
ac2f15b3 367usage(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}