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