Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / kerberosIV / appl / bsd / rsh.c
1 /*-
2  * Copyright (c) 1983, 1990 The Regents of the University of California.
3  * 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 #include "bsd_locl.h"
35
36 RCSID("$Id: rsh.c,v 1.43.2.2 2000/10/10 12:53:50 assar Exp $");
37
38 CREDENTIALS cred;
39 Key_schedule schedule;
40 int use_kerberos = 1, doencrypt;
41 char dst_realm_buf[REALM_SZ], *dest_realm;
42
43 /*
44  * rsh - remote shell
45  */
46 int rfd2;
47
48 static void
49 usage(void)
50 {
51     fprintf(stderr,
52             "usage: rsh [-ndKx] [-k realm] [-p port] [-l login] host [command]\n");
53     exit(1);
54 }
55
56 static char *
57 copyargs(char **argv)
58 {
59     int cc;
60     char **ap, *p;
61     char *args;
62
63     cc = 0;
64     for (ap = argv; *ap; ++ap)
65         cc += strlen(*ap) + 1;
66     args = malloc(cc);
67     if (args == NULL)
68         errx(1, "Out of memory.");
69     for (p = args, ap = argv; *ap; ++ap) {
70         strcpy(p, *ap);
71         while(*p)
72             ++p;
73         if (ap[1])
74             *p++ = ' ';
75     }
76     return(args);
77 }
78
79 static RETSIGTYPE
80 sendsig(int signo_)
81 {
82     char signo = signo_;
83 #ifndef NOENCRYPTION
84     if (doencrypt)
85         des_enc_write(rfd2, &signo, 1, schedule, &cred.session);
86     else
87 #endif
88         write(rfd2, &signo, 1);
89 }
90
91 static void
92 talk(int nflag, sigset_t omask, int pid, int rem)
93 {
94     int cc, wc;
95     char *bp;
96     fd_set readfrom, ready, rembits;
97     char buf[DES_RW_MAXWRITE];
98
99     if (pid == 0) {
100         if (nflag)
101             goto done;
102
103         close(rfd2);
104
105     reread:             errno = 0;
106     if ((cc = read(0, buf, sizeof buf)) <= 0)
107         goto done;
108     bp = buf;
109
110     rewrite:   
111     FD_ZERO(&rembits);
112     if (rem >= FD_SETSIZE)
113         errx(1, "fd too large");
114     FD_SET(rem, &rembits);
115     if (select(rem + 1, 0, &rembits, 0, 0) < 0) {
116         if (errno != EINTR) 
117             err(1, "select");
118         goto rewrite;
119     }
120     if (!FD_ISSET(rem, &rembits))
121         goto rewrite;
122 #ifndef NOENCRYPTION
123     if (doencrypt)
124         wc = des_enc_write(rem, bp, cc, schedule, &cred.session);
125     else
126 #endif
127         wc = write(rem, bp, cc);
128     if (wc < 0) {
129         if (errno == EWOULDBLOCK)
130             goto rewrite;
131         goto done;
132     }
133     bp += wc;
134     cc -= wc;
135     if (cc == 0)
136         goto reread;
137     goto rewrite;
138     done:
139     shutdown(rem, 1);
140     exit(0);
141     }
142
143     if (sigprocmask(SIG_SETMASK, &omask, 0) != 0)
144         warn("sigprocmask");
145     FD_ZERO(&readfrom);
146     if (rem >= FD_SETSIZE || rfd2 >= FD_SETSIZE)
147         errx(1, "fd too large");
148     FD_SET(rem, &readfrom);
149     FD_SET(rfd2, &readfrom);
150     do {
151         ready = readfrom;
152         if (select(max(rem,rfd2)+1, &ready, 0, 0, 0) < 0) {
153             if (errno != EINTR)
154                 err(1, "select");
155             continue;
156         }
157         if (FD_ISSET(rfd2, &ready)) {
158             errno = 0;
159 #ifndef NOENCRYPTION
160             if (doencrypt)
161                 cc = des_enc_read(rfd2, buf, sizeof buf,
162                                   schedule, &cred.session);
163             else
164 #endif
165                 cc = read(rfd2, buf, sizeof buf);
166             if (cc <= 0) {
167                 if (errno != EWOULDBLOCK)
168                     FD_CLR(rfd2, &readfrom);
169             } else
170                 write(2, buf, cc);
171         }
172         if (FD_ISSET(rem, &ready)) {
173             errno = 0;
174 #ifndef NOENCRYPTION
175             if (doencrypt)
176                 cc = des_enc_read(rem, buf, sizeof buf,
177                                   schedule, &cred.session);
178             else
179 #endif
180                 cc = read(rem, buf, sizeof buf);
181             if (cc <= 0) {
182                 if (errno != EWOULDBLOCK)
183                     FD_CLR(rem, &readfrom);
184             } else
185                 write(1, buf, cc);
186         }
187     } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
188 }
189
190 int
191 main(int argc, char **argv)
192 {
193     struct passwd *pw;
194     int sv_port, user_port = 0;
195     sigset_t omask;
196     int argoff, ch, dflag, nflag, nfork, one, pid, rem, uid;
197     char *args, *host, *user, *local_user;
198
199     argoff = dflag = nflag = nfork = 0;
200     one = 1;
201     host = user = NULL;
202     pid = 1;
203
204     set_progname(argv[0]);
205
206     /* handle "rsh host flags" */
207     if (argc > 2 && argv[1][0] != '-') {
208         host = argv[1];
209         argoff = 1;
210     }
211
212 #define OPTIONS "+8KLde:k:l:np:wx"
213     while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1)
214         switch(ch) {
215         case 'K':
216             use_kerberos = 0;
217             break;
218         case 'L':       /* -8Lew are ignored to allow rlogin aliases */
219         case 'e':
220         case 'w':
221         case '8':
222             break;
223         case 'd':
224             dflag = 1;
225             break;
226         case 'l':
227             user = optarg;
228             break;
229         case 'k':
230             dest_realm = dst_realm_buf;
231             strlcpy(dest_realm, optarg, REALM_SZ);
232             break;
233         case 'n':
234             nflag = nfork = 1;
235             break;
236         case 'x':
237             doencrypt = 1;
238             break;
239         case 'p': {
240             char *endptr;
241
242             user_port = strtol (optarg, &endptr, 0);
243             if (user_port == 0 && optarg == endptr)
244                 errx (1, "Bad port `%s'", optarg);
245             user_port = htons(user_port);
246             break;
247         }
248         case '?':
249         default:
250             usage();
251         }
252     optind += argoff;
253
254     /* if haven't gotten a host yet, do so */
255     if (!host && !(host = argv[optind++]))
256         usage();
257
258     /* if no further arguments, must have been called as rlogin. */
259     if (!argv[optind]) {
260         *argv = "rlogin";
261         paranoid_setuid (getuid ());
262         execv(_PATH_RLOGIN, argv);
263         err(1, "can't exec %s", _PATH_RLOGIN);
264     }
265
266 #ifndef __CYGWIN32__
267     if (!(pw = k_getpwuid(uid = getuid())))
268         errx(1, "unknown user id.");
269     local_user = pw->pw_name;
270     if (!user)
271         user = local_user;
272 #else
273     if (!user)
274         errx(1, "Sorry, you need to specify the username (with -l)");
275     local_user = user;
276 #endif
277
278     /* -n must still fork but does not turn of the -n functionality */
279     if (doencrypt)
280         nfork = 0;
281
282     args = copyargs(argv+optind);
283
284     if (user_port)
285         sv_port = user_port;
286     else
287         sv_port = get_shell_port(use_kerberos, doencrypt);
288
289     if (use_kerberos) {
290         paranoid_setuid(getuid());
291         rem = KSUCCESS;
292         errno = 0;
293         if (dest_realm == NULL)
294             dest_realm = krb_realmofhost(host);
295
296         if (doencrypt)
297             rem = krcmd_mutual(&host, sv_port, user, args,
298                                &rfd2, dest_realm, &cred, schedule);
299         else
300             rem = krcmd(&host, sv_port, user, args, &rfd2,
301                         dest_realm);
302         if (rem < 0) {
303             int i = 0;
304             char **newargv;
305
306             if (errno == ECONNREFUSED)
307                 warning("remote host doesn't support Kerberos");
308             if (errno == ENOENT)
309                 warning("can't provide Kerberos auth data");
310             newargv = malloc((argc + 2) * sizeof(*newargv));
311             if (newargv == NULL)
312                 err(1, "malloc");
313             newargv[i] = argv[i];
314             ++i;
315             if (argv[i][0] != '-') {
316                 newargv[i] = argv[i];
317                 ++i;
318             }
319             newargv[i++] = "-K";
320             for(; i <= argc; ++i)
321                 newargv[i] = argv[i - 1];
322             newargv[argc + 1] = NULL;
323             execv(_PATH_RSH, newargv);
324         }
325     } else {
326         if (doencrypt)
327             errx(1, "the -x flag requires Kerberos authentication.");
328         if (geteuid() != 0)
329             errx(1, "not installed setuid root, "
330                  "only root may use non kerberized rsh");
331         rem = rcmd(&host, sv_port, local_user, user, args, &rfd2);
332     }
333
334     if (rem < 0)
335         exit(1);
336
337     if (rfd2 < 0)
338         errx(1, "can't establish stderr.");
339 #if defined(SO_DEBUG) && defined(HAVE_SETSOCKOPT)
340     if (dflag) {
341         if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, (void *)&one,
342                        sizeof(one)) < 0)
343             warn("setsockopt");
344         if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, (void *)&one,
345                        sizeof(one)) < 0)
346             warn("setsockopt");
347     }
348 #endif
349
350     paranoid_setuid(uid);
351     {
352         sigset_t sigmsk;
353         sigemptyset(&sigmsk);
354         sigaddset(&sigmsk, SIGINT);
355         sigaddset(&sigmsk, SIGQUIT);
356         sigaddset(&sigmsk, SIGTERM);
357         if (sigprocmask(SIG_BLOCK, &sigmsk, &omask) != 0)
358             warn("sigprocmask");
359     }
360     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
361         signal(SIGINT, sendsig);
362     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
363         signal(SIGQUIT, sendsig);
364     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
365         signal(SIGTERM, sendsig);
366     signal(SIGPIPE, SIG_IGN);
367
368     if (!nfork) {
369         pid = fork();
370         if (pid < 0)
371             err(1, "fork");
372     }
373
374     if (!doencrypt) {
375         ioctl(rfd2, FIONBIO, &one);
376         ioctl(rem, FIONBIO, &one);
377     }
378
379     talk(nflag, omask, pid, rem);
380     
381     if (!nflag)
382         kill(pid, SIGKILL);
383     exit(0);
384 }