rshd.c revision 1593
1139749Simp/*- 254773Simp * Copyright (c) 1988, 1989, 1992, 1993, 1994 354773Simp * The Regents of the University of California. All rights reserved. 454773Simp * 554773Simp * Redistribution and use in source and binary forms, with or without 654773Simp * modification, are permitted provided that the following conditions 754773Simp * are met: 854773Simp * 1. Redistributions of source code must retain the above copyright 954773Simp * notice, this list of conditions and the following disclaimer. 1054773Simp * 2. Redistributions in binary form must reproduce the above copyright 1154773Simp * notice, this list of conditions and the following disclaimer in the 1254773Simp * documentation and/or other materials provided with the distribution. 1354773Simp * 3. All advertising materials mentioning features or use of this software 1454773Simp * must display the following acknowledgement: 1554773Simp * This product includes software developed by the University of 1654773Simp * California, Berkeley and its contributors. 1754773Simp * 4. Neither the name of the University nor the names of its contributors 1854773Simp * may be used to endorse or promote products derived from this software 1954773Simp * without specific prior written permission. 2054773Simp * 2154773Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2254773Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2354773Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2454773Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2554773Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2654773Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2754773Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2854773Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2954773Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3054773Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3154773Simp * SUCH DAMAGE. 32119419Sobrien */ 33119419Sobrien 34119419Sobrien#ifndef lint 3554773Simpstatic char copyright[] = 3654773Simp"@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\n\ 3754773Simp The Regents of the University of California. All rights reserved.\n"; 3854773Simp#endif /* not lint */ 3954773Simp 4054773Simp#ifndef lint 4154773Simpstatic char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94"; 4254773Simp#endif /* not lint */ 4354773Simp 4454773Simp/* 4554773Simp * remote shell server: 4654773Simp * [port]\0 4754773Simp * remuser\0 4854773Simp * locuser\0 4954773Simp * command\0 5054773Simp * data 5154773Simp */ 5254773Simp#include <sys/param.h> 5354773Simp#include <sys/ioctl.h> 5454773Simp#include <sys/time.h> 5554773Simp#include <sys/socket.h> 5654773Simp 5754773Simp#include <netinet/in.h> 5854773Simp#include <arpa/inet.h> 5954773Simp#include <netdb.h> 6054773Simp 6154773Simp#include <errno.h> 6254773Simp#include <fcntl.h> 6354773Simp#include <paths.h> 6454773Simp#include <pwd.h> 6554773Simp#include <signal.h> 6654773Simp#include <stdio.h> 6754773Simp#include <stdlib.h> 6854773Simp#include <string.h> 6954773Simp#include <syslog.h> 7054773Simp#include <unistd.h> 7154773Simp 7254773Simpint keepalive = 1; 7354773Simpint check_all; 7454773Simpint log_success; /* If TRUE, log all successful accesses */ 7554773Simpint sent_null; 7654773Simp 7754773Simpvoid doit __P((struct sockaddr_in *)); 7854773Simpvoid error __P((const char *, ...)); 7954773Simpvoid getstr __P((char *, int, char *)); 8054773Simpint local_domain __P((char *)); 8154773Simpchar *topdomain __P((char *)); 8254773Simpvoid usage __P((void)); 8354773Simp 8454773Simp#ifdef KERBEROS 85199559Sjhb#include <kerberosIV/des.h> 8654773Simp#include <kerberosIV/krb.h> 8754773Simp#define VERSION_SIZE 9 8854773Simp#define SECURE_MESSAGE "This rsh session is using DES encryption for all transmissions.\r\n" 8954773Simp#define OPTIONS "alnkvxL" 9054773Simpchar authbuf[sizeof(AUTH_DAT)]; 9154994Simpchar tickbuf[sizeof(KTEXT_ST)]; 9254994Simpint doencrypt, use_kerberos, vacuous; 9354994SimpKey_schedule schedule; 9454994Simp#else 9554994Simp#define OPTIONS "alnL" 9654994Simp#endif 9754994Simp 9854773Simpint 9954773Simpmain(argc, argv) 10054773Simp int argc; 10154773Simp char *argv[]; 10254773Simp{ 10354773Simp extern int __check_rhosts_file; 10454773Simp struct linger linger; 10554773Simp int ch, on = 1, fromlen; 10654773Simp struct sockaddr_in from; 10754773Simp 10854773Simp openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON); 10954773Simp 11054773Simp opterr = 0; 11154773Simp while ((ch = getopt(argc, argv, OPTIONS)) != EOF) 11254773Simp switch (ch) { 11354773Simp case 'a': 11454773Simp check_all = 1; 11554773Simp break; 11654994Simp case 'l': 11754773Simp __check_rhosts_file = 0; 11854994Simp break; 11954994Simp case 'n': 12054773Simp keepalive = 0; 12154994Simp break; 12254773Simp#ifdef KERBEROS 12354994Simp case 'k': 12454773Simp use_kerberos = 1; 125199559Sjhb break; 126121589Simp 127121589Simp case 'v': 12854773Simp vacuous = 1; 129121589Simp break; 130121589Simp 131121589Simp#ifdef CRYPT 132121589Simp case 'x': 133199559Sjhb doencrypt = 1; 134121589Simp break; 13554773Simp#endif 136147256Sbrooks#endif 13754773Simp case 'L': 13854773Simp log_success = 1; 13954773Simp break; 14054773Simp case '?': 14154773Simp default: 14254773Simp usage(); 14354994Simp break; 14454994Simp } 14554994Simp 146148144Simp argc -= optind; 14754994Simp argv += optind; 14854994Simp 14954994Simp#ifdef KERBEROS 15071060Stoshi if (use_kerberos && vacuous) { 151147872Simp syslog(LOG_ERR, "only one of -k and -v allowed"); 152147872Simp exit(2); 15354994Simp } 15454773Simp#ifdef CRYPT 15554773Simp if (doencrypt && !use_kerberos) { 15654773Simp syslog(LOG_ERR, "-k is required for -x"); 15754994Simp exit(2); 15854773Simp } 15954994Simp#endif 160147256Sbrooks#endif 161147797Simp 162121589Simp fromlen = sizeof (from); 16354773Simp if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 164121589Simp syslog(LOG_ERR, "getpeername: %m"); 165122427Simp _exit(1); 166147256Sbrooks } 16754773Simp if (keepalive && 168147256Sbrooks setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 169147256Sbrooks sizeof(on)) < 0) 170147256Sbrooks syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 171147256Sbrooks linger.l_onoff = 1; 172147256Sbrooks linger.l_linger = 60; /* XXX */ 173147256Sbrooks if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, 174121589Simp sizeof (linger)) < 0) 175199559Sjhb syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 17654994Simp doit(&from); 17754773Simp /* NOTREACHED */ 17854773Simp} 179147797Simp 180147797Simpchar username[20] = "USER="; 181147797Simpchar homedir[64] = "HOME="; 182147797Simpchar shell[64] = "SHELL="; 183147797Simpchar path[100] = "PATH="; 184147797Simpchar *envinit[] = 185149095Simp {homedir, shell, path, username, 0}; 186147797Simpchar **environ; 187147797Simp 188147797Simpvoid 189147797Simpdoit(fromp) 19054773Simp struct sockaddr_in *fromp; 19154773Simp{ 19254773Simp extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */ 19354773Simp struct hostent *hp; 19454773Simp struct passwd *pwd; 195121514Simp u_short port; 196147256Sbrooks fd_set ready, readfrom; 19754773Simp int cc, nfd, pv[2], pid, s; 198121514Simp int one = 1; 19954773Simp char *hostname, *errorstr, *errorhost; 20054773Simp char *cp, sig, buf[BUFSIZ]; 20154773Simp char cmdbuf[NCARGS+1], locuser[16], remuser[16]; 20254773Simp char remotehost[2 * MAXHOSTNAMELEN + 1]; 203121816Sbrooks 20454773Simp#ifdef KERBEROS 20554773Simp AUTH_DAT *kdata = (AUTH_DAT *) NULL; 20654773Simp KTEXT ticket = (KTEXT) NULL; 20754773Simp char instance[INST_SZ], version[VERSION_SIZE]; 208155280Simp struct sockaddr_in fromaddr; 209207554Ssobomax int rc; 210207554Ssobomax long authopts; 211155280Simp int pv1[2], pv2[2]; 21254773Simp fd_set wready, writeto; 213147256Sbrooks 21454994Simp fromaddr = *fromp; 21554773Simp#endif 216122427Simp 217122427Simp (void) signal(SIGINT, SIG_DFL); 218122427Simp (void) signal(SIGQUIT, SIG_DFL); 219122427Simp (void) signal(SIGTERM, SIG_DFL); 220122427Simp#ifdef DEBUG 221166901Spiso { int t = open(_PATH_TTY, 2); 222166901Spiso if (t >= 0) { 223122427Simp ioctl(t, TIOCNOTTY, (char *)0); 224122427Simp (void) close(t); 225122427Simp } 22654994Simp } 22754773Simp#endif 22854773Simp fromp->sin_port = ntohs((u_short)fromp->sin_port); 22954773Simp if (fromp->sin_family != AF_INET) { 23069955Simp syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", 23169955Simp fromp->sin_family); 23269955Simp exit(1); 233147256Sbrooks } 234147256Sbrooks#ifdef IP_OPTIONS 23569955Simp { 236199559Sjhb u_char optbuf[BUFSIZ/3], *cp; 237199559Sjhb char lbuf[BUFSIZ], *lp; 238121589Simp int optsize = sizeof(optbuf), ipproto; 239199559Sjhb struct protoent *ip; 240199559Sjhb 241150306Simp if ((ip = getprotobyname("ip")) != NULL) 242147256Sbrooks ipproto = ip->p_proto; 243150183Sru else 24469955Simp ipproto = IPPROTO_IP; 24569955Simp if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) && 24669955Simp optsize != 0) { 247121589Simp lp = lbuf; 248121589Simp for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 249121589Simp sprintf(lp, " %2.2x", *cp); 250121589Simp syslog(LOG_NOTICE, 251121589Simp "Connection received from %s using IP options (ignored):%s", 252121589Simp inet_ntoa(fromp->sin_addr), lbuf); 253121589Simp if (setsockopt(0, ipproto, IP_OPTIONS, 254121589Simp (char *)NULL, optsize) != 0) { 255121589Simp syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 25654773Simp exit(1); 25754773Simp } 25854773Simp } 259121589Simp } 260121589Simp#endif 26154773Simp 262121553Simp#ifdef KERBEROS 263147256Sbrooks if (!use_kerberos) 26454773Simp#endif 26554773Simp if (fromp->sin_port >= IPPORT_RESERVED || 26654773Simp fromp->sin_port < IPPORT_RESERVED/2) { 267121589Simp syslog(LOG_NOTICE|LOG_AUTH, 26854773Simp "Connection from %s on illegal port %u", 26954773Simp inet_ntoa(fromp->sin_addr), 27054773Simp fromp->sin_port); 27154773Simp exit(1); 27254773Simp } 27354773Simp 274121514Simp (void) alarm(60); 275121514Simp port = 0; 276121514Simp for (;;) { 277121514Simp char c; 278121514Simp if ((cc = read(STDIN_FILENO, &c, 1)) != 1) { 279121514Simp if (cc < 0) 28054773Simp syslog(LOG_NOTICE, "read: %m"); 281121514Simp shutdown(0, 1+1); 28254773Simp exit(1); 28354773Simp } 28454773Simp if (c== 0) 28554773Simp break; 28654773Simp port = port * 10 + c - '0'; 28754773Simp } 288121514Simp 289121514Simp (void) alarm(0); 29054773Simp if (port != 0) { 29154773Simp int lport = IPPORT_RESERVED - 1; 29254773Simp s = rresvport(&lport); 293121514Simp if (s < 0) { 29454773Simp syslog(LOG_ERR, "can't get stderr port: %m"); 295121514Simp exit(1); 29654773Simp } 29754773Simp#ifdef KERBEROS 29854773Simp if (!use_kerberos) 29954773Simp#endif 300121514Simp if (port >= IPPORT_RESERVED) { 301121514Simp syslog(LOG_ERR, "2nd port not reserved\n"); 302121514Simp exit(1); 30354773Simp } 30454773Simp fromp->sin_port = htons(port); 30554773Simp if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) { 30654773Simp syslog(LOG_INFO, "connect second port %d: %m", port); 30754773Simp exit(1); 308121514Simp } 30954773Simp } 31054773Simp 31154773Simp#ifdef KERBEROS 31254773Simp if (vacuous) { 31354773Simp error("rshd: remote host requires Kerberos authentication\n"); 31454773Simp exit(1); 31554773Simp } 31654773Simp#endif 31754773Simp 31854773Simp#ifdef notdef 31954773Simp /* from inetd, socket is already on 0, 1, 2 */ 32054773Simp dup2(f, 0); 32154773Simp dup2(f, 1); 32254773Simp dup2(f, 2); 32354773Simp#endif 324121514Simp errorstr = NULL; 32554773Simp hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr), 32654773Simp fromp->sin_family); 32754773Simp if (hp) { 32854773Simp /* 32954773Simp * If name returned by gethostbyaddr is in our domain, 330121514Simp * attempt to verify that we haven't been fooled by someone 33154773Simp * in a remote net; look up the name and check that this 33254773Simp * address corresponds to the name. 33354773Simp */ 33454773Simp hostname = hp->h_name; 33554773Simp#ifdef KERBEROS 33654773Simp if (!use_kerberos) 337121514Simp#endif 33854773Simp if (check_all || local_domain(hp->h_name)) { 33954773Simp strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 34054773Simp remotehost[sizeof(remotehost) - 1] = 0; 34154773Simp errorhost = remotehost; 34254773Simp hp = gethostbyname(remotehost); 34354773Simp if (hp == NULL) { 34454773Simp syslog(LOG_INFO, 345148887Srwatson "Couldn't look up address for %s", 346148887Srwatson remotehost); 347199559Sjhb errorstr = 34854773Simp "Couldn't look up address for your host (%s)\n"; 34954773Simp hostname = inet_ntoa(fromp->sin_addr); 35054773Simp } else for (; ; hp->h_addr_list++) { 35154773Simp if (hp->h_addr_list[0] == NULL) { 352121589Simp syslog(LOG_NOTICE, 353121589Simp "Host addr %s not listed for host %s", 35454773Simp inet_ntoa(fromp->sin_addr), 355121589Simp hp->h_name); 356121589Simp errorstr = 357121589Simp "Host address mismatch for %s\n"; 358121589Simp hostname = inet_ntoa(fromp->sin_addr); 359121589Simp break; 360121589Simp } 361121589Simp if (!bcmp(hp->h_addr_list[0], 36254773Simp (caddr_t)&fromp->sin_addr, 36354773Simp sizeof(fromp->sin_addr))) { 36454773Simp hostname = hp->h_name; 365121589Simp break; 366121589Simp } 36754773Simp } 368121553Simp } 369121589Simp } else 370121589Simp errorhost = hostname = inet_ntoa(fromp->sin_addr); 371121589Simp 372121589Simp#ifdef KERBEROS 37354773Simp if (use_kerberos) { 374121589Simp kdata = (AUTH_DAT *) authbuf; 375121589Simp ticket = (KTEXT) tickbuf; 376121589Simp authopts = 0L; 37754773Simp strcpy(instance, "*"); 37866058Simp version[VERSION_SIZE - 1] = '\0'; 37954773Simp#ifdef CRYPT 380121589Simp if (doencrypt) { 38154773Simp struct sockaddr_in local_addr; 382154100Simp rc = sizeof(local_addr); 38354773Simp if (getsockname(0, (struct sockaddr *)&local_addr, 38454773Simp &rc) < 0) { 385104257Sbrooks syslog(LOG_ERR, "getsockname: %m"); 38654773Simp error("rlogind: getsockname: %m"); 38754773Simp exit(1); 38854773Simp } 38954773Simp authopts = KOPT_DO_MUTUAL; 39054773Simp rc = krb_recvauth(authopts, 0, ticket, 39154773Simp "rcmd", instance, &fromaddr, 39254773Simp &local_addr, kdata, "", schedule, 393154100Simp version); 394121589Simp des_set_key(kdata->session, schedule); 39554773Simp } else 39654773Simp#endif 39754773Simp rc = krb_recvauth(authopts, 0, ticket, "rcmd", 39854773Simp instance, &fromaddr, 39954773Simp (struct sockaddr_in *) 0, 40054773Simp kdata, "", (bit_64 *) 0, version); 40154773Simp if (rc != KSUCCESS) { 40254773Simp error("Kerberos authentication failure: %s\n", 40354773Simp krb_err_txt[rc]); 40454773Simp exit(1); 40554773Simp } 40654773Simp } else 40754773Simp#endif 40854773Simp getstr(remuser, sizeof(remuser), "remuser"); 40954773Simp 410104257Sbrooks getstr(locuser, sizeof(locuser), "locuser"); 411154100Simp getstr(cmdbuf, sizeof(cmdbuf), "command"); 412155283Simp setpwent(); 41354773Simp pwd = getpwnam(locuser); 41454773Simp if (pwd == NULL) { 41554773Simp syslog(LOG_INFO|LOG_AUTH, 41654773Simp "%s@%s as %s: unknown login. cmd='%.80s'", 41754773Simp remuser, hostname, locuser, cmdbuf); 41854773Simp if (errorstr == NULL) 41954773Simp errorstr = "Login incorrect.\n"; 42054773Simp goto fail; 42154773Simp } 42254773Simp if (chdir(pwd->pw_dir) < 0) { 42354773Simp (void) chdir("/"); 42454773Simp#ifdef notdef 42554773Simp syslog(LOG_INFO|LOG_AUTH, 42654773Simp "%s@%s as %s: no home directory. cmd='%.80s'", 42754773Simp remuser, hostname, locuser, cmdbuf); 42854773Simp error("No remote directory.\n"); 42954773Simp exit(1); 43054773Simp#endif 43154773Simp } 43254773Simp 43354773Simp#ifdef KERBEROS 43454773Simp if (use_kerberos) { 43554773Simp if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') { 43654773Simp if (kuserok(kdata, locuser) != 0) { 43754773Simp syslog(LOG_INFO|LOG_AUTH, 43854773Simp "Kerberos rsh denied to %s.%s@%s", 43954773Simp kdata->pname, kdata->pinst, kdata->prealm); 440121514Simp error("Permission denied.\n"); 441121514Simp exit(1); 44254773Simp } 44354773Simp } 44454773Simp } else 44554773Simp#endif 446250460Seadler 44754773Simp if (errorstr || 44854773Simp pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && 44954773Simp iruserok(fromp->sin_addr.s_addr, pwd->pw_uid == 0, 45054773Simp remuser, locuser) < 0) { 451121514Simp if (__rcmd_errstr) 45254773Simp syslog(LOG_INFO|LOG_AUTH, 45354773Simp "%s@%s as %s: permission denied (%s). cmd='%.80s'", 45454773Simp remuser, hostname, locuser, __rcmd_errstr, 45566058Simp cmdbuf); 45654773Simp else 45754773Simp syslog(LOG_INFO|LOG_AUTH, 45854773Simp "%s@%s as %s: permission denied. cmd='%.80s'", 45954773Simp remuser, hostname, locuser, cmdbuf); 46054773Simpfail: 46154773Simp if (errorstr == NULL) 46254773Simp errorstr = "Permission denied.\n"; 46354773Simp error(errorstr, errorhost); 46454773Simp exit(1); 465121514Simp } 466121514Simp 46754773Simp if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { 46854773Simp error("Logins currently disabled.\n"); 469199559Sjhb exit(1); 470154100Simp } 47154773Simp 47254773Simp (void) write(STDERR_FILENO, "\0", 1); 47354773Simp sent_null = 1; 47454773Simp 47554773Simp if (port) { 47654773Simp if (pipe(pv) < 0) { 477121514Simp error("Can't make pipe.\n"); 47854773Simp exit(1); 47966058Simp } 480104257Sbrooks#ifdef CRYPT 48154773Simp#ifdef KERBEROS 48254773Simp if (doencrypt) { 48354773Simp if (pipe(pv1) < 0) { 48454773Simp error("Can't make 2nd pipe.\n"); 48554773Simp exit(1); 486121514Simp } 48754773Simp if (pipe(pv2) < 0) { 48854773Simp error("Can't make 3rd pipe.\n"); 48954773Simp exit(1); 49054773Simp } 491121514Simp } 49254773Simp#endif 49354773Simp#endif 49454773Simp pid = fork(); 49554773Simp if (pid == -1) { 49654773Simp error("Can't fork; try again.\n"); 497121514Simp exit(1); 498121514Simp } 499121514Simp if (pid) { 50054773Simp#ifdef CRYPT 50154773Simp#ifdef KERBEROS 50254773Simp if (doencrypt) { 50354773Simp static char msg[] = SECURE_MESSAGE; 50454773Simp (void) close(pv1[1]); 505155283Simp (void) close(pv2[1]); 50654773Simp des_write(s, msg, sizeof(msg) - 1); 50754773Simp 50854773Simp } else 50954773Simp#endif 51054773Simp#endif 51154773Simp { 51254773Simp (void) close(0); 51354773Simp (void) close(1); 51454773Simp } 515121514Simp (void) close(2); 516121514Simp (void) close(pv[1]); 51754773Simp 51854773Simp FD_ZERO(&readfrom); 51954773Simp FD_SET(s, &readfrom); 52054773Simp FD_SET(pv[0], &readfrom); 52154773Simp if (pv[0] > s) 522121514Simp nfd = pv[0]; 523121514Simp else 52454773Simp nfd = s; 52554773Simp#ifdef CRYPT 52654773Simp#ifdef KERBEROS 52754773Simp if (doencrypt) { 52854773Simp FD_ZERO(&writeto); 52954773Simp FD_SET(pv2[0], &writeto); 530121514Simp FD_SET(pv1[0], &readfrom); 53154773Simp 53254773Simp nfd = MAX(nfd, pv2[0]); 53354773Simp nfd = MAX(nfd, pv1[0]); 534121514Simp } else 53554773Simp#endif 53654773Simp#endif 53754773Simp ioctl(pv[0], FIONBIO, (char *)&one); 53854773Simp 53954773Simp /* should set s nbio! */ 54054773Simp nfd++; 541121514Simp do { 54254773Simp ready = readfrom; 54354773Simp#ifdef CRYPT 54454773Simp#ifdef KERBEROS 54554773Simp if (doencrypt) { 54654773Simp wready = writeto; 547121514Simp if (select(nfd, &ready, 548121514Simp &wready, (fd_set *) 0, 54954773Simp (struct timeval *) 0) < 0) 55054773Simp break; 551121514Simp } else 55254773Simp#endif 553154100Simp#endif 554199559Sjhb if (select(nfd, &ready, (fd_set *)0, 55554773Simp (fd_set *)0, (struct timeval *)0) < 0) 556106937Ssam break; 55754773Simp if (FD_ISSET(s, &ready)) { 558154100Simp int ret; 55954773Simp#ifdef CRYPT 56054773Simp#ifdef KERBEROS 56154773Simp if (doencrypt) 56254773Simp ret = des_read(s, &sig, 1); 56354773Simp else 56454773Simp#endif 56554773Simp#endif 56654773Simp ret = read(s, &sig, 1); 56754773Simp if (ret <= 0) 56854773Simp FD_CLR(s, &readfrom); 569121514Simp else 57054773Simp killpg(pid, sig); 57154773Simp } 57254773Simp if (FD_ISSET(pv[0], &ready)) { 57354773Simp errno = 0; 57454773Simp cc = read(pv[0], buf, sizeof(buf)); 57554773Simp if (cc <= 0) { 57654773Simp shutdown(s, 1+1); 57754773Simp FD_CLR(pv[0], &readfrom); 57854773Simp } else { 57954773Simp#ifdef CRYPT 58054773Simp#ifdef KERBEROS 58154773Simp if (doencrypt) 58254773Simp (void) 58354773Simp des_write(s, buf, cc); 58454773Simp else 58554773Simp#endif 58654773Simp#endif 587121553Simp (void) 588121589Simp write(s, buf, cc); 589121589Simp } 59054773Simp } 59154773Simp#ifdef CRYPT 59254773Simp#ifdef KERBEROS 593121589Simp if (doencrypt && FD_ISSET(pv1[0], &ready)) { 594121589Simp errno = 0; 595121589Simp cc = read(pv1[0], buf, sizeof(buf)); 596121589Simp if (cc <= 0) { 59754773Simp shutdown(pv1[0], 1+1); 59854773Simp FD_CLR(pv1[0], &readfrom); 59954773Simp } else 60054773Simp (void) des_write(STDOUT_FILENO, 60154773Simp buf, cc); 60254773Simp } 60354773Simp 60454773Simp if (doencrypt && FD_ISSET(pv2[0], &wready)) { 60554773Simp errno = 0; 60654773Simp cc = des_read(STDIN_FILENO, 607154100Simp buf, sizeof(buf)); 60854773Simp if (cc <= 0) { 609104257Sbrooks shutdown(pv2[0], 1+1); 61054773Simp FD_CLR(pv2[0], &writeto); 61154773Simp } else 61254773Simp (void) write(pv2[0], buf, cc); 61354773Simp } 61454773Simp#endif 61554773Simp#endif 61654773Simp 61754773Simp } while (FD_ISSET(s, &readfrom) || 61854773Simp#ifdef CRYPT 61954773Simp#ifdef KERBEROS 62054773Simp (doencrypt && FD_ISSET(pv1[0], &readfrom)) || 62154773Simp#endif 62254773Simp#endif 62354773Simp FD_ISSET(pv[0], &readfrom)); 62454773Simp exit(0); 62554773Simp } 626104257Sbrooks setpgrp(0, getpid()); 627154100Simp (void) close(s); 628155283Simp (void) close(pv[0]); 62954773Simp#ifdef CRYPT 63054773Simp#ifdef KERBEROS 63154773Simp if (doencrypt) { 63254773Simp close(pv1[0]); close(pv2[0]); 63354773Simp dup2(pv1[1], 1); 63454773Simp dup2(pv2[1], 0); 63554773Simp close(pv1[1]); 63654773Simp close(pv2[1]); 63754773Simp } 63854773Simp#endif 63954773Simp#endif 64054773Simp dup2(pv[1], 2); 64154773Simp close(pv[1]); 64254773Simp } 64354773Simp if (*pwd->pw_shell == '\0') 64454773Simp pwd->pw_shell = _PATH_BSHELL; 64554773Simp#if BSD > 43 64654773Simp if (setlogin(pwd->pw_name) < 0) 64754773Simp syslog(LOG_ERR, "setlogin() failed: %m"); 64854773Simp#endif 64954773Simp (void) setgid((gid_t)pwd->pw_gid); 65054773Simp initgroups(pwd->pw_name, pwd->pw_gid); 65154773Simp (void) setuid((uid_t)pwd->pw_uid); 65254773Simp environ = envinit; 65354773Simp strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 654121514Simp strcat(path, _PATH_DEFPATH); 65554773Simp strncat(shell, pwd->pw_shell, sizeof(shell)-7); 65654773Simp strncat(username, pwd->pw_name, sizeof(username)-6); 65754773Simp cp = strrchr(pwd->pw_shell, '/'); 65854773Simp if (cp) 65954773Simp cp++; 660121514Simp else 66154773Simp cp = pwd->pw_shell; 662104257Sbrooks endpwent(); 663199559Sjhb if (log_success || pwd->pw_uid == 0) { 66454773Simp#ifdef KERBEROS 66554773Simp if (use_kerberos) 66654773Simp syslog(LOG_INFO|LOG_AUTH, 66754773Simp "Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'", 66854773Simp kdata->pname, kdata->pinst, kdata->prealm, 669121514Simp hostname, locuser, cmdbuf); 67054773Simp else 67154773Simp#endif 67254773Simp syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'", 67354773Simp remuser, hostname, locuser, cmdbuf); 67454773Simp } 67554773Simp execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); 676104257Sbrooks perror(pwd->pw_shell); 67754773Simp exit(1); 67854773Simp} 67954773Simp 68054773Simp/* 681121514Simp * Report error to client. Note: can't be used until second socket has 68254773Simp * connected to client, or older clients will hang waiting for that 683121514Simp * connection first. 68454773Simp */ 68554773Simp#if __STDC__ 68654773Simp#include <stdarg.h> 68754773Simp#else 68854773Simp#include <varargs.h> 68954773Simp#endif 690121514Simp 69154773Simpvoid 69254773Simp#if __STDC__ 69354773Simperror(const char *fmt, ...) 69454773Simp#else 69554773Simperror(fmt, va_alist) 696121514Simp char *fmt; 697121514Simp va_dcl 698121514Simp#endif 69954773Simp{ 70054773Simp va_list ap; 70154773Simp int len; 70254773Simp char *bp, buf[BUFSIZ]; 70354773Simp#if __STDC__ 704155283Simp va_start(ap, fmt); 70554773Simp#else 70654773Simp va_start(ap); 70754773Simp#endif 70854773Simp bp = buf; 70954773Simp if (sent_null == 0) { 71054773Simp *bp++ = 1; 71154773Simp len = 1; 71254773Simp } else 71354773Simp len = 0; 714121514Simp (void)vsnprintf(bp, sizeof(buf) - 1, fmt, ap); 715121514Simp (void)write(STDERR_FILENO, buf, len + strlen(bp)); 71654773Simp} 71754773Simp 71854773Simpvoid 71954773Simpgetstr(buf, cnt, err) 720121514Simp char *buf, *err; 721121514Simp int cnt; 72254773Simp{ 72354773Simp char c; 72454773Simp 72554773Simp do { 72654773Simp if (read(STDIN_FILENO, &c, 1) != 1) 72754773Simp exit(1); 728121514Simp *buf++ = c; 72954773Simp if (--cnt == 0) { 73054773Simp error("%s too long\n", err); 73154773Simp exit(1); 732121514Simp } 73354773Simp } while (c != 0); 73454773Simp} 73554773Simp 73654773Simp/* 73754773Simp * Check whether host h is in our local domain, 73854773Simp * defined as sharing the last two components of the domain part, 739121514Simp * or the entire domain part if the local domain has only one component. 74054773Simp * If either name is unqualified (contains no '.'), 74154773Simp * assume that the host is local, as it will be 74254773Simp * interpreted as such. 74354773Simp */ 74454773Simpint 745121514Simplocal_domain(h) 746121514Simp char *h; 74754773Simp{ 748121514Simp char localhost[MAXHOSTNAMELEN]; 74954773Simp char *p1, *p2; 750106937Ssam 75154773Simp localhost[0] = 0; 752154100Simp (void) gethostname(localhost, sizeof(localhost)); 75354773Simp p1 = topdomain(localhost); 75454773Simp p2 = topdomain(h); 75554773Simp if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 75654773Simp return (1); 75754773Simp return (0); 75854773Simp} 75954773Simp 760154100Simpchar * 761199559Sjhbtopdomain(h) 76254773Simp char *h; 76354773Simp{ 76454773Simp char *p, *maybe = NULL; 76554773Simp int dots = 0; 76654773Simp 767154100Simp for (p = h + strlen(h); p >= h; p--) { 768199559Sjhb if (*p == '.') { 76954773Simp if (++dots == 2) 77054773Simp return (p); 77154773Simp maybe = p; 77254773Simp } 77354773Simp } 77454994Simp return (maybe); 77554773Simp} 776199559Sjhb 777199559Sjhbvoid 778199559Sjhbusage() 779199559Sjhb{ 780199559Sjhb 781199559Sjhb syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS); 782199559Sjhb exit(2); 783199559Sjhb} 784199559Sjhb