]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/rsh/rsh.c
This commit was generated by cvs2svn to compensate for changes in r94670,
[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 static const char sccsid[] = "From: @(#)rsh.c   8.3 (Berkeley) 4/6/94";
42 #endif /* not lint */
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46
47 #include <sys/param.h>
48 #include <sys/signal.h>
49 #include <sys/socket.h>
50 #include <sys/ioctl.h>
51 #include <sys/file.h>
52 #include <sys/time.h>
53
54 #include <netinet/in.h>
55 #include <netdb.h>
56
57 #include <err.h>
58 #include <errno.h>
59 #include <libutil.h>
60 #include <pwd.h>
61 #include <signal.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66 #include <err.h>
67
68 #include "pathnames.h"
69
70 #ifdef KERBEROS
71 #include <openssl/des.h>
72 #include <krb.h>
73 #include "krb.h"
74
75 CREDENTIALS cred;
76 Key_schedule schedule;
77 int use_kerberos = 1, doencrypt;
78 char dst_realm_buf[REALM_SZ], *dest_realm;
79 extern char *krb_realmofhost();
80 #endif
81
82 /*
83  * rsh - remote shell
84  */
85 int     rfd2;
86
87 int family = PF_UNSPEC;
88 char rlogin[] = "rlogin";
89
90 char   *copyargs(char * const *);
91 void    sendsig(int);
92 void    talk(int, long, pid_t, int, int);
93 void    usage(void);
94
95 int
96 main(int argc, char *argv[])
97 {
98         struct passwd const *pw;
99         struct servent const *sp;
100         long omask;
101         int argoff, asrsh, ch, dflag, nflag, one, rem;
102         pid_t pid = 0;
103         uid_t uid;
104         char *args, *host, *p, *user;
105         int timeout = 0;
106 #ifdef KERBEROS
107         const char *k;
108 #endif
109
110         argoff = asrsh = dflag = nflag = 0;
111         one = 1;
112         host = user = NULL;
113
114         /* if called as something other than "rsh", use it as the host name */
115         if ((p = strrchr(argv[0], '/')))
116                 ++p;
117         else
118                 p = argv[0];
119         if (strcmp(p, "rsh"))
120                 host = p;
121         else
122                 asrsh = 1;
123
124         /* handle "rsh host flags" */
125         if (!host && argc > 2 && argv[1][0] != '-') {
126                 host = argv[1];
127                 argoff = 1;
128         }
129
130 #ifdef KERBEROS
131 #ifdef CRYPT
132 #define OPTIONS "468KLde:k:l:nt:wx"
133 #else
134 #define OPTIONS "468KLde:k:l:nt:w"
135 #endif
136 #else
137 #define OPTIONS "468KLde:l:nt:w"
138 #endif
139         while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
140                 switch(ch) {
141                 case '4':
142                         family = PF_INET;
143                         break;
144
145                 case '6':
146                         family = PF_INET6;
147                         break;
148
149                 case 'K':
150 #ifdef KERBEROS
151                         use_kerberos = 0;
152 #endif
153                         break;
154                 case 'L':       /* -8Lew are ignored to allow rlogin aliases */
155                 case 'e':
156                 case 'w':
157                 case '8':
158                         break;
159                 case 'd':
160                         dflag = 1;
161                         break;
162                 case 'l':
163                         user = optarg;
164                         break;
165 #ifdef KERBEROS
166                 case 'k':
167                         dest_realm = dst_realm_buf;
168                         strncpy(dest_realm, optarg, REALM_SZ);
169                         break;
170 #endif
171                 case 'n':
172                         nflag = 1;
173                         break;
174 #ifdef KERBEROS
175 #ifdef CRYPT
176                 case 'x':
177                         doencrypt = 1;
178                         break;
179 #endif
180 #endif
181                 case 't':
182                         timeout = atoi(optarg);
183                         break;
184                 case '?':
185                 default:
186                         usage();
187                 }
188         optind += argoff;
189
190         /* if haven't gotten a host yet, do so */
191         if (!host && !(host = argv[optind++]))
192                 usage();
193
194         /* if no further arguments, must have been called as rlogin. */
195         if (!argv[optind]) {
196                 if (asrsh)
197                         *argv = rlogin;
198                 execv(_PATH_RLOGIN, argv);
199                 err(1, "can't exec %s", _PATH_RLOGIN);
200         }
201
202         argc -= optind;
203         argv += optind;
204
205         if (!(pw = getpwuid(uid = getuid())))
206                 errx(1, "unknown user id");
207         if (!user)
208                 user = pw->pw_name;
209
210 #ifdef KERBEROS
211 #ifdef CRYPT
212         /* -x turns off -n */
213         if (doencrypt)
214                 nflag = 0;
215 #endif
216 #endif
217
218         args = copyargs(argv);
219
220         sp = NULL;
221 #ifdef KERBEROS
222         k = auth_getval("auth_list");
223         if (k && !strstr(k, "kerberos"))
224             use_kerberos = 0;
225         if (use_kerberos) {
226                 sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
227                 if (sp == NULL) {
228                         use_kerberos = 0;
229                         warnx(
230         "warning, using standard rsh: can't get entry for %s/tcp service",
231                             doencrypt ? "ekshell" : "kshell");
232                 }
233         }
234 #endif
235         if (sp == NULL)
236                 sp = getservbyname("shell", "tcp");
237         if (sp == NULL)
238                 errx(1, "shell/tcp: unknown service");
239
240 #ifdef KERBEROS
241 try_connect:
242         if (use_kerberos) {
243                 struct hostent *hp;
244
245                 /* fully qualify hostname (needed for krb_realmofhost) */
246                 hp = gethostbyname(host);
247                 if (hp != NULL && !(host = strdup(hp->h_name)))
248                         err(1, NULL);
249
250                 rem = KSUCCESS;
251                 errno = 0;
252                 if (dest_realm == NULL)
253                         dest_realm = krb_realmofhost(host);
254
255 #ifdef CRYPT
256                 if (doencrypt) {
257                         rem = krcmd_mutual(&host, sp->s_port, user, args,
258                             &rfd2, dest_realm, &cred, schedule);
259                         des_set_key(&cred.session, schedule);
260                 } else
261 #endif
262                         rem = krcmd(&host, sp->s_port, user, args, &rfd2,
263                             dest_realm);
264                 if (rem < 0) {
265                         use_kerberos = 0;
266                         sp = getservbyname("shell", "tcp");
267                         if (sp == NULL)
268                                 errx(1, "shell/tcp: unknown service");
269                         if (errno == ECONNREFUSED)
270                                 warnx(
271                 "warning, using standard rsh: remote host doesn't support Kerberos");
272                         if (errno == ENOENT)
273                                 warnx(
274                 "warning, using standard rsh: can't provide Kerberos auth data");
275                         goto try_connect;
276                 }
277         } else {
278                 if (doencrypt)
279                         errx(1, "the -x flag requires Kerberos authentication");
280                 rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args,
281                               &rfd2, family);
282         }
283 #else
284         rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
285                       family);
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         else
317                 (void)shutdown(rem, 1);
318
319 #ifdef KERBEROS
320 #ifdef CRYPT
321         if (!doencrypt)
322 #endif
323 #endif
324         {
325                 (void)ioctl(rfd2, FIONBIO, &one);
326                 (void)ioctl(rem, FIONBIO, &one);
327         }
328
329         talk(nflag, omask, pid, rem, timeout);
330
331         if (!nflag)
332                 (void)kill(pid, SIGKILL);
333         exit(0);
334 }
335
336 void
337 talk(int nflag, long omask, pid_t pid, int rem, int timeout)
338 {
339         int cc, wc;
340         fd_set readfrom, ready, rembits;
341         char buf[BUFSIZ];
342         const char *bp;
343         struct timeval tvtimeout;
344         int nfds, srval;
345
346         if (!nflag && pid == 0) {
347                 (void)close(rfd2);
348
349 reread:         errno = 0;
350                 if ((cc = read(0, buf, sizeof buf)) <= 0)
351                         goto done;
352                 bp = buf;
353
354 rewrite:
355                 FD_ZERO(&rembits);
356                 FD_SET(rem, &rembits);
357                 nfds = rem + 1;
358                 if (select(nfds, 0, &rembits, 0, 0) < 0) {
359                         if (errno != EINTR)
360                                 err(1, "select");
361                         goto rewrite;
362                 }
363                 if (!FD_ISSET(rem, &rembits))
364                         goto rewrite;
365 #ifdef KERBEROS
366 #ifdef CRYPT
367                 if (doencrypt)
368                         wc = des_enc_write(rem, bp, cc, schedule, &cred.session);
369                 else
370 #endif
371 #endif
372                         wc = write(rem, bp, cc);
373                 if (wc < 0) {
374                         if (errno == EWOULDBLOCK)
375                                 goto rewrite;
376                         goto done;
377                 }
378                 bp += wc;
379                 cc -= wc;
380                 if (cc == 0)
381                         goto reread;
382                 goto rewrite;
383 done:
384                 (void)shutdown(rem, 1);
385                 exit(0);
386         }
387
388         tvtimeout.tv_sec = timeout;
389         tvtimeout.tv_usec = 0;
390
391         (void)sigsetmask(omask);
392         FD_ZERO(&readfrom);
393         FD_SET(rfd2, &readfrom);
394         FD_SET(rem, &readfrom);
395         nfds = MAX(rfd2+1, rem+1);
396         do {
397                 ready = readfrom;
398                 if (timeout) {
399                         srval = select(nfds, &ready, 0, 0, &tvtimeout);
400                 } else {
401                         srval = select(nfds, &ready, 0, 0, 0);
402                 }
403
404                 if (srval < 0) {
405                         if (errno != EINTR)
406                                 err(1, "select");
407                         continue;
408                 }
409                 if (srval == 0)
410                         errx(1, "timeout reached (%d seconds)\n", timeout);
411                 if (FD_ISSET(rfd2, &ready)) {
412                         errno = 0;
413 #ifdef KERBEROS
414 #ifdef CRYPT
415                         if (doencrypt)
416                                 cc = des_enc_read(rfd2, buf, sizeof buf, schedule, &cred.session);
417                         else
418 #endif
419 #endif
420                                 cc = read(rfd2, buf, sizeof buf);
421                         if (cc <= 0) {
422                                 if (errno != EWOULDBLOCK)
423                                         FD_CLR(rfd2, &readfrom);
424                         } else
425                                 (void)write(STDERR_FILENO, buf, cc);
426                 }
427                 if (FD_ISSET(rem, &ready)) {
428                         errno = 0;
429 #ifdef KERBEROS
430 #ifdef CRYPT
431                         if (doencrypt)
432                                 cc = des_enc_read(rem, buf, sizeof buf, schedule, &cred.session);
433                         else
434 #endif
435 #endif
436                                 cc = read(rem, buf, sizeof buf);
437                         if (cc <= 0) {
438                                 if (errno != EWOULDBLOCK)
439                                         FD_CLR(rem, &readfrom);
440                         } else
441                                 (void)write(STDOUT_FILENO, buf, cc);
442                 }
443         } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
444 }
445
446 void
447 sendsig(int sig)
448 {
449         char signo;
450
451         signo = sig;
452 #ifdef KERBEROS
453 #ifdef CRYPT
454         if (doencrypt)
455                 (void)des_enc_write(rfd2, &signo, 1, schedule, &cred.session);
456         else
457 #endif
458 #endif
459                 (void)write(rfd2, &signo, 1);
460 }
461
462 char *
463 copyargs(char * const *argv)
464 {
465         int cc;
466         char *args, *p;
467         char * const *ap;
468
469         cc = 0;
470         for (ap = argv; *ap; ++ap)
471                 cc += strlen(*ap) + 1;
472         if (!(args = malloc((u_int)cc)))
473                 err(1, NULL);
474         for (p = args, ap = argv; *ap; ++ap) {
475                 (void)strcpy(p, *ap);
476                 for (p = strcpy(p, *ap); *p; ++p);
477                 if (ap[1])
478                         *p++ = ' ';
479         }
480         return (args);
481 }
482
483 void
484 usage(void)
485 {
486
487         (void)fprintf(stderr,
488             "usage: rsh [-46] [-ndK%s]%s[-l login] [-t timeout] host [command]\n",
489 #ifdef KERBEROS
490 #ifdef CRYPT
491             "x", " [-k realm] ");
492 #else
493             "", " [-k realm] ");
494 #endif
495 #else
496             "", " ");
497 #endif
498         exit(1);
499 }
500