]> git.saurik.com Git - apple/network_cmds.git/blob - rsh.tproj/rsh.c
network_cmds-76.tar.gz
[apple/network_cmds.git] / rsh.tproj / rsh.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /*-
25 * Copyright (c) 1983, 1990, 1993, 1994
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57
58 /*
59 * $Source: /cvs/Darwin/Commands/NeXT/network_cmds/rsh.tproj/rsh.c,v $
60 * $Header: /cvs/Darwin/Commands/NeXT/network_cmds/rsh.tproj/rsh.c,v 1.1.1.1 1999/05/02 03:58:17 wsanchez Exp $
61 */
62
63 #include <sys/types.h>
64 #include <sys/signal.h>
65 #include <sys/socket.h>
66 #include <sys/ioctl.h>
67 #include <sys/file.h>
68
69 #include <netinet/in.h>
70 #include <netdb.h>
71
72 #include <err.h>
73 #include <errno.h>
74 #include <pwd.h>
75 #include <signal.h>
76 #include <stdio.h>
77 #include <stdlib.h>
78 #include <string.h>
79 #include <unistd.h>
80 #include <varargs.h>
81
82 #include "pathnames.h"
83
84 #ifdef KERBEROS
85 #include <kerberosIV/des.h>
86 #include <kerberosIV/krb.h>
87
88 CREDENTIALS cred;
89 Key_schedule schedule;
90 int use_kerberos = 1, doencrypt;
91 char dst_realm_buf[REALM_SZ], *dest_realm;
92 extern char *krb_realmofhost();
93 #endif
94
95 /*
96 * rsh - remote shell
97 */
98 int rfd2;
99
100 char *copyargs __P((char **));
101 void sendsig __P((int));
102 void talk __P((int, long, pid_t, int));
103 void usage __P((void));
104 void warning __P(());
105
106 int
107 main(argc, argv)
108 int argc;
109 char **argv;
110 {
111 struct passwd *pw;
112 struct servent *sp;
113 long omask;
114 int argoff, asrsh, ch, dflag, nflag, one, rem;
115 pid_t pid;
116 uid_t uid;
117 char *args, *host, *p, *user;
118
119 argoff = asrsh = dflag = nflag = 0;
120 one = 1;
121 host = user = NULL;
122
123 /* if called as something other than "rsh", use it as the host name */
124 if (p = strrchr(argv[0], '/'))
125 ++p;
126 else
127 p = argv[0];
128 if (strcmp(p, "rsh"))
129 host = p;
130 else
131 asrsh = 1;
132
133 /* handle "rsh host flags" */
134 if (!host && argc > 2 && argv[1][0] != '-') {
135 host = argv[1];
136 argoff = 1;
137 }
138
139 #ifdef KERBEROS
140 #ifdef CRYPT
141 #define OPTIONS "8KLdek:l:nwx"
142 #else
143 #define OPTIONS "8KLdek:l:nw"
144 #endif
145 #else
146 #define OPTIONS "8KLdel:nw"
147 #endif
148 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
149 switch(ch) {
150 case 'K':
151 #ifdef KERBEROS
152 use_kerberos = 0;
153 #endif
154 break;
155 case 'L': /* -8Lew are ignored to allow rlogin aliases */
156 case 'e':
157 case 'w':
158 case '8':
159 break;
160 case 'd':
161 dflag = 1;
162 break;
163 case 'l':
164 user = optarg;
165 break;
166 #ifdef KERBEROS
167 case 'k':
168 dest_realm = dst_realm_buf;
169 strncpy(dest_realm, optarg, REALM_SZ);
170 break;
171 #endif
172 case 'n':
173 nflag = 1;
174 break;
175 #ifdef KERBEROS
176 #ifdef CRYPT
177 case 'x':
178 doencrypt = 1;
179 des_set_key(cred.session, schedule);
180 break;
181 #endif
182 #endif
183 case '?':
184 default:
185 usage();
186 }
187 optind += argoff;
188
189 /* if haven't gotten a host yet, do so */
190 if (!host && !(host = argv[optind++]))
191 usage();
192
193 /* if no further arguments, must have been called as rlogin. */
194 if (!argv[optind]) {
195 if (asrsh)
196 *argv = "rlogin";
197 execv(_PATH_RLOGIN, argv);
198 err(1, "can't exec %s", _PATH_RLOGIN);
199 }
200
201 argc -= optind;
202 argv += optind;
203
204 if (!(pw = getpwuid(uid = getuid())))
205 errx(1, "unknown user id");
206 /* Accept user1@host format, though "-l user2" overrides user1 */
207 p = strchr(host, '@');
208 if (p) {
209 *p = '\0';
210 if (!user && p > host)
211 user = host;
212 host = p + 1;
213 if (*host == '\0')
214 usage();
215 }
216 if (!user)
217 user = pw->pw_name;
218
219 #ifdef KERBEROS
220 #ifdef CRYPT
221 /* -x turns off -n */
222 if (doencrypt)
223 nflag = 0;
224 #endif
225 #endif
226
227 args = copyargs(argv);
228
229 sp = NULL;
230 #ifdef KERBEROS
231 if (use_kerberos) {
232 sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
233 if (sp == NULL) {
234 use_kerberos = 0;
235 warning("can't get entry for %s/tcp service",
236 doencrypt ? "ekshell" : "kshell");
237 }
238 }
239 #endif
240 if (sp == NULL)
241 sp = getservbyname("shell", "tcp");
242 if (sp == NULL)
243 errx(1, "shell/tcp: unknown service");
244
245 #ifdef KERBEROS
246 try_connect:
247 if (use_kerberos) {
248 struct hostent *hp;
249
250 /* fully qualify hostname (needed for krb_realmofhost) */
251 hp = gethostbyname(host);
252 if (hp != NULL && !(host = strdup(hp->h_name)))
253 err(1, NULL);
254
255 rem = KSUCCESS;
256 errno = 0;
257 if (dest_realm == NULL)
258 dest_realm = krb_realmofhost(host);
259
260 #ifdef CRYPT
261 if (doencrypt)
262 rem = krcmd_mutual(&host, sp->s_port, user, args,
263 &rfd2, dest_realm, &cred, schedule);
264 else
265 #endif
266 rem = krcmd(&host, sp->s_port, user, args, &rfd2,
267 dest_realm);
268 if (rem < 0) {
269 use_kerberos = 0;
270 sp = getservbyname("shell", "tcp");
271 if (sp == NULL)
272 errx(1, "shell/tcp: unknown service");
273 if (errno == ECONNREFUSED)
274 warning("remote host doesn't support Kerberos");
275 if (errno == ENOENT)
276 warning("can't provide Kerberos auth data");
277 goto try_connect;
278 }
279 } else {
280 if (doencrypt)
281 errx(1, "the -x flag requires Kerberos authentication");
282 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
283 }
284 #else
285 rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
286 #endif
287
288 if (rem < 0)
289 exit(1);
290
291 if (rfd2 < 0)
292 errx(1, "can't establish stderr");
293 if (dflag) {
294 if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
295 sizeof(one)) < 0)
296 warn("setsockopt");
297 if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
298 sizeof(one)) < 0)
299 warn("setsockopt");
300 }
301
302 (void)setuid(uid);
303 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
304 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
305 (void)signal(SIGINT, sendsig);
306 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
307 (void)signal(SIGQUIT, sendsig);
308 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
309 (void)signal(SIGTERM, sendsig);
310
311 if (!nflag) {
312 pid = fork();
313 if (pid < 0)
314 err(1, "fork");
315 }
316
317 #ifdef KERBEROS
318 #ifdef CRYPT
319 if (!doencrypt)
320 #endif
321 #endif
322 {
323 (void)ioctl(rfd2, FIONBIO, &one);
324 (void)ioctl(rem, FIONBIO, &one);
325 }
326
327 talk(nflag, omask, pid, rem);
328
329 if (!nflag)
330 (void)kill(pid, SIGKILL);
331 exit(0);
332 }
333
334 void
335 talk(nflag, omask, pid, rem)
336 int nflag;
337 long omask;
338 pid_t pid;
339 int rem;
340 {
341 int cc, wc;
342 fd_set readfrom, ready, rembits;
343 char *bp, buf[BUFSIZ];
344
345 if (!nflag && pid == 0) {
346 (void)close(rfd2);
347
348 reread: errno = 0;
349 if ((cc = read(0, buf, sizeof buf)) <= 0)
350 goto done;
351 bp = buf;
352
353 rewrite:
354 FD_ZERO(&rembits);
355 FD_SET(rem, &rembits);
356 if (select(16, 0, &rembits, 0, 0) < 0) {
357 if (errno != EINTR)
358 err(1, "select");
359 goto rewrite;
360 }
361 if (!FD_ISSET(rem, &rembits))
362 goto rewrite;
363 #ifdef KERBEROS
364 #ifdef CRYPT
365 if (doencrypt)
366 wc = des_write(rem, bp, cc);
367 else
368 #endif
369 #endif
370 wc = write(rem, bp, cc);
371 if (wc < 0) {
372 if (errno == EWOULDBLOCK)
373 goto rewrite;
374 goto done;
375 }
376 bp += wc;
377 cc -= wc;
378 if (cc == 0)
379 goto reread;
380 goto rewrite;
381 done:
382 (void)shutdown(rem, 1);
383 exit(0);
384 }
385
386 (void)sigsetmask(omask);
387 FD_ZERO(&readfrom);
388 FD_SET(rfd2, &readfrom);
389 FD_SET(rem, &readfrom);
390 do {
391 ready = readfrom;
392 if (select(16, &ready, 0, 0, 0) < 0) {
393 if (errno != EINTR)
394 err(1, "select");
395 continue;
396 }
397 if (FD_ISSET(rfd2, &ready)) {
398 errno = 0;
399 #ifdef KERBEROS
400 #ifdef CRYPT
401 if (doencrypt)
402 cc = des_read(rfd2, buf, sizeof buf);
403 else
404 #endif
405 #endif
406 cc = read(rfd2, buf, sizeof buf);
407 if (cc <= 0) {
408 if (errno != EWOULDBLOCK)
409 FD_CLR(rfd2, &readfrom);
410 } else
411 (void)write(2, buf, cc);
412 }
413 if (FD_ISSET(rem, &ready)) {
414 errno = 0;
415 #ifdef KERBEROS
416 #ifdef CRYPT
417 if (doencrypt)
418 cc = des_read(rem, buf, sizeof buf);
419 else
420 #endif
421 #endif
422 cc = read(rem, buf, sizeof buf);
423 if (cc <= 0) {
424 if (errno != EWOULDBLOCK)
425 FD_CLR(rem, &readfrom);
426 } else
427 (void)write(1, buf, cc);
428 }
429 } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
430 }
431
432 void
433 sendsig(sig)
434 int sig;
435 {
436 char signo;
437
438 signo = sig;
439 #ifdef KERBEROS
440 #ifdef CRYPT
441 if (doencrypt)
442 (void)des_write(rfd2, &signo, 1);
443 else
444 #endif
445 #endif
446 (void)write(rfd2, &signo, 1);
447 }
448
449 #ifdef KERBEROS
450 /* VARARGS */
451 void
452 warning(va_alist)
453 va_dcl
454 {
455 va_list ap;
456 char *fmt;
457
458 (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
459 va_start(ap);
460 fmt = va_arg(ap, char *);
461 vfprintf(stderr, fmt, ap);
462 va_end(ap);
463 (void)fprintf(stderr, ".\n");
464 }
465 #endif
466
467 char *
468 copyargs(argv)
469 char **argv;
470 {
471 int cc;
472 char **ap, *args, *p;
473
474 cc = 0;
475 for (ap = argv; *ap; ++ap)
476 cc += strlen(*ap) + 1;
477 if (!(args = malloc((u_int)cc)))
478 err(1, NULL);
479 for (p = args, ap = argv; *ap; ++ap) {
480 (void)strcpy(p, *ap);
481 for (p = strcpy(p, *ap); *p; ++p);
482 if (ap[1])
483 *p++ = ' ';
484 }
485 return (args);
486 }
487
488 void
489 usage()
490 {
491
492 (void)fprintf(stderr,
493 "usage: rsh [-nd%s]%s[-l login] [login@]host [command]\n",
494 #ifdef KERBEROS
495 #ifdef CRYPT
496 "x", " [-k realm] ");
497 #else
498 "", " [-k realm] ");
499 #endif
500 #else
501 "", " ");
502 #endif
503 exit(1);
504 }