File:  [DragonFly] / src / libexec / rshd / rshd.c
Revision 1.3: download - view: text, annotated - select for diffs
Fri Nov 14 03:54:31 2003 UTC (11 years ago) by dillon
Branches: MAIN
CVS tags: HEAD, DragonFly_Stable, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_RELEASE_1_8_Slip, DragonFly_RELEASE_1_8, DragonFly_RELEASE_1_6_Slip, DragonFly_RELEASE_1_6, DragonFly_RELEASE_1_4_Slip, DragonFly_RELEASE_1_4, DragonFly_RELEASE_1_2_Slip, DragonFly_RELEASE_1_2, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
__P removal.

Submitted-by: Craig Dooley <craig@xlnx-x.net>

    1: /*-
    2:  * Copyright (c) 1988, 1989, 1992, 1993, 1994
    3:  *	The Regents of the University of California.  All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  * 3. All advertising materials mentioning features or use of this software
   14:  *    must display the following acknowledgement:
   15:  *	This product includes software developed by the University of
   16:  *	California, Berkeley and its contributors.
   17:  * 4. Neither the name of the University nor the names of its contributors
   18:  *    may be used to endorse or promote products derived from this software
   19:  *    without specific prior written permission.
   20:  *
   21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31:  * SUCH DAMAGE.
   32:  *
   33:  * @(#) Copyright (c) 1988, 1989, 1992, 1993, 1994 The Regents of the University of California.  All rights reserved.
   34:  * @(#)rshd.c	8.2 (Berkeley) 4/6/94
   35:  * $FreeBSD: src/libexec/rshd/rshd.c,v 1.30.2.5 2002/05/14 22:27:21 des Exp $
   36:  * $DragonFly: src/libexec/rshd/rshd.c,v 1.3 2003/11/14 03:54:31 dillon Exp $
   37:  */
   38: 
   39: /*
   40:  * remote shell server:
   41:  *	[port]\0
   42:  *	remuser\0
   43:  *	locuser\0
   44:  *	command\0
   45:  *	data
   46:  */
   47: #include <sys/param.h>
   48: #include <sys/ioctl.h>
   49: #include <sys/time.h>
   50: #include <sys/socket.h>
   51: 
   52: #include <netinet/in_systm.h>
   53: #include <netinet/in.h>
   54: #include <netinet/ip.h>
   55: #include <netinet/tcp.h>
   56: #include <arpa/inet.h>
   57: #include <netdb.h>
   58: 
   59: #include <errno.h>
   60: #include <fcntl.h>
   61: #include <libutil.h>
   62: #include <paths.h>
   63: #include <pwd.h>
   64: #include <signal.h>
   65: #include <stdio.h>
   66: #include <stdlib.h>
   67: #include <string.h>
   68: #include <syslog.h>
   69: #include <unistd.h>
   70: #ifdef	LOGIN_CAP
   71: #include <login_cap.h>
   72: #endif
   73: 
   74: /* wrapper for KAME-special getnameinfo() */
   75: #ifndef NI_WITHSCOPEID
   76: #define	NI_WITHSCOPEID	0
   77: #endif
   78: 
   79: int	keepalive = 1;
   80: int	log_success;		/* If TRUE, log all successful accesses */
   81: int	sent_null;
   82: int	no_delay;
   83: #ifdef CRYPT
   84: int	doencrypt = 0;
   85: #endif
   86: 
   87: union sockunion {
   88: 	struct sockinet {
   89: 		u_char si_len;
   90: 		u_char si_family;
   91: 		u_short si_port;
   92: 	} su_si;
   93: 	struct sockaddr_in  su_sin;
   94: 	struct sockaddr_in6 su_sin6;
   95: };
   96: #define su_len		su_si.si_len
   97: #define su_family	su_si.si_family
   98: #define su_port		su_si.si_port
   99: 
  100: void	 doit (union sockunion *);
  101: void	 error (const char *, ...);
  102: void	 getstr (char *, int, char *);
  103: int	 local_domain (char *);
  104: char	*topdomain (char *);
  105: void	 usage (void);
  106: 
  107: #define	OPTIONS	"alnDL"
  108: 
  109: int
  110: main(argc, argv)
  111: 	int argc;
  112: 	char *argv[];
  113: {
  114: 	extern int __check_rhosts_file;
  115: 	struct linger linger;
  116: 	int ch, on = 1, fromlen;
  117: 	struct sockaddr_storage from;
  118: 
  119: 	openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
  120: 
  121: 	opterr = 0;
  122: 	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
  123: 		switch (ch) {
  124: 		case 'a':
  125: 			/* ignored for compatibility */
  126: 			break;
  127: 		case 'l':
  128: 			__check_rhosts_file = 0;
  129: 			break;
  130: 		case 'n':
  131: 			keepalive = 0;
  132: 			break;
  133: #ifdef CRYPT
  134: 		case 'x':
  135: 			doencrypt = 1;
  136: 			break;
  137: #endif
  138: 		case 'D':
  139: 			no_delay = 1;
  140: 			break;
  141: 		case 'L':
  142: 			log_success = 1;
  143: 			break;
  144: 		case '?':
  145: 		default:
  146: 			usage();
  147: 			break;
  148: 		}
  149: 
  150: 	argc -= optind;
  151: 	argv += optind;
  152: 
  153: #ifdef CRYPT
  154: 	if (doencrypt) {
  155: 		syslog(LOG_ERR, "-k is required for -x");
  156: 		exit(2);
  157: 	}
  158: #endif
  159: 
  160: 	fromlen = sizeof (from);
  161: 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
  162: 		syslog(LOG_ERR, "getpeername: %m");
  163: 		exit(1);
  164: 	}
  165: 	if (keepalive &&
  166: 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
  167: 	    sizeof(on)) < 0)
  168: 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  169: 	linger.l_onoff = 1;
  170: 	linger.l_linger = 60;			/* XXX */
  171: 	if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
  172: 	    sizeof (linger)) < 0)
  173: 		syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
  174: 	if (no_delay &&
  175: 	    setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
  176: 		syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
  177: 	doit((union sockunion *)&from);
  178: 	/* NOTREACHED */
  179: 	return(0);
  180: }
  181: 
  182: char	username[20] = "USER=";
  183: char	homedir[64] = "HOME=";
  184: char	shell[64] = "SHELL=";
  185: char	path[100] = "PATH=";
  186: char	*envinit[] =
  187: 	    {homedir, shell, path, username, 0};
  188: char	**environ;
  189: 
  190: void
  191: doit(fromp)
  192: 	union sockunion *fromp;
  193: {
  194: 	extern char *__rcmd_errstr;	/* syslog hook from libc/net/rcmd.c. */
  195: 	struct passwd *pwd;
  196: 	u_short port;
  197: 	fd_set ready, readfrom;
  198: 	int cc, nfd, pv[2], pid, s;
  199: 	int one = 1;
  200: 	char *errorstr;
  201: 	char *cp, sig, buf[BUFSIZ];
  202: 	char cmdbuf[NCARGS+1], locuser[16], remuser[16];
  203: 	char fromhost[2 * MAXHOSTNAMELEN + 1];
  204: 	char numericname[INET6_ADDRSTRLEN];
  205: 	int af = fromp->su_family, err;
  206: #ifdef	CRYPT
  207: 	int rc;
  208: 	int pv1[2], pv2[2];
  209: #endif
  210: #ifdef	LOGIN_CAP
  211: 	login_cap_t *lc;
  212: #endif
  213: 
  214: 	(void) signal(SIGINT, SIG_DFL);
  215: 	(void) signal(SIGQUIT, SIG_DFL);
  216: 	(void) signal(SIGTERM, SIG_DFL);
  217: 	fromp->su_port = ntohs((u_short)fromp->su_port);
  218: 	if (af != AF_INET
  219: #ifdef INET6
  220: 	    && af != AF_INET6
  221: #endif
  222: 	    ) {
  223: 		syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", af);
  224: 		exit(1);
  225: 	}
  226: 	err = getnameinfo((struct sockaddr *)fromp, fromp->su_len, numericname,
  227: 			  sizeof(numericname), NULL, 0,
  228: 			  NI_NUMERICHOST|NI_WITHSCOPEID);
  229: 	/* XXX: do 'err' check */
  230: #ifdef IP_OPTIONS
  231:       if (af == AF_INET) {
  232: 	u_char optbuf[BUFSIZ/3];
  233: 	int optsize = sizeof(optbuf), ipproto, i;
  234: 	struct protoent *ip;
  235: 
  236: 	if ((ip = getprotobyname("ip")) != NULL)
  237: 		ipproto = ip->p_proto;
  238: 	else
  239: 		ipproto = IPPROTO_IP;
  240: 	if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) &&
  241: 	    optsize != 0) {
  242: 		for (i = 0; i < optsize; ) {
  243: 			u_char c = optbuf[i];
  244: 			if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
  245: 				syslog(LOG_NOTICE,
  246: 					"connection refused from %s with IP option %s",
  247: 					numericname,
  248: 					c == IPOPT_LSRR ? "LSRR" : "SSRR");
  249: 				exit(1);
  250: 			}
  251: 			if (c == IPOPT_EOL)
  252: 				break;
  253: 			i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
  254: 		}
  255: 	}
  256:       }
  257: #endif
  258: 
  259: 	if (fromp->su_port >= IPPORT_RESERVED ||
  260: 	    fromp->su_port < IPPORT_RESERVED/2) {
  261: 		syslog(LOG_NOTICE|LOG_AUTH,
  262: 		    "connection from %s on illegal port %u",
  263: 		    numericname,
  264: 		    fromp->su_port);
  265: 		exit(1);
  266: 	}
  267: 
  268: 	(void) alarm(60);
  269: 	port = 0;
  270: 	s = 0;		/* not set or used if port == 0 */
  271: 	for (;;) {
  272: 		char c;
  273: 		if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
  274: 			if (cc < 0)
  275: 				syslog(LOG_NOTICE, "read: %m");
  276: 			shutdown(0, 1+1);
  277: 			exit(1);
  278: 		}
  279: 		if (c == 0)
  280: 			break;
  281: 		port = port * 10 + c - '0';
  282: 	}
  283: 
  284: 	(void) alarm(0);
  285: 	if (port != 0) {
  286: 		int lport = IPPORT_RESERVED - 1;
  287: 		s = rresvport_af(&lport, af);
  288: 		if (s < 0) {
  289: 			syslog(LOG_ERR, "can't get stderr port: %m");
  290: 			exit(1);
  291: 		}
  292: 		if (port >= IPPORT_RESERVED ||
  293: 		    port < IPPORT_RESERVED/2) {
  294: 			syslog(LOG_NOTICE|LOG_AUTH,
  295: 			    "2nd socket from %s on unreserved port %u",
  296: 			    numericname,
  297: 			    port);
  298: 			exit(1);
  299: 		}
  300: 		fromp->su_port = htons(port);
  301: 		if (connect(s, (struct sockaddr *)fromp, fromp->su_len) < 0) {
  302: 			syslog(LOG_INFO, "connect second port %d: %m", port);
  303: 			exit(1);
  304: 		}
  305: 	}
  306: 
  307: 	errorstr = NULL;
  308: 	realhostname_sa(fromhost, sizeof(fromhost) - 1,
  309: 			(struct sockaddr *)fromp,
  310: 			fromp->su_len);
  311: 	fromhost[sizeof(fromhost) - 1] = '\0';
  312: 
  313: #ifdef CRYPT
  314: 	if (doencrypt && af == AF_INET) {
  315: 		struct sockaddr_in local_addr;
  316: 		rc = sizeof(local_addr);
  317: 		if (getsockname(0, (struct sockaddr *)&local_addr,
  318: 		    &rc) < 0) {
  319: 			syslog(LOG_ERR, "getsockname: %m");
  320: 			error("rlogind: getsockname: %m");
  321: 			exit(1);
  322: 		}
  323: 		authopts = KOPT_DO_MUTUAL;
  324: 		rc = krb_recvauth(authopts, 0, ticket,
  325: 			"rcmd", instance, &fromaddr,
  326: 			&local_addr, kdata, "", schedule,
  327: 			version);
  328: 		des_set_key(&kdata->session, schedule);
  329: 	}
  330: #endif
  331: 	(void) alarm(60);
  332: 	getstr(remuser, sizeof(remuser), "remuser");
  333: 	getstr(locuser, sizeof(locuser), "locuser");
  334: 	getstr(cmdbuf, sizeof(cmdbuf), "command");
  335: 	(void) alarm(0);
  336: 	setpwent();
  337: 	pwd = getpwnam(locuser);
  338: 	if (pwd == NULL) {
  339: 		syslog(LOG_INFO|LOG_AUTH,
  340: 		    "%s@%s as %s: unknown login. cmd='%.80s'",
  341: 		    remuser, fromhost, locuser, cmdbuf);
  342: 		if (errorstr == NULL)
  343: 			errorstr = "Login incorrect.\n";
  344: 		goto fail;
  345: 	}
  346: #ifdef	LOGIN_CAP
  347: 	lc = login_getpwclass(pwd);
  348: #endif
  349: 	if (chdir(pwd->pw_dir) < 0) {
  350: #ifdef	LOGIN_CAP
  351: 		if (chdir("/") < 0 ||
  352: 		    login_getcapbool(lc, "requirehome", !!pwd->pw_uid)) {
  353: 			syslog(LOG_INFO|LOG_AUTH,
  354: 			"%s@%s as %s: no home directory. cmd='%.80s'",
  355: 			remuser, fromhost, locuser, cmdbuf);
  356: 			error("No remote home directory.\n");
  357: 			exit(0);
  358: 		}
  359: #else
  360: 		(void) chdir("/");
  361: #ifdef notdef
  362: 		syslog(LOG_INFO|LOG_AUTH,
  363: 		    "%s@%s as %s: no home directory. cmd='%.80s'",
  364: 		    remuser, fromhost, locuser, cmdbuf);
  365: 		error("No remote directory.\n");
  366: 		exit(1);
  367: #endif
  368: #endif
  369: 		pwd->pw_dir = "/";
  370: 	}
  371: 
  372: 		if (errorstr ||
  373: 		    (pwd->pw_expire && time(NULL) >= pwd->pw_expire) ||
  374: 		    iruserok_sa(fromp, fromp->su_len, pwd->pw_uid == 0,
  375: 				 remuser, locuser) < 0) {
  376: 			if (__rcmd_errstr)
  377: 				syslog(LOG_INFO|LOG_AUTH,
  378: 			    "%s@%s as %s: permission denied (%s). cmd='%.80s'",
  379: 				    remuser, fromhost, locuser, __rcmd_errstr,
  380: 				    cmdbuf);
  381: 			else
  382: 				syslog(LOG_INFO|LOG_AUTH,
  383: 			    "%s@%s as %s: permission denied. cmd='%.80s'",
  384: 				    remuser, fromhost, locuser, cmdbuf);
  385: fail:
  386: 			if (errorstr == NULL)
  387: 				errorstr = "Login incorrect.\n";
  388: 			error(errorstr, fromhost);
  389: 			exit(1);
  390: 		}
  391: 
  392: 	if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) {
  393: 		error("Logins currently disabled.\n");
  394: 		exit(1);
  395: 	}
  396: #ifdef	LOGIN_CAP
  397: 	if (lc != NULL && fromp->su_family == AF_INET) {	/*XXX*/
  398: 		char	remote_ip[MAXHOSTNAMELEN];
  399: 
  400: 		strncpy(remote_ip, numericname,
  401: 			sizeof(remote_ip) - 1);
  402: 		remote_ip[sizeof(remote_ip) - 1] = 0;
  403: 		if (!auth_hostok(lc, fromhost, remote_ip)) {
  404: 			syslog(LOG_INFO|LOG_AUTH,
  405: 			    "%s@%s as %s: permission denied (%s). cmd='%.80s'",
  406: 			    remuser, fromhost, locuser, __rcmd_errstr,
  407: 			    cmdbuf);
  408: 			error("Login incorrect.\n");
  409: 			exit(1);
  410: 		}
  411: 		if (!auth_timeok(lc, time(NULL))) {
  412: 			error("Logins not available right now\n");
  413: 			exit(1);
  414: 		}
  415: 	}
  416: #endif	/* !LOGIN_CAP */
  417: #if	BSD > 43
  418: 	/* before fork, while we're session leader */
  419: 	if (setlogin(pwd->pw_name) < 0)
  420: 		syslog(LOG_ERR, "setlogin() failed: %m");
  421: #endif
  422: 
  423: 	(void) write(STDERR_FILENO, "\0", 1);
  424: 	sent_null = 1;
  425: 
  426: 	if (port) {
  427: 		if (pipe(pv) < 0) {
  428: 			error("Can't make pipe.\n");
  429: 			exit(1);
  430: 		}
  431: #ifdef CRYPT
  432: 		if (doencrypt) {
  433: 			if (pipe(pv1) < 0) {
  434: 				error("Can't make 2nd pipe.\n");
  435: 				exit(1);
  436: 			}
  437: 			if (pipe(pv2) < 0) {
  438: 				error("Can't make 3rd pipe.\n");
  439: 				exit(1);
  440: 			}
  441: 		}
  442: #endif
  443: 		pid = fork();
  444: 		if (pid == -1)  {
  445: 			error("Can't fork; try again.\n");
  446: 			exit(1);
  447: 		}
  448: 		if (pid) {
  449: #ifdef CRYPT
  450: 			if (doencrypt) {
  451: 				static char msg[] = SECURE_MESSAGE;
  452: 				(void) close(pv1[1]);
  453: 				(void) close(pv2[1]);
  454: 				des_enc_write(s, msg, sizeof(msg) - 1, 
  455: 					schedule, &kdata->session);
  456: 
  457: 			} else
  458: #endif
  459: 			{
  460: 				(void) close(0);
  461: 				(void) close(1);
  462: 			}
  463: 			(void) close(2);
  464: 			(void) close(pv[1]);
  465: 
  466: 			FD_ZERO(&readfrom);
  467: 			FD_SET(s, &readfrom);
  468: 			FD_SET(pv[0], &readfrom);
  469: 			if (pv[0] > s)
  470: 				nfd = pv[0];
  471: 			else
  472: 				nfd = s;
  473: #ifdef CRYPT
  474: 			if (doencrypt) {
  475: 				FD_ZERO(&writeto);
  476: 				FD_SET(pv2[0], &writeto);
  477: 				FD_SET(pv1[0], &readfrom);
  478: 
  479: 				nfd = MAX(nfd, pv2[0]);
  480: 				nfd = MAX(nfd, pv1[0]);
  481: 			} else
  482: #endif
  483: 				ioctl(pv[0], FIONBIO, (char *)&one);
  484: 
  485: 			/* should set s nbio! */
  486: 			nfd++;
  487: 			do {
  488: 				ready = readfrom;
  489: #ifdef CRYPT
  490: 				if (doencrypt) {
  491: 					wready = writeto;
  492: 					if (select(nfd, &ready,
  493: 					    &wready, (fd_set *) 0,
  494: 					    (struct timeval *) 0) < 0)
  495: 						break;
  496: 				} else
  497: #endif
  498: 					if (select(nfd, &ready, (fd_set *)0,
  499: 					  (fd_set *)0, (struct timeval *)0) < 0)
  500: 						break;
  501: 				if (FD_ISSET(s, &ready)) {
  502: 					int	ret;
  503: #ifdef CRYPT
  504: 					if (doencrypt)
  505: 						ret = des_enc_read(s, &sig, 1,
  506: 						schedule, &kdata->session);
  507: 					else
  508: #endif
  509: 						ret = read(s, &sig, 1);
  510: 					if (ret <= 0)
  511: 						FD_CLR(s, &readfrom);
  512: 					else
  513: 						killpg(pid, sig);
  514: 				}
  515: 				if (FD_ISSET(pv[0], &ready)) {
  516: 					errno = 0;
  517: 					cc = read(pv[0], buf, sizeof(buf));
  518: 					if (cc <= 0) {
  519: 						shutdown(s, 1+1);
  520: 						FD_CLR(pv[0], &readfrom);
  521: 					} else {
  522: #ifdef CRYPT
  523: 						if (doencrypt)
  524: 							(void)
  525: 							  des_enc_write(s, buf, cc,
  526: 								schedule, &kdata->session);
  527: 						else
  528: #endif
  529: 							(void)
  530: 							  write(s, buf, cc);
  531: 					}
  532: 				}
  533: #ifdef CRYPT
  534: 				if (doencrypt && FD_ISSET(pv1[0], &ready)) {
  535: 					errno = 0;
  536: 					cc = read(pv1[0], buf, sizeof(buf));
  537: 					if (cc <= 0) {
  538: 						shutdown(pv1[0], 1+1);
  539: 						FD_CLR(pv1[0], &readfrom);
  540: 					} else
  541: 						(void) des_enc_write(STDOUT_FILENO,
  542: 						    buf, cc,
  543: 							schedule, &kdata->session);
  544: 				}
  545: 
  546: 				if (doencrypt && FD_ISSET(pv2[0], &wready)) {
  547: 					errno = 0;
  548: 					cc = des_enc_read(STDIN_FILENO,
  549: 					    buf, sizeof(buf),
  550: 						schedule, &kdata->session);
  551: 					if (cc <= 0) {
  552: 						shutdown(pv2[0], 1+1);
  553: 						FD_CLR(pv2[0], &writeto);
  554: 					} else
  555: 						(void) write(pv2[0], buf, cc);
  556: 				}
  557: #endif
  558: 
  559: 			} while (FD_ISSET(s, &readfrom) ||
  560: #ifdef CRYPT
  561: 			    (doencrypt && FD_ISSET(pv1[0], &readfrom)) ||
  562: #endif
  563: 			    FD_ISSET(pv[0], &readfrom));
  564: 			exit(0);
  565: 		}
  566: 		setpgrp(0, getpid());
  567: 		(void) close(s);
  568: 		(void) close(pv[0]);
  569: #ifdef CRYPT
  570: 		if (doencrypt) {
  571: 			close(pv1[0]); close(pv2[0]);
  572: 			dup2(pv1[1], 1);
  573: 			dup2(pv2[1], 0);
  574: 			close(pv1[1]);
  575: 			close(pv2[1]);
  576: 		}
  577: #endif
  578: 		dup2(pv[1], 2);
  579: 		close(pv[1]);
  580: 	}
  581: 	if (*pwd->pw_shell == '\0')
  582: 		pwd->pw_shell = _PATH_BSHELL;
  583: 	environ = envinit;
  584: 	strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
  585: 	strcat(path, _PATH_DEFPATH);
  586: 	strncat(shell, pwd->pw_shell, sizeof(shell)-7);
  587: 	strncat(username, pwd->pw_name, sizeof(username)-6);
  588: 	cp = strrchr(pwd->pw_shell, '/');
  589: 	if (cp)
  590: 		cp++;
  591: 	else
  592: 		cp = pwd->pw_shell;
  593: #ifdef	LOGIN_CAP
  594: 	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) {
  595:                 syslog(LOG_ERR, "setusercontext: %m");
  596: 		exit(1);
  597: 	}
  598: 	login_close(lc);
  599: #else
  600: 	(void) setgid((gid_t)pwd->pw_gid);
  601: 	initgroups(pwd->pw_name, pwd->pw_gid);
  602: 	(void) setuid((uid_t)pwd->pw_uid);
  603: #endif
  604: 	endpwent();
  605: 	if (log_success || pwd->pw_uid == 0) {
  606: 		    syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
  607: 			remuser, fromhost, locuser, cmdbuf);
  608: 	}
  609: 	execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
  610: 	perror(pwd->pw_shell);
  611: 	exit(1);
  612: }
  613: 
  614: /*
  615:  * Report error to client.  Note: can't be used until second socket has
  616:  * connected to client, or older clients will hang waiting for that
  617:  * connection first.
  618:  */
  619: #if __STDC__
  620: #include <stdarg.h>
  621: #else
  622: #include <varargs.h>
  623: #endif
  624: 
  625: void
  626: #if __STDC__
  627: error(const char *fmt, ...)
  628: #else
  629: error(fmt, va_alist)
  630: 	char *fmt;
  631:         va_dcl
  632: #endif
  633: {
  634: 	va_list ap;
  635: 	int len;
  636: 	char *bp, buf[BUFSIZ];
  637: #if __STDC__
  638: 	va_start(ap, fmt);
  639: #else
  640: 	va_start(ap);
  641: #endif
  642: 	bp = buf;
  643: 	if (sent_null == 0) {
  644: 		*bp++ = 1;
  645: 		len = 1;
  646: 	} else
  647: 		len = 0;
  648: 	(void)vsnprintf(bp, sizeof(buf) - 1, fmt, ap);
  649: 	(void)write(STDERR_FILENO, buf, len + strlen(bp));
  650: }
  651: 
  652: void
  653: getstr(buf, cnt, err)
  654: 	char *buf, *err;
  655: 	int cnt;
  656: {
  657: 	char c;
  658: 
  659: 	do {
  660: 		if (read(STDIN_FILENO, &c, 1) != 1)
  661: 			exit(1);
  662: 		*buf++ = c;
  663: 		if (--cnt == 0) {
  664: 			error("%s too long\n", err);
  665: 			exit(1);
  666: 		}
  667: 	} while (c != 0);
  668: }
  669: 
  670: /*
  671:  * Check whether host h is in our local domain,
  672:  * defined as sharing the last two components of the domain part,
  673:  * or the entire domain part if the local domain has only one component.
  674:  * If either name is unqualified (contains no '.'),
  675:  * assume that the host is local, as it will be
  676:  * interpreted as such.
  677:  */
  678: int
  679: local_domain(h)
  680: 	char *h;
  681: {
  682: 	char localhost[MAXHOSTNAMELEN];
  683: 	char *p1, *p2;
  684: 
  685: 	localhost[0] = 0;
  686: 	(void) gethostname(localhost, sizeof(localhost) - 1);
  687: 	localhost[sizeof(localhost) - 1] = '\0';
  688: 	p1 = topdomain(localhost);
  689: 	p2 = topdomain(h);
  690: 	if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
  691: 		return (1);
  692: 	return (0);
  693: }
  694: 
  695: char *
  696: topdomain(h)
  697: 	char *h;
  698: {
  699: 	char *p, *maybe = NULL;
  700: 	int dots = 0;
  701: 
  702: 	for (p = h + strlen(h); p >= h; p--) {
  703: 		if (*p == '.') {
  704: 			if (++dots == 2)
  705: 				return (p);
  706: 			maybe = p;
  707: 		}
  708: 	}
  709: 	return (maybe);
  710: }
  711: 
  712: void
  713: usage()
  714: {
  715: 
  716: 	syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS);
  717: 	exit(2);
  718: }