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