int main (int argc, char **argv) { int index; struct passwd *pw; struct servent *sp; sigset_t sigs, osigs; int asrsh, rem; pid_t pid = 0; uid_t uid; char *args, *host; set_program_name (argv[0]); asrsh = 0; host = user = NULL; /* If called as something other than "rsh", use it as the host name */ { char *p = strrchr (argv[0], '/'); if (p) ++p; else p = argv[0]; if (strcmp (p, "rsh")) host = p; else asrsh = 1; } /* Parse command line */ iu_argp_init ("rsh", default_program_authors); argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &index, NULL); if (index < argc) host = argv[index++]; /* To few args. */ if (!host) error (EXIT_FAILURE, 0, "host not specified"); /* If no further arguments, must have been called as rlogin. */ if (!argv[index]) { if (asrsh) *argv = (char *) "rlogin"; seteuid (getuid ()); setuid (getuid ()); execv (PATH_RLOGIN, argv); error (EXIT_FAILURE, errno, "cannot execute %s", PATH_RLOGIN); } argc -= index; argv += index; /* We must be setuid root. */ if (geteuid ()) error (EXIT_FAILURE, 0, "must be setuid root.\n"); if (!(pw = getpwuid (uid = getuid ()))) error (EXIT_FAILURE, 0, "unknown user id"); /* Accept user1@host format, though "-l user2" overrides user1 */ { char *p = strchr (host, '@'); if (p) { *p = '\0'; if (!user && p > host) user = host; host = p + 1; if (*host == '\0') error (EXIT_FAILURE, 0, "empty host name"); } } #if defined KERBEROS || defined SHISHI # ifdef ENCRYPTION /* -x turns off -n */ if (doencrypt) null_input_option = 0; # endif #endif args = copyargs (argv); sp = NULL; #ifdef KERBEROS if (use_kerberos) { sp = getservbyname ((doencrypt ? "ekshell" : "kshell"), "tcp"); if (sp == NULL) { use_kerberos = 0; warning ("can't get entry for %s/tcp service", doencrypt ? "ekshell" : "kshell"); } } #elif defined(SHISHI) if (use_kerberos) { sp = getservbyname ("kshell", "tcp"); if (sp == NULL) { use_kerberos = 0; warning ("can't get entry for %s/tcp service", "kshell"); } } #endif if (sp == NULL) sp = getservbyname ("shell", "tcp"); if (sp == NULL) error (EXIT_FAILURE, 0, "shell/tcp: unknown service"); #if defined KERBEROS || defined SHISHI try_connect: if (use_kerberos) { struct hostent *hp; /* fully qualify hostname (needed for krb_realmofhost) */ hp = gethostbyname (host); if (hp != NULL && !(host = strdup (hp->h_name))) error (EXIT_FAILURE, errno, "strdup"); # if defined KERBEROS rem = KSUCCESS; errno = 0; if (dest_realm == NULL) dest_realm = krb_realmofhost (host); # elif defined (SHISHI) rem = SHISHI_OK; errno = 0; # endif # ifdef ENCRYPTION if (doencrypt) # if defined SHISHI { int i; char *term; term = xmalloc (strlen (args) + 4); strcpy (term, "-x "); strcat (term, args); rem = krcmd_mutual (&h, &host, sp->s_port, &user, term, &rfd2, dest_realm, &enckey); if (rem > 0) { keytype = shishi_key_type (enckey); keylen = shishi_cipher_blocksize (keytype); ivtab[0] = &iv1; ivtab[1] = &iv2; ivtab[2] = &iv3; ivtab[3] = &iv4; for (i = 0; i < 4; i++) { ivtab[i]->ivlen = keylen; switch (keytype) { case SHISHI_DES_CBC_CRC: case SHISHI_DES_CBC_MD4: case SHISHI_DES_CBC_MD5: case SHISHI_DES_CBC_NONE: case SHISHI_DES3_CBC_HMAC_SHA1_KD: ivtab[i]->keyusage = SHISHI_KEYUSAGE_KCMD_DES; ivtab[i]->iv = malloc (ivtab[i]->ivlen); memset (ivtab[i]->iv, 2 * i + 1 * (i < 2) - 4 * (i >= 2), ivtab[i]->ivlen); ivtab[i]->ctx = shishi_crypto (h, enckey, ivtab[i]->keyusage, shishi_key_type (enckey), ivtab[i]->iv, ivtab[i]->ivlen); break; case SHISHI_ARCFOUR_HMAC: case SHISHI_ARCFOUR_HMAC_EXP: ivtab[i]->keyusage = SHISHI_KEYUSAGE_KCMD_DES + 2 + 4 * i; ivtab[i]->ctx = shishi_crypto (h, enckey, ivtab[i]->keyusage, shishi_key_type (enckey), NULL, 0); break; default: ivtab[i]->keyusage = SHISHI_KEYUSAGE_KCMD_DES + 2 + 4 * i; ivtab[i]->iv = malloc (ivtab[i]->ivlen); memset (ivtab[i]->iv, 0, ivtab[i]->ivlen); ivtab[i]->ctx = shishi_crypto (h, enckey, ivtab[i]->keyusage, shishi_key_type (enckey), ivtab[i]->iv, ivtab[i]->ivlen); } } } free (term); } else # else rem = krcmd_mutual (&host, sp->s_port, user, args, &rfd2, dest_realm, &cred, schedule); else # endif # endif rem = krcmd ( # if defined SHISHI &h, &host, sp->s_port, &user, args, &rfd2, dest_realm); # else &host, sp->s_port, user, args, &rfd2, dest_realm); # endif if (rem < 0) { use_kerberos = 0; sp = getservbyname ("shell", "tcp"); if (sp == NULL) error (EXIT_FAILURE, 0, "shell/tcp: unknown service"); if (errno == ECONNREFUSED) warning ("remote host doesn't support Kerberos"); if (errno == ENOENT) warning ("can't provide Kerberos auth data"); goto try_connect; } }
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*/ }