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