1 /*
2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 1983 Regents of the University of California.
8 * All rights reserved. The Berkeley software License Agreement
9 * specifies the terms and conditions for redistribution.
10 *
11 */
12
13 #define _FILE_OFFSET_BITS 64
14
15 #include <sys/time.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <sys/ioctl.h>
19 /* just for FIONBIO ... */
20 #include <sys/filio.h>
21 #include <sys/stat.h>
22 #include <sys/select.h>
23
24 #include <netinet/in.h>
25
26 #include <assert.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <signal.h>
34 #include <pwd.h>
35 #include <netdb.h>
36 #include <locale.h>
37 #include <priv_utils.h>
38
39 #include <k5-int.h>
40 #include <profile/prof_int.h>
41 #include <com_err.h>
42 #include <kcmd.h>
43 #include <krb5.h>
44
45 /* signal disposition - signal handler or SIG_IGN, SIG_ERR, etc. */
46 typedef void (*sigdisp_t)(int);
47
48 extern errcode_t profile_get_options_boolean(profile_t, char **,
49 profile_options_boolean *);
50 extern errcode_t profile_get_options_string(profile_t, char **,
51 profile_option_strings *);
52
53 #define RSH_BUFSIZ (1024 * 50)
54
55 static char des_inbuf[2 * RSH_BUFSIZ]; /* needs to be > largest read size */
56 static char des_outbuf[2 * RSH_BUFSIZ]; /* needs to be > largest write size */
57 static krb5_data desinbuf, desoutbuf;
58 static krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */
59 static krb5_context bsd_context = NULL;
60 static krb5_auth_context auth_context;
61 static krb5_creds *cred;
62 static krb5_keyblock *session_key;
63
64 static int encrypt_flag; /* Flag set, when encryption is used */
65 static int krb5auth_flag; /* Flag set, when KERBEROS is enabled */
66 static profile_options_boolean autologin_option[] = {
67 { "autologin", &krb5auth_flag, 0 },
68 { NULL, NULL, 0 }
69 };
70
71 static int no_krb5auth_flag = 0;
72 static int fflag; /* Flag set, if creds to be fwd'ed via -f */
73 static int Fflag; /* Flag set, if fwd'able creds to be fwd'ed via -F */
74
75 /* Flag set, if -PN / -PO is specified */
76 static boolean_t rcmdoption_done;
77
78 /* Flags set, if corres. cmd line options are turned on */
79 static boolean_t encrypt_done, fwd_done, fwdable_done;
80
81 static profile_options_boolean option[] = {
82 { "encrypt", &encrypt_flag, 0 },
83 { "forward", &fflag, 0 },
84 { "forwardable", &Fflag, 0 },
85 { NULL, NULL, 0 }
86 };
87
88 static char *rcmdproto;
89 static profile_option_strings rcmdversion[] = {
90 { "rcmd_protocol", &rcmdproto, 0 },
91 { NULL, NULL, 0 }
92 };
93
94 static char *realmdef[] = { "realms", NULL, "rsh", NULL };
95 static char *appdef[] = { "appdefaults", "rsh", NULL };
96
97 static void sendsig(int);
98 static sigdisp_t sigdisp(int);
99 static boolean_t init_service(boolean_t);
100 static int desrshread(int, char *, int);
101 static int desrshwrite(int, char *, int);
102
103 static int options;
104 static int rfd2;
105 static int portnumber;
106
107 static const char rlogin_path[] = "/usr/bin/rlogin";
108 static const char dash_x[] = "-x "; /* Note the blank after -x */
109
110 static boolean_t readiv, writeiv;
111
112 #define set2mask(setp) ((setp)->__sigbits[0])
113 #define mask2set(mask, setp) \
114 ((mask) == -1 ? sigfillset(setp) : (set2mask(setp) = (mask)))
115
116 #ifdef DEBUG
117 #define DEBUGOPTSTRING "D:"
118 #else
119 #define DEBUGOPTSTRING ""
120 #endif /* DEBUG */
121
122 static void
sigsetmask(int mask)123 sigsetmask(int mask)
124 {
125 sigset_t nset;
126
127 (void) sigprocmask(0, NULL, &nset);
128 mask2set(mask, &nset);
129 (void) sigprocmask(SIG_SETMASK, &nset, NULL);
130 }
131
132 static int
sigblock(int mask)133 sigblock(int mask)
134 {
135 sigset_t oset;
136 sigset_t nset;
137
138 (void) sigprocmask(0, NULL, &nset);
139 mask2set(mask, &nset);
140 (void) sigprocmask(SIG_BLOCK, &nset, &oset);
141 return (set2mask(&oset));
142 }
143
144 /*
145 * Get signal disposition (or signal handler) for a given signal
146 */
147 static sigdisp_t
sigdisp(int sig)148 sigdisp(int sig)
149 {
150 struct sigaction act;
151
152 act.sa_handler = NULL;
153 act.sa_flags = 0;
154 (void) sigemptyset(&act.sa_mask);
155 (void) sigaction(sig, NULL, &act);
156 return (act.sa_handler);
157 }
158
159 static pid_t child_pid = -1;
160
161 /*
162 * If you do a command like "rsh host output | wc"
163 * and wc terminates, then the parent will receive SIGPIPE
164 * and the child needs to be terminated.
165 */
166 /* ARGSUSED */
167 static void
sigpipehandler(int signal)168 sigpipehandler(int signal)
169 {
170 if (child_pid != -1)
171 (void) kill(child_pid, SIGKILL);
172 exit(EXIT_SUCCESS);
173 }
174
175 #define mask(s) (1 << ((s) - 1))
176
177 static void
usage(void)178 usage(void) {
179 (void) fprintf(stderr, "%s\n%s\n",
180 gettext("usage: rsh [ -PN / -PO ] [ -l login ] [ -n ] "
181 "[ -k realm ] [ -a ] [ -x ] [ -f / -F ] host command"),
182 gettext(" rsh [ -PN / -PO ] [ -l login ] [ -k realm ] "
183 "[ -a ] [ -x ] [ -f / -F ] host"));
184 exit(EXIT_FAILURE);
185 }
186
187 static void
die(const char * message)188 die(const char *message)
189 {
190 (void) fputs(message, stderr);
191 usage();
192 }
193
194 static void
usage_forward(void)195 usage_forward(void)
196 {
197 die(gettext("rsh: Only one of -f and -F allowed.\n"));
198 }
199
200 /*
201 * rsh - remote shell
202 */
203 /* VARARGS */
204 int
main(int argc,char ** argv)205 main(int argc, char **argv)
206 {
207 int c, rem;
208 char *cmd, *cp, **ap, buf[RSH_BUFSIZ], **argv0, *args, *args_no_x;
209 char *host = NULL, *user = NULL;
210 int cc;
211 boolean_t asrsh = B_FALSE;
212 struct passwd *pwd;
213 boolean_t readfrom_rem;
214 boolean_t readfrom_rfd2;
215 int one = 1;
216 int omask;
217 boolean_t nflag = B_FALSE;
218 char *krb_realm = NULL;
219 krb5_flags authopts;
220 krb5_error_code status;
221 enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL;
222 uid_t uid = getuid();
223
224 c = (argc + 1) * sizeof (char *);
225 if ((argv0 = malloc(c)) == NULL) {
226 perror("malloc");
227 return (EXIT_FAILURE);
228 }
229 (void) memcpy(argv0, argv, c);
230
231 (void) setlocale(LC_ALL, "");
232
233 (void) textdomain(TEXT_DOMAIN);
234
235 /*
236 * Determine command name used to invoke to rlogin(1). Users can
237 * create links named by a host pointing to the binary and type
238 * "hostname" to log into that host afterwards.
239 */
240 cmd = strrchr(argv[0], '/');
241 cmd = (cmd != NULL) ? (cmd + 1) : argv[0];
242
243 /*
244 * Add "remsh" as an alias for "rsh" (System III, V networking
245 * add-ons often used this name for the remote shell since rsh
246 * was already taken for the restricted shell). Note that this
247 * usurps the ability to use "remsh" as the name of a host (by
248 * symlinking it to rsh), so we go one step farther: if the
249 * file "/usr/bin/remsh" does not exist, we behave as if "remsh"
250 * is a host name. If it does exist, we accept "remsh" as an
251 * "rsh" alias.
252 */
253 if (strcmp(cmd, "remsh") == 0) {
254 struct stat sb;
255
256 if (stat("/usr/bin/remsh", &sb) < 0)
257 host = cmd;
258 } else if (strcmp(cmd, "rsh") != 0) {
259 host = cmd;
260 }
261
262 /* Handle legacy synopsis "rsh hostname options [command]". */
263 if (host == NULL) {
264 if (argc < 2)
265 usage();
266 if (*argv[1] != '-') {
267 host = argv[1];
268 argc--;
269 argv[1] = argv[0];
270 argv++;
271 asrsh = B_TRUE;
272 }
273 }
274
275 while ((c = getopt(argc, argv,
276 DEBUGOPTSTRING "8AFKLP:ade:fk:l:nwx")) != -1) {
277 switch (c) {
278 #ifdef DEBUG
279 case 'D':
280 portnumber = htons(atoi(optarg));
281 krb5auth_flag++;
282 break;
283 #endif /* DEBUG */
284 case 'F':
285 if (fflag)
286 usage_forward();
287 Fflag = 1;
288 krb5auth_flag++;
289 fwdable_done = B_TRUE;
290 break;
291 case 'f':
292 if (Fflag)
293 usage_forward();
294 fflag = 1;
295 krb5auth_flag++;
296 fwd_done = B_TRUE;
297 break;
298 case 'P':
299 if (strcmp(optarg, "N") == 0)
300 kcmd_proto = KCMD_NEW_PROTOCOL;
301 else if (strcmp(optarg, "O") == 0)
302 kcmd_proto = KCMD_OLD_PROTOCOL;
303 else
304 die(gettext("rsh: Only -PN or -PO "
305 "allowed.\n"));
306 if (rcmdoption_done)
307 die(gettext("rsh: Only one of -PN and -PO "
308 "allowed.\n"));
309 rcmdoption_done = B_TRUE;
310 krb5auth_flag++;
311 break;
312 case 'a':
313 krb5auth_flag++;
314 break;
315 case 'K':
316 no_krb5auth_flag++;
317 break;
318 case 'd':
319 options |= SO_DEBUG;
320 break;
321 case 'k':
322 krb_realm = optarg;
323 krb5auth_flag++;
324 break;
325 case 'l':
326 user = optarg;
327 break;
328 case 'n':
329 if (!nflag) {
330 if (close(STDIN_FILENO) < 0) {
331 perror("close");
332 return (EXIT_FAILURE);
333 }
334 /*
335 * "STDION_FILENO" defined to 0 by POSIX
336 * and hence the lowest file descriptor.
337 * So the open(2) below is guaranteed to
338 * reopen it because we closed it above.
339 */
340 if (open("/dev/null", O_RDONLY) < 0) {
341 perror("open");
342 return (EXIT_FAILURE);
343 }
344 nflag = B_TRUE;
345 }
346 break;
347 case 'x':
348 encrypt_flag = 1;
349 krb5auth_flag++;
350 encrypt_done = B_TRUE;
351 break;
352 /*
353 * Ignore the -L, -w, -e and -8 flags to allow aliases with
354 * rlogin to work. Actually rlogin(1) doesn't understand
355 * -w either but because "rsh -w hostname command" used
356 * to work we still accept it.
357 */
358 case '8':
359 case 'L':
360 case 'e':
361 case 'w':
362 /*
363 * On the lines of the -L, -w, -e and -8 options above, we
364 * ignore the -A option too, in order to allow aliases with
365 * rlogin to work.
366 *
367 * Mind you !, the -a option to trigger Kerberos authentication
368 * in rsh, has a totally different usage in rlogin, its the
369 * -A option (in rlogin) which needs to be used to talk
370 * Kerberos.
371 */
372 case 'A':
373 break;
374 default:
375 usage();
376 }
377 }
378
379 argc -= optind;
380 argv += optind;
381
382 if (host == NULL) {
383 if (argc == 0)
384 usage();
385 argc--;
386 host = *argv++;
387 asrsh = B_TRUE;
388 }
389
390 if (argc == 0) {
391 (void) setreuid(uid, uid);
392 if (nflag)
393 usage();
394 if (asrsh)
395 *argv0 = "rlogin";
396 (void) execv(rlogin_path, argv0);
397 perror(rlogin_path);
398
399 (void) fprintf(stderr, gettext("No local rlogin "
400 "program found.\n"));
401 return (EXIT_FAILURE);
402 }
403
404 if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) {
405 (void) fprintf(stderr,
406 gettext("Insufficient privileges, "
407 "rsh must be set-uid root\n"));
408 return (EXIT_FAILURE);
409 }
410
411 pwd = getpwuid(uid);
412 if (pwd == NULL) {
413 (void) fprintf(stderr, gettext("who are you?\n"));
414 return (EXIT_FAILURE);
415 }
416 if (user == NULL)
417 user = pwd->pw_name;
418
419 /*
420 * if the user disables krb5 on the cmdline (-K), then skip
421 * all krb5 setup.
422 *
423 * if the user does not disable krb5 or enable krb5 on the
424 * cmdline, check krb5.conf to see if it should be enabled.
425 */
426
427 if (no_krb5auth_flag) {
428 krb5auth_flag = 0;
429 Fflag = fflag = encrypt_flag = 0;
430 } else if (!krb5auth_flag) {
431 /* is autologin set in krb5.conf? */
432 status = krb5_init_context(&bsd_context);
433 /* don't sweat failure here */
434 if (!status) {
435 /*
436 * note that the call to profile_get_options_boolean
437 * with autologin_option can affect value of
438 * krb5auth_flag
439 */
440 (void) profile_get_options_boolean(bsd_context->profile,
441 appdef,
442 autologin_option);
443 }
444 }
445
446 if (krb5auth_flag) {
447 if (!bsd_context) {
448 status = krb5_init_context(&bsd_context);
449 if (status) {
450 com_err("rsh", status,
451 "while initializing krb5");
452 return (EXIT_FAILURE);
453
454 }
455 }
456
457 /*
458 * Get our local realm to look up local realm options.
459 */
460 status = krb5_get_default_realm(bsd_context, &realmdef[1]);
461 if (status) {
462 com_err("rsh", status,
463 gettext("while getting default realm"));
464 return (EXIT_FAILURE);
465 }
466 /*
467 * Check the realms section in krb5.conf for encryption,
468 * forward & forwardable info
469 */
470 (void) profile_get_options_boolean(bsd_context->profile,
471 realmdef, option);
472 /*
473 * Check the appdefaults section
474 */
475 (void) profile_get_options_boolean(bsd_context->profile,
476 appdef, option);
477 (void) profile_get_options_string(bsd_context->profile,
478 appdef, rcmdversion);
479 /*
480 * Set the *_flag variables, if the corresponding *_done are
481 * set to 1, because we dont want the config file values
482 * overriding the command line options.
483 */
484 if (encrypt_done)
485 encrypt_flag = 1;
486 if (fwd_done) {
487 fflag = 1;
488 Fflag = 0;
489 } else if (fwdable_done) {
490 Fflag = 1;
491 fflag = 0;
492 }
493 if (!rcmdoption_done && (rcmdproto != NULL)) {
494 if (strncmp(rcmdproto, "rcmdv2", 6) == 0) {
495 kcmd_proto = KCMD_NEW_PROTOCOL;
496 } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) {
497 kcmd_proto = KCMD_OLD_PROTOCOL;
498 } else {
499 (void) fprintf(stderr, gettext("Unrecognized "
500 "KCMD protocol (%s)"), rcmdproto);
501 return (EXIT_FAILURE);
502 }
503 }
504
505
506 if (encrypt_flag && (!krb5_privacy_allowed())) {
507 (void) fprintf(stderr, gettext("rsh: Encryption not "
508 "supported.\n"));
509 return (EXIT_FAILURE);
510 }
511 }
512
513 /*
514 * Connect with the service (shell/kshell) on the daemon side
515 */
516 if (portnumber == 0) {
517 while (!init_service(krb5auth_flag)) {
518 /*
519 * Connecting to the 'kshell' service failed,
520 * fallback to normal rsh; Reset all KRB5 flags
521 * and connect to 'shell' service on the server
522 */
523 krb5auth_flag = 0;
524 encrypt_flag = fflag = Fflag = 0;
525 }
526 }
527
528 cc = encrypt_flag ? strlen(dash_x) : 0;
529 for (ap = argv; *ap != NULL; ap++)
530 cc += strlen(*ap) + 1;
531 cp = args = malloc(cc);
532 if (cp == NULL)
533 perror("malloc");
534 if (encrypt_flag) {
535 int length;
536
537 length = strlcpy(args, dash_x, cc);
538 cp += length;
539 cc -= length;
540 }
541 args_no_x = args;
542
543 for (ap = argv; *ap != NULL; ap++) {
544 int length;
545
546 length = strlcpy(cp, *ap, cc);
547 assert(length < cc);
548 cp += length;
549 cc -= length;
550 if (ap[1] != NULL) {
551 *cp++ = ' ';
552 cc--;
553 }
554 }
555
556 if (krb5auth_flag) {
557 authopts = AP_OPTS_MUTUAL_REQUIRED;
558 /*
559 * Piggy-back forwarding flags on top of authopts;
560 * they will be reset in kcmd
561 */
562 if (fflag || Fflag)
563 authopts |= OPTS_FORWARD_CREDS;
564 if (Fflag)
565 authopts |= OPTS_FORWARDABLE_CREDS;
566
567 status = kcmd(&rem, &host, portnumber,
568 pwd->pw_name, user,
569 args, &rfd2, "host", krb_realm,
570 bsd_context, &auth_context, &cred,
571 NULL, /* No need for sequence number */
572 NULL, /* No need for server seq # */
573 authopts,
574 1, /* Always set anyport */
575 &kcmd_proto);
576 if (status != 0) {
577 /*
578 * If new protocol requested, we dont fallback to
579 * less secure ones.
580 */
581 if (kcmd_proto == KCMD_NEW_PROTOCOL) {
582 (void) fprintf(stderr, gettext("rsh: kcmdv2 "
583 "to host %s failed - %s\n"
584 "Fallback to normal rsh denied."),
585 host, error_message(status));
586 return (EXIT_FAILURE);
587 }
588 /* check NO_TKT_FILE or equivalent... */
589 if (status != -1) {
590 (void) fprintf(stderr,
591 gettext("rsh: kcmd to host %s failed - %s\n"
592 "trying normal rsh...\n\n"),
593 host, error_message(status));
594 } else {
595 (void) fprintf(stderr,
596 gettext("trying normal rsh...\n"));
597 }
598 /*
599 * kcmd() failed, so we now fallback to normal rsh,
600 * after resetting the KRB5 flags and the 'args' array
601 */
602 krb5auth_flag = 0;
603 encrypt_flag = fflag = Fflag = 0;
604 args = args_no_x;
605 (void) init_service(B_FALSE);
606 } else {
607 /*
608 * Set up buffers for desread and deswrite.
609 */
610 desinbuf.data = des_inbuf;
611 desoutbuf.data = des_outbuf;
612 desinbuf.length = sizeof (des_inbuf);
613 desoutbuf.length = sizeof (des_outbuf);
614
615 session_key = &cred->keyblock;
616
617 if (kcmd_proto == KCMD_NEW_PROTOCOL) {
618 status = krb5_auth_con_getlocalsubkey(
619 bsd_context,
620 auth_context,
621 &session_key);
622 if (status) {
623 com_err("rsh", status,
624 "determining subkey for session");
625 return (EXIT_FAILURE);
626 }
627 if (session_key == NULL) {
628 com_err("rsh", 0, "no subkey "
629 "negotiated for connection");
630 return (EXIT_FAILURE);
631 }
632 }
633
634 eblock.crypto_entry = session_key->enctype;
635 eblock.key = (krb5_keyblock *)session_key;
636
637 init_encrypt(encrypt_flag, bsd_context, kcmd_proto,
638 &desinbuf, &desoutbuf, CLIENT, &eblock);
639 if (encrypt_flag) {
640 char *s = gettext("This rsh session is using "
641 "encryption for all data transmissions.");
642 (void) write(STDERR_FILENO, s, strlen(s));
643 (void) write(STDERR_FILENO, "\r\n", 2);
644 }
645 }
646 }
647
648 /*
649 * Don't merge this with the "if" statement above because
650 * "krb5auth_flag" might be set to false inside it.
651 */
652 if (!krb5auth_flag) {
653 rem = rcmd_af(&host, portnumber, pwd->pw_name, user, args,
654 &rfd2, AF_INET6);
655 if (rem < 0)
656 return (EXIT_FAILURE);
657 }
658 __priv_relinquish();
659
660 if (rfd2 < 0) {
661 (void) fprintf(stderr, gettext("rsh: can't establish "
662 "stderr\n"));
663 return (EXIT_FAILURE);
664 }
665 if (options & SO_DEBUG) {
666 if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char *)&one,
667 sizeof (one)) < 0)
668 perror("rsh: setsockopt (stdin)");
669 if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, (char *)&one,
670 sizeof (one)) < 0)
671 perror("rsh: setsockopt (stderr)");
672 }
673 omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
674
675 if (sigdisp(SIGINT) != SIG_IGN)
676 (void) sigset(SIGINT, sendsig);
677 if (sigdisp(SIGQUIT) != SIG_IGN)
678 (void) sigset(SIGQUIT, sendsig);
679 if (sigdisp(SIGTERM) != SIG_IGN)
680 (void) sigset(SIGTERM, sendsig);
681
682 if (nflag) {
683 (void) shutdown(rem, SHUT_WR);
684 } else {
685 child_pid = fork();
686 if (child_pid < 0) {
687 perror("rsh: fork");
688 return (EXIT_FAILURE);
689 }
690
691 if (!encrypt_flag) {
692 (void) ioctl(rfd2, FIONBIO, &one);
693 (void) ioctl(rem, FIONBIO, &one);
694 }
695
696 if (child_pid == 0) {
697 /* Child */
698 fd_set remset;
699 char *bp;
700 int wc;
701 (void) close(rfd2);
702 reread:
703 errno = 0;
704 cc = read(0, buf, sizeof (buf));
705 if (cc <= 0)
706 goto done;
707 bp = buf;
708 rewrite:
709 FD_ZERO(&remset);
710 FD_SET(rem, &remset);
711 if (select(rem + 1, NULL, &remset, NULL, NULL) < 0) {
712 if (errno != EINTR) {
713 perror("rsh: select");
714 return (EXIT_FAILURE);
715 }
716 goto rewrite;
717 }
718 if (!FD_ISSET(rem, &remset))
719 goto rewrite;
720 writeiv = B_FALSE;
721 wc = desrshwrite(rem, bp, cc);
722 if (wc < 0) {
723 if (errno == EWOULDBLOCK)
724 goto rewrite;
725 goto done;
726 }
727 cc -= wc; bp += wc;
728 if (cc == 0)
729 goto reread;
730 goto rewrite;
731 done:
732 (void) shutdown(rem, SHUT_WR);
733 return (EXIT_SUCCESS);
734 }
735 }
736
737 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
738
739 sigsetmask(omask);
740 readfrom_rem = B_TRUE;
741 readfrom_rfd2 = B_TRUE;
742 (void) sigset(SIGPIPE, sigpipehandler);
743 do {
744 fd_set readyset;
745
746 FD_ZERO(&readyset);
747 if (readfrom_rem)
748 FD_SET(rem, &readyset);
749 if (readfrom_rfd2)
750 FD_SET(rfd2, &readyset);
751 if (select(MAX(rem, rfd2) + 1, &readyset, NULL, NULL,
752 NULL) < 0) {
753 if (errno != EINTR) {
754 perror("rsh: select");
755 return (EXIT_FAILURE);
756 }
757 continue;
758 }
759 if (FD_ISSET(rfd2, &readyset)) {
760 errno = 0;
761 readiv = B_TRUE;
762 cc = desrshread(rfd2, buf, sizeof (buf));
763 if (cc <= 0) {
764 if (errno != EWOULDBLOCK)
765 readfrom_rfd2 = B_FALSE;
766 } else {
767 (void) write(STDERR_FILENO, buf, cc);
768 }
769 }
770 if (FD_ISSET(rem, &readyset)) {
771 errno = 0;
772 readiv = B_FALSE;
773 cc = desrshread(rem, buf, sizeof (buf));
774 if (cc <= 0) {
775 if (errno != EWOULDBLOCK)
776 readfrom_rem = B_FALSE;
777 } else
778 (void) write(STDOUT_FILENO, buf, cc);
779 }
780 } while (readfrom_rem || readfrom_rfd2);
781
782 if (!nflag)
783 (void) kill(child_pid, SIGKILL);
784 return (EXIT_SUCCESS);
785 }
786
787 static void
sendsig(int signum)788 sendsig(int signum)
789 {
790 char buffer;
791
792 writeiv = B_TRUE;
793 buffer = (char)signum;
794 (void) desrshwrite(rfd2, &buffer, 1);
795 }
796
797 static boolean_t
init_service(boolean_t krb5flag)798 init_service(boolean_t krb5flag)
799 {
800 struct servent *sp;
801
802 if (krb5flag) {
803 sp = getservbyname("kshell", "tcp");
804 if (sp == NULL) {
805 (void) fprintf(stderr,
806 gettext("rsh: kshell/tcp: unknown service.\n"
807 "trying normal shell/tcp service\n"));
808 return (B_FALSE);
809 }
810 } else {
811 sp = getservbyname("shell", "tcp");
812 if (sp == NULL) {
813 portnumber = htons(IPPORT_CMDSERVER);
814 return (B_TRUE);
815 }
816 }
817
818 portnumber = sp->s_port;
819 return (B_TRUE);
820 }
821
822 static int
desrshread(int fd,char * buf,int len)823 desrshread(int fd, char *buf, int len)
824 {
825 return (desread(fd, buf, len, readiv ? 1 : 0));
826 }
827
828 static int
desrshwrite(int fd,char * buf,int len)829 desrshwrite(int fd, char *buf, int len)
830 {
831 return (deswrite(fd, buf, len, writeiv ? 1 : 0));
832 }
833