void tolocal(int argc, char *argv[]) { int i, len, tos; char *bp, *host, *src, *suser; for (i = 0; i < argc - 1; i++) { if (!(src = colon(argv[i]))) { /* Local to local. */ len = strlen(_PATH_CP) + strlen(argv[i]) + strlen(argv[argc - 1]) + 20; if (!(bp = malloc(len))) err(1, "malloc"); (void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, iamrecursive ? " -PR" : "", pflag ? " -p" : "", argv[i], argv[argc - 1]); if (susystem(bp, userid)) ++errs; (void)free(bp); continue; } *src++ = 0; if (*src == 0) src = period; if ((host = strchr(argv[i], '@')) == NULL) { host = argv[i]; suser = pwd->pw_name; } else { *host++ = 0; suser = argv[i]; if (*suser == '\0') suser = pwd->pw_name; else if (!okname(suser)) { ++errs; continue; } } len = strlen(src) + CMDNEEDS + 20; if ((bp = malloc(len)) == NULL) err(1, "malloc"); (void)snprintf(bp, len, "%s -f %s", cmd, src); rem = rcmd_af(&host, port, pwd->pw_name, suser, bp, 0, family); (void)free(bp); if (rem < 0) { ++errs; continue; } (void)seteuid(userid); if (family == PF_INET) { tos = IPTOS_THROUGHPUT; if (setsockopt(rem, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0) warn("TOS (ignored)"); } sink(1, argv + argc - 1); (void)seteuid(0); (void)close(rem); rem = -1; } }
int rcmd(char **ahost, unsigned short rport, const char *locuser, const char *remuser, const char *cmd, int *fd2p) { int rcmd_ret; rcmd_ret = rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); return (rcmd_ret); }
void tolocal(int argc, char *argv[]) { int i; size_t len; char *bp, *host, *src, *suser; for (i = 0; i < argc - 1; i++) { if (!(src = colon(argv[i]))) { /* Local to local. */ len = strlen(_PATH_CP) + strlen(argv[i]) + strlen(argv[argc - 1]) + 20; if (!(bp = malloc(len))) err(1, NULL); (void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, iamrecursive ? " -r" : "", pflag ? " -p" : "", argv[i], argv[argc - 1]); if (susystem(bp)) ++errs; (void)free(bp); continue; } *src++ = 0; if (*src == 0) src = dot; if ((host = strchr(argv[i], '@')) == NULL) { host = argv[i]; suser = pwname; } else { *host++ = 0; suser = argv[i]; if (*suser == '\0') suser = pwname; else if (!okname(suser)) continue; } host = unbracket(host); len = strlen(src) + CMDNEEDS + 20; if ((bp = malloc(len)) == NULL) err(1, NULL); (void)snprintf(bp, len, "%s -f %s", cmd, src); rem = rcmd_af(&host, port, pwname, suser, bp, NULL, family); (void)free(bp); if (rem < 0) { ++errs; continue; } sink(1, argv + argc - 1); (void)close(rem); rem = -1; } }
/* * Run the remote command. We aren't interested in any io, Only the * return code. */ static int remote_command(char *command, char *host) { struct passwd *pw; if ((pw = getpwuid(getuid())) != NULL) { int fd; if ((fd = rcmd_af(&host, htons(514), pw->pw_name, "root", command, NULL, AF_INET6)) < 0) return (-1); (void) close(fd); return (0); } else return (-1); }
void toremote(char *targ, int argc, char *argv[]) { int i, tos; char *bp, *host, *src, *suser, *thost, *tuser; *targ++ = 0; if (*targ == 0) targ = period; if ((thost = strchr(argv[argc - 1], '@'))) { /* user@host */ *thost++ = 0; tuser = argv[argc - 1]; if (*tuser == '\0') tuser = NULL; else if (!okname(tuser)) exit(1); } else { thost = argv[argc - 1]; tuser = NULL; } for (i = 0; i < argc - 1; i++) { src = colon(argv[i]); if (src) { /* remote to remote */ *src++ = 0; if (*src == 0) src = period; host = strchr(argv[i], '@'); if (host) { *host++ = 0; suser = argv[i]; if (*suser == '\0') suser = pwd->pw_name; else if (!okname(suser)) { ++errs; continue; } if (asprintf(&bp, "%s %s -l %s -n %s %s '%s%s%s:%s'", _PATH_RSH, host, suser, cmd, src, tuser ? tuser : "", tuser ? "@" : "", thost, targ) == -1) err(1, "asprintf"); } else if (asprintf(&bp, "exec %s %s -n %s %s '%s%s%s:%s'", _PATH_RSH, argv[i], cmd, src, tuser ? tuser : "", tuser ? "@" : "", thost, targ) == -1) err(1, "asprintf"); (void)susystem(bp, userid); (void)free(bp); } else { /* local to remote */ if (rem == -1) { if (asprintf(&bp, "%s -t %s", cmd, targ) == -1) err(1, "asprintf"); host = thost; rem = rcmd_af(&host, port, pwd->pw_name, tuser ? tuser : pwd->pw_name, bp, 0, family); if (rem < 0) exit(1); if (family == PF_INET) { tos = IPTOS_THROUGHPUT; if (setsockopt(rem, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0) warn("TOS (ignored)"); } if (response() < 0) exit(1); (void)free(bp); (void)setuid(userid); } source(1, argv+i); } } }
/* VARARGS */ int main(int argc, char **argv) { int c, rem; char *cmd, *cp, **ap, buf[RSH_BUFSIZ], **argv0, *args, *args_no_x; char *host = NULL, *user = NULL; int cc; boolean_t asrsh = B_FALSE; struct passwd *pwd; boolean_t readfrom_rem; boolean_t readfrom_rfd2; int one = 1; int omask; boolean_t nflag = B_FALSE; char *krb_realm = NULL; krb5_flags authopts; krb5_error_code status; enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL; uid_t uid = getuid(); c = (argc + 1) * sizeof (char *); if ((argv0 = malloc(c)) == NULL) { perror("malloc"); return (EXIT_FAILURE); } (void) memcpy(argv0, argv, c); (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); /* * Determine command name used to invoke to rlogin(1). Users can * create links named by a host pointing to the binary and type * "hostname" to log into that host afterwards. */ cmd = strrchr(argv[0], '/'); cmd = (cmd != NULL) ? (cmd + 1) : argv[0]; /* * Add "remsh" as an alias for "rsh" (System III, V networking * add-ons often used this name for the remote shell since rsh * was already taken for the restricted shell). Note that this * usurps the ability to use "remsh" as the name of a host (by * symlinking it to rsh), so we go one step farther: if the * file "/usr/bin/remsh" does not exist, we behave as if "remsh" * is a host name. If it does exist, we accept "remsh" as an * "rsh" alias. */ if (strcmp(cmd, "remsh") == 0) { struct stat sb; if (stat("/usr/bin/remsh", &sb) < 0) host = cmd; } else if (strcmp(cmd, "rsh") != 0) { host = cmd; } /* Handle legacy synopsis "rsh hostname options [command]". */ if (host == NULL) { if (argc < 2) usage(); if (*argv[1] != '-') { host = argv[1]; argc--; argv[1] = argv[0]; argv++; asrsh = B_TRUE; } } while ((c = getopt(argc, argv, DEBUGOPTSTRING "8AFKLP:ade:fk:l:nwx")) != -1) { switch (c) { #ifdef DEBUG case 'D': portnumber = htons(atoi(optarg)); krb5auth_flag++; break; #endif /* DEBUG */ case 'F': if (fflag) usage_forward(); Fflag = 1; krb5auth_flag++; fwdable_done = B_TRUE; break; case 'f': if (Fflag) usage_forward(); fflag = 1; krb5auth_flag++; fwd_done = B_TRUE; break; case 'P': if (strcmp(optarg, "N") == 0) kcmd_proto = KCMD_NEW_PROTOCOL; else if (strcmp(optarg, "O") == 0) kcmd_proto = KCMD_OLD_PROTOCOL; else die(gettext("rsh: Only -PN or -PO " "allowed.\n")); if (rcmdoption_done) die(gettext("rsh: Only one of -PN and -PO " "allowed.\n")); rcmdoption_done = B_TRUE; krb5auth_flag++; break; case 'a': krb5auth_flag++; break; case 'K': no_krb5auth_flag++; break; case 'd': options |= SO_DEBUG; break; case 'k': krb_realm = optarg; krb5auth_flag++; break; case 'l': user = optarg; break; case 'n': if (!nflag) { if (close(STDIN_FILENO) < 0) { perror("close"); return (EXIT_FAILURE); } /* * "STDION_FILENO" defined to 0 by POSIX * and hence the lowest file descriptor. * So the open(2) below is guaranteed to * reopen it because we closed it above. */ if (open("/dev/null", O_RDONLY) < 0) { perror("open"); return (EXIT_FAILURE); } nflag = B_TRUE; } break; case 'x': encrypt_flag = 1; krb5auth_flag++; encrypt_done = B_TRUE; break; /* * Ignore the -L, -w, -e and -8 flags to allow aliases with * rlogin to work. Actually rlogin(1) doesn't understand * -w either but because "rsh -w hostname command" used * to work we still accept it. */ case '8': case 'L': case 'e': case 'w': /* * On the lines of the -L, -w, -e and -8 options above, we * ignore the -A option too, in order to allow aliases with * rlogin to work. * * Mind you !, the -a option to trigger Kerberos authentication * in rsh, has a totally different usage in rlogin, its the * -A option (in rlogin) which needs to be used to talk * Kerberos. */ case 'A': break; default: usage(); } } argc -= optind; argv += optind; if (host == NULL) { if (argc == 0) usage(); argc--; host = *argv++; asrsh = B_TRUE; } if (argc == 0) { (void) setreuid(uid, uid); if (nflag) usage(); if (asrsh) *argv0 = "rlogin"; (void) execv(rlogin_path, argv0); perror(rlogin_path); (void) fprintf(stderr, gettext("No local rlogin " "program found.\n")); return (EXIT_FAILURE); } if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) { (void) fprintf(stderr, gettext("Insufficient privileges, " "rsh must be set-uid root\n")); return (EXIT_FAILURE); } pwd = getpwuid(uid); if (pwd == NULL) { (void) fprintf(stderr, gettext("who are you?\n")); return (EXIT_FAILURE); } if (user == NULL) user = pwd->pw_name; /* * if the user disables krb5 on the cmdline (-K), then skip * all krb5 setup. * * if the user does not disable krb5 or enable krb5 on the * cmdline, check krb5.conf to see if it should be enabled. */ if (no_krb5auth_flag) { krb5auth_flag = 0; Fflag = fflag = encrypt_flag = 0; } else if (!krb5auth_flag) { /* is autologin set in krb5.conf? */ status = krb5_init_context(&bsd_context); /* don't sweat failure here */ if (!status) { /* * note that the call to profile_get_options_boolean * with autologin_option can affect value of * krb5auth_flag */ (void) profile_get_options_boolean(bsd_context->profile, appdef, autologin_option); } } if (krb5auth_flag) { if (!bsd_context) { status = krb5_init_context(&bsd_context); if (status) { com_err("rsh", status, "while initializing krb5"); return (EXIT_FAILURE); } } /* * Get our local realm to look up local realm options. */ status = krb5_get_default_realm(bsd_context, &realmdef[1]); if (status) { com_err("rsh", status, gettext("while getting default realm")); return (EXIT_FAILURE); } /* * Check the realms section in krb5.conf for encryption, * forward & forwardable info */ profile_get_options_boolean(bsd_context->profile, realmdef, option); /* * Check the appdefaults section */ profile_get_options_boolean(bsd_context->profile, appdef, option); profile_get_options_string(bsd_context->profile, appdef, rcmdversion); /* * Set the *_flag variables, if the corresponding *_done are * set to 1, because we dont want the config file values * overriding the command line options. */ if (encrypt_done) encrypt_flag = 1; if (fwd_done) { fflag = 1; Fflag = 0; } else if (fwdable_done) { Fflag = 1; fflag = 0; } if (!rcmdoption_done && (rcmdproto != NULL)) { if (strncmp(rcmdproto, "rcmdv2", 6) == 0) { kcmd_proto = KCMD_NEW_PROTOCOL; } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) { kcmd_proto = KCMD_OLD_PROTOCOL; } else { (void) fprintf(stderr, gettext("Unrecognized " "KCMD protocol (%s)"), rcmdproto); return (EXIT_FAILURE); } } if (encrypt_flag && (!krb5_privacy_allowed())) { (void) fprintf(stderr, gettext("rsh: Encryption not " "supported.\n")); return (EXIT_FAILURE); } } /* * Connect with the service (shell/kshell) on the daemon side */ if (portnumber == 0) { while (!init_service(krb5auth_flag)) { /* * Connecting to the 'kshell' service failed, * fallback to normal rsh; Reset all KRB5 flags * and connect to 'shell' service on the server */ krb5auth_flag = 0; encrypt_flag = fflag = Fflag = 0; } } cc = encrypt_flag ? strlen(dash_x) : 0; for (ap = argv; *ap != NULL; ap++) cc += strlen(*ap) + 1; cp = args = malloc(cc); if (cp == NULL) perror("malloc"); if (encrypt_flag) { int length; length = strlcpy(args, dash_x, cc); cp += length; cc -= length; } args_no_x = args; for (ap = argv; *ap != NULL; ap++) { int length; length = strlcpy(cp, *ap, cc); assert(length < cc); cp += length; cc -= length; if (ap[1] != NULL) { *cp++ = ' '; cc--; } } if (krb5auth_flag) { authopts = AP_OPTS_MUTUAL_REQUIRED; /* * Piggy-back forwarding flags on top of authopts; * they will be reset in kcmd */ if (fflag || Fflag) authopts |= OPTS_FORWARD_CREDS; if (Fflag) authopts |= OPTS_FORWARDABLE_CREDS; status = kcmd(&rem, &host, portnumber, pwd->pw_name, user, args, &rfd2, "host", krb_realm, bsd_context, &auth_context, &cred, NULL, /* No need for sequence number */ NULL, /* No need for server seq # */ authopts, 1, /* Always set anyport */ &kcmd_proto); if (status != 0) { /* * If new protocol requested, we dont fallback to * less secure ones. */ if (kcmd_proto == KCMD_NEW_PROTOCOL) { (void) fprintf(stderr, gettext("rsh: kcmdv2 " "to host %s failed - %s\n" "Fallback to normal rsh denied."), host, error_message(status)); return (EXIT_FAILURE); } /* check NO_TKT_FILE or equivalent... */ if (status != -1) { (void) fprintf(stderr, gettext("rsh: kcmd to host %s failed - %s\n" "trying normal rsh...\n\n"), host, error_message(status)); } else { (void) fprintf(stderr, gettext("trying normal rsh...\n")); } /* * kcmd() failed, so we now fallback to normal rsh, * after resetting the KRB5 flags and the 'args' array */ krb5auth_flag = 0; encrypt_flag = fflag = Fflag = 0; args = args_no_x; (void) init_service(B_FALSE); } else { /* * Set up buffers for desread and deswrite. */ desinbuf.data = des_inbuf; desoutbuf.data = des_outbuf; desinbuf.length = sizeof (des_inbuf); desoutbuf.length = sizeof (des_outbuf); session_key = &cred->keyblock; if (kcmd_proto == KCMD_NEW_PROTOCOL) { status = krb5_auth_con_getlocalsubkey( bsd_context, auth_context, &session_key); if (status) { com_err("rsh", status, "determining subkey for session"); return (EXIT_FAILURE); } if (session_key == NULL) { com_err("rsh", 0, "no subkey " "negotiated for connection"); return (EXIT_FAILURE); } } eblock.crypto_entry = session_key->enctype; eblock.key = (krb5_keyblock *)session_key; init_encrypt(encrypt_flag, bsd_context, kcmd_proto, &desinbuf, &desoutbuf, CLIENT, &eblock); if (encrypt_flag) { char *s = gettext("This rsh session is using " "encryption for all data transmissions."); (void) write(STDERR_FILENO, s, strlen(s)); (void) write(STDERR_FILENO, "\r\n", 2); } } } /* * Don't merge this with the "if" statement above because * "krb5auth_flag" might be set to false inside it. */ if (!krb5auth_flag) { rem = rcmd_af(&host, portnumber, pwd->pw_name, user, args, &rfd2, AF_INET6); if (rem < 0) return (EXIT_FAILURE); } __priv_relinquish(); if (rfd2 < 0) { (void) fprintf(stderr, gettext("rsh: can't establish " "stderr\n")); return (EXIT_FAILURE); } if (options & SO_DEBUG) { if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char *)&one, sizeof (one)) < 0) perror("rsh: setsockopt (stdin)"); if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, (char *)&one, sizeof (one)) < 0) perror("rsh: setsockopt (stderr)"); } omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM)); if (sigdisp(SIGINT) != SIG_IGN) (void) sigset(SIGINT, sendsig); if (sigdisp(SIGQUIT) != SIG_IGN) (void) sigset(SIGQUIT, sendsig); if (sigdisp(SIGTERM) != SIG_IGN) (void) sigset(SIGTERM, sendsig); if (nflag) { (void) shutdown(rem, SHUT_WR); } else { child_pid = fork(); if (child_pid < 0) { perror("rsh: fork"); return (EXIT_FAILURE); } if (!encrypt_flag) { (void) ioctl(rfd2, FIONBIO, &one); (void) ioctl(rem, FIONBIO, &one); } if (child_pid == 0) { /* Child */ fd_set remset; char *bp; int wc; (void) close(rfd2); reread: errno = 0; cc = read(0, buf, sizeof (buf)); if (cc <= 0) goto done; bp = buf; rewrite: FD_ZERO(&remset); FD_SET(rem, &remset); if (select(rem + 1, NULL, &remset, NULL, NULL) < 0) { if (errno != EINTR) { perror("rsh: select"); return (EXIT_FAILURE); } goto rewrite; } if (!FD_ISSET(rem, &remset)) goto rewrite; writeiv = B_FALSE; wc = desrshwrite(rem, bp, cc); if (wc < 0) { if (errno == EWOULDBLOCK) goto rewrite; goto done; } cc -= wc; bp += wc; if (cc == 0) goto reread; goto rewrite; done: (void) shutdown(rem, SHUT_WR); return (EXIT_SUCCESS); } } #define MAX(a, b) (((a) > (b)) ? (a) : (b)) sigsetmask(omask); readfrom_rem = B_TRUE; readfrom_rfd2 = B_TRUE; (void) sigset(SIGPIPE, sigpipehandler); do { fd_set readyset; FD_ZERO(&readyset); if (readfrom_rem) FD_SET(rem, &readyset); if (readfrom_rfd2) FD_SET(rfd2, &readyset); if (select(MAX(rem, rfd2) + 1, &readyset, NULL, NULL, NULL) < 0) { if (errno != EINTR) { perror("rsh: select"); return (EXIT_FAILURE); } continue; } if (FD_ISSET(rfd2, &readyset)) { errno = 0; readiv = B_TRUE; cc = desrshread(rfd2, buf, sizeof (buf)); if (cc <= 0) { if (errno != EWOULDBLOCK) readfrom_rfd2 = B_FALSE; } else { (void) write(STDERR_FILENO, buf, cc); } } if (FD_ISSET(rem, &readyset)) { errno = 0; readiv = B_FALSE; cc = desrshread(rem, buf, sizeof (buf)); if (cc <= 0) { if (errno != EWOULDBLOCK) readfrom_rem = B_FALSE; } else (void) write(STDOUT_FILENO, buf, cc); } } while (readfrom_rem || readfrom_rfd2); if (!nflag) (void) kill(child_pid, SIGKILL); return (EXIT_SUCCESS); }
int main(int argc, char **argv) { int c; char *cp, *cmd, *name = NULL; struct passwd *pwd; uid_t uid; int options = 0, oldmask; int on = 1; speed_t speed = 0; int getattr_ret; char *tmp; int sock; krb5_flags authopts; krb5_error_code status; enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) { (void) fprintf(stderr, gettext("Insufficient privileges, " "rlogin must be set-uid root\n")); exit(1); } { int it; if ((getattr_ret = tcgetattr(STDIN_FILENO, &savetty)) < 0) perror("tcgetattr"); it = ioctl(STDIN_FILENO, I_FIND, "ttcompat"); if (it < 0) { perror("ioctl I_FIND ttcompat"); return (EXIT_FAILURE); } if (it == 0) { if (ioctl(STDIN_FILENO, I_PUSH, "ttcompat") < 0) { perror("ioctl I_PUSH ttcompat"); exit(EXIT_FAILURE); } ttcompat = B_TRUE; } } /* * Determine command name used to invoke to rlogin(1). Users can * create links named by a host pointing to the binary and type * "hostname" to log into that host afterwards. */ cmd = strrchr(argv[0], '/'); cmd = (cmd != NULL) ? (cmd + 1) : argv[0]; if (strcmp(cmd, rlogin) == 0) { if (argc < 2) usage(); if (*argv[1] != '-') { host = argv[1]; argc--; argv[1] = argv[0]; argv++; } } else { host = cmd; } while ((c = getopt(argc, argv, DEBUGOPTSTRING "8AEFLP:ade:fk:l:x")) != -1) { switch (c) { case '8': eight = B_TRUE; break; case 'A': krb5auth_flag = B_TRUE; break; #ifdef DEBUG case 'D': portnumber = htons(atoi(optarg)); krb5auth_flag = B_TRUE; break; #endif /* DEBUG */ case 'E': nocmdchar = B_TRUE; break; case 'F': if (fflag) usage_forward(); Fflag = 1; krb5auth_flag = B_TRUE; fwdable_done = B_TRUE; break; case 'f': if (Fflag) usage_forward(); fflag = 1; krb5auth_flag = B_TRUE; fwd_done = B_TRUE; break; case 'L': litout = B_TRUE; break; case 'P': if (strcmp(optarg, "N") == 0) kcmd_proto = KCMD_NEW_PROTOCOL; else if (strcmp(optarg, "O") == 0) kcmd_proto = KCMD_OLD_PROTOCOL; else die(gettext("rlogin: Only -PN or -PO " "allowed.\n")); if (rcmdoption_done) die(gettext("rlogin: Only one of -PN and -PO " "allowed.\n")); rcmdoption_done = B_TRUE; krb5auth_flag = B_TRUE; break; case 'a': /* * Force the remote host to prompt for a password by sending * a NULL username. This option is mutually exclusive with * the -A, -x, -f, -F, -k <realm> options. */ null_local_username = B_TRUE; break; case 'd': options |= SO_DEBUG; break; case 'e': { int c; cp = optarg; if ((c = *cp) != '\\') { cmdchar = c; } else { c = cp[1]; if (c == '\0' || c == '\\') { cmdchar = '\\'; } else if (c >= '0' && c <= '7') { long lc; lc = strtol(&cp[1], NULL, 8); if (lc < 0 || lc > 255) die(gettext("rlogin: octal " "escape character %s too " "large.\n"), cp); cmdchar = (char)lc; } else { die(gettext("rlogin: unrecognized " "escape character option %s.\n"), cp); } } break; } case 'k': krb_realm = optarg; krb5auth_flag = B_TRUE; break; case 'l': name = optarg; break; case 'x': encrypt_flag = 1; krb5auth_flag = B_TRUE; encrypt_done = B_TRUE; break; default: usage(); } } argc -= optind; argv += optind; if (host == NULL) { if (argc == 0) usage(); argc--; host = *argv++; } if (argc > 0) usage(); pwd = getpwuid(uid = getuid()); if (pwd == NULL) { (void) fprintf(stderr, gettext("getpwuid(): can not find " "password entry for user id %d."), uid); return (EXIT_FAILURE); } if (name == NULL) name = pwd->pw_name; /* * If the `-a' option is issued on the cmd line, we reset all * flags associated with other KRB5 specific options, since * the -a option is mutually exclusive with the rest. */ if (null_local_username) { krb5auth_flag = B_FALSE; fflag = Fflag = encrypt_flag = 0; (void) fprintf(stderr, gettext("Note: The -a option nullifies " "all other Kerberos-specific\noptions " "you may have used.\n")); } if (krb5auth_flag) { status = krb5_init_context(&bsd_context); if (status) { com_err(rlogin, status, gettext("while initializing" " krb5")); return (EXIT_FAILURE); } /* * Set up buffers for desread and deswrite. */ desinbuf.data = des_inbuf; desoutbuf.data = des_outbuf; desinbuf.length = sizeof (des_inbuf); desoutbuf.length = sizeof (des_outbuf); /* * Get our local realm to look up local realm options. */ status = krb5_get_default_realm(bsd_context, &realmdef[1]); if (status) { com_err(rlogin, status, gettext("while getting default realm")); return (EXIT_FAILURE); } /* * Check the realms section in krb5.conf for encryption, * forward & forwardable info */ profile_get_options_boolean(bsd_context->profile, realmdef, option); /* * Check the appdefaults section */ profile_get_options_boolean(bsd_context->profile, appdef, option); profile_get_options_string(bsd_context->profile, appdef, rcmdversion); /* * Set the *_flag variables, if the corresponding *_done are * set to 1, because we dont want the config file values * overriding the command line options. */ if (encrypt_done) encrypt_flag = 1; if (fwd_done) { fflag = 1; Fflag = 0; } else if (fwdable_done) { Fflag = 1; fflag = 0; } if (!rcmdoption_done && (rcmdproto != NULL)) { if (strncmp(rcmdproto, "rcmdv2", 6) == 0) { kcmd_proto = KCMD_NEW_PROTOCOL; } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) { kcmd_proto = KCMD_OLD_PROTOCOL; } else { (void) fprintf(stderr, gettext("Unrecognized " "KCMD protocol (%s)"), rcmdproto); return (EXIT_FAILURE); } } if (encrypt_flag && (!krb5_privacy_allowed())) { (void) fprintf(stderr, gettext("rlogin: "******"Encryption not supported.\n")); return (EXIT_FAILURE); } } if (port_number == 0) { if (krb5auth_flag) { struct servent *sp; /* * If the krb5auth_flag is set (via -A, -f, -F, -k) & * if there is an entry in /etc/services for Kerberos * login, attempt to login with Kerberos. If we fail * at any step, use the standard rlogin */ sp = getservbyname(encrypt_flag ? "eklogin" : "klogin", "tcp"); if (sp == NULL) { port_number = encrypt_flag ? htons(2105) : htons(543); } else { port_number = sp->s_port; } } else { port_number = htons(IPPORT_LOGINSERVER); } } cp = getenv("TERM"); if (cp) { (void) strncpy(term, cp, sizeof (term)); term[sizeof (term) - 1] = '\0'; } if (getattr_ret == 0) { speed = cfgetospeed(&savetty); /* * "Be conservative in what we send" -- Only send baud rates * which at least all 4.x BSD derivatives are known to handle * correctly. * NOTE: This code assumes new termios speed values will * be "higher" speeds. */ if (speed > B38400) speed = B38400; } /* * Only put the terminal speed info in if we have room * so we don't overflow the buffer, and only if we have * a speed we recognize. */ if (speed > 0 && speed < sizeof (speeds)/sizeof (char *) && strlen(term) + strlen("/") + strlen(speeds[speed]) + 1 < sizeof (term)) { (void) strcat(term, "/"); (void) strcat(term, speeds[speed]); } (void) sigset(SIGPIPE, (sigdisp_t)lostpeer); /* will use SIGUSR1 for window size hack, so hold it off */ oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); /* * Determine if v4 literal address and if so store it to one * side. This is to correct the undesired behaviour of rcmd_af * which converts a passed in v4 literal address to a v4 mapped * v6 literal address. If it was a v4 literal we then re-assign * it to host. */ tmp = NULL; if (inet_addr(host) != (in_addr_t)-1) tmp = host; if (krb5auth_flag) { authopts = AP_OPTS_MUTUAL_REQUIRED; /* Piggy-back forwarding flags on top of authopts; */ /* they will be reset in kcmd */ if (fflag || Fflag) authopts |= OPTS_FORWARD_CREDS; if (Fflag) authopts |= OPTS_FORWARDABLE_CREDS; status = kcmd(&sock, &host, port_number, null_local_username ? "" : pwd->pw_name, name, term, NULL, "host", krb_realm, bsd_context, &auth_context, &cred, NULL, /* No need for sequence number */ NULL, /* No need for server seq # */ authopts, 0, /* Not any port # */ &kcmd_proto); if (status != 0) { /* * If new protocol requested, we dont fallback to * less secure ones. */ if (kcmd_proto == KCMD_NEW_PROTOCOL) { (void) fprintf(stderr, gettext("rlogin: kcmdv2 " "to host %s failed - %s\n" "Fallback to normal rlogin denied."), host, error_message(status)); return (EXIT_FAILURE); } if (status != -1) { (void) fprintf(stderr, gettext("rlogin: kcmd " "to host %s failed - %s,\n" "trying normal rlogin...\n\n"), host, error_message(status)); } else { (void) fprintf(stderr, gettext("trying normal rlogin...\n")); } /* * kcmd() failed, so we have to * fallback to normal rlogin */ port_number = htons(IPPORT_LOGINSERVER); krb5auth_flag = B_FALSE; fflag = Fflag = encrypt_flag = 0; null_local_username = B_FALSE; } else { (void) fprintf(stderr, gettext("connected with Kerberos V5\n")); /* * Setup eblock for desread and deswrite. */ session_key = &cred->keyblock; if (kcmd_proto == KCMD_NEW_PROTOCOL) { status = krb5_auth_con_getlocalsubkey( bsd_context, auth_context, &session_key); if (status) { com_err(rlogin, status, "determining subkey for session"); return (EXIT_FAILURE); } if (session_key == NULL) { com_err(rlogin, 0, "no subkey negotiated for " "connection"); return (EXIT_FAILURE); } } eblock.crypto_entry = session_key->enctype; eblock.key = (krb5_keyblock *)session_key; init_encrypt(encrypt_flag, bsd_context, kcmd_proto, &desinbuf, &desoutbuf, CLIENT, &eblock); rem = sock; if (rem < 0) pop(EXIT_FAILURE); } } /* * Don't merge this with the "if" statement above because * "krb5auth_flag" might be set to false inside it. */ if (!krb5auth_flag) { rem = rcmd_af(&host, port_number, null_local_username ? "" : pwd->pw_name, name, term, NULL, AF_INET6); if (rem < 0) pop(EXIT_FAILURE); } /* Never need our privilege again */ __priv_relinquish(); if (tmp != NULL) host = tmp; if (options & SO_DEBUG && setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) perror("rlogin: setsockopt (SO_DEBUG)"); { int bufsize = 8192; (void) setsockopt(rem, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof (int)); } doit(oldmask); return (0); }
int main(int argc, char **argv) { struct passwd const *pw; struct servent const *sp; long omask; int argoff, asrsh, ch, dflag, nflag, one, rem; pid_t pid = 0; uid_t uid; char *args, *host, *p, *user; int timeout = 0; argoff = asrsh = dflag = nflag = 0; one = 1; host = user = NULL; /* if called as something other than "rsh", use it as the host name */ if ((p = strrchr(argv[0], '/'))) ++p; else p = argv[0]; if (strcmp(p, "rsh")) host = p; else asrsh = 1; /* handle "rsh host flags" */ if (!host && argc > 2 && argv[1][0] != '-') { host = argv[1]; argoff = 1; } #define OPTIONS "468Lde:l:nt:w" while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) switch(ch) { case '4': family = PF_INET; break; case '6': family = PF_INET6; break; case 'L': /* -8Lew are ignored to allow rlogin aliases */ case 'e': case 'w': case '8': break; case 'd': dflag = 1; break; case 'l': user = optarg; break; case 'n': nflag = 1; break; case 't': timeout = atoi(optarg); break; case '?': default: usage(); } optind += argoff; /* if haven't gotten a host yet, do so */ if (!host && !(host = argv[optind++])) usage(); /* if no further arguments, must have been called as rlogin. */ if (!argv[optind]) { if (asrsh) *argv = rlogin; execv(_PATH_RLOGIN, argv); err(1, "can't exec %s", _PATH_RLOGIN); } argc -= optind; argv += optind; if (!(pw = getpwuid(uid = getuid()))) errx(1, "unknown user id"); if (!user) user = pw->pw_name; args = copyargs(argv); sp = NULL; if (sp == NULL) sp = getservbyname("shell", "tcp"); if (sp == NULL) errx(1, "shell/tcp: unknown service"); if (timeout) { signal(SIGALRM, connect_timeout); alarm(timeout); } rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2, family); if (timeout) { signal(SIGALRM, SIG_DFL); alarm(0); } if (rem < 0) exit(1); if (rfd2 < 0) errx(1, "can't establish stderr"); if (dflag) { if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) warn("setsockopt"); if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) warn("setsockopt"); } setuid(uid); omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, sendsig); if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) signal(SIGQUIT, sendsig); if (signal(SIGTERM, SIG_IGN) != SIG_IGN) signal(SIGTERM, sendsig); if (!nflag) { pid = fork(); if (pid < 0) err(1, "fork"); } else shutdown(rem, SHUT_WR); ioctl(rfd2, FIONBIO, &one); ioctl(rem, FIONBIO, &one); talk(nflag, omask, pid, rem, timeout); if (!nflag) kill(pid, SIGKILL); exit(0); }
int rcmd(char **ahost, int rport, const char *locuser, const char *remuser, const char *cmd, int *fd2p) { return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); }
int main(int argc, char *argv[]) { struct passwd *pw; struct servent *sp; struct termios tty; long omask; int argoff, ch, dflag, Dflag, one; uid_t uid; char *host, *localname, *p, *user, term[1024]; speed_t ospeed; struct sockaddr_storage ss; socklen_t sslen; size_t len, len2; int i; argoff = dflag = Dflag = 0; one = 1; host = localname = user = NULL; if ((p = strrchr(argv[0], '/'))) ++p; else p = argv[0]; if (strcmp(p, "rlogin")) host = p; /* handle "rlogin host flags" */ if (!host && argc > 2 && argv[1][0] != '-') { host = argv[1]; argoff = 1; } #define OPTIONS "468DEde:i:l:" while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) switch(ch) { case '4': family = PF_INET; break; case '6': family = PF_INET6; break; case '8': eight = 1; break; case 'D': Dflag = 1; break; case 'E': noescape = 1; break; case 'd': dflag = 1; break; case 'e': noescape = 0; escapechar = getescape(optarg); break; case 'i': if (getuid() != 0) errx(1, "-i user: permission denied"); localname = optarg; break; case 'l': user = optarg; break; case '?': default: usage(); } optind += argoff; /* if haven't gotten a host yet, do so */ if (!host && !(host = argv[optind++])) usage(); if (argv[optind]) usage(); if (!(pw = getpwuid(uid = getuid()))) errx(1, "unknown user id"); if (!user) user = pw->pw_name; if (!localname) localname = pw->pw_name; sp = NULL; sp = getservbyname("login", "tcp"); if (sp == NULL) errx(1, "login/tcp: unknown service"); if ((p = getenv("TERM")) != NULL) (void)strlcpy(term, p, sizeof(term)); len = strlen(term); if (len < (sizeof(term) - 1) && tcgetattr(0, &tty) == 0) { /* start at 2 to include the / */ for (ospeed = i = cfgetospeed(&tty), len2 = 2; i > 9; len2++) i /= 10; if (len + len2 < sizeof(term)) (void)snprintf(term + len, len2 + 1, "/%d", ospeed); } (void)get_window_size(0, &winsize); (void)signal(SIGPIPE, lostpeer); /* will use SIGUSR1 for window size hack, so hold it off */ omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); /* * We set SIGURG and SIGUSR1 below so that an * incoming signal will be held pending rather than being * discarded. Note that these routines will be ready to get * a signal by the time that they are unblocked below. */ (void)signal(SIGURG, copytochild); (void)signal(SIGUSR1, writeroob); rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, family); if (rem < 0) exit(1); if (dflag && setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) warn("setsockopt"); if (Dflag && setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) warn("setsockopt NODELAY (ignored)"); sslen = sizeof(ss); one = IPTOS_LOWDELAY; if (getsockname(rem, (struct sockaddr *)&ss, &sslen) == 0 && ss.ss_family == AF_INET) { if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) warn("setsockopt TOS (ignored)"); } else if (ss.ss_family == AF_INET) warn("setsockopt getsockname failed"); (void)setuid(uid); doit(omask); /*NOTREACHED*/ }
int main(int argc, char *argv[]) { struct passwd *pw; struct servent *sp; struct sgttyb ttyb; long omask; int argoff, ch, dflag, Dflag, one, uid; char *host, *localname, *p, *user, term[1024]; #ifdef KERBEROS char *k; #endif struct sockaddr_storage ss; int sslen; argoff = dflag = Dflag = 0; one = 1; host = localname = user = NULL; if ((p = strrchr(argv[0], '/'))) ++p; else p = argv[0]; if (strcmp(p, "rlogin")) host = p; /* handle "rlogin host flags" */ if (!host && argc > 2 && argv[1][0] != '-') { host = argv[1]; argoff = 1; } #ifdef KERBEROS #define OPTIONS "468DEKLde:i:k:l:x" #else #define OPTIONS "468DEKLde:i:l:" #endif while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != -1) switch(ch) { case '4': family = PF_INET; break; case '6': family = PF_INET6; break; case '8': eight = 1; break; case 'D': Dflag = 1; break; case 'E': noescape = 1; break; case 'K': #ifdef KERBEROS use_kerberos = 0; #endif break; case 'L': litout = 1; break; case 'd': dflag = 1; break; case 'e': noescape = 0; escapechar = getescape(optarg); break; case 'i': if (getuid() != 0) errx(1, "-i user: permission denied"); localname = optarg; break; #ifdef KERBEROS case 'k': dest_realm = dst_realm_buf; (void)strncpy(dest_realm, optarg, REALM_SZ); break; #endif case 'l': user = optarg; break; #ifdef CRYPT #ifdef KERBEROS case 'x': doencrypt = 1; break; #endif #endif case '?': default: usage(); } optind += argoff; /* if haven't gotten a host yet, do so */ if (!host && !(host = argv[optind++])) usage(); if (argv[optind]) usage(); if (!(pw = getpwuid(uid = getuid()))) errx(1, "unknown user id"); if (!user) user = pw->pw_name; if (!localname) localname = pw->pw_name; sp = NULL; #ifdef KERBEROS k = auth_getval("auth_list"); if (k && !strstr(k, "kerberos")) use_kerberos = 0; if (use_kerberos) { sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); if (sp == NULL) { use_kerberos = 0; warn("can't get entry for %s/tcp service", doencrypt ? "eklogin" : "klogin"); } } #endif if (sp == NULL) sp = getservbyname("login", "tcp"); if (sp == NULL) errx(1, "login/tcp: unknown service"); #define MAX_TERM_LENGTH (sizeof(term) - 1 - MAX_SPEED_LENGTH - 1) (void)strncpy(term, (p = getenv("TERM")) ? p : "network", MAX_TERM_LENGTH); term[MAX_TERM_LENGTH] = '\0'; if (ioctl(0, TIOCGETP, &ttyb) == 0) { (void)strcat(term, "/"); (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); } (void)get_window_size(0, &winsize); (void)signal(SIGPIPE, lostpeer); /* will use SIGUSR1 for window size hack, so hold it off */ omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); /* * We set SIGURG and SIGUSR1 below so that an * incoming signal will be held pending rather than being * discarded. Note that these routines will be ready to get * a signal by the time that they are unblocked below. */ (void)signal(SIGURG, copytochild); (void)signal(SIGUSR1, writeroob); #ifdef KERBEROS if (use_kerberos) { setuid(getuid()); rem = KSUCCESS; errno = 0; if (dest_realm == NULL) dest_realm = krb_realmofhost(host); #ifdef CRYPT if (doencrypt) { rem = krcmd_mutual(&host, sp->s_port, user, term, 0, dest_realm, &cred, schedule); des_set_key(&cred.session, schedule); } else #endif /* CRYPT */ rem = krcmd(&host, sp->s_port, user, term, 0, dest_realm); if (rem < 0) { int i; char **newargv; sp = getservbyname("login", "tcp"); if (sp == NULL) errx(1, "unknown service login/tcp"); if (errno == ECONNREFUSED) warn("remote host doesn't support Kerberos"); if (errno == ENOENT) warn("can't provide Kerberos auth data"); newargv = malloc((argc + 2) * sizeof(*newargv)); if (newargv == NULL) err(1, "malloc"); newargv[0] = argv[0]; newargv[1] = "-K"; for(i = 1; i < argc; ++i) newargv[i + 1] = argv[i]; newargv[argc + 1] = NULL; execv(_PATH_RLOGIN, newargv); } } else { #ifdef CRYPT if (doencrypt) errx(1, "the -x flag requires Kerberos authentication"); #endif /* CRYPT */ rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, family); } #else rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, family); #endif /* KERBEROS */ if (rem < 0) exit(1); if (dflag && setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) warn("setsockopt"); if (Dflag && setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) warn("setsockopt NODELAY (ignored)"); sslen = sizeof(ss); one = IPTOS_LOWDELAY; if (getsockname(rem, (struct sockaddr *)&ss, &sslen) == 0 && ss.ss_family == AF_INET) { if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) warn("setsockopt TOS (ignored)"); } else if (ss.ss_family == AF_INET) warn("setsockopt getsockname failed"); (void)setuid(uid); doit(omask); /*NOTREACHED*/ }
void toremote(char *targ, int argc, char *argv[]) { int i; size_t len; char *bp, *host, *src, *suser, *thost, *tuser; *targ++ = 0; if (*targ == 0) targ = dot; if ((thost = strchr(argv[argc - 1], '@')) != NULL) { /* user@host */ *thost++ = 0; tuser = argv[argc - 1]; if (*tuser == '\0') tuser = NULL; else if (!okname(tuser)) exit(1); } else { thost = argv[argc - 1]; tuser = NULL; } thost = unbracket(thost); for (i = 0; i < argc - 1; i++) { src = colon(argv[i]); if (src) { /* remote to remote */ *src++ = 0; if (*src == 0) src = dot; host = strchr(argv[i], '@'); len = strlen(_PATH_RSH) + strlen(argv[i]) + strlen(src) + (tuser ? strlen(tuser) : 0) + strlen(thost) + strlen(targ) + CMDNEEDS + 20; if (!(bp = malloc(len))) err(1, NULL); if (host) { *host++ = 0; host = unbracket(host); suser = argv[i]; if (*suser == '\0') suser = pwname; else if (!okname(suser)) { (void)free(bp); continue; } (void)snprintf(bp, len, "%s %s -l %s -n %s %s '%s%s%s:%s'", _PATH_RSH, host, suser, cmd, src, tuser ? tuser : "", tuser ? "@" : "", thost, targ); } else { host = unbracket(argv[i]); (void)snprintf(bp, len, "exec %s %s -n %s %s '%s%s%s:%s'", _PATH_RSH, argv[i], cmd, src, tuser ? tuser : "", tuser ? "@" : "", thost, targ); } (void)susystem(bp); (void)free(bp); } else { /* local to remote */ if (rem == -1) { len = strlen(targ) + CMDNEEDS + 20; if (!(bp = malloc(len))) err(1, NULL); (void)snprintf(bp, len, "%s -t %s", cmd, targ); host = thost; rem = rcmd_af(&host, port, pwname, tuser ? tuser : pwname, bp, NULL, family); if (rem < 0) exit(1); if (response() < 0) exit(1); (void)free(bp); } source(1, argv+i); } } }