diff options
Diffstat (limited to 'libexec/rshd/rshd.c')
-rw-r--r-- | libexec/rshd/rshd.c | 229 |
1 files changed, 228 insertions, 1 deletions
diff --git a/libexec/rshd/rshd.c b/libexec/rshd/rshd.c index 029bd5bfc12..d85fc68faa9 100644 --- a/libexec/rshd/rshd.c +++ b/libexec/rshd/rshd.c @@ -39,7 +39,7 @@ static char copyright[] = #ifndef lint /* from: static char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94"; */ -static char *rcsid = "$Id: rshd.c,v 1.2 1995/11/20 09:38:09 deraadt Exp $"; +static char *rcsid = "$Id: rshd.c,v 1.3 1995/12/16 22:20:23 tholo Exp $"; #endif /* not lint */ /* @@ -82,7 +82,19 @@ int local_domain __P((char *)); char *topdomain __P((char *)); void usage __P((void)); +#ifdef KERBEROS +#include <kerberosIV/des.h> +#include <kerberosIV/krb.h> +#define VERSION_SIZE 9 +#define SECURE_MESSAGE "This rsh session is using DES encryption for all transmissions.\r\n" +#define OPTIONS "alnkvxL" +char authbuf[sizeof(AUTH_DAT)]; +char tickbuf[sizeof(KTEXT_ST)]; +int doencrypt, use_kerberos, vacuous; +Key_schedule schedule; +#else #define OPTIONS "alnL" +#endif int main(argc, argv) @@ -108,6 +120,21 @@ main(argc, argv) case 'n': keepalive = 0; break; +#ifdef KERBEROS + case 'k': + use_kerberos = 1; + break; + + case 'v': + vacuous = 1; + break; + +#ifdef CRYPT + case 'x': + doencrypt = 1; + break; +#endif +#endif case 'L': log_success = 1; break; @@ -120,6 +147,18 @@ main(argc, argv) argc -= optind; argv += optind; +#ifdef KERBEROS + if (use_kerberos && vacuous) { + syslog(LOG_ERR, "only one of -k and -v allowed"); + exit(2); + } +#ifdef CRYPT + if (doencrypt && !use_kerberos) { + syslog(LOG_ERR, "-k is required for -x"); + exit(2); + } +#endif +#endif fromlen = sizeof (from); if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { @@ -164,6 +203,18 @@ doit(fromp) char remotehost[2 * MAXHOSTNAMELEN + 1]; char hostnamebuf[2 * MAXHOSTNAMELEN + 1]; +#ifdef KERBEROS + AUTH_DAT *kdata = (AUTH_DAT *) NULL; + KTEXT ticket = (KTEXT) NULL; + char instance[INST_SZ], version[VERSION_SIZE]; + struct sockaddr_in fromaddr; + int rc; + long authopts; + int pv1[2], pv2[2]; + fd_set wready, writeto; + + fromaddr = *fromp; +#endif (void) signal(SIGINT, SIG_DFL); (void) signal(SIGQUIT, SIG_DFL); @@ -210,6 +261,9 @@ doit(fromp) } #endif +#ifdef KERBEROS + if (!use_kerberos) +#endif if (fromp->sin_port >= IPPORT_RESERVED || fromp->sin_port < IPPORT_RESERVED/2) { syslog(LOG_NOTICE|LOG_AUTH, @@ -242,6 +296,9 @@ doit(fromp) syslog(LOG_ERR, "can't get stderr port: %m"); exit(1); } +#ifdef KERBEROS + if (!use_kerberos) +#endif if (port >= IPPORT_RESERVED) { syslog(LOG_ERR, "2nd port not reserved\n"); exit(1); @@ -253,6 +310,12 @@ doit(fromp) } } +#ifdef KERBEROS + if (vacuous) { + error("rshd: remote host requires Kerberos authentication\n"); + exit(1); + } +#endif #ifdef notdef /* from inetd, socket is already on 0, 1, 2 */ @@ -271,6 +334,9 @@ doit(fromp) * address corresponds to the name. */ hostname = hp->h_name; +#ifdef KERBEROS + if (!use_kerberos) +#endif if (check_all || local_domain(hp->h_name)) { strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); remotehost[sizeof(remotehost) - 1] = 0; @@ -310,6 +376,42 @@ doit(fromp) sizeof(hostnamebuf) - 1); hostnamebuf[sizeof(hostnamebuf) - 1] = '\0'; +#ifdef KERBEROS + if (use_kerberos) { + kdata = (AUTH_DAT *) authbuf; + ticket = (KTEXT) tickbuf; + authopts = 0L; + strcpy(instance, "*"); + version[VERSION_SIZE - 1] = '\0'; +#ifdef CRYPT + if (doencrypt) { + struct sockaddr_in local_addr; + rc = sizeof(local_addr); + if (getsockname(0, (struct sockaddr *)&local_addr, + &rc) < 0) { + syslog(LOG_ERR, "getsockname: %m"); + error("rlogind: getsockname: %m"); + exit(1); + } + authopts = KOPT_DO_MUTUAL; + rc = krb_recvauth(authopts, 0, ticket, + "rcmd", instance, &fromaddr, + &local_addr, kdata, "", schedule, + version); + des_set_key(kdata->session, schedule); + } else +#endif + rc = krb_recvauth(authopts, 0, ticket, "rcmd", + instance, &fromaddr, + (struct sockaddr_in *) 0, + kdata, "", (bit_64 *) 0, version); + if (rc != KSUCCESS) { + error("Kerberos authentication failure: %s\n", + krb_err_txt[rc]); + exit(1); + } + } else +#endif getstr(remuser, sizeof(remuser), "remuser"); getstr(locuser, sizeof(locuser), "locuser"); @@ -335,6 +437,19 @@ doit(fromp) #endif } +#ifdef KERBEROS + if (use_kerberos) { + if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') { + if (kuserok(kdata, locuser) != 0) { + syslog(LOG_INFO|LOG_AUTH, + "Kerberos rsh denied to %s.%s@%s", + kdata->pname, kdata->pinst, kdata->prealm); + error("Permission denied.\n"); + exit(1); + } + } + } else +#endif if (errorstr || pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && iruserok(fromp->sin_addr.s_addr, pwd->pw_uid == 0, @@ -368,12 +483,37 @@ fail: error("Can't make pipe.\n"); exit(1); } +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt) { + if (pipe(pv1) < 0) { + error("Can't make 2nd pipe.\n"); + exit(1); + } + if (pipe(pv2) < 0) { + error("Can't make 3rd pipe.\n"); + exit(1); + } + } +#endif +#endif pid = fork(); if (pid == -1) { error("Can't fork; try again.\n"); exit(1); } if (pid) { +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt) { + static char msg[] = SECURE_MESSAGE; + (void) close(pv1[1]); + (void) close(pv2[1]); + des_write(s, msg, sizeof(msg) - 1); + + } else +#endif +#endif { (void) close(0); (void) close(1); @@ -388,17 +528,47 @@ fail: nfd = pv[0]; else nfd = s; +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt) { + FD_ZERO(&writeto); + FD_SET(pv2[0], &writeto); + FD_SET(pv1[0], &readfrom); + + nfd = MAX(nfd, pv2[0]); + nfd = MAX(nfd, pv1[0]); + } else +#endif +#endif ioctl(pv[0], FIONBIO, (char *)&one); /* should set s nbio! */ nfd++; do { ready = readfrom; +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt) { + wready = writeto; + if (select(nfd, &ready, + &wready, (fd_set *) 0, + (struct timeval *) 0) < 0) + break; + } else +#endif +#endif if (select(nfd, &ready, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) break; if (FD_ISSET(s, &ready)) { int ret; +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt) + ret = des_read(s, &sig, 1); + else +#endif +#endif ret = read(s, &sig, 1); if (ret <= 0) FD_CLR(s, &readfrom); @@ -412,18 +582,67 @@ fail: shutdown(s, 1+1); FD_CLR(pv[0], &readfrom); } else { +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt) + (void) + des_write(s, buf, cc); + else +#endif +#endif (void) write(s, buf, cc); } } +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt && FD_ISSET(pv1[0], &ready)) { + errno = 0; + cc = read(pv1[0], buf, sizeof(buf)); + if (cc <= 0) { + shutdown(pv1[0], 1+1); + FD_CLR(pv1[0], &readfrom); + } else + (void) des_write(STDOUT_FILENO, + buf, cc); + } + + if (doencrypt && FD_ISSET(pv2[0], &wready)) { + errno = 0; + cc = des_read(STDIN_FILENO, + buf, sizeof(buf)); + if (cc <= 0) { + shutdown(pv2[0], 1+1); + FD_CLR(pv2[0], &writeto); + } else + (void) write(pv2[0], buf, cc); + } +#endif +#endif } while (FD_ISSET(s, &readfrom) || +#ifdef CRYPT +#ifdef KERBEROS + (doencrypt && FD_ISSET(pv1[0], &readfrom)) || +#endif +#endif FD_ISSET(pv[0], &readfrom)); exit(0); } setpgrp(0, getpid()); (void) close(s); (void) close(pv[0]); +#ifdef CRYPT +#ifdef KERBEROS + if (doencrypt) { + close(pv1[0]); close(pv2[0]); + dup2(pv1[1], 1); + dup2(pv2[1], 0); + close(pv1[1]); + close(pv2[1]); + } +#endif +#endif dup2(pv[1], 2); close(pv[1]); } @@ -448,6 +667,14 @@ fail: cp = pwd->pw_shell; endpwent(); if (log_success || pwd->pw_uid == 0) { +#ifdef KERBEROS + if (use_kerberos) + syslog(LOG_INFO|LOG_AUTH, + "Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'", + kdata->pname, kdata->pinst, kdata->prealm, + hostname, locuser, cmdbuf); + else +#endif syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'", remuser, hostname, locuser, cmdbuf); } |