remove-rx-2tier-freepacketq-20050403
[openafs.git] / src / rsh / rsh.c
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 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 RCSID
22     ("$Header$");
23
24 #include <unistd.h>             /* select() prototype */
25 #include <sys/types.h>          /* fd_set on older platforms */
26 #include <sys/time.h>           /* struct timeval, select() prototype */
27 #ifndef FD_SET
28 # include <sys/select.h>        /* fd_set on newer platforms */
29 #endif
30 #include <sys/socket.h>
31 #ifdef  AFS_SUN5_ENV
32 #define BSD_COMP
33 #endif
34 #include <sys/ioctl.h>
35 #include <sys/file.h>
36
37 #include <netinet/in.h>
38
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <errno.h>
43 #include <signal.h>
44 #include <pwd.h>
45 #include <netdb.h>
46
47 #ifdef  AFS_AIX32_ENV
48 /*#ifdef MSG
49 #include "rsh_msg.h" 
50 #define MSGSTR(n,s) NLgetamsg(MF_RSH, MS_RSH, n, s) 
51 #else*/
52 #define MSGSTR(n,s) s
53 /*#endif*/
54
55 #ifdef KAUTH
56 #include <afs/auth.h>
57 #include <afs/cellconfig.h>
58 #endif /* KAUTH */
59 #endif
60
61 #ifdef AFS_HPUX_ENV
62 #include <sys/stat.h>
63 extern char **environ;
64 char **vp;
65 #define RSHNAME "remsh"
66 #else
67 #define RSHNAME "rsh"
68 #endif /* AFS_HPUX_ENV */
69
70 /*
71  * rsh - remote shell
72  */
73 /* VARARGS */
74 int error();
75
76 int errno;
77 int options;
78 int rfd2;
79 int nflag;
80 void sendsig();
81
82 #define mask(s) (1 << ((s) - 1))
83 #if defined(AFS_AIX32_ENV) && (defined(NLS) || defined(KJI))
84 #include <locale.h>
85 #endif
86
87 #include "AFS_component_version_number.c"
88
89 /*
90  * rlogin directory
91  *
92  * We don't really need a definition for AFS_SGI_ENV since SGI's own rsh
93  * does the right thing.
94  *
95  * In some older platforms, such as SunOS 4.x, rlogin lives in /usr/ucb.
96  * But for all our currently supported platforms for AFS 3.5, it's in /usr/bin.
97  */
98 #ifdef  AFS_SGI_ENV
99 #define _PATH_RLOGIN    "/usr/bsd/rlogin"
100 #else
101 #define _PATH_RLOGIN    "/usr/bin/rlogin"
102 #endif
103
104 main(argc, argv0)
105      int argc;
106      char **argv0;
107 {
108     int rem, pid;
109     char *host, *cp, **ap, buf[BUFSIZ], *args, **argv = argv0, *user = 0;
110     register int cc;
111     int asrsh = 0;
112     struct passwd *pwd;
113     fd_set readfrom, ready;
114     int one = 1;
115     struct servent *sp;
116
117     sigset_t oset;
118     sigset_t sigBlock;
119     int someSignals[100];
120
121 #ifdef  AFS_HPUX_ENV
122     int fd;
123     struct stat stat_buf;
124     char *clientname;
125 #endif
126 #if defined(AFS_AIX32_ENV)
127     struct sigaction ign_act, save_old_act;
128 #ifdef KAUTH
129     int pass_tokens;
130 #endif /* KAUTH */
131
132 #if defined(AFS_AIX32_ENV) && (defined(NLS) || defined(KJI))
133     setlocale(LC_ALL, "");
134 #endif
135
136 #ifdef  notdef
137     /*
138      * If we're being called as a non-afs version of the program, and if AFS extensions
139      * have been loaded, run the AFS version  of the program.
140      */
141     check_and_run_afs_vers(argv);
142 #endif
143     memset(&ign_act, 0, sizeof(ign_act));
144     ign_act.sa_handler = SIG_IGN;
145 #endif
146     host = strrchr(argv[0], '/');
147     if (host)
148         host++;
149     else
150         host = argv[0];
151     argv++, --argc;
152 #ifdef  AFS_HPUX_ENV
153     /* if invoked as something other than remsh or rsh, use the 
154      * invocation name as the host name to connect to (clever).
155      */
156     if (!strcmp(host, "remsh") || !strcmp(host, "rsh")) {
157         clientname = host;
158         host = *argv++, --argc;
159         asrsh = 1;
160     } else {
161         clientname = "remsh";
162     }
163 #else
164     if (!strcmp(host, RSHNAME)) {
165         if (argc == 0)
166             goto usage;
167         if (*argv[0] != '-') {
168             host = *argv++, --argc;
169             asrsh = 1;
170         } else
171             host = 0;
172     }
173 #endif
174 #ifdef KAUTH
175     pass_tokens = (int)getenv("KAUTH");
176     if (pass_tokens) {
177         pass_tokens = (!strcmp((char *)pass_tokens, "afs"));
178     }
179 #endif /* KAUTH */
180 #ifdef  AFS_HPUX_ENV
181     /* make sure file descriptors 0, 1, and 2 are open */
182     for (fd = 0; fd <= 2; fd++) {
183         if (fstat(fd, &stat_buf) != 0) {
184             if (open("/dev/null", O_RDWR) < 0) {
185                 fprintf(stderr, "%s: ", clientname);
186                 perror("open:");
187                 exit(1);
188             }
189         }
190     }
191     /* save a copy of original environment in case we exec rlogin */
192     {
193         int vecsize = 0, envsize = 0, i = 0;
194         vp = environ;
195         while (vp != (char **)NULL && *vp != (char *)NULL) {
196             vecsize++;
197             envsize += strlen(*vp) + 1;
198             vp++;
199         }
200         vp = (char **)malloc((vecsize + 1) * sizeof(char *));
201         cp = malloc(envsize);
202         while (i < vecsize) {
203             vp[i] = cp;
204             strcpy(vp[i], environ[i]);
205             while (*cp != (char)NULL)
206                 cp++;
207             cp++;
208             i++;
209         }
210     }
211
212     /* clear timers, close open files, and wipe out environment */
213     cleanenv(&environ, "LANG", "LANGOPTS", "NLSPATH", "LOCALDOMAIN",
214              "HOSTALIASES", 0);
215 #endif
216   another:
217     if (argc > 0 && !strcmp(*argv, "-l")) {
218         argv++, argc--;
219         if (argc > 0)
220             user = *argv++, argc--;
221         goto another;
222     }
223     if (argc > 0 && !strcmp(*argv, "-n")) {
224         argv++, argc--;
225         nflag++;
226 #ifdef  AFS_SUN_ENV
227         (void)close(0);
228         (void)open("/dev/null", 0);
229 #endif
230         goto another;
231     }
232     if (argc > 0 && !strcmp(*argv, "-d")) {
233         argv++, argc--;
234         options |= SO_DEBUG;
235         goto another;
236     }
237 #ifdef KAUTH
238     if (argc > 0 && !strcmp(*argv, "-v")) {
239         argv++, argc--;
240         pass_tokens = 1;
241         goto another;
242     }
243     if (argc > 0 && !strcmp(*argv, "-V")) {
244         argv++, argc--;
245         pass_tokens = 0;
246         goto another;
247     }
248 #endif /* KAUTH */
249     /*
250      * Ignore the -L, -w, -e and -8 flags to allow aliases with rlogin
251      * to work
252      *
253      * There must be a better way to do this! -jmb
254      */
255     if (argc > 0 && !strncmp(*argv, "-L", 2)) {
256         argv++, argc--;
257         goto another;
258     }
259     if (argc > 0 && !strncmp(*argv, "-w", 2)) {
260         argv++, argc--;
261         goto another;
262     }
263     if (argc > 0 && !strncmp(*argv, "-e", 2)) {
264         argv++, argc--;
265         goto another;
266     }
267     if (argc > 0 && !strncmp(*argv, "-8", 2)) {
268         argv++, argc--;
269         goto another;
270     }
271 #ifdef  AFS_HPUX_ENV
272     if (argc > 0 && !strncmp(*argv, "-7", 2)) {
273         argv++, argc--;
274         goto another;
275     }
276 #endif
277     if (host == 0) {
278         if (argc == 0)
279             goto usage;
280         host = *argv++, --argc;
281         asrsh = 1;
282     }
283     if (argv[0] == 0) {
284         if (asrsh)
285             *argv0 = "rlogin";
286
287 #ifdef AFS_HPUX_ENV
288         execve(_PATH_RLOGIN, argv0, vp);
289 #else
290         execv(_PATH_RLOGIN, argv0);
291 #endif
292         perror(_PATH_RLOGIN);
293         exit(1);
294     }
295     pwd = getpwuid(getuid());
296     if (pwd == 0) {
297         fprintf(stderr, "who are you?\n");
298         exit(1);
299     }
300     cc = 0;
301     for (ap = argv; *ap; ap++)
302         cc += strlen(*ap) + 1;
303     cp = args = malloc(cc);
304     for (ap = argv; *ap; ap++) {
305         (void)strcpy(cp, *ap);
306         while (*cp)
307             cp++;
308         if (ap[1])
309             *cp++ = ' ';
310     }
311     sp = getservbyname("shell", "tcp");
312     if (sp == 0) {
313         fprintf(stderr, "%s: shell/tcp: unknown service\n", RSHNAME);
314         exit(1);
315     }
316     rem = rcmd(&host, sp->s_port, pwd->pw_name,
317 #ifdef  AFS_AIX32_ENV
318                user ? user : pwd->pw_name, args, &rfd2, /* long timeout? */
319                1);
320 #else
321                user ? user : pwd->pw_name, args, &rfd2);
322 #endif
323     if (rem < 0)
324         exit(1);
325     if (rfd2 < 0) {
326         fprintf(stderr, "%s: can't establish stderr\n", RSHNAME);
327         exit(2);
328     }
329     if (options & SO_DEBUG) {
330         if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char *)&one, sizeof(one)) <
331             0)
332             perror("setsockopt (stdin)");
333         if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, (char *)&one, sizeof(one))
334             < 0)
335             perror("setsockopt (stderr)");
336     }
337     (void)setuid(getuid());
338
339     memset((char *)someSignals, 0, sizeof(someSignals));
340 #ifdef  AFS_HPUX_ENV
341     someSignals[0] =
342         mask(SIGINT) | mask(SIGQUIT) | mask(SIGTERM) | mask(SIGHUP);
343 #else
344     someSignals[0] = mask(SIGINT) | mask(SIGQUIT) | mask(SIGTERM);
345 #endif
346     sigBlock = *((sigset_t *) someSignals);
347     sigprocmask(SIG_BLOCK, &sigBlock, &oset);
348 #ifdef  AFS_AIX32_ENV
349     (void)sigaction(SIGINT, &ign_act, &save_old_act);
350     if (save_old_act.sa_handler != SIG_IGN)
351         (void)signal(SIGINT, sendsig);
352     (void)sigaction(SIGQUIT, &ign_act, &save_old_act);
353     if (save_old_act.sa_handler != SIG_IGN)
354         (void)signal(SIGQUIT, sendsig);
355     (void)sigaction(SIGTERM, &ign_act, &save_old_act);
356     if (save_old_act.sa_handler != SIG_IGN)
357         (void)signal(SIGTERM, sendsig);
358 #else
359     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
360         signal(SIGINT, sendsig);
361     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
362         signal(SIGQUIT, sendsig);
363     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
364         signal(SIGTERM, sendsig);
365 #ifdef  AFS_HPUX_ENV
366     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
367         signal(SIGHUP, sendsig);
368     /* ignore the death of my child -- banish zombies! */
369     signal(SIGCLD, SIG_IGN);
370 #endif
371 #endif
372     if (nflag == 0) {
373         pid = fork();
374         if (pid < 0) {
375             perror("fork");
376             exit(1);
377         }
378     }
379     ioctl(rfd2, FIONBIO, &one);
380     ioctl(rem, FIONBIO, &one);
381     if (nflag == 0 && pid == 0) {
382         char *bp;
383         int wc;
384         fd_set rembits;
385         (void)close(rfd2);
386       reread:
387         errno = 0;
388         cc = read(0, buf, sizeof buf);
389         if (cc <= 0)
390             goto done;
391         bp = buf;
392       rewrite:
393         FD_ZERO(&rembits);
394         FD_SET(rem, &rembits);
395         if (select(rem + 1, 0, &rembits, 0, 0) < 0) {
396             if (errno != EINTR) {
397                 perror("select");
398                 exit(1);
399             }
400             goto rewrite;
401         }
402         if (!FD_ISSET(rem, &rembits))
403             goto rewrite;
404         wc = write(rem, bp, cc);
405         if (wc < 0) {
406             if (errno == EWOULDBLOCK)
407                 goto rewrite;
408             goto done;
409         }
410         cc -= wc;
411         bp += wc;
412         if (cc == 0)
413             goto reread;
414         goto rewrite;
415       done:
416         (void)shutdown(rem, 1);
417         exit(0);
418     }
419     sigprocmask(SIG_SETMASK, &oset, (sigset_t *) 0);
420     FD_ZERO(&readfrom);
421     FD_SET(rfd2, &readfrom);
422     FD_SET(rem, &readfrom);
423     for (;;) {
424         int maxfd;
425         maxfd = -1;
426         if (FD_ISSET(rfd2, &readfrom) && maxfd < rfd2)
427             maxfd = rfd2;
428         if (FD_ISSET(rem, &readfrom) && maxfd < rem)
429             maxfd = rem;
430         if (maxfd == -1)
431             break;
432         ready = readfrom;
433         if (select(maxfd + 1, &ready, 0, 0, 0) < 0) {
434             if (errno != EINTR) {
435                 perror("select");
436                 exit(1);
437             }
438             continue;
439         }
440         if (FD_ISSET(rfd2, &ready)) {
441             errno = 0;
442             cc = read(rfd2, buf, sizeof buf);
443             if (cc <= 0) {
444                 if (errno != EWOULDBLOCK)
445                     FD_CLR(rfd2, &readfrom);
446             } else
447                 (void)write(2, buf, cc);
448         }
449         if (FD_ISSET(rem, &ready)) {
450             errno = 0;
451             cc = read(rem, buf, sizeof buf);
452             if (cc <= 0) {
453                 if (errno != EWOULDBLOCK)
454                     FD_CLR(rem, &readfrom);
455             } else
456                 (void)write(1, buf, cc);
457         }
458     }
459     if (nflag == 0)
460         (void)kill(pid, SIGKILL);
461     exit(0);
462   usage:
463     fprintf(stderr, "usage: %s host [ -l login ] [ -n ] command\n", RSHNAME);
464     exit(1);
465 }
466
467 void
468 sendsig(signo)
469      char signo;
470 {
471
472     (void)write(rfd2, &signo, 1);
473 }