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 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 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 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 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 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 188 die(const char *message) 189 { 190 (void) fputs(message, stderr); 191 usage(); 192 } 193 194 static 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 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 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 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 823 desrshread(int fd, char *buf, int len) 824 { 825 return (desread(fd, buf, len, readiv ? 1 : 0)); 826 } 827 828 static int 829 desrshwrite(int fd, char *buf, int len) 830 { 831 return (deswrite(fd, buf, len, writeiv ? 1 : 0)); 832 } 833