10Sstevel@tonic-gate /* 2*8175SPeter.Shoults@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate /* 70Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 80Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 90Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 100Sstevel@tonic-gate * 110Sstevel@tonic-gate */ 120Sstevel@tonic-gate 130Sstevel@tonic-gate #define _FILE_OFFSET_BITS 64 140Sstevel@tonic-gate 150Sstevel@tonic-gate #include <sys/time.h> 160Sstevel@tonic-gate #include <sys/types.h> 170Sstevel@tonic-gate #include <sys/socket.h> 180Sstevel@tonic-gate #include <sys/ioctl.h> 190Sstevel@tonic-gate /* just for FIONBIO ... */ 200Sstevel@tonic-gate #include <sys/filio.h> 210Sstevel@tonic-gate #include <sys/stat.h> 220Sstevel@tonic-gate #include <sys/select.h> 230Sstevel@tonic-gate 240Sstevel@tonic-gate #include <netinet/in.h> 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <assert.h> 270Sstevel@tonic-gate #include <fcntl.h> 280Sstevel@tonic-gate #include <stdlib.h> 290Sstevel@tonic-gate #include <string.h> 300Sstevel@tonic-gate #include <unistd.h> 310Sstevel@tonic-gate #include <stdio.h> 320Sstevel@tonic-gate #include <errno.h> 330Sstevel@tonic-gate #include <signal.h> 340Sstevel@tonic-gate #include <pwd.h> 350Sstevel@tonic-gate #include <netdb.h> 360Sstevel@tonic-gate #include <locale.h> 370Sstevel@tonic-gate #include <priv_utils.h> 380Sstevel@tonic-gate 390Sstevel@tonic-gate #include <k5-int.h> 400Sstevel@tonic-gate #include <profile/prof_int.h> 410Sstevel@tonic-gate #include <com_err.h> 420Sstevel@tonic-gate #include <kcmd.h> 430Sstevel@tonic-gate #include <krb5.h> 440Sstevel@tonic-gate 450Sstevel@tonic-gate /* signal disposition - signal handler or SIG_IGN, SIG_ERR, etc. */ 460Sstevel@tonic-gate typedef void (*sigdisp_t)(int); 470Sstevel@tonic-gate 480Sstevel@tonic-gate extern errcode_t profile_get_options_boolean(profile_t, char **, 490Sstevel@tonic-gate profile_options_boolean *); 500Sstevel@tonic-gate extern errcode_t profile_get_options_string(profile_t, char **, 510Sstevel@tonic-gate profile_option_strings *); 520Sstevel@tonic-gate 530Sstevel@tonic-gate #define RSH_BUFSIZ (1024 * 50) 540Sstevel@tonic-gate 550Sstevel@tonic-gate static char des_inbuf[2 * RSH_BUFSIZ]; /* needs to be > largest read size */ 560Sstevel@tonic-gate static char des_outbuf[2 * RSH_BUFSIZ]; /* needs to be > largest write size */ 570Sstevel@tonic-gate static krb5_data desinbuf, desoutbuf; 580Sstevel@tonic-gate static krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */ 59*8175SPeter.Shoults@Sun.COM static krb5_context bsd_context = NULL; 600Sstevel@tonic-gate static krb5_auth_context auth_context; 610Sstevel@tonic-gate static krb5_creds *cred; 620Sstevel@tonic-gate static krb5_keyblock *session_key; 630Sstevel@tonic-gate 640Sstevel@tonic-gate static int encrypt_flag; /* Flag set, when encryption is used */ 65*8175SPeter.Shoults@Sun.COM static int krb5auth_flag; /* Flag set, when KERBEROS is enabled */ 66*8175SPeter.Shoults@Sun.COM static profile_options_boolean autologin_option[] = { 67*8175SPeter.Shoults@Sun.COM { "autologin", &krb5auth_flag, 0 }, 68*8175SPeter.Shoults@Sun.COM { NULL, NULL, 0 } 69*8175SPeter.Shoults@Sun.COM }; 70*8175SPeter.Shoults@Sun.COM 71*8175SPeter.Shoults@Sun.COM static int no_krb5auth_flag = 0; 720Sstevel@tonic-gate static int fflag; /* Flag set, if creds to be fwd'ed via -f */ 730Sstevel@tonic-gate static int Fflag; /* Flag set, if fwd'able creds to be fwd'ed via -F */ 740Sstevel@tonic-gate 750Sstevel@tonic-gate /* Flag set, if -PN / -PO is specified */ 760Sstevel@tonic-gate static boolean_t rcmdoption_done; 770Sstevel@tonic-gate 780Sstevel@tonic-gate /* Flags set, if corres. cmd line options are turned on */ 790Sstevel@tonic-gate static boolean_t encrypt_done, fwd_done, fwdable_done; 800Sstevel@tonic-gate 810Sstevel@tonic-gate static profile_options_boolean option[] = { 820Sstevel@tonic-gate { "encrypt", &encrypt_flag, 0 }, 830Sstevel@tonic-gate { "forward", &fflag, 0 }, 840Sstevel@tonic-gate { "forwardable", &Fflag, 0 }, 850Sstevel@tonic-gate { NULL, NULL, 0 } 860Sstevel@tonic-gate }; 870Sstevel@tonic-gate 880Sstevel@tonic-gate static char *rcmdproto; 890Sstevel@tonic-gate static profile_option_strings rcmdversion[] = { 900Sstevel@tonic-gate { "rcmd_protocol", &rcmdproto, 0 }, 910Sstevel@tonic-gate { NULL, NULL, 0 } 920Sstevel@tonic-gate }; 930Sstevel@tonic-gate 940Sstevel@tonic-gate static char *realmdef[] = { "realms", NULL, "rsh", NULL }; 950Sstevel@tonic-gate static char *appdef[] = { "appdefaults", "rsh", NULL }; 960Sstevel@tonic-gate 970Sstevel@tonic-gate static void sendsig(int); 980Sstevel@tonic-gate static sigdisp_t sigdisp(int); 990Sstevel@tonic-gate static boolean_t init_service(boolean_t); 1000Sstevel@tonic-gate static int desrshread(int, char *, int); 1010Sstevel@tonic-gate static int desrshwrite(int, char *, int); 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate static int options; 1040Sstevel@tonic-gate static int rfd2; 1050Sstevel@tonic-gate static int portnumber; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate static const char rlogin_path[] = "/usr/bin/rlogin"; 1080Sstevel@tonic-gate static const char dash_x[] = "-x "; /* Note the blank after -x */ 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate static boolean_t readiv, writeiv; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate #define set2mask(setp) ((setp)->__sigbits[0]) 1130Sstevel@tonic-gate #define mask2set(mask, setp) \ 1140Sstevel@tonic-gate ((mask) == -1 ? sigfillset(setp) : (set2mask(setp) = (mask))) 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate #ifdef DEBUG 1170Sstevel@tonic-gate #define DEBUGOPTSTRING "D:" 1180Sstevel@tonic-gate #else 1190Sstevel@tonic-gate #define DEBUGOPTSTRING "" 1200Sstevel@tonic-gate #endif /* DEBUG */ 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate static void 1230Sstevel@tonic-gate sigsetmask(int mask) 1240Sstevel@tonic-gate { 1250Sstevel@tonic-gate sigset_t nset; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate (void) sigprocmask(0, NULL, &nset); 1280Sstevel@tonic-gate mask2set(mask, &nset); 1290Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &nset, NULL); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate static int 1330Sstevel@tonic-gate sigblock(int mask) 1340Sstevel@tonic-gate { 1350Sstevel@tonic-gate sigset_t oset; 1360Sstevel@tonic-gate sigset_t nset; 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate (void) sigprocmask(0, NULL, &nset); 1390Sstevel@tonic-gate mask2set(mask, &nset); 1400Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &nset, &oset); 1410Sstevel@tonic-gate return (set2mask(&oset)); 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate /* 1450Sstevel@tonic-gate * Get signal disposition (or signal handler) for a given signal 1460Sstevel@tonic-gate */ 1470Sstevel@tonic-gate static sigdisp_t 1480Sstevel@tonic-gate sigdisp(int sig) 1490Sstevel@tonic-gate { 1500Sstevel@tonic-gate struct sigaction act; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate act.sa_handler = NULL; 1530Sstevel@tonic-gate act.sa_flags = 0; 1540Sstevel@tonic-gate (void) sigemptyset(&act.sa_mask); 1550Sstevel@tonic-gate (void) sigaction(sig, NULL, &act); 1560Sstevel@tonic-gate return (act.sa_handler); 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate static pid_t child_pid = -1; 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1620Sstevel@tonic-gate * If you do a command like "rsh host output | wc" 1630Sstevel@tonic-gate * and wc terminates, then the parent will receive SIGPIPE 1640Sstevel@tonic-gate * and the child needs to be terminated. 1650Sstevel@tonic-gate */ 1660Sstevel@tonic-gate /* ARGSUSED */ 1670Sstevel@tonic-gate static void 1680Sstevel@tonic-gate sigpipehandler(int signal) 1690Sstevel@tonic-gate { 1700Sstevel@tonic-gate if (child_pid != -1) 1710Sstevel@tonic-gate (void) kill(child_pid, SIGKILL); 1720Sstevel@tonic-gate exit(EXIT_SUCCESS); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate #define mask(s) (1 << ((s) - 1)) 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate static void 1780Sstevel@tonic-gate usage(void) { 1790Sstevel@tonic-gate (void) fprintf(stderr, "%s\n%s\n", 1800Sstevel@tonic-gate gettext("usage: rsh [ -PN / -PO ] [ -l login ] [ -n ] " 1810Sstevel@tonic-gate "[ -k realm ] [ -a ] [ -x ] [ -f / -F ] host command"), 1820Sstevel@tonic-gate gettext(" rsh [ -PN / -PO ] [ -l login ] [ -k realm ] " 1830Sstevel@tonic-gate "[ -a ] [ -x ] [ -f / -F ] host")); 1840Sstevel@tonic-gate exit(EXIT_FAILURE); 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate static void 1880Sstevel@tonic-gate die(const char *message) 1890Sstevel@tonic-gate { 1900Sstevel@tonic-gate (void) fputs(message, stderr); 1910Sstevel@tonic-gate usage(); 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate static void 1950Sstevel@tonic-gate usage_forward(void) 1960Sstevel@tonic-gate { 1970Sstevel@tonic-gate die(gettext("rsh: Only one of -f and -F allowed.\n")); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /* 2010Sstevel@tonic-gate * rsh - remote shell 2020Sstevel@tonic-gate */ 2030Sstevel@tonic-gate /* VARARGS */ 2040Sstevel@tonic-gate int 2050Sstevel@tonic-gate main(int argc, char **argv) 2060Sstevel@tonic-gate { 2070Sstevel@tonic-gate int c, rem; 2080Sstevel@tonic-gate char *cmd, *cp, **ap, buf[RSH_BUFSIZ], **argv0, *args, *args_no_x; 2090Sstevel@tonic-gate char *host = NULL, *user = NULL; 2100Sstevel@tonic-gate int cc; 2110Sstevel@tonic-gate boolean_t asrsh = B_FALSE; 2120Sstevel@tonic-gate struct passwd *pwd; 2130Sstevel@tonic-gate boolean_t readfrom_rem; 2140Sstevel@tonic-gate boolean_t readfrom_rfd2; 2150Sstevel@tonic-gate int one = 1; 2160Sstevel@tonic-gate int omask; 2170Sstevel@tonic-gate boolean_t nflag = B_FALSE; 2180Sstevel@tonic-gate char *krb_realm = NULL; 2190Sstevel@tonic-gate krb5_flags authopts; 2200Sstevel@tonic-gate krb5_error_code status; 2210Sstevel@tonic-gate enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL; 2220Sstevel@tonic-gate uid_t uid = getuid(); 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate c = (argc + 1) * sizeof (char *); 2250Sstevel@tonic-gate if ((argv0 = malloc(c)) == NULL) { 2260Sstevel@tonic-gate perror("malloc"); 2270Sstevel@tonic-gate return (EXIT_FAILURE); 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate (void) memcpy(argv0, argv, c); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate /* 2360Sstevel@tonic-gate * Determine command name used to invoke to rlogin(1). Users can 2370Sstevel@tonic-gate * create links named by a host pointing to the binary and type 2380Sstevel@tonic-gate * "hostname" to log into that host afterwards. 2390Sstevel@tonic-gate */ 2400Sstevel@tonic-gate cmd = strrchr(argv[0], '/'); 2410Sstevel@tonic-gate cmd = (cmd != NULL) ? (cmd + 1) : argv[0]; 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate /* 2440Sstevel@tonic-gate * Add "remsh" as an alias for "rsh" (System III, V networking 2450Sstevel@tonic-gate * add-ons often used this name for the remote shell since rsh 2460Sstevel@tonic-gate * was already taken for the restricted shell). Note that this 2470Sstevel@tonic-gate * usurps the ability to use "remsh" as the name of a host (by 2480Sstevel@tonic-gate * symlinking it to rsh), so we go one step farther: if the 2490Sstevel@tonic-gate * file "/usr/bin/remsh" does not exist, we behave as if "remsh" 2500Sstevel@tonic-gate * is a host name. If it does exist, we accept "remsh" as an 2510Sstevel@tonic-gate * "rsh" alias. 2520Sstevel@tonic-gate */ 2530Sstevel@tonic-gate if (strcmp(cmd, "remsh") == 0) { 2540Sstevel@tonic-gate struct stat sb; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate if (stat("/usr/bin/remsh", &sb) < 0) 2570Sstevel@tonic-gate host = cmd; 2580Sstevel@tonic-gate } else if (strcmp(cmd, "rsh") != 0) { 2590Sstevel@tonic-gate host = cmd; 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* Handle legacy synopsis "rsh hostname options [command]". */ 2630Sstevel@tonic-gate if (host == NULL) { 2640Sstevel@tonic-gate if (argc < 2) 2650Sstevel@tonic-gate usage(); 2660Sstevel@tonic-gate if (*argv[1] != '-') { 2670Sstevel@tonic-gate host = argv[1]; 2680Sstevel@tonic-gate argc--; 2690Sstevel@tonic-gate argv[1] = argv[0]; 2700Sstevel@tonic-gate argv++; 2710Sstevel@tonic-gate asrsh = B_TRUE; 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate while ((c = getopt(argc, argv, 276*8175SPeter.Shoults@Sun.COM DEBUGOPTSTRING "8AFKLP:ade:fk:l:nwx")) != -1) { 2770Sstevel@tonic-gate switch (c) { 2780Sstevel@tonic-gate #ifdef DEBUG 2790Sstevel@tonic-gate case 'D': 2800Sstevel@tonic-gate portnumber = htons(atoi(optarg)); 281*8175SPeter.Shoults@Sun.COM krb5auth_flag++; 2820Sstevel@tonic-gate break; 2830Sstevel@tonic-gate #endif /* DEBUG */ 2840Sstevel@tonic-gate case 'F': 2850Sstevel@tonic-gate if (fflag) 2860Sstevel@tonic-gate usage_forward(); 2870Sstevel@tonic-gate Fflag = 1; 288*8175SPeter.Shoults@Sun.COM krb5auth_flag++; 2890Sstevel@tonic-gate fwdable_done = B_TRUE; 2900Sstevel@tonic-gate break; 2910Sstevel@tonic-gate case 'f': 2920Sstevel@tonic-gate if (Fflag) 2930Sstevel@tonic-gate usage_forward(); 2940Sstevel@tonic-gate fflag = 1; 295*8175SPeter.Shoults@Sun.COM krb5auth_flag++; 2960Sstevel@tonic-gate fwd_done = B_TRUE; 2970Sstevel@tonic-gate break; 2980Sstevel@tonic-gate case 'P': 2990Sstevel@tonic-gate if (strcmp(optarg, "N") == 0) 3000Sstevel@tonic-gate kcmd_proto = KCMD_NEW_PROTOCOL; 3010Sstevel@tonic-gate else if (strcmp(optarg, "O") == 0) 3020Sstevel@tonic-gate kcmd_proto = KCMD_OLD_PROTOCOL; 3030Sstevel@tonic-gate else 3040Sstevel@tonic-gate die(gettext("rsh: Only -PN or -PO " 3050Sstevel@tonic-gate "allowed.\n")); 3060Sstevel@tonic-gate if (rcmdoption_done) 3070Sstevel@tonic-gate die(gettext("rsh: Only one of -PN and -PO " 3080Sstevel@tonic-gate "allowed.\n")); 3090Sstevel@tonic-gate rcmdoption_done = B_TRUE; 310*8175SPeter.Shoults@Sun.COM krb5auth_flag++; 3110Sstevel@tonic-gate break; 3120Sstevel@tonic-gate case 'a': 313*8175SPeter.Shoults@Sun.COM krb5auth_flag++; 314*8175SPeter.Shoults@Sun.COM break; 315*8175SPeter.Shoults@Sun.COM case 'K': 316*8175SPeter.Shoults@Sun.COM no_krb5auth_flag++; 3170Sstevel@tonic-gate break; 3180Sstevel@tonic-gate case 'd': 3190Sstevel@tonic-gate options |= SO_DEBUG; 3200Sstevel@tonic-gate break; 3210Sstevel@tonic-gate case 'k': 3220Sstevel@tonic-gate krb_realm = optarg; 323*8175SPeter.Shoults@Sun.COM krb5auth_flag++; 3240Sstevel@tonic-gate break; 3250Sstevel@tonic-gate case 'l': 3260Sstevel@tonic-gate user = optarg; 3270Sstevel@tonic-gate break; 3280Sstevel@tonic-gate case 'n': 3290Sstevel@tonic-gate if (!nflag) { 3300Sstevel@tonic-gate if (close(STDIN_FILENO) < 0) { 3310Sstevel@tonic-gate perror("close"); 3320Sstevel@tonic-gate return (EXIT_FAILURE); 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate /* 3350Sstevel@tonic-gate * "STDION_FILENO" defined to 0 by POSIX 3360Sstevel@tonic-gate * and hence the lowest file descriptor. 3370Sstevel@tonic-gate * So the open(2) below is guaranteed to 3380Sstevel@tonic-gate * reopen it because we closed it above. 3390Sstevel@tonic-gate */ 3400Sstevel@tonic-gate if (open("/dev/null", O_RDONLY) < 0) { 3410Sstevel@tonic-gate perror("open"); 3420Sstevel@tonic-gate return (EXIT_FAILURE); 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate nflag = B_TRUE; 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate break; 3470Sstevel@tonic-gate case 'x': 3480Sstevel@tonic-gate encrypt_flag = 1; 349*8175SPeter.Shoults@Sun.COM krb5auth_flag++; 3500Sstevel@tonic-gate encrypt_done = B_TRUE; 3510Sstevel@tonic-gate break; 3520Sstevel@tonic-gate /* 3530Sstevel@tonic-gate * Ignore the -L, -w, -e and -8 flags to allow aliases with 3540Sstevel@tonic-gate * rlogin to work. Actually rlogin(1) doesn't understand 3550Sstevel@tonic-gate * -w either but because "rsh -w hostname command" used 3560Sstevel@tonic-gate * to work we still accept it. 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate case '8': 3590Sstevel@tonic-gate case 'L': 3600Sstevel@tonic-gate case 'e': 3610Sstevel@tonic-gate case 'w': 3620Sstevel@tonic-gate /* 3630Sstevel@tonic-gate * On the lines of the -L, -w, -e and -8 options above, we 3640Sstevel@tonic-gate * ignore the -A option too, in order to allow aliases with 3650Sstevel@tonic-gate * rlogin to work. 3660Sstevel@tonic-gate * 3670Sstevel@tonic-gate * Mind you !, the -a option to trigger Kerberos authentication 3680Sstevel@tonic-gate * in rsh, has a totally different usage in rlogin, its the 3690Sstevel@tonic-gate * -A option (in rlogin) which needs to be used to talk 3700Sstevel@tonic-gate * Kerberos. 3710Sstevel@tonic-gate */ 3720Sstevel@tonic-gate case 'A': 3730Sstevel@tonic-gate break; 3740Sstevel@tonic-gate default: 3750Sstevel@tonic-gate usage(); 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate argc -= optind; 3800Sstevel@tonic-gate argv += optind; 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate if (host == NULL) { 3830Sstevel@tonic-gate if (argc == 0) 3840Sstevel@tonic-gate usage(); 3850Sstevel@tonic-gate argc--; 3860Sstevel@tonic-gate host = *argv++; 3870Sstevel@tonic-gate asrsh = B_TRUE; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate if (argc == 0) { 3910Sstevel@tonic-gate (void) setreuid(uid, uid); 3920Sstevel@tonic-gate if (nflag) 3930Sstevel@tonic-gate usage(); 3940Sstevel@tonic-gate if (asrsh) 3950Sstevel@tonic-gate *argv0 = "rlogin"; 3960Sstevel@tonic-gate (void) execv(rlogin_path, argv0); 3970Sstevel@tonic-gate perror(rlogin_path); 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate (void) fprintf(stderr, gettext("No local rlogin " 4000Sstevel@tonic-gate "program found.\n")); 4010Sstevel@tonic-gate return (EXIT_FAILURE); 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) { 4050Sstevel@tonic-gate (void) fprintf(stderr, 4060Sstevel@tonic-gate gettext("Insufficient privileges, " 4070Sstevel@tonic-gate "rsh must be set-uid root\n")); 4080Sstevel@tonic-gate return (EXIT_FAILURE); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate pwd = getpwuid(uid); 4120Sstevel@tonic-gate if (pwd == NULL) { 4130Sstevel@tonic-gate (void) fprintf(stderr, gettext("who are you?\n")); 4140Sstevel@tonic-gate return (EXIT_FAILURE); 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate if (user == NULL) 4170Sstevel@tonic-gate user = pwd->pw_name; 4180Sstevel@tonic-gate 419*8175SPeter.Shoults@Sun.COM /* 420*8175SPeter.Shoults@Sun.COM * if the user disables krb5 on the cmdline (-K), then skip 421*8175SPeter.Shoults@Sun.COM * all krb5 setup. 422*8175SPeter.Shoults@Sun.COM * 423*8175SPeter.Shoults@Sun.COM * if the user does not disable krb5 or enable krb5 on the 424*8175SPeter.Shoults@Sun.COM * cmdline, check krb5.conf to see if it should be enabled. 425*8175SPeter.Shoults@Sun.COM */ 426*8175SPeter.Shoults@Sun.COM 427*8175SPeter.Shoults@Sun.COM if (no_krb5auth_flag) { 428*8175SPeter.Shoults@Sun.COM krb5auth_flag = 0; 429*8175SPeter.Shoults@Sun.COM Fflag = fflag = encrypt_flag = 0; 430*8175SPeter.Shoults@Sun.COM } else if (!krb5auth_flag) { 431*8175SPeter.Shoults@Sun.COM /* is autologin set in krb5.conf? */ 4320Sstevel@tonic-gate status = krb5_init_context(&bsd_context); 433*8175SPeter.Shoults@Sun.COM /* don't sweat failure here */ 434*8175SPeter.Shoults@Sun.COM if (!status) { 435*8175SPeter.Shoults@Sun.COM /* 436*8175SPeter.Shoults@Sun.COM * note that the call to profile_get_options_boolean 437*8175SPeter.Shoults@Sun.COM * with autologin_option can affect value of 438*8175SPeter.Shoults@Sun.COM * krb5auth_flag 439*8175SPeter.Shoults@Sun.COM */ 440*8175SPeter.Shoults@Sun.COM (void) profile_get_options_boolean(bsd_context->profile, 441*8175SPeter.Shoults@Sun.COM appdef, 442*8175SPeter.Shoults@Sun.COM autologin_option); 443*8175SPeter.Shoults@Sun.COM } 444*8175SPeter.Shoults@Sun.COM } 445*8175SPeter.Shoults@Sun.COM 446*8175SPeter.Shoults@Sun.COM if (krb5auth_flag) { 447*8175SPeter.Shoults@Sun.COM if (!bsd_context) { 448*8175SPeter.Shoults@Sun.COM status = krb5_init_context(&bsd_context); 449*8175SPeter.Shoults@Sun.COM if (status) { 450*8175SPeter.Shoults@Sun.COM com_err("rsh", status, 451*8175SPeter.Shoults@Sun.COM "while initializing krb5"); 452*8175SPeter.Shoults@Sun.COM return (EXIT_FAILURE); 453*8175SPeter.Shoults@Sun.COM 454*8175SPeter.Shoults@Sun.COM } 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate /* 4580Sstevel@tonic-gate * Get our local realm to look up local realm options. 4590Sstevel@tonic-gate */ 4600Sstevel@tonic-gate status = krb5_get_default_realm(bsd_context, &realmdef[1]); 4610Sstevel@tonic-gate if (status) { 4620Sstevel@tonic-gate com_err("rsh", status, 4630Sstevel@tonic-gate gettext("while getting default realm")); 4640Sstevel@tonic-gate return (EXIT_FAILURE); 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate /* 4670Sstevel@tonic-gate * Check the realms section in krb5.conf for encryption, 4680Sstevel@tonic-gate * forward & forwardable info 4690Sstevel@tonic-gate */ 4700Sstevel@tonic-gate profile_get_options_boolean(bsd_context->profile, realmdef, 4710Sstevel@tonic-gate option); 4720Sstevel@tonic-gate /* 4730Sstevel@tonic-gate * Check the appdefaults section 4740Sstevel@tonic-gate */ 4750Sstevel@tonic-gate profile_get_options_boolean(bsd_context->profile, appdef, 4760Sstevel@tonic-gate option); 4770Sstevel@tonic-gate profile_get_options_string(bsd_context->profile, appdef, 4780Sstevel@tonic-gate rcmdversion); 4790Sstevel@tonic-gate /* 4800Sstevel@tonic-gate * Set the *_flag variables, if the corresponding *_done are 4810Sstevel@tonic-gate * set to 1, because we dont want the config file values 4820Sstevel@tonic-gate * overriding the command line options. 4830Sstevel@tonic-gate */ 4840Sstevel@tonic-gate if (encrypt_done) 4850Sstevel@tonic-gate encrypt_flag = 1; 4860Sstevel@tonic-gate if (fwd_done) { 4870Sstevel@tonic-gate fflag = 1; 4880Sstevel@tonic-gate Fflag = 0; 4890Sstevel@tonic-gate } else if (fwdable_done) { 4900Sstevel@tonic-gate Fflag = 1; 4910Sstevel@tonic-gate fflag = 0; 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate if (!rcmdoption_done && (rcmdproto != NULL)) { 4940Sstevel@tonic-gate if (strncmp(rcmdproto, "rcmdv2", 6) == 0) { 4950Sstevel@tonic-gate kcmd_proto = KCMD_NEW_PROTOCOL; 4960Sstevel@tonic-gate } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) { 4970Sstevel@tonic-gate kcmd_proto = KCMD_OLD_PROTOCOL; 4980Sstevel@tonic-gate } else { 4990Sstevel@tonic-gate (void) fprintf(stderr, gettext("Unrecognized " 5000Sstevel@tonic-gate "KCMD protocol (%s)"), rcmdproto); 5010Sstevel@tonic-gate return (EXIT_FAILURE); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate if (encrypt_flag && (!krb5_privacy_allowed())) { 5070Sstevel@tonic-gate (void) fprintf(stderr, gettext("rsh: Encryption not " 5080Sstevel@tonic-gate "supported.\n")); 5090Sstevel@tonic-gate return (EXIT_FAILURE); 5100Sstevel@tonic-gate } 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate /* 5140Sstevel@tonic-gate * Connect with the service (shell/kshell) on the daemon side 5150Sstevel@tonic-gate */ 5160Sstevel@tonic-gate if (portnumber == 0) { 5170Sstevel@tonic-gate while (!init_service(krb5auth_flag)) { 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate * Connecting to the 'kshell' service failed, 5200Sstevel@tonic-gate * fallback to normal rsh; Reset all KRB5 flags 5210Sstevel@tonic-gate * and connect to 'shell' service on the server 5220Sstevel@tonic-gate */ 523*8175SPeter.Shoults@Sun.COM krb5auth_flag = 0; 5240Sstevel@tonic-gate encrypt_flag = fflag = Fflag = 0; 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate cc = encrypt_flag ? strlen(dash_x) : 0; 5290Sstevel@tonic-gate for (ap = argv; *ap != NULL; ap++) 5300Sstevel@tonic-gate cc += strlen(*ap) + 1; 5310Sstevel@tonic-gate cp = args = malloc(cc); 5320Sstevel@tonic-gate if (cp == NULL) 5330Sstevel@tonic-gate perror("malloc"); 5340Sstevel@tonic-gate if (encrypt_flag) { 5350Sstevel@tonic-gate int length; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate length = strlcpy(args, dash_x, cc); 5380Sstevel@tonic-gate cp += length; 5390Sstevel@tonic-gate cc -= length; 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate args_no_x = args; 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate for (ap = argv; *ap != NULL; ap++) { 5440Sstevel@tonic-gate int length; 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate length = strlcpy(cp, *ap, cc); 5470Sstevel@tonic-gate assert(length < cc); 5480Sstevel@tonic-gate cp += length; 5490Sstevel@tonic-gate cc -= length; 5500Sstevel@tonic-gate if (ap[1] != NULL) { 5510Sstevel@tonic-gate *cp++ = ' '; 5520Sstevel@tonic-gate cc--; 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate if (krb5auth_flag) { 5570Sstevel@tonic-gate authopts = AP_OPTS_MUTUAL_REQUIRED; 5580Sstevel@tonic-gate /* 5590Sstevel@tonic-gate * Piggy-back forwarding flags on top of authopts; 5600Sstevel@tonic-gate * they will be reset in kcmd 5610Sstevel@tonic-gate */ 5620Sstevel@tonic-gate if (fflag || Fflag) 5630Sstevel@tonic-gate authopts |= OPTS_FORWARD_CREDS; 5640Sstevel@tonic-gate if (Fflag) 5650Sstevel@tonic-gate authopts |= OPTS_FORWARDABLE_CREDS; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate status = kcmd(&rem, &host, portnumber, 5680Sstevel@tonic-gate pwd->pw_name, user, 5690Sstevel@tonic-gate args, &rfd2, "host", krb_realm, 5700Sstevel@tonic-gate bsd_context, &auth_context, &cred, 5710Sstevel@tonic-gate NULL, /* No need for sequence number */ 5720Sstevel@tonic-gate NULL, /* No need for server seq # */ 5730Sstevel@tonic-gate authopts, 5740Sstevel@tonic-gate 1, /* Always set anyport */ 5750Sstevel@tonic-gate &kcmd_proto); 5760Sstevel@tonic-gate if (status != 0) { 5770Sstevel@tonic-gate /* 5780Sstevel@tonic-gate * If new protocol requested, we dont fallback to 5790Sstevel@tonic-gate * less secure ones. 5800Sstevel@tonic-gate */ 5810Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 5820Sstevel@tonic-gate (void) fprintf(stderr, gettext("rsh: kcmdv2 " 5830Sstevel@tonic-gate "to host %s failed - %s\n" 5840Sstevel@tonic-gate "Fallback to normal rsh denied."), 5850Sstevel@tonic-gate host, error_message(status)); 5860Sstevel@tonic-gate return (EXIT_FAILURE); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate /* check NO_TKT_FILE or equivalent... */ 5890Sstevel@tonic-gate if (status != -1) { 5900Sstevel@tonic-gate (void) fprintf(stderr, 5910Sstevel@tonic-gate gettext("rsh: kcmd to host %s failed - %s\n" 5920Sstevel@tonic-gate "trying normal rsh...\n\n"), 5930Sstevel@tonic-gate host, error_message(status)); 5940Sstevel@tonic-gate } else { 5950Sstevel@tonic-gate (void) fprintf(stderr, 5960Sstevel@tonic-gate gettext("trying normal rsh...\n")); 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate /* 5990Sstevel@tonic-gate * kcmd() failed, so we now fallback to normal rsh, 6000Sstevel@tonic-gate * after resetting the KRB5 flags and the 'args' array 6010Sstevel@tonic-gate */ 602*8175SPeter.Shoults@Sun.COM krb5auth_flag = 0; 6030Sstevel@tonic-gate encrypt_flag = fflag = Fflag = 0; 6040Sstevel@tonic-gate args = args_no_x; 6050Sstevel@tonic-gate (void) init_service(B_FALSE); 6060Sstevel@tonic-gate } else { 6070Sstevel@tonic-gate /* 6080Sstevel@tonic-gate * Set up buffers for desread and deswrite. 6090Sstevel@tonic-gate */ 6100Sstevel@tonic-gate desinbuf.data = des_inbuf; 6110Sstevel@tonic-gate desoutbuf.data = des_outbuf; 6120Sstevel@tonic-gate desinbuf.length = sizeof (des_inbuf); 6130Sstevel@tonic-gate desoutbuf.length = sizeof (des_outbuf); 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate session_key = &cred->keyblock; 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 6180Sstevel@tonic-gate status = krb5_auth_con_getlocalsubkey( 6190Sstevel@tonic-gate bsd_context, 6200Sstevel@tonic-gate auth_context, 6210Sstevel@tonic-gate &session_key); 6220Sstevel@tonic-gate if (status) { 6230Sstevel@tonic-gate com_err("rsh", status, 6240Sstevel@tonic-gate "determining subkey for session"); 6250Sstevel@tonic-gate return (EXIT_FAILURE); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate if (session_key == NULL) { 6280Sstevel@tonic-gate com_err("rsh", 0, "no subkey " 6290Sstevel@tonic-gate "negotiated for connection"); 6300Sstevel@tonic-gate return (EXIT_FAILURE); 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate eblock.crypto_entry = session_key->enctype; 6350Sstevel@tonic-gate eblock.key = (krb5_keyblock *)session_key; 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate init_encrypt(encrypt_flag, bsd_context, kcmd_proto, 6380Sstevel@tonic-gate &desinbuf, &desoutbuf, CLIENT, &eblock); 6390Sstevel@tonic-gate if (encrypt_flag) { 6400Sstevel@tonic-gate char *s = gettext("This rsh session is using " 6410Sstevel@tonic-gate "encryption for all data transmissions."); 6420Sstevel@tonic-gate (void) write(STDERR_FILENO, s, strlen(s)); 6430Sstevel@tonic-gate (void) write(STDERR_FILENO, "\r\n", 2); 6440Sstevel@tonic-gate } 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate /* 6490Sstevel@tonic-gate * Don't merge this with the "if" statement above because 6500Sstevel@tonic-gate * "krb5auth_flag" might be set to false inside it. 6510Sstevel@tonic-gate */ 6520Sstevel@tonic-gate if (!krb5auth_flag) { 6530Sstevel@tonic-gate rem = rcmd_af(&host, portnumber, pwd->pw_name, user, args, 6540Sstevel@tonic-gate &rfd2, AF_INET6); 6550Sstevel@tonic-gate if (rem < 0) 6560Sstevel@tonic-gate return (EXIT_FAILURE); 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate __priv_relinquish(); 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate if (rfd2 < 0) { 6610Sstevel@tonic-gate (void) fprintf(stderr, gettext("rsh: can't establish " 6620Sstevel@tonic-gate "stderr\n")); 6630Sstevel@tonic-gate return (EXIT_FAILURE); 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate if (options & SO_DEBUG) { 6660Sstevel@tonic-gate if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char *)&one, 6670Sstevel@tonic-gate sizeof (one)) < 0) 6680Sstevel@tonic-gate perror("rsh: setsockopt (stdin)"); 6690Sstevel@tonic-gate if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, (char *)&one, 6700Sstevel@tonic-gate sizeof (one)) < 0) 6710Sstevel@tonic-gate perror("rsh: setsockopt (stderr)"); 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM)); 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate if (sigdisp(SIGINT) != SIG_IGN) 6760Sstevel@tonic-gate (void) sigset(SIGINT, sendsig); 6770Sstevel@tonic-gate if (sigdisp(SIGQUIT) != SIG_IGN) 6780Sstevel@tonic-gate (void) sigset(SIGQUIT, sendsig); 6790Sstevel@tonic-gate if (sigdisp(SIGTERM) != SIG_IGN) 6800Sstevel@tonic-gate (void) sigset(SIGTERM, sendsig); 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate if (nflag) { 6830Sstevel@tonic-gate (void) shutdown(rem, SHUT_WR); 6840Sstevel@tonic-gate } else { 6850Sstevel@tonic-gate child_pid = fork(); 6860Sstevel@tonic-gate if (child_pid < 0) { 6870Sstevel@tonic-gate perror("rsh: fork"); 6880Sstevel@tonic-gate return (EXIT_FAILURE); 6890Sstevel@tonic-gate } 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate if (!encrypt_flag) { 6920Sstevel@tonic-gate (void) ioctl(rfd2, FIONBIO, &one); 6930Sstevel@tonic-gate (void) ioctl(rem, FIONBIO, &one); 6940Sstevel@tonic-gate } 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate if (child_pid == 0) { 6970Sstevel@tonic-gate /* Child */ 6980Sstevel@tonic-gate fd_set remset; 6990Sstevel@tonic-gate char *bp; 7000Sstevel@tonic-gate int wc; 7010Sstevel@tonic-gate (void) close(rfd2); 7020Sstevel@tonic-gate reread: 7030Sstevel@tonic-gate errno = 0; 7040Sstevel@tonic-gate cc = read(0, buf, sizeof (buf)); 7050Sstevel@tonic-gate if (cc <= 0) 7060Sstevel@tonic-gate goto done; 7070Sstevel@tonic-gate bp = buf; 7080Sstevel@tonic-gate rewrite: 7090Sstevel@tonic-gate FD_ZERO(&remset); 7100Sstevel@tonic-gate FD_SET(rem, &remset); 7110Sstevel@tonic-gate if (select(rem + 1, NULL, &remset, NULL, NULL) < 0) { 7120Sstevel@tonic-gate if (errno != EINTR) { 7130Sstevel@tonic-gate perror("rsh: select"); 7140Sstevel@tonic-gate return (EXIT_FAILURE); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate goto rewrite; 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate if (!FD_ISSET(rem, &remset)) 7190Sstevel@tonic-gate goto rewrite; 7200Sstevel@tonic-gate writeiv = B_FALSE; 7210Sstevel@tonic-gate wc = desrshwrite(rem, bp, cc); 7220Sstevel@tonic-gate if (wc < 0) { 7230Sstevel@tonic-gate if (errno == EWOULDBLOCK) 7240Sstevel@tonic-gate goto rewrite; 7250Sstevel@tonic-gate goto done; 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate cc -= wc; bp += wc; 7280Sstevel@tonic-gate if (cc == 0) 7290Sstevel@tonic-gate goto reread; 7300Sstevel@tonic-gate goto rewrite; 7310Sstevel@tonic-gate done: 7320Sstevel@tonic-gate (void) shutdown(rem, SHUT_WR); 7330Sstevel@tonic-gate return (EXIT_SUCCESS); 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate 7370Sstevel@tonic-gate #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate sigsetmask(omask); 7400Sstevel@tonic-gate readfrom_rem = B_TRUE; 7410Sstevel@tonic-gate readfrom_rfd2 = B_TRUE; 7420Sstevel@tonic-gate (void) sigset(SIGPIPE, sigpipehandler); 7430Sstevel@tonic-gate do { 7440Sstevel@tonic-gate fd_set readyset; 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate FD_ZERO(&readyset); 7470Sstevel@tonic-gate if (readfrom_rem) 7480Sstevel@tonic-gate FD_SET(rem, &readyset); 7490Sstevel@tonic-gate if (readfrom_rfd2) 7500Sstevel@tonic-gate FD_SET(rfd2, &readyset); 7510Sstevel@tonic-gate if (select(MAX(rem, rfd2) + 1, &readyset, NULL, NULL, 7520Sstevel@tonic-gate NULL) < 0) { 7530Sstevel@tonic-gate if (errno != EINTR) { 7540Sstevel@tonic-gate perror("rsh: select"); 7550Sstevel@tonic-gate return (EXIT_FAILURE); 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate continue; 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate if (FD_ISSET(rfd2, &readyset)) { 7600Sstevel@tonic-gate errno = 0; 7610Sstevel@tonic-gate readiv = B_TRUE; 7620Sstevel@tonic-gate cc = desrshread(rfd2, buf, sizeof (buf)); 7630Sstevel@tonic-gate if (cc <= 0) { 7640Sstevel@tonic-gate if (errno != EWOULDBLOCK) 7650Sstevel@tonic-gate readfrom_rfd2 = B_FALSE; 7660Sstevel@tonic-gate } else { 7670Sstevel@tonic-gate (void) write(STDERR_FILENO, buf, cc); 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate } 7700Sstevel@tonic-gate if (FD_ISSET(rem, &readyset)) { 7710Sstevel@tonic-gate errno = 0; 7720Sstevel@tonic-gate readiv = B_FALSE; 7730Sstevel@tonic-gate cc = desrshread(rem, buf, sizeof (buf)); 7740Sstevel@tonic-gate if (cc <= 0) { 7750Sstevel@tonic-gate if (errno != EWOULDBLOCK) 7760Sstevel@tonic-gate readfrom_rem = B_FALSE; 7770Sstevel@tonic-gate } else 7780Sstevel@tonic-gate (void) write(STDOUT_FILENO, buf, cc); 7790Sstevel@tonic-gate } 7800Sstevel@tonic-gate } while (readfrom_rem || readfrom_rfd2); 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate if (!nflag) 7830Sstevel@tonic-gate (void) kill(child_pid, SIGKILL); 7840Sstevel@tonic-gate return (EXIT_SUCCESS); 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate static void 7880Sstevel@tonic-gate sendsig(int signum) 7890Sstevel@tonic-gate { 7900Sstevel@tonic-gate char buffer; 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate writeiv = B_TRUE; 7930Sstevel@tonic-gate buffer = (char)signum; 7940Sstevel@tonic-gate (void) desrshwrite(rfd2, &buffer, 1); 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate static boolean_t 7980Sstevel@tonic-gate init_service(boolean_t krb5flag) 7990Sstevel@tonic-gate { 8000Sstevel@tonic-gate struct servent *sp; 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate if (krb5flag) { 8030Sstevel@tonic-gate sp = getservbyname("kshell", "tcp"); 8040Sstevel@tonic-gate if (sp == NULL) { 8050Sstevel@tonic-gate (void) fprintf(stderr, 8060Sstevel@tonic-gate gettext("rsh: kshell/tcp: unknown service.\n" 8070Sstevel@tonic-gate "trying normal shell/tcp service\n")); 8080Sstevel@tonic-gate return (B_FALSE); 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate } else { 8110Sstevel@tonic-gate sp = getservbyname("shell", "tcp"); 8120Sstevel@tonic-gate if (sp == NULL) { 8130Sstevel@tonic-gate portnumber = htons(IPPORT_CMDSERVER); 8140Sstevel@tonic-gate return (B_TRUE); 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate } 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate portnumber = sp->s_port; 8190Sstevel@tonic-gate return (B_TRUE); 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate static int 8230Sstevel@tonic-gate desrshread(int fd, char *buf, int len) 8240Sstevel@tonic-gate { 8250Sstevel@tonic-gate return (desread(fd, buf, len, readiv ? 1 : 0)); 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate static int 8290Sstevel@tonic-gate desrshwrite(int fd, char *buf, int len) 8300Sstevel@tonic-gate { 8310Sstevel@tonic-gate return (deswrite(fd, buf, len, writeiv ? 1 : 0)); 8320Sstevel@tonic-gate } 833