xref: /minix3/libexec/rshd/rshd.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
193d36fc9SDavid van Moolenbroek /*	$NetBSD: rshd.c,v 1.50 2012/07/14 15:06:26 darrenr Exp $	*/
293d36fc9SDavid van Moolenbroek 
393d36fc9SDavid van Moolenbroek /*
493d36fc9SDavid van Moolenbroek  * Copyright (C) 1998 WIDE Project.
593d36fc9SDavid van Moolenbroek  * All rights reserved.
693d36fc9SDavid van Moolenbroek  *
793d36fc9SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
893d36fc9SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
993d36fc9SDavid van Moolenbroek  * are met:
1093d36fc9SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
1193d36fc9SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
1293d36fc9SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
1393d36fc9SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
1493d36fc9SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
1593d36fc9SDavid van Moolenbroek  * 3. All advertising materials mentioning features or use of this software
1693d36fc9SDavid van Moolenbroek  *    must display the following acknowledgement:
1793d36fc9SDavid van Moolenbroek  *    This product includes software developed by WIDE Project and
1893d36fc9SDavid van Moolenbroek  *    its contributors.
1993d36fc9SDavid van Moolenbroek  * 4. Neither the name of the project nor the names of its contributors
2093d36fc9SDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
2193d36fc9SDavid van Moolenbroek  *    without specific prior written permission.
2293d36fc9SDavid van Moolenbroek  *
2393d36fc9SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2493d36fc9SDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2593d36fc9SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2693d36fc9SDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2793d36fc9SDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2893d36fc9SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2993d36fc9SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3093d36fc9SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3193d36fc9SDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3293d36fc9SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3393d36fc9SDavid van Moolenbroek  * SUCH DAMAGE.
3493d36fc9SDavid van Moolenbroek  */
3593d36fc9SDavid van Moolenbroek 
3693d36fc9SDavid van Moolenbroek /*-
3793d36fc9SDavid van Moolenbroek  * Copyright (c) 1988, 1989, 1992, 1993, 1994
3893d36fc9SDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
3993d36fc9SDavid van Moolenbroek  *
4093d36fc9SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
4193d36fc9SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
4293d36fc9SDavid van Moolenbroek  * are met:
4393d36fc9SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
4493d36fc9SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
4593d36fc9SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
4693d36fc9SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
4793d36fc9SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
4893d36fc9SDavid van Moolenbroek  * 3. Neither the name of the University nor the names of its contributors
4993d36fc9SDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
5093d36fc9SDavid van Moolenbroek  *    without specific prior written permission.
5193d36fc9SDavid van Moolenbroek  *
5293d36fc9SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5393d36fc9SDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5493d36fc9SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5593d36fc9SDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5693d36fc9SDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5793d36fc9SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5893d36fc9SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5993d36fc9SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6093d36fc9SDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6193d36fc9SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6293d36fc9SDavid van Moolenbroek  * SUCH DAMAGE.
6393d36fc9SDavid van Moolenbroek  */
6493d36fc9SDavid van Moolenbroek 
6593d36fc9SDavid van Moolenbroek #include <sys/cdefs.h>
6693d36fc9SDavid van Moolenbroek #ifndef lint
6793d36fc9SDavid van Moolenbroek __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\
6893d36fc9SDavid van Moolenbroek  The Regents of the University of California.  All rights reserved.");
6993d36fc9SDavid van Moolenbroek #if 0
7093d36fc9SDavid van Moolenbroek static char sccsid[] = "@(#)rshd.c	8.2 (Berkeley) 4/6/94";
7193d36fc9SDavid van Moolenbroek #else
7293d36fc9SDavid van Moolenbroek __RCSID("$NetBSD: rshd.c,v 1.50 2012/07/14 15:06:26 darrenr Exp $");
7393d36fc9SDavid van Moolenbroek #endif
7493d36fc9SDavid van Moolenbroek #endif /* not lint */
7593d36fc9SDavid van Moolenbroek 
7693d36fc9SDavid van Moolenbroek /*
7793d36fc9SDavid van Moolenbroek  * remote shell server:
7893d36fc9SDavid van Moolenbroek  *	[port]\0
7993d36fc9SDavid van Moolenbroek  *	remuser\0
8093d36fc9SDavid van Moolenbroek  *	locuser\0
8193d36fc9SDavid van Moolenbroek  *	command\0
8293d36fc9SDavid van Moolenbroek  *	data
8393d36fc9SDavid van Moolenbroek  */
8493d36fc9SDavid van Moolenbroek #include <sys/param.h>
8593d36fc9SDavid van Moolenbroek #include <sys/ioctl.h>
8693d36fc9SDavid van Moolenbroek #include <sys/time.h>
8793d36fc9SDavid van Moolenbroek #include <sys/socket.h>
8893d36fc9SDavid van Moolenbroek 
8993d36fc9SDavid van Moolenbroek #include <netinet/in_systm.h>
9093d36fc9SDavid van Moolenbroek #include <netinet/in.h>
9193d36fc9SDavid van Moolenbroek #include <netinet/ip.h>
9293d36fc9SDavid van Moolenbroek #include <netinet/tcp.h>
9393d36fc9SDavid van Moolenbroek #include <arpa/inet.h>
9493d36fc9SDavid van Moolenbroek #include <netdb.h>
9593d36fc9SDavid van Moolenbroek 
9693d36fc9SDavid van Moolenbroek #include <errno.h>
9793d36fc9SDavid van Moolenbroek #include <fcntl.h>
9893d36fc9SDavid van Moolenbroek #include <paths.h>
9993d36fc9SDavid van Moolenbroek #include <pwd.h>
10093d36fc9SDavid van Moolenbroek #include <signal.h>
10193d36fc9SDavid van Moolenbroek #include <stdio.h>
10293d36fc9SDavid van Moolenbroek #include <stdlib.h>
10393d36fc9SDavid van Moolenbroek #include <string.h>
10493d36fc9SDavid van Moolenbroek #include <syslog.h>
10593d36fc9SDavid van Moolenbroek #include <unistd.h>
10693d36fc9SDavid van Moolenbroek #include <poll.h>
10793d36fc9SDavid van Moolenbroek #ifdef  LOGIN_CAP
10893d36fc9SDavid van Moolenbroek #include <login_cap.h>
10993d36fc9SDavid van Moolenbroek #endif
11093d36fc9SDavid van Moolenbroek 
11193d36fc9SDavid van Moolenbroek #ifdef USE_PAM
11293d36fc9SDavid van Moolenbroek #include <security/pam_appl.h>
11393d36fc9SDavid van Moolenbroek #include <security/openpam.h>
11493d36fc9SDavid van Moolenbroek #include <sys/wait.h>
11593d36fc9SDavid van Moolenbroek 
11693d36fc9SDavid van Moolenbroek static struct pam_conv pamc = { openpam_nullconv, NULL };
11793d36fc9SDavid van Moolenbroek static pam_handle_t *pamh;
11893d36fc9SDavid van Moolenbroek static int pam_err;
11993d36fc9SDavid van Moolenbroek 
12093d36fc9SDavid van Moolenbroek #define PAM_END do { \
12193d36fc9SDavid van Moolenbroek 	if ((pam_err = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \
12293d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR|LOG_AUTH, "pam_setcred(): %s", \
12393d36fc9SDavid van Moolenbroek 		    pam_strerror(pamh, pam_err)); \
12493d36fc9SDavid van Moolenbroek 	if ((pam_err = pam_close_session(pamh,0)) != PAM_SUCCESS) \
12593d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR|LOG_AUTH, "pam_close_session(): %s", \
12693d36fc9SDavid van Moolenbroek 		    pam_strerror(pamh, pam_err)); \
12793d36fc9SDavid van Moolenbroek 	if ((pam_err = pam_end(pamh, pam_err)) != PAM_SUCCESS) \
12893d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR|LOG_AUTH, "pam_end(): %s", \
12993d36fc9SDavid van Moolenbroek 		    pam_strerror(pamh, pam_err)); \
13093d36fc9SDavid van Moolenbroek } while (/*CONSTCOND*/0)
13193d36fc9SDavid van Moolenbroek #else
13293d36fc9SDavid van Moolenbroek #define PAM_END
13393d36fc9SDavid van Moolenbroek #endif
13493d36fc9SDavid van Moolenbroek 
13593d36fc9SDavid van Moolenbroek static int	keepalive = 1;
13693d36fc9SDavid van Moolenbroek static int	check_all;
13793d36fc9SDavid van Moolenbroek static int	log_success;		/* If TRUE, log all successful accesses */
13893d36fc9SDavid van Moolenbroek static int	sent_null;
13993d36fc9SDavid van Moolenbroek 
14093d36fc9SDavid van Moolenbroek __dead static void	 doit(struct sockaddr *, struct sockaddr *);
14193d36fc9SDavid van Moolenbroek __dead static void	 rshd_errx(int, const char *, ...) __printflike(2, 3);
14293d36fc9SDavid van Moolenbroek static void	 getstr(char *, int, const char *);
14393d36fc9SDavid van Moolenbroek static int	 local_domain(char *);
14493d36fc9SDavid van Moolenbroek static char	*topdomain(char *);
14593d36fc9SDavid van Moolenbroek __dead static void	 usage(void);
14693d36fc9SDavid van Moolenbroek 
14793d36fc9SDavid van Moolenbroek #define	OPTIONS	"aLln"
14893d36fc9SDavid van Moolenbroek extern int __check_rhosts_file;
14993d36fc9SDavid van Moolenbroek extern char *__rcmd_errstr;	/* syslog hook from libc/net/rcmd.c. */
150*0a6a1f1dSLionel Sambuc #if defined(__minix) && defined(USE_PAM)
15193d36fc9SDavid van Moolenbroek static const char incorrect[] = "Login incorrect.";
152*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) && defined(USE_PAM) */
15393d36fc9SDavid van Moolenbroek 
15493d36fc9SDavid van Moolenbroek int
main(int argc,char * argv[])15593d36fc9SDavid van Moolenbroek main(int argc, char *argv[])
15693d36fc9SDavid van Moolenbroek {
15793d36fc9SDavid van Moolenbroek 	struct linger linger;
15893d36fc9SDavid van Moolenbroek 	int ch, on = 1;
15993d36fc9SDavid van Moolenbroek 	socklen_t fromlen;
16093d36fc9SDavid van Moolenbroek 	socklen_t locallen;
16193d36fc9SDavid van Moolenbroek 	struct sockaddr_storage from;
16293d36fc9SDavid van Moolenbroek 	struct sockaddr_storage local;
16393d36fc9SDavid van Moolenbroek 	struct protoent *proto;
16493d36fc9SDavid van Moolenbroek 
16593d36fc9SDavid van Moolenbroek 	openlog("rshd", LOG_PID, LOG_DAEMON);
16693d36fc9SDavid van Moolenbroek 
16793d36fc9SDavid van Moolenbroek 	opterr = 0;
16893d36fc9SDavid van Moolenbroek 	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
16993d36fc9SDavid van Moolenbroek 		switch (ch) {
17093d36fc9SDavid van Moolenbroek 		case 'a':
17193d36fc9SDavid van Moolenbroek 			check_all = 1;
17293d36fc9SDavid van Moolenbroek 			break;
17393d36fc9SDavid van Moolenbroek 		case 'l':
17493d36fc9SDavid van Moolenbroek 			__check_rhosts_file = 0;
17593d36fc9SDavid van Moolenbroek 			break;
17693d36fc9SDavid van Moolenbroek 		case 'n':
17793d36fc9SDavid van Moolenbroek 			keepalive = 0;
17893d36fc9SDavid van Moolenbroek 			break;
17993d36fc9SDavid van Moolenbroek 		case 'L':
18093d36fc9SDavid van Moolenbroek 			log_success = 1;
18193d36fc9SDavid van Moolenbroek 			break;
18293d36fc9SDavid van Moolenbroek 		case '?':
18393d36fc9SDavid van Moolenbroek 		default:
18493d36fc9SDavid van Moolenbroek 			usage();
18593d36fc9SDavid van Moolenbroek 			break;
18693d36fc9SDavid van Moolenbroek 		}
18793d36fc9SDavid van Moolenbroek 
18893d36fc9SDavid van Moolenbroek 	argc -= optind;
18993d36fc9SDavid van Moolenbroek 	argv += optind;
19093d36fc9SDavid van Moolenbroek 
19193d36fc9SDavid van Moolenbroek 	fromlen = sizeof(from); /* xxx */
19293d36fc9SDavid van Moolenbroek 	locallen = sizeof(local); /* xxx */
19393d36fc9SDavid van Moolenbroek 	if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) {
19493d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "getpeername: %m");
19593d36fc9SDavid van Moolenbroek 		return EXIT_FAILURE;
19693d36fc9SDavid van Moolenbroek 	}
19793d36fc9SDavid van Moolenbroek 	if (getsockname(STDIN_FILENO, (struct sockaddr *)&local,
19893d36fc9SDavid van Moolenbroek 	    &locallen) < 0) {
19993d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "getsockname: %m");
20093d36fc9SDavid van Moolenbroek 		return EXIT_FAILURE;
20193d36fc9SDavid van Moolenbroek 	}
20293d36fc9SDavid van Moolenbroek #if 0
20393d36fc9SDavid van Moolenbroek 	if (((struct sockaddr *)&from)->sa_family == AF_INET6 &&
20493d36fc9SDavid van Moolenbroek 	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr) &&
20593d36fc9SDavid van Moolenbroek 	    sizeof(struct sockaddr_in) <= sizeof(from)) {
20693d36fc9SDavid van Moolenbroek 		struct sockaddr_in sin;
20793d36fc9SDavid van Moolenbroek 		struct sockaddr_in6 *sin6;
20893d36fc9SDavid van Moolenbroek 		const int off = sizeof(struct sockaddr_in6) -
20993d36fc9SDavid van Moolenbroek 		    sizeof(struct sockaddr_in);
21093d36fc9SDavid van Moolenbroek 
21193d36fc9SDavid van Moolenbroek 		sin6 = (struct sockaddr_in6 *)&from;
21293d36fc9SDavid van Moolenbroek 		(void)memset(&sin, 0, sizeof(sin));
21393d36fc9SDavid van Moolenbroek 		sin.sin_family = AF_INET;
21493d36fc9SDavid van Moolenbroek 		sin.sin_len = sizeof(struct sockaddr_in);
21593d36fc9SDavid van Moolenbroek 		(void)memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[off],
21693d36fc9SDavid van Moolenbroek 		    sizeof(sin.sin_addr));
21793d36fc9SDavid van Moolenbroek 		(void)memcpy(&from, &sin, sizeof(sin));
21893d36fc9SDavid van Moolenbroek 		fromlen = sin.sin_len;
21993d36fc9SDavid van Moolenbroek 	}
22093d36fc9SDavid van Moolenbroek #else
22193d36fc9SDavid van Moolenbroek 	if (((struct sockaddr *)&from)->sa_family == AF_INET6 &&
22293d36fc9SDavid van Moolenbroek 	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr)) {
22393d36fc9SDavid van Moolenbroek 		char hbuf[NI_MAXHOST];
22493d36fc9SDavid van Moolenbroek 		if (getnameinfo((struct sockaddr *)&from, fromlen, hbuf,
22593d36fc9SDavid van Moolenbroek 				sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) {
22693d36fc9SDavid van Moolenbroek 			strlcpy(hbuf, "invalid", sizeof(hbuf));
22793d36fc9SDavid van Moolenbroek 		}
22893d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "malformed \"from\" address (v4 mapped, %s)",
22993d36fc9SDavid van Moolenbroek 		    hbuf);
23093d36fc9SDavid van Moolenbroek 		return EXIT_FAILURE;
23193d36fc9SDavid van Moolenbroek 	}
23293d36fc9SDavid van Moolenbroek #endif
23393d36fc9SDavid van Moolenbroek 	if (keepalive &&
23493d36fc9SDavid van Moolenbroek 	    setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
23593d36fc9SDavid van Moolenbroek 	    sizeof(on)) < 0)
23693d36fc9SDavid van Moolenbroek 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
23793d36fc9SDavid van Moolenbroek 	linger.l_onoff = 1;
23893d36fc9SDavid van Moolenbroek 	linger.l_linger = 60;			/* XXX */
23993d36fc9SDavid van Moolenbroek 	if (setsockopt(STDIN_FILENO, SOL_SOCKET, SO_LINGER, (char *)&linger,
24093d36fc9SDavid van Moolenbroek 	    sizeof (linger)) < 0)
24193d36fc9SDavid van Moolenbroek 		syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
24293d36fc9SDavid van Moolenbroek 	proto = getprotobyname("tcp");
24393d36fc9SDavid van Moolenbroek 	(void)setsockopt(STDIN_FILENO, proto->p_proto, TCP_NODELAY, &on,
24493d36fc9SDavid van Moolenbroek 	    sizeof(on));
24593d36fc9SDavid van Moolenbroek 	doit((struct sockaddr *)&from, (struct sockaddr *)&local);
24693d36fc9SDavid van Moolenbroek }
24793d36fc9SDavid van Moolenbroek 
24893d36fc9SDavid van Moolenbroek extern char	**environ;
24993d36fc9SDavid van Moolenbroek 
25093d36fc9SDavid van Moolenbroek static void
doit(struct sockaddr * fromp,struct sockaddr * localp)25193d36fc9SDavid van Moolenbroek doit(struct sockaddr *fromp, struct sockaddr *localp)
25293d36fc9SDavid van Moolenbroek {
25393d36fc9SDavid van Moolenbroek 	struct passwd *pwd, pwres;
25493d36fc9SDavid van Moolenbroek 	in_port_t port;
25593d36fc9SDavid van Moolenbroek 	struct pollfd set[2];
25693d36fc9SDavid van Moolenbroek 	int cc, pv[2], pid, s = -1;	/* XXX gcc */
25793d36fc9SDavid van Moolenbroek 	int one = 1;
25893d36fc9SDavid van Moolenbroek 	char *hostname, *errorhost = NULL;	/* XXX gcc */
25993d36fc9SDavid van Moolenbroek 	const char *cp;
26093d36fc9SDavid van Moolenbroek 	char sig, buf[BUFSIZ];
26193d36fc9SDavid van Moolenbroek 	char cmdbuf[NCARGS+1], locuser[16], remuser[16];
26293d36fc9SDavid van Moolenbroek 	char remotehost[2 * MAXHOSTNAMELEN + 1];
26393d36fc9SDavid van Moolenbroek 	char hostnamebuf[2 * MAXHOSTNAMELEN + 1];
26493d36fc9SDavid van Moolenbroek #ifdef  LOGIN_CAP
26593d36fc9SDavid van Moolenbroek 	login_cap_t *lc;
26693d36fc9SDavid van Moolenbroek #endif
26793d36fc9SDavid van Moolenbroek 	char naddr[NI_MAXHOST];
26893d36fc9SDavid van Moolenbroek 	char saddr[NI_MAXHOST];
26993d36fc9SDavid van Moolenbroek 	char raddr[NI_MAXHOST];
27093d36fc9SDavid van Moolenbroek 	char pbuf[NI_MAXSERV];
27193d36fc9SDavid van Moolenbroek 	int af = fromp->sa_family;
27293d36fc9SDavid van Moolenbroek 	u_int16_t *portp;
27393d36fc9SDavid van Moolenbroek 	struct addrinfo hints, *res, *res0;
27493d36fc9SDavid van Moolenbroek 	int gaierror;
27593d36fc9SDavid van Moolenbroek 	const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
27693d36fc9SDavid van Moolenbroek 	const char *errormsg = NULL, *errorstr = NULL;
27793d36fc9SDavid van Moolenbroek 	char pwbuf[1024];
27893d36fc9SDavid van Moolenbroek 
27993d36fc9SDavid van Moolenbroek 	(void)signal(SIGINT, SIG_DFL);
28093d36fc9SDavid van Moolenbroek 	(void)signal(SIGQUIT, SIG_DFL);
28193d36fc9SDavid van Moolenbroek 	(void)signal(SIGTERM, SIG_DFL);
28293d36fc9SDavid van Moolenbroek #ifdef DEBUG
28393d36fc9SDavid van Moolenbroek 	{
28493d36fc9SDavid van Moolenbroek 		int t = open(_PATH_TTY, O_RDWR);
28593d36fc9SDavid van Moolenbroek 		if (t >= 0) {
28693d36fc9SDavid van Moolenbroek 			ioctl(t, TIOCNOTTY, NULL);
28793d36fc9SDavid van Moolenbroek 			(void)close(t);
28893d36fc9SDavid van Moolenbroek 		}
28993d36fc9SDavid van Moolenbroek 	}
29093d36fc9SDavid van Moolenbroek #endif
29193d36fc9SDavid van Moolenbroek 	switch (af) {
29293d36fc9SDavid van Moolenbroek 	case AF_INET:
29393d36fc9SDavid van Moolenbroek 		portp = &((struct sockaddr_in *)fromp)->sin_port;
29493d36fc9SDavid van Moolenbroek 		break;
29593d36fc9SDavid van Moolenbroek #ifdef INET6
29693d36fc9SDavid van Moolenbroek 	case AF_INET6:
29793d36fc9SDavid van Moolenbroek 		portp = &((struct sockaddr_in6 *)fromp)->sin6_port;
29893d36fc9SDavid van Moolenbroek 		break;
29993d36fc9SDavid van Moolenbroek #endif
30093d36fc9SDavid van Moolenbroek 	default:
30193d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
30293d36fc9SDavid van Moolenbroek 		exit(EXIT_FAILURE);
30393d36fc9SDavid van Moolenbroek 	}
30493d36fc9SDavid van Moolenbroek 	if (getnameinfo(fromp, fromp->sa_len, naddr, sizeof(naddr),
30593d36fc9SDavid van Moolenbroek 			pbuf, sizeof(pbuf), niflags) != 0) {
30693d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "malformed \"from\" address (af %d)", af);
30793d36fc9SDavid van Moolenbroek 		exit(EXIT_FAILURE);
30893d36fc9SDavid van Moolenbroek 	}
30993d36fc9SDavid van Moolenbroek #ifdef IP_OPTIONS
31093d36fc9SDavid van Moolenbroek 	if (af == AF_INET) {
31193d36fc9SDavid van Moolenbroek 
31293d36fc9SDavid van Moolenbroek 	u_char optbuf[BUFSIZ/3];
31393d36fc9SDavid van Moolenbroek 	socklen_t optsize = sizeof(optbuf);
31493d36fc9SDavid van Moolenbroek 	int ipproto;
31593d36fc9SDavid van Moolenbroek 	unsigned int i;
31693d36fc9SDavid van Moolenbroek 	struct protoent *ip;
31793d36fc9SDavid van Moolenbroek 
31893d36fc9SDavid van Moolenbroek 	if ((ip = getprotobyname("ip")) != NULL)
31993d36fc9SDavid van Moolenbroek 		ipproto = ip->p_proto;
32093d36fc9SDavid van Moolenbroek 	else
32193d36fc9SDavid van Moolenbroek 		ipproto = IPPROTO_IP;
32293d36fc9SDavid van Moolenbroek 	if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) &&
32393d36fc9SDavid van Moolenbroek 	    optsize != 0) {
32493d36fc9SDavid van Moolenbroek 	    	for (i = 0; i < optsize;) {
32593d36fc9SDavid van Moolenbroek 			u_char c = optbuf[i];
32693d36fc9SDavid van Moolenbroek 			if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
32793d36fc9SDavid van Moolenbroek 				syslog(LOG_NOTICE,
32893d36fc9SDavid van Moolenbroek 				    "Connection refused from %s "
32993d36fc9SDavid van Moolenbroek 				    "with IP option %s",
33093d36fc9SDavid van Moolenbroek 				    inet_ntoa((
33193d36fc9SDavid van Moolenbroek 				    (struct sockaddr_in *)fromp)->sin_addr),
33293d36fc9SDavid van Moolenbroek 				    c == IPOPT_LSRR ? "LSRR" : "SSRR");
33393d36fc9SDavid van Moolenbroek 				exit(EXIT_FAILURE);
33493d36fc9SDavid van Moolenbroek 			}
33593d36fc9SDavid van Moolenbroek 			if (c == IPOPT_EOL)
33693d36fc9SDavid van Moolenbroek 				break;
33793d36fc9SDavid van Moolenbroek 			i += (c == IPOPT_NOP) ? 1 : optbuf[i + 1];
33893d36fc9SDavid van Moolenbroek 		}
33993d36fc9SDavid van Moolenbroek 	}
34093d36fc9SDavid van Moolenbroek 	}
34193d36fc9SDavid van Moolenbroek #endif
34293d36fc9SDavid van Moolenbroek 	if (ntohs(*portp) >= IPPORT_RESERVED
34393d36fc9SDavid van Moolenbroek 	    || ntohs(*portp) < IPPORT_RESERVED / 2) {
34493d36fc9SDavid van Moolenbroek 		syslog(LOG_NOTICE|LOG_AUTH,
34593d36fc9SDavid van Moolenbroek 		    "Connection from %s on illegal port %u",
34693d36fc9SDavid van Moolenbroek 		    naddr, ntohs(*portp));
34793d36fc9SDavid van Moolenbroek 		exit(EXIT_FAILURE);
34893d36fc9SDavid van Moolenbroek 	}
34993d36fc9SDavid van Moolenbroek 
35093d36fc9SDavid van Moolenbroek 	(void) alarm(60);
35193d36fc9SDavid van Moolenbroek 	port = 0;
35293d36fc9SDavid van Moolenbroek 	for (;;) {
35393d36fc9SDavid van Moolenbroek 		char c;
35493d36fc9SDavid van Moolenbroek 
35593d36fc9SDavid van Moolenbroek 		if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
35693d36fc9SDavid van Moolenbroek 			if (cc < 0)
35793d36fc9SDavid van Moolenbroek 				syslog(LOG_ERR, "read: %m");
35893d36fc9SDavid van Moolenbroek 			(void)shutdown(0, SHUT_RDWR);
35993d36fc9SDavid van Moolenbroek 			exit(EXIT_FAILURE);
36093d36fc9SDavid van Moolenbroek 		}
36193d36fc9SDavid van Moolenbroek 		if (c == 0)
36293d36fc9SDavid van Moolenbroek 			break;
36393d36fc9SDavid van Moolenbroek 		port = port * 10 + c - '0';
36493d36fc9SDavid van Moolenbroek 	}
36593d36fc9SDavid van Moolenbroek 
36693d36fc9SDavid van Moolenbroek 	(void) alarm(0);
36793d36fc9SDavid van Moolenbroek 	if (port != 0) {
36893d36fc9SDavid van Moolenbroek 		int lport = IPPORT_RESERVED - 1;
36993d36fc9SDavid van Moolenbroek 		s = rresvport_af_addr(&lport, af, localp);
37093d36fc9SDavid van Moolenbroek 		if (s < 0) {
37193d36fc9SDavid van Moolenbroek 			syslog(LOG_ERR, "can't get stderr port: %m");
37293d36fc9SDavid van Moolenbroek 			exit(EXIT_FAILURE);
37393d36fc9SDavid van Moolenbroek 		}
37493d36fc9SDavid van Moolenbroek 		if (port >= IPPORT_RESERVED) {
37593d36fc9SDavid van Moolenbroek 			syslog(LOG_ERR, "2nd port not reserved");
37693d36fc9SDavid van Moolenbroek 			exit(EXIT_FAILURE);
37793d36fc9SDavid van Moolenbroek 		}
37893d36fc9SDavid van Moolenbroek 		*portp = htons(port);
37993d36fc9SDavid van Moolenbroek 		if (connect(s, fromp, fromp->sa_len) < 0) {
38093d36fc9SDavid van Moolenbroek 			syslog(LOG_ERR, "connect second port %d: %m", port);
38193d36fc9SDavid van Moolenbroek 			exit(EXIT_FAILURE);
38293d36fc9SDavid van Moolenbroek 		}
38393d36fc9SDavid van Moolenbroek 	}
38493d36fc9SDavid van Moolenbroek 
38593d36fc9SDavid van Moolenbroek 
38693d36fc9SDavid van Moolenbroek #ifdef notdef
38793d36fc9SDavid van Moolenbroek 	/* from inetd, socket is already on 0, 1, 2 */
38893d36fc9SDavid van Moolenbroek 	(void)dup2(f, STDIN_FILENO);
38993d36fc9SDavid van Moolenbroek 	(void)dup2(f, STDOUT_FILENO);
39093d36fc9SDavid van Moolenbroek 	(void)dup2(f, STDERR_FILENO);
39193d36fc9SDavid van Moolenbroek #endif
39293d36fc9SDavid van Moolenbroek 	if (getnameinfo(fromp, fromp->sa_len, saddr, sizeof(saddr),
39393d36fc9SDavid van Moolenbroek 			NULL, 0, NI_NAMEREQD) == 0) {
39493d36fc9SDavid van Moolenbroek 		/*
39593d36fc9SDavid van Moolenbroek 		 * If name returned by getnameinfo is in our domain,
39693d36fc9SDavid van Moolenbroek 		 * attempt to verify that we haven't been fooled by someone
39793d36fc9SDavid van Moolenbroek 		 * in a remote net; look up the name and check that this
39893d36fc9SDavid van Moolenbroek 		 * address corresponds to the name.
39993d36fc9SDavid van Moolenbroek 		 */
40093d36fc9SDavid van Moolenbroek 		hostname = saddr;
40193d36fc9SDavid van Moolenbroek 		res0 = NULL;
40293d36fc9SDavid van Moolenbroek 		if (check_all || local_domain(saddr)) {
40393d36fc9SDavid van Moolenbroek 			(void)strlcpy(remotehost, saddr, sizeof(remotehost));
40493d36fc9SDavid van Moolenbroek 			errorhost = remotehost;
40593d36fc9SDavid van Moolenbroek 			(void)memset(&hints, 0, sizeof(hints));
40693d36fc9SDavid van Moolenbroek 			hints.ai_family = fromp->sa_family;
40793d36fc9SDavid van Moolenbroek 			hints.ai_socktype = SOCK_STREAM;
40893d36fc9SDavid van Moolenbroek 			hints.ai_flags = AI_CANONNAME;
40993d36fc9SDavid van Moolenbroek 			gaierror = getaddrinfo(remotehost, pbuf, &hints, &res0);
41093d36fc9SDavid van Moolenbroek 			if (gaierror) {
41193d36fc9SDavid van Moolenbroek 				syslog(LOG_NOTICE,
41293d36fc9SDavid van Moolenbroek 				    "Couldn't look up address for %s: %s",
41393d36fc9SDavid van Moolenbroek 				    remotehost, gai_strerror(gaierror));
41493d36fc9SDavid van Moolenbroek 				errorstr =
41593d36fc9SDavid van Moolenbroek 				"Couldn't look up address for your host (%s)\n";
41693d36fc9SDavid van Moolenbroek 				hostname = naddr;
41793d36fc9SDavid van Moolenbroek 			} else {
41893d36fc9SDavid van Moolenbroek 				for (res = res0; res; res = res->ai_next) {
41993d36fc9SDavid van Moolenbroek 					if (res->ai_family != fromp->sa_family)
42093d36fc9SDavid van Moolenbroek 						continue;
42193d36fc9SDavid van Moolenbroek 					if (res->ai_addrlen != fromp->sa_len)
42293d36fc9SDavid van Moolenbroek 						continue;
42393d36fc9SDavid van Moolenbroek 					if (getnameinfo(res->ai_addr,
42493d36fc9SDavid van Moolenbroek 						res->ai_addrlen,
42593d36fc9SDavid van Moolenbroek 						raddr, sizeof(raddr), NULL, 0,
42693d36fc9SDavid van Moolenbroek 						niflags) == 0
42793d36fc9SDavid van Moolenbroek 					 && strcmp(naddr, raddr) == 0) {
42893d36fc9SDavid van Moolenbroek 						hostname = res->ai_canonname
42993d36fc9SDavid van Moolenbroek 							? res->ai_canonname
43093d36fc9SDavid van Moolenbroek 							: saddr;
43193d36fc9SDavid van Moolenbroek 						break;
43293d36fc9SDavid van Moolenbroek 					}
43393d36fc9SDavid van Moolenbroek 				}
43493d36fc9SDavid van Moolenbroek 				if (res == NULL) {
43593d36fc9SDavid van Moolenbroek 					syslog(LOG_NOTICE,
43693d36fc9SDavid van Moolenbroek 					  "Host addr %s not listed for host %s",
43793d36fc9SDavid van Moolenbroek 					    naddr, res0->ai_canonname
43893d36fc9SDavid van Moolenbroek 						    ? res0->ai_canonname
43993d36fc9SDavid van Moolenbroek 						    : saddr);
44093d36fc9SDavid van Moolenbroek 					errorstr =
44193d36fc9SDavid van Moolenbroek 					    "Host address mismatch for %s\n";
44293d36fc9SDavid van Moolenbroek 					hostname = naddr;
44393d36fc9SDavid van Moolenbroek 				}
44493d36fc9SDavid van Moolenbroek 			}
44593d36fc9SDavid van Moolenbroek 		}
44693d36fc9SDavid van Moolenbroek 		(void)strlcpy(hostnamebuf, hostname, sizeof(hostnamebuf));
44793d36fc9SDavid van Moolenbroek 		hostname = hostnamebuf;
44893d36fc9SDavid van Moolenbroek 		if (res0)
44993d36fc9SDavid van Moolenbroek 			freeaddrinfo(res0);
45093d36fc9SDavid van Moolenbroek 	} else {
45193d36fc9SDavid van Moolenbroek 		(void)strlcpy(hostnamebuf, naddr, sizeof(hostnamebuf));
45293d36fc9SDavid van Moolenbroek 		errorhost = hostname = hostnamebuf;
45393d36fc9SDavid van Moolenbroek 	}
45493d36fc9SDavid van Moolenbroek 
45593d36fc9SDavid van Moolenbroek 	(void)alarm(60);
45693d36fc9SDavid van Moolenbroek 	getstr(remuser, sizeof(remuser), "remuser");
45793d36fc9SDavid van Moolenbroek 	getstr(locuser, sizeof(locuser), "locuser");
45893d36fc9SDavid van Moolenbroek 	getstr(cmdbuf, sizeof(cmdbuf), "command");
45993d36fc9SDavid van Moolenbroek 	(void)alarm(0);
46093d36fc9SDavid van Moolenbroek 
46193d36fc9SDavid van Moolenbroek #ifdef USE_PAM
46293d36fc9SDavid van Moolenbroek 	pam_err = pam_start("rsh", locuser, &pamc, &pamh);
46393d36fc9SDavid van Moolenbroek 	if (pam_err != PAM_SUCCESS) {
46493d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR|LOG_AUTH, "pam_start(): %s",
46593d36fc9SDavid van Moolenbroek 		    pam_strerror(pamh, pam_err));
46693d36fc9SDavid van Moolenbroek 		rshd_errx(EXIT_FAILURE, incorrect);
46793d36fc9SDavid van Moolenbroek 	}
46893d36fc9SDavid van Moolenbroek 
46993d36fc9SDavid van Moolenbroek 	if ((pam_err = pam_set_item(pamh, PAM_RUSER, remuser)) != PAM_SUCCESS ||
47093d36fc9SDavid van Moolenbroek 	    (pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS){
47193d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR|LOG_AUTH, "pam_set_item(): %s",
47293d36fc9SDavid van Moolenbroek 		    pam_strerror(pamh, pam_err));
47393d36fc9SDavid van Moolenbroek 		rshd_errx(EXIT_FAILURE, incorrect);
47493d36fc9SDavid van Moolenbroek 	}
47593d36fc9SDavid van Moolenbroek 
47693d36fc9SDavid van Moolenbroek 	pam_err = pam_authenticate(pamh, 0);
47793d36fc9SDavid van Moolenbroek 	if (pam_err == PAM_SUCCESS) {
47893d36fc9SDavid van Moolenbroek 		if ((pam_err = pam_get_user(pamh, &cp, NULL)) == PAM_SUCCESS) {
47993d36fc9SDavid van Moolenbroek 			(void)strlcpy(locuser, cp, sizeof(locuser));
48093d36fc9SDavid van Moolenbroek 			/* XXX truncation! */
48193d36fc9SDavid van Moolenbroek  		}
48293d36fc9SDavid van Moolenbroek 		pam_err = pam_acct_mgmt(pamh, 0);
48393d36fc9SDavid van Moolenbroek 	}
48493d36fc9SDavid van Moolenbroek 	if (pam_err != PAM_SUCCESS) {
48593d36fc9SDavid van Moolenbroek 		errorstr = incorrect;
48693d36fc9SDavid van Moolenbroek 		errormsg = pam_strerror(pamh, pam_err);
48793d36fc9SDavid van Moolenbroek 		goto badlogin;
48893d36fc9SDavid van Moolenbroek  	}
48993d36fc9SDavid van Moolenbroek #endif /* USE_PAM */
49093d36fc9SDavid van Moolenbroek 	setpwent();
49193d36fc9SDavid van Moolenbroek 	if (getpwnam_r(locuser, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
49293d36fc9SDavid van Moolenbroek 	    pwd == NULL) {
49393d36fc9SDavid van Moolenbroek 		syslog(LOG_INFO|LOG_AUTH,
49493d36fc9SDavid van Moolenbroek 		    "%s@%s as %s: unknown login. cmd='%.80s'",
49593d36fc9SDavid van Moolenbroek 		    remuser, hostname, locuser, cmdbuf);
49693d36fc9SDavid van Moolenbroek 		if (errorstr == NULL)
49793d36fc9SDavid van Moolenbroek 			errorstr = "Permission denied.";
49893d36fc9SDavid van Moolenbroek 		rshd_errx(EXIT_FAILURE, errorstr, errorhost);
49993d36fc9SDavid van Moolenbroek 	}
50093d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
50193d36fc9SDavid van Moolenbroek 	lc = login_getclass(pwd ? pwd->pw_class : NULL);
50293d36fc9SDavid van Moolenbroek #endif
50393d36fc9SDavid van Moolenbroek 
50493d36fc9SDavid van Moolenbroek 	if (chdir(pwd->pw_dir) < 0) {
50593d36fc9SDavid van Moolenbroek 		if (chdir("/") < 0
50693d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
50793d36fc9SDavid van Moolenbroek 		    || login_getcapbool(lc, "requirehome", pwd->pw_uid ? 1 : 0)
50893d36fc9SDavid van Moolenbroek #endif
50993d36fc9SDavid van Moolenbroek 		) {
51093d36fc9SDavid van Moolenbroek 			syslog(LOG_INFO|LOG_AUTH,
51193d36fc9SDavid van Moolenbroek 			    "%s@%s as %s: no home directory. cmd='%.80s'",
51293d36fc9SDavid van Moolenbroek 			    remuser, hostname, locuser, cmdbuf);
51393d36fc9SDavid van Moolenbroek 			rshd_errx(EXIT_SUCCESS, "No remote home directory.");
51493d36fc9SDavid van Moolenbroek 		}
51593d36fc9SDavid van Moolenbroek 	}
51693d36fc9SDavid van Moolenbroek 
51793d36fc9SDavid van Moolenbroek #ifndef USE_PAM
51893d36fc9SDavid van Moolenbroek 	if (errorstr ||
51993d36fc9SDavid van Moolenbroek 	    (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
52093d36fc9SDavid van Moolenbroek 		iruserok_sa(fromp, fromp->sa_len, pwd->pw_uid == 0, remuser,
52193d36fc9SDavid van Moolenbroek 			locuser) < 0)) {
52293d36fc9SDavid van Moolenbroek 		errormsg = __rcmd_errstr ? __rcmd_errstr : "unknown error";
52393d36fc9SDavid van Moolenbroek 		if (errorstr == NULL)
52493d36fc9SDavid van Moolenbroek 			errorstr = "Permission denied.";
52593d36fc9SDavid van Moolenbroek 		goto badlogin;
52693d36fc9SDavid van Moolenbroek 	}
52793d36fc9SDavid van Moolenbroek 
52893d36fc9SDavid van Moolenbroek 	if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK))
52993d36fc9SDavid van Moolenbroek 		rshd_errx(EXIT_FAILURE, "Logins currently disabled.");
53093d36fc9SDavid van Moolenbroek #endif
53193d36fc9SDavid van Moolenbroek 
53293d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
53393d36fc9SDavid van Moolenbroek 	/*
53493d36fc9SDavid van Moolenbroek 	 * PAM modules might add supplementary groups in
53593d36fc9SDavid van Moolenbroek 	 * pam_setcred(), so initialize them first.
53693d36fc9SDavid van Moolenbroek 	 * But we need to open the session as root.
53793d36fc9SDavid van Moolenbroek 	 */
53893d36fc9SDavid van Moolenbroek 	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
53993d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "setusercontext: %m");
54093d36fc9SDavid van Moolenbroek 		exit(EXIT_FAILURE);
54193d36fc9SDavid van Moolenbroek 	}
54293d36fc9SDavid van Moolenbroek #else
54393d36fc9SDavid van Moolenbroek 	initgroups(pwd->pw_name, pwd->pw_gid);
54493d36fc9SDavid van Moolenbroek #endif
54593d36fc9SDavid van Moolenbroek 
54693d36fc9SDavid van Moolenbroek #ifdef USE_PAM
54793d36fc9SDavid van Moolenbroek 	if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
54893d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "pam_open_session: %s",
54993d36fc9SDavid van Moolenbroek 		    pam_strerror(pamh, pam_err));
55093d36fc9SDavid van Moolenbroek 	} else if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED))
55193d36fc9SDavid van Moolenbroek 	    != PAM_SUCCESS) {
55293d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, pam_err));
55393d36fc9SDavid van Moolenbroek 	}
55493d36fc9SDavid van Moolenbroek #endif
55593d36fc9SDavid van Moolenbroek 
55693d36fc9SDavid van Moolenbroek 	(void)write(STDERR_FILENO, "\0", 1);
55793d36fc9SDavid van Moolenbroek 	sent_null = 1;
55893d36fc9SDavid van Moolenbroek 
55993d36fc9SDavid van Moolenbroek 	if (port) {
56093d36fc9SDavid van Moolenbroek 		if (pipe(pv) < 0)
56193d36fc9SDavid van Moolenbroek 			rshd_errx(EXIT_FAILURE, "Can't make pipe. (%s)",
56293d36fc9SDavid van Moolenbroek 			    strerror(errno));
56393d36fc9SDavid van Moolenbroek 		pid = fork();
56493d36fc9SDavid van Moolenbroek 		if (pid == -1)
56593d36fc9SDavid van Moolenbroek 			rshd_errx(EXIT_FAILURE, "Can't fork. (%s)",
56693d36fc9SDavid van Moolenbroek 			    strerror(errno));
56793d36fc9SDavid van Moolenbroek 		if (pid) {
56893d36fc9SDavid van Moolenbroek 			(void)close(STDIN_FILENO);
56993d36fc9SDavid van Moolenbroek 			(void)close(STDOUT_FILENO);
57093d36fc9SDavid van Moolenbroek 			(void)close(STDERR_FILENO);
57193d36fc9SDavid van Moolenbroek 			(void)close(pv[1]);
57293d36fc9SDavid van Moolenbroek 
57393d36fc9SDavid van Moolenbroek 			set[0].fd = s;
57493d36fc9SDavid van Moolenbroek 			set[0].events = POLLIN;
57593d36fc9SDavid van Moolenbroek 			set[1].fd = pv[0];
57693d36fc9SDavid van Moolenbroek 			set[1].events = POLLIN;
57793d36fc9SDavid van Moolenbroek 			ioctl(pv[0], FIONBIO, (char *)&one);
57893d36fc9SDavid van Moolenbroek 
57993d36fc9SDavid van Moolenbroek 			/* should set s nbio! */
58093d36fc9SDavid van Moolenbroek 			do {
581*0a6a1f1dSLionel Sambuc #if defined(__minix)
58293d36fc9SDavid van Moolenbroek 				if (set[0].events == 0 && set[1].events == 0)
58393d36fc9SDavid van Moolenbroek 					break;
584*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) */
58593d36fc9SDavid van Moolenbroek 				if (poll(set, 2, INFTIM) < 0)
58693d36fc9SDavid van Moolenbroek 					break;
58793d36fc9SDavid van Moolenbroek 				if (set[0].revents & POLLIN) {
58893d36fc9SDavid van Moolenbroek 					int	ret;
58993d36fc9SDavid van Moolenbroek 
59093d36fc9SDavid van Moolenbroek 					ret = read(s, &sig, 1);
59193d36fc9SDavid van Moolenbroek 					if (ret <= 0)
59293d36fc9SDavid van Moolenbroek 						set[0].events = 0;
59393d36fc9SDavid van Moolenbroek 					else
59493d36fc9SDavid van Moolenbroek 						killpg(pid, sig);
59593d36fc9SDavid van Moolenbroek 				}
59693d36fc9SDavid van Moolenbroek 				if (set[1].revents & POLLIN) {
59793d36fc9SDavid van Moolenbroek 					errno = 0;
59893d36fc9SDavid van Moolenbroek 					cc = read(pv[0], buf, sizeof(buf));
59993d36fc9SDavid van Moolenbroek 					if (cc <= 0) {
60093d36fc9SDavid van Moolenbroek 						shutdown(s, SHUT_RDWR);
60193d36fc9SDavid van Moolenbroek 						set[1].events = 0;
60293d36fc9SDavid van Moolenbroek 					} else {
60393d36fc9SDavid van Moolenbroek 						(void)write(s, buf, cc);
60493d36fc9SDavid van Moolenbroek 					}
60593d36fc9SDavid van Moolenbroek 				}
60693d36fc9SDavid van Moolenbroek 
60793d36fc9SDavid van Moolenbroek 			} while ((set[0].revents | set[1].revents) & POLLIN);
60893d36fc9SDavid van Moolenbroek 			PAM_END;
60993d36fc9SDavid van Moolenbroek 			exit(EXIT_SUCCESS);
61093d36fc9SDavid van Moolenbroek 		}
61193d36fc9SDavid van Moolenbroek 		(void)close(s);
61293d36fc9SDavid van Moolenbroek 		(void)close(pv[0]);
61393d36fc9SDavid van Moolenbroek 		(void)dup2(pv[1], STDERR_FILENO);
61493d36fc9SDavid van Moolenbroek 		close(pv[1]);
61593d36fc9SDavid van Moolenbroek 	}
61693d36fc9SDavid van Moolenbroek #ifdef USE_PAM
61793d36fc9SDavid van Moolenbroek 	else {
61893d36fc9SDavid van Moolenbroek 		pid = fork();
61993d36fc9SDavid van Moolenbroek 		if (pid == -1)
62093d36fc9SDavid van Moolenbroek 			rshd_errx(EXIT_FAILURE, "Can't fork. (%s)",
62193d36fc9SDavid van Moolenbroek 			    strerror(errno));
62293d36fc9SDavid van Moolenbroek 		if (pid) {
62393d36fc9SDavid van Moolenbroek 			pid_t xpid;
62493d36fc9SDavid van Moolenbroek 			int status;
62593d36fc9SDavid van Moolenbroek 			if ((xpid = waitpid(pid, &status, 0)) != pid) {
62693d36fc9SDavid van Moolenbroek 				pam_err = pam_close_session(pamh, 0);
62793d36fc9SDavid van Moolenbroek 				if (pam_err != PAM_SUCCESS) {
62893d36fc9SDavid van Moolenbroek 					syslog(LOG_ERR,
62993d36fc9SDavid van Moolenbroek 					    "pam_close_session: %s",
63093d36fc9SDavid van Moolenbroek 					    pam_strerror(pamh, pam_err));
63193d36fc9SDavid van Moolenbroek 				}
63293d36fc9SDavid van Moolenbroek 				PAM_END;
63393d36fc9SDavid van Moolenbroek 				if (xpid != -1)
63493d36fc9SDavid van Moolenbroek 					syslog(LOG_WARNING,
63593d36fc9SDavid van Moolenbroek 					    "wrong PID: %d != %d", pid, xpid);
63693d36fc9SDavid van Moolenbroek 				else
63793d36fc9SDavid van Moolenbroek 					syslog(LOG_WARNING,
63893d36fc9SDavid van Moolenbroek 					    "wait pid=%d failed %m", pid);
63993d36fc9SDavid van Moolenbroek 				exit(EXIT_FAILURE);
64093d36fc9SDavid van Moolenbroek 			}
64193d36fc9SDavid van Moolenbroek 			exit(EXIT_SUCCESS);
64293d36fc9SDavid van Moolenbroek 		}
64393d36fc9SDavid van Moolenbroek 	}
64493d36fc9SDavid van Moolenbroek #endif
64593d36fc9SDavid van Moolenbroek 
64693d36fc9SDavid van Moolenbroek #ifdef F_CLOSEM
64793d36fc9SDavid van Moolenbroek 	(void)fcntl(STDERR_FILENO + 1, F_CLOSEM, 0);
64893d36fc9SDavid van Moolenbroek #else
64993d36fc9SDavid van Moolenbroek 	for (fd = getdtablesize(); fd > STDERR_FILENO; fd--)
65093d36fc9SDavid van Moolenbroek 		(void)close(fd);
65193d36fc9SDavid van Moolenbroek #endif
65293d36fc9SDavid van Moolenbroek 	if (setsid() == -1)
65393d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "setsid() failed: %m");
65493d36fc9SDavid van Moolenbroek #ifdef USE_PAM
65593d36fc9SDavid van Moolenbroek 	if (setlogin(pwd->pw_name) < 0)
65693d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "setlogin() failed: %m");
65793d36fc9SDavid van Moolenbroek 
65893d36fc9SDavid van Moolenbroek 	if (*pwd->pw_shell == '\0')
65993d36fc9SDavid van Moolenbroek 		pwd->pw_shell = __UNCONST(_PATH_BSHELL);
66093d36fc9SDavid van Moolenbroek 
66193d36fc9SDavid van Moolenbroek 	(void)pam_setenv(pamh, "HOME", pwd->pw_dir, 1);
66293d36fc9SDavid van Moolenbroek 	(void)pam_setenv(pamh, "SHELL", pwd->pw_shell, 1);
66393d36fc9SDavid van Moolenbroek 	(void)pam_setenv(pamh, "USER", pwd->pw_name, 1);
66493d36fc9SDavid van Moolenbroek 	(void)pam_setenv(pamh, "PATH", _PATH_DEFPATH, 1);
66593d36fc9SDavid van Moolenbroek 	environ = pam_getenvlist(pamh);
66693d36fc9SDavid van Moolenbroek 	(void)pam_end(pamh, pam_err);
66793d36fc9SDavid van Moolenbroek #else
66893d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
66993d36fc9SDavid van Moolenbroek 	{
67093d36fc9SDavid van Moolenbroek 		char *sh;
67193d36fc9SDavid van Moolenbroek 		if ((sh = login_getcapstr(lc, "shell", NULL, NULL))) {
67293d36fc9SDavid van Moolenbroek 			if(!(sh = strdup(sh))) {
67393d36fc9SDavid van Moolenbroek 				syslog(LOG_ERR, "Cannot alloc mem");
67493d36fc9SDavid van Moolenbroek 				exit(EXIT_FAILURE);
67593d36fc9SDavid van Moolenbroek 			}
67693d36fc9SDavid van Moolenbroek 			pwd->pw_shell = sh;
67793d36fc9SDavid van Moolenbroek 		}
67893d36fc9SDavid van Moolenbroek 	}
67993d36fc9SDavid van Moolenbroek #endif
68093d36fc9SDavid van Moolenbroek {
68193d36fc9SDavid van Moolenbroek 	static char *envinit[] = { NULL };
68293d36fc9SDavid van Moolenbroek 	environ = envinit;
68393d36fc9SDavid van Moolenbroek }
68493d36fc9SDavid van Moolenbroek 	setenv("PATH", _PATH_DEFPATH, 1);
68593d36fc9SDavid van Moolenbroek 	setenv("HOME", pwd->pw_dir, 1);
68693d36fc9SDavid van Moolenbroek 	setenv("SHELL", pwd->pw_shell, 1);
68793d36fc9SDavid van Moolenbroek 	setenv("USER", pwd->pw_name, 1);
68893d36fc9SDavid van Moolenbroek #endif
68993d36fc9SDavid van Moolenbroek 
69093d36fc9SDavid van Moolenbroek 	cp = strrchr(pwd->pw_shell, '/');
69193d36fc9SDavid van Moolenbroek 	if (cp)
69293d36fc9SDavid van Moolenbroek 		cp++;
69393d36fc9SDavid van Moolenbroek 	else
69493d36fc9SDavid van Moolenbroek 		cp = pwd->pw_shell;
69593d36fc9SDavid van Moolenbroek 
69693d36fc9SDavid van Moolenbroek #ifdef LOGIN_CAP
69793d36fc9SDavid van Moolenbroek 	if (setusercontext(lc, pwd, pwd->pw_uid,
69893d36fc9SDavid van Moolenbroek 		LOGIN_SETALL & ~LOGIN_SETGROUP) < 0) {
69993d36fc9SDavid van Moolenbroek 		syslog(LOG_ERR, "setusercontext(): %m");
70093d36fc9SDavid van Moolenbroek 		exit(EXIT_FAILURE);
70193d36fc9SDavid van Moolenbroek 	}
70293d36fc9SDavid van Moolenbroek 	login_close(lc);
70393d36fc9SDavid van Moolenbroek #else
70493d36fc9SDavid van Moolenbroek 	(void)setgid((gid_t)pwd->pw_gid);
70593d36fc9SDavid van Moolenbroek 	(void)setuid((uid_t)pwd->pw_uid);
70693d36fc9SDavid van Moolenbroek #endif
70793d36fc9SDavid van Moolenbroek 	endpwent();
70893d36fc9SDavid van Moolenbroek 	if (log_success || pwd->pw_uid == 0) {
70993d36fc9SDavid van Moolenbroek 		syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
71093d36fc9SDavid van Moolenbroek 		    remuser, hostname, locuser, cmdbuf);
71193d36fc9SDavid van Moolenbroek 	}
71293d36fc9SDavid van Moolenbroek 	(void)execl(pwd->pw_shell, cp, "-c", cmdbuf, NULL);
71393d36fc9SDavid van Moolenbroek 	rshd_errx(EXIT_FAILURE, "%s: %s", pwd->pw_shell, strerror(errno));
71493d36fc9SDavid van Moolenbroek badlogin:
71593d36fc9SDavid van Moolenbroek 	syslog(LOG_INFO|LOG_AUTH,
71693d36fc9SDavid van Moolenbroek 	    "%s@%s as %s: permission denied (%s). cmd='%.80s'",
71793d36fc9SDavid van Moolenbroek 	    remuser, hostname, locuser, errormsg, cmdbuf);
71893d36fc9SDavid van Moolenbroek 	rshd_errx(EXIT_FAILURE, errorstr, errorhost);
71993d36fc9SDavid van Moolenbroek }
72093d36fc9SDavid van Moolenbroek 
72193d36fc9SDavid van Moolenbroek /*
72293d36fc9SDavid van Moolenbroek  * Report error to client.  Note: can't be used until second socket has
72393d36fc9SDavid van Moolenbroek  * connected to client, or older clients will hang waiting for that
72493d36fc9SDavid van Moolenbroek  * connection first.
72593d36fc9SDavid van Moolenbroek  */
72693d36fc9SDavid van Moolenbroek 
72793d36fc9SDavid van Moolenbroek #include <stdarg.h>
72893d36fc9SDavid van Moolenbroek 
72993d36fc9SDavid van Moolenbroek static void
rshd_errx(int error,const char * fmt,...)73093d36fc9SDavid van Moolenbroek rshd_errx(int error, const char *fmt, ...)
73193d36fc9SDavid van Moolenbroek {
73293d36fc9SDavid van Moolenbroek 	va_list ap;
73393d36fc9SDavid van Moolenbroek 	int len, rv;
73493d36fc9SDavid van Moolenbroek 	char *bp, buf[BUFSIZ];
73593d36fc9SDavid van Moolenbroek 	va_start(ap, fmt);
73693d36fc9SDavid van Moolenbroek 	bp = buf;
73793d36fc9SDavid van Moolenbroek 	if (sent_null == 0) {
73893d36fc9SDavid van Moolenbroek 		*bp++ = 1;
73993d36fc9SDavid van Moolenbroek 		len = 1;
74093d36fc9SDavid van Moolenbroek 	} else
74193d36fc9SDavid van Moolenbroek 		len = 0;
74293d36fc9SDavid van Moolenbroek 	rv = vsnprintf(bp, sizeof(buf) - 2, fmt, ap);
74393d36fc9SDavid van Moolenbroek 	bp[rv++] = '\n';
74493d36fc9SDavid van Moolenbroek 	(void)write(STDERR_FILENO, buf, len + rv);
74593d36fc9SDavid van Moolenbroek 	va_end(ap);
74693d36fc9SDavid van Moolenbroek 	exit(error);
74793d36fc9SDavid van Moolenbroek }
74893d36fc9SDavid van Moolenbroek 
74993d36fc9SDavid van Moolenbroek static void
getstr(char * buf,int cnt,const char * err)75093d36fc9SDavid van Moolenbroek getstr(char *buf, int cnt, const char *err)
75193d36fc9SDavid van Moolenbroek {
75293d36fc9SDavid van Moolenbroek 	char c;
75393d36fc9SDavid van Moolenbroek 
75493d36fc9SDavid van Moolenbroek 	do {
75593d36fc9SDavid van Moolenbroek 		if (read(STDIN_FILENO, &c, 1) != 1)
75693d36fc9SDavid van Moolenbroek 			exit(EXIT_FAILURE);
75793d36fc9SDavid van Moolenbroek 		*buf++ = c;
75893d36fc9SDavid van Moolenbroek 		if (--cnt == 0)
75993d36fc9SDavid van Moolenbroek 			rshd_errx(EXIT_FAILURE, "%s too long", err);
76093d36fc9SDavid van Moolenbroek 	} while (c != 0);
76193d36fc9SDavid van Moolenbroek }
76293d36fc9SDavid van Moolenbroek 
76393d36fc9SDavid van Moolenbroek /*
76493d36fc9SDavid van Moolenbroek  * Check whether host h is in our local domain,
76593d36fc9SDavid van Moolenbroek  * defined as sharing the last two components of the domain part,
76693d36fc9SDavid van Moolenbroek  * or the entire domain part if the local domain has only one component.
76793d36fc9SDavid van Moolenbroek  * If either name is unqualified (contains no '.'),
76893d36fc9SDavid van Moolenbroek  * assume that the host is local, as it will be
76993d36fc9SDavid van Moolenbroek  * interpreted as such.
77093d36fc9SDavid van Moolenbroek  */
77193d36fc9SDavid van Moolenbroek static int
local_domain(char * h)77293d36fc9SDavid van Moolenbroek local_domain(char *h)
77393d36fc9SDavid van Moolenbroek {
77493d36fc9SDavid van Moolenbroek 	char localhost[MAXHOSTNAMELEN + 1];
77593d36fc9SDavid van Moolenbroek 	char *p1, *p2;
77693d36fc9SDavid van Moolenbroek 
77793d36fc9SDavid van Moolenbroek 	localhost[0] = 0;
77893d36fc9SDavid van Moolenbroek 	(void)gethostname(localhost, sizeof(localhost));
77993d36fc9SDavid van Moolenbroek 	localhost[sizeof(localhost) - 1] = '\0';
78093d36fc9SDavid van Moolenbroek 	p1 = topdomain(localhost);
78193d36fc9SDavid van Moolenbroek 	p2 = topdomain(h);
78293d36fc9SDavid van Moolenbroek 	if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
78393d36fc9SDavid van Moolenbroek 		return (1);
78493d36fc9SDavid van Moolenbroek 	return (0);
78593d36fc9SDavid van Moolenbroek }
78693d36fc9SDavid van Moolenbroek 
78793d36fc9SDavid van Moolenbroek static char *
topdomain(char * h)78893d36fc9SDavid van Moolenbroek topdomain(char *h)
78993d36fc9SDavid van Moolenbroek {
79093d36fc9SDavid van Moolenbroek 	char *p, *maybe = NULL;
79193d36fc9SDavid van Moolenbroek 	int dots = 0;
79293d36fc9SDavid van Moolenbroek 
79393d36fc9SDavid van Moolenbroek 	for (p = h + strlen(h); p >= h; p--) {
79493d36fc9SDavid van Moolenbroek 		if (*p == '.') {
79593d36fc9SDavid van Moolenbroek 			if (++dots == 2)
79693d36fc9SDavid van Moolenbroek 				return (p);
79793d36fc9SDavid van Moolenbroek 			maybe = p;
79893d36fc9SDavid van Moolenbroek 		}
79993d36fc9SDavid van Moolenbroek 	}
80093d36fc9SDavid van Moolenbroek 	return (maybe);
80193d36fc9SDavid van Moolenbroek }
80293d36fc9SDavid van Moolenbroek 
80393d36fc9SDavid van Moolenbroek static void
usage(void)80493d36fc9SDavid van Moolenbroek usage(void)
80593d36fc9SDavid van Moolenbroek {
80693d36fc9SDavid van Moolenbroek 
80793d36fc9SDavid van Moolenbroek 	syslog(LOG_ERR, "Usage: %s [-%s]", getprogname(), OPTIONS);
80893d36fc9SDavid van Moolenbroek 	exit(EXIT_FAILURE);
80993d36fc9SDavid van Moolenbroek }
810