inetd.c revision 98562
1139776Simp/*
21541Srgrimes * Copyright (c) 1983, 1991, 1993, 1994
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311541Srgrimes * SUCH DAMAGE.
3222521Sdyson */
331541Srgrimes
3422521Sdyson#ifndef lint
3522521Sdysonstatic const char copyright[] =
3622521Sdyson"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
3722521Sdyson	The Regents of the University of California.  All rights reserved.\n";
3822521Sdyson#endif /* not lint */
3950477Speter
401541Srgrimes#ifndef lint
411541Srgrimes#if 0
421541Srgrimesstatic char sccsid[] = "@(#)from: inetd.c	8.4 (Berkeley) 4/13/94";
431541Srgrimes#endif
441541Srgrimesstatic const char rcsid[] =
4577130Sru  "$FreeBSD: head/usr.sbin/inetd/inetd.c 98562 2002-06-21 11:42:37Z jmallett $";
461541Srgrimes#endif /* not lint */
4796755Strhodes
481541Srgrimes/*
4996755Strhodes * Inetd - Internet super-server
501541Srgrimes *
5135256Sdes * This program invokes all internet services as needed.  Connection-oriented
521541Srgrimes * services are invoked each time a connection is made, by creating a process.
531541Srgrimes * This process is passed the connection as file descriptor 0 and is expected
541541Srgrimes * to do a getpeername to find out the source host and port.
551541Srgrimes *
5696755Strhodes * Datagram oriented services are invoked when a datagram
571541Srgrimes * arrives; a process is created and passed a pending message
581541Srgrimes * on file descriptor 0.  Datagram servers may either connect
5996755Strhodes * to their peer, freeing up the original socket for inetd
601541Srgrimes * to receive further messages on, or ``take over the socket'',
611541Srgrimes * processing all arriving datagrams and, eventually, timing
621541Srgrimes * out.	 The first type of server is said to be ``multi-threaded'';
631541Srgrimes * the second type of server ``single-threaded''.
641541Srgrimes *
651541Srgrimes * Inetd uses a configuration file which is read at startup
661541Srgrimes * and, possibly, at some later time in response to a hangup signal.
671541Srgrimes * The configuration file is ``free format'' with fields given in the
6877130Sru * order shown below.  Continuation lines for an entry must begin with
6977130Sru * a space or tab.  All fields must be present in each entry.
701541Srgrimes *
711541Srgrimes *	service name			must be in /etc/services
721541Srgrimes *					or name a tcpmux service
731541Srgrimes *					or specify a unix domain socket
741541Srgrimes *	socket type			stream/dgram/raw/rdm/seqpacket
751541Srgrimes *	protocol			tcp[4][6][/faith,ttcp], udp[4][6], unix
761541Srgrimes *	wait/nowait			single-threaded/multi-threaded
771541Srgrimes *	user				user to run daemon as
7896755Strhodes *	server program			full path name
791541Srgrimes *	server program arguments	maximum of MAXARGS (20)
801541Srgrimes *
8126963Salex * TCP services without official port numbers are handled with the
821541Srgrimes * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
831541Srgrimes * requests. When a connection is made from a foreign host, the service
841541Srgrimes * requested is passed to tcpmux, which looks it up in the servtab list
851541Srgrimes * and returns the proper entry for the service. Tcpmux returns a
861541Srgrimes * negative reply if the service doesn't exist, otherwise the invoked
871541Srgrimes * server is expected to return the positive reply if the service type in
881541Srgrimes * inetd.conf file has the prefix "tcpmux/". If the service type has the
891541Srgrimes * prefix "tcpmux/+", tcpmux will return the positive reply for the
901541Srgrimes * process; this is for compatibility with older server code, and also
911541Srgrimes * allows you to invoke programs that use stdin/stdout without putting any
9222521Sdyson * special server code in them. Services that use tcpmux are "nowait"
9322521Sdyson * because they do not have a well-known port and hence cannot listen
9422521Sdyson * for new requests.
9522521Sdyson *
9622521Sdyson * For RPC services
971541Srgrimes *	service name/version		must be in /etc/rpc
9822521Sdyson *	socket type			stream/dgram/raw/rdm/seqpacket
9922521Sdyson *	protocol			rpc/tcp, rpc/udp
10022521Sdyson *	wait/nowait			single-threaded/multi-threaded
10122521Sdyson *	user				user to run daemon as
10222521Sdyson *	server program			full path name
10322521Sdyson *	server program arguments	maximum of MAXARGS
10422521Sdyson *
10522521Sdyson * Comment lines are indicated by a `#' in column 1.
10622521Sdyson *
1071541Srgrimes * #ifdef IPSEC
1081541Srgrimes * Comment lines that start with "#@" denote IPsec policy string, as described
1091541Srgrimes * in ipsec_set_policy(3).  This will affect all the following items in
1101541Srgrimes * inetd.conf(8).  To reset the policy, just use "#@" line.  By default,
1111541Srgrimes * there's no IPsec policy.
1121541Srgrimes * #endif
1131541Srgrimes */
1141541Srgrimes#include <sys/param.h>
1151541Srgrimes#include <sys/ioctl.h>
1161541Srgrimes#include <sys/wait.h>
1171541Srgrimes#include <sys/time.h>
1181541Srgrimes#include <sys/resource.h>
1191541Srgrimes#include <sys/stat.h>
1201541Srgrimes#include <sys/un.h>
1218876Srgrimes
1221541Srgrimes#include <netinet/in.h>
1231541Srgrimes#include <netinet/tcp.h>
1241541Srgrimes#include <arpa/inet.h>
1251541Srgrimes#include <rpc/rpc.h>
12677130Sru#include <rpc/pmap_clnt.h>
1271541Srgrimes
1281541Srgrimes#include <errno.h>
1291541Srgrimes#include <err.h>
1301541Srgrimes#include <fcntl.h>
1318876Srgrimes#include <grp.h>
1321541Srgrimes#include <netdb.h>
1331541Srgrimes#include <pwd.h>
1341541Srgrimes#include <signal.h>
1351541Srgrimes#include <stdio.h>
1361541Srgrimes#include <stdlib.h>
1371541Srgrimes#include <string.h>
1381541Srgrimes#include <syslog.h>
1391541Srgrimes#include <tcpd.h>
14096755Strhodes#include <unistd.h>
1411541Srgrimes#include <libutil.h>
1421541Srgrimes#include <sysexits.h>
1431541Srgrimes#include <ctype.h>
1441541Srgrimes
1458876Srgrimes#include "inetd.h"
1461541Srgrimes#include "pathnames.h"
1471541Srgrimes
1481541Srgrimes#ifdef IPSEC
1491541Srgrimes#include <netinet6/ipsec.h>
1501541Srgrimes#ifndef IPSEC_POLICY_IPSEC	/* no ipsec support on old ipsec */
1518876Srgrimes#undef IPSEC
1521541Srgrimes#endif
1531541Srgrimes#endif
1541541Srgrimes
1551541Srgrimes/* wrapper for KAME-special getnameinfo() */
156108470Sschweikh#ifndef NI_WITHSCOPEID
1571541Srgrimes#define NI_WITHSCOPEID	0
1581541Srgrimes#endif
1591541Srgrimes
16026964Salex#ifndef LIBWRAP_ALLOW_FACILITY
1611541Srgrimes# define LIBWRAP_ALLOW_FACILITY LOG_AUTH
1621541Srgrimes#endif
1631541Srgrimes#ifndef LIBWRAP_ALLOW_SEVERITY
16426964Salex# define LIBWRAP_ALLOW_SEVERITY LOG_INFO
1651541Srgrimes#endif
1661541Srgrimes#ifndef LIBWRAP_DENY_FACILITY
1671541Srgrimes# define LIBWRAP_DENY_FACILITY LOG_AUTH
16826964Salex#endif
1691541Srgrimes#ifndef LIBWRAP_DENY_SEVERITY
1701541Srgrimes# define LIBWRAP_DENY_SEVERITY LOG_WARNING
1711541Srgrimes#endif
1721541Srgrimes
1731541Srgrimes#define ISWRAP(sep)	\
17476166Smarkm	   ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \
1752960Swollman	&& (sep->se_family == AF_INET || sep->se_family == AF_INET6) \
17676166Smarkm	&& ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \
17776166Smarkm	    || (sep)->se_socktype == SOCK_DGRAM))
17876166Smarkm
17976166Smarkm#ifdef LOGIN_CAP
18076166Smarkm#include <login_cap.h>
18112769Sphk
1821541Srgrimes/* see init.c */
18376166Smarkm#define RESOURCE_RC "daemon"
18477031Sru
1851541Srgrimes#endif
18666356Sbp
18766356Sbp#ifndef	MAXCHILD
18866356Sbp#define	MAXCHILD	-1		/* maximum number of this service
18966356Sbp					   < 0 = no limit */
19066356Sbp#endif
19112769Sphk
19212769Sphk#ifndef	MAXCPM
19312769Sphk#define	MAXCPM		-1		/* rate limit invocations from a
1941541Srgrimes					   single remote address,
1951541Srgrimes					   < 0 = no limit */
1961541Srgrimes#endif
1971541Srgrimes
1981541Srgrimes#ifndef TOOMANY
1991541Srgrimes#define	TOOMANY		256		/* don't start more than TOOMANY */
2001541Srgrimes#endif
2011541Srgrimes#define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
2021541Srgrimes#define	RETRYTIME	(60*10)		/* retry after bind or server fail */
2031541Srgrimes#define MAX_MAXCHLD	32767		/* max allowable max children */
2041541Srgrimes
2051541Srgrimes#define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
2061541Srgrimes
2071541Srgrimesvoid		close_sep(struct servtab *);
2081541Srgrimesvoid		flag_signal(int);
2091541Srgrimesvoid		flag_config(int);
2101541Srgrimesvoid		config(void);
2111541Srgrimesint		cpmip(const struct servtab *, int);
2121541Srgrimesvoid		endconfig(void);
2131541Srgrimesstruct servtab *enter(struct servtab *);
2141541Srgrimesvoid		freeconfig(struct servtab *);
2151541Srgrimesstruct servtab *getconfigent(void);
2161541Srgrimesint		matchservent(const char *, const char *, const char *);
2171541Srgrimeschar	       *nextline(FILE *);
2188876Srgrimesvoid		addchild(struct servtab *, int);
21922521Sdysonvoid		flag_reapchild(int);
220140728Sphkvoid		reapchild(void);
2211541Srgrimesvoid		enable(struct servtab *);
222140732Sphkvoid		disable(struct servtab *);
2231541Srgrimesvoid		flag_retry(int);
2241541Srgrimesvoid		retry(void);
2251541Srgrimesint		setconfig(void);
2261541Srgrimesvoid		setup(struct servtab *);
2271541Srgrimes#ifdef IPSEC
2281541Srgrimesvoid		ipsecsetup(struct servtab *);
2291541Srgrimes#endif
2301541Srgrimesvoid		unregisterrpc(register struct servtab *sep);
2311541Srgrimes
2321541Srgrimesint	allow_severity;
23350616Sbdeint	deny_severity;
2341541Srgrimesint	wrap_ex = 0;
2351541Srgrimesint	wrap_bi = 0;
2361541Srgrimesint	debug = 0;
2371541Srgrimesint	log = 0;
2381541Srgrimesint	maxsock;			/* highest-numbered descriptor */
23950616Sbdefd_set	allsock;
2401541Srgrimesint	options;
2411541Srgrimesint	timingout;
2421541Srgrimesint	toomany = TOOMANY;
2431541Srgrimesint	maxchild = MAXCHILD;
2441541Srgrimesint	maxcpm = MAXCPM;
2451541Srgrimesstruct	servent *sp;
2461541Srgrimesstruct	rpcent *rpc;
2471541Srgrimeschar	*hostname = NULL;
2481541Srgrimesstruct	sockaddr_in *bind_sa4;
2491541Srgrimesint	no_v4bind = 1;
2501541Srgrimes#ifdef INET6
2518876Srgrimesstruct	sockaddr_in6 *bind_sa6;
2521541Srgrimesint	no_v6bind = 1;
2531541Srgrimes#endif
2541541Srgrimesint	signalpipe[2];
2551541Srgrimes#ifdef SANITY_CHECK
2561541Srgrimesint	nsock;
2571541Srgrimes#endif
25824987Skatouid_t	euid;
259138290Sphkgid_t	egid;
26024987Skatomode_t	mask;
2611541Srgrimes
2621541Srgrimesstruct	servtab *servtab;
2631541Srgrimes
2641541Srgrimesextern struct biltin biltins[];
2651541Srgrimes
2661541Srgrimes#define NUMINT	(sizeof(intab) / sizeof(struct inent))
2671541Srgrimesconst char	*CONFIG = _PATH_INETDCONF;
2681541Srgrimesconst char	*pid_file = _PATH_INETDPID;
26966356Sbp
2701541Srgrimesint
2711541Srgrimesgetvalue(const char *arg, int *value, const char *whine)
2728876Srgrimes{
2731541Srgrimes	int  tmp;
2741541Srgrimes	char *p;
2751541Srgrimes
2761541Srgrimes	tmp = strtol(arg, &p, 0);
2771541Srgrimes	if (tmp < 0 || *p) {
2781541Srgrimes		syslog(LOG_ERR, whine, arg);
27966356Sbp		return 1;			/* failure */
280140165Sphk	}
28166356Sbp	*value = tmp;
28266356Sbp	return 0;				/* success */
28366356Sbp}
28466356Sbp
2851541Srgrimesint
2861541Srgrimesmain(int argc, char **argv)
2871541Srgrimes{
2881541Srgrimes	struct servtab *sep;
2891541Srgrimes	struct passwd *pwd;
2901541Srgrimes	struct group *grp;
2911541Srgrimes	struct sigaction sa, saalrm, sachld, sahup, sapipe;
2921541Srgrimes	int tmpint, ch, dofork;
2931541Srgrimes	pid_t pid;
2941541Srgrimes	char buf[50];
2951541Srgrimes#ifdef LOGIN_CAP
2961541Srgrimes	login_cap_t *lc = NULL;
29766356Sbp#endif
29866356Sbp	struct request_info req;
299175294Sattilio	int denied;
30066356Sbp	char *service = NULL;
30166356Sbp	union {
3021541Srgrimes		struct sockaddr peer_un;
3031541Srgrimes		struct sockaddr_in peer_un4;
3041541Srgrimes		struct sockaddr_in6 peer_un6;
3051541Srgrimes		struct sockaddr_storage peer_max;
3061541Srgrimes	} p_un;
3071541Srgrimes#define peer	p_un.peer_un
3081541Srgrimes#define peer4	p_un.peer_un4
3091541Srgrimes#define peer6	p_un.peer_un6
3101541Srgrimes#define peermax	p_un.peer_max
3111541Srgrimes	int i;
3121541Srgrimes	struct addrinfo hints, *res;
3131541Srgrimes	const char *servname;
3141541Srgrimes	int error;
3151541Srgrimes
3161541Srgrimes	openlog("inetd", LOG_PID | LOG_NOWAIT | LOG_PERROR, LOG_DAEMON);
3171541Srgrimes
3181541Srgrimes	while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:")) != -1)
3191541Srgrimes		switch(ch) {
3201541Srgrimes		case 'd':
3211541Srgrimes			debug = 1;
3221541Srgrimes			options |= SO_DEBUG;
3231541Srgrimes			break;
32429584Sphk		case 'l':
32598183Ssemenu			log = 1;
3261541Srgrimes			break;
3271541Srgrimes		case 'R':
3281541Srgrimes			getvalue(optarg, &toomany,
3291541Srgrimes				"-R %s: bad value for service invocation rate");
3301541Srgrimes			break;
3311541Srgrimes		case 'c':
33222521Sdyson			getvalue(optarg, &maxchild,
33322521Sdyson				"-c %s: bad value for maximum children");
33422521Sdyson			break;
33522521Sdyson		case 'C':
33622521Sdyson			getvalue(optarg, &maxcpm,
33722521Sdyson				"-C %s: bad value for maximum children/minute");
338140728Sphk			break;
33922521Sdyson		case 'a':
34022521Sdyson			hostname = optarg;
34166356Sbp			break;
34222521Sdyson		case 'p':
34366356Sbp			pid_file = optarg;
34422521Sdyson			break;
3451541Srgrimes		case 'w':
34666356Sbp			wrap_ex++;
34722521Sdyson			break;
34822521Sdyson		case 'W':
34966356Sbp			wrap_bi++;
35066356Sbp			break;
35166356Sbp		case '?':
35266356Sbp		default:
35366356Sbp			syslog(LOG_ERR,
35466356Sbp				"usage: inetd [-dlwW] [-a address] [-R rate]"
35566356Sbp				" [-c maximum] [-C rate]"
35622521Sdyson				" [-p pidfile] [conf-file]");
35766356Sbp			exit(EX_USAGE);
35822521Sdyson		}
35922521Sdyson	/*
36066356Sbp	 * Initialize Bind Addrs.
36166356Sbp	 *   When hostname is NULL, wild card bind addrs are obtained from
36266356Sbp	 *   getaddrinfo(). But getaddrinfo() requires at least one of
36366356Sbp	 *   hostname or servname is non NULL.
36466356Sbp	 *   So when hostname is NULL, set dummy value to servname.
36566356Sbp	 */
36666356Sbp	servname = (hostname == NULL) ? "discard" /* dummy */ : NULL;
36798183Ssemenu
368229431Skib	bzero(&hints, sizeof(struct addrinfo));
369185335Skib	hints.ai_flags = AI_PASSIVE;
37066356Sbp	hints.ai_family = AF_UNSPEC;
37122521Sdyson	error = getaddrinfo(hostname, servname, &hints, &res);
37222521Sdyson	if (error != 0) {
37322521Sdyson		syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error));
37422521Sdyson		if (error == EAI_SYSTEM)
375140776Sphk			syslog(LOG_ERR, "%s", strerror(errno));
376140776Sphk		exit(EX_USAGE);
377140776Sphk	}
378140776Sphk	do {
379140776Sphk		if (res->ai_addr == NULL) {
380140776Sphk			syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname);
381140776Sphk			exit(EX_USAGE);
382140776Sphk		}
383140776Sphk		switch (res->ai_addr->sa_family) {
384140776Sphk		case AF_INET:
385140776Sphk			if (no_v4bind == 0)
386140776Sphk				continue;
387140776Sphk			bind_sa4 = (struct sockaddr_in *)res->ai_addr;
388140776Sphk			/* init port num in case servname is dummy */
3891541Srgrimes			bind_sa4->sin_port = 0;
39022521Sdyson			no_v4bind = 0;
39122521Sdyson			continue;
392105211Sphk#ifdef INET6
393140728Sphk		case AF_INET6:
39422521Sdyson			if (no_v6bind == 0)
39522521Sdyson				continue;
39622521Sdyson			bind_sa6 = (struct sockaddr_in6 *)res->ai_addr;
39722521Sdyson			/* init port num in case servname is dummy */
39822521Sdyson			bind_sa6->sin6_port = 0;
39922597Smpp			no_v6bind = 0;
40022597Smpp			continue;
40122521Sdyson#endif
40222521Sdyson		}
40322521Sdyson		if (no_v4bind == 0
40422521Sdyson#ifdef INET6
40522521Sdyson		    && no_v6bind == 0
40622521Sdyson#endif
40722521Sdyson		    )
40822521Sdyson			break;
40922521Sdyson	} while ((res = res->ai_next) != NULL);
41022521Sdyson	if (no_v4bind != 0
41136840Speter#ifdef INET6
41236840Speter	    && no_v6bind != 0
41322521Sdyson#endif
41422521Sdyson	    ) {
41522521Sdyson		syslog(LOG_ERR, "-a %s: unknown address family", hostname);
41622521Sdyson		exit(EX_USAGE);
41722521Sdyson	}
41822521Sdyson
41922521Sdyson	euid = geteuid();
42022521Sdyson	egid = getegid();
42122521Sdyson	umask(mask = umask(0777));
42222521Sdyson
42322521Sdyson	argc -= optind;
42422521Sdyson	argv += optind;
42566356Sbp
42622607Smpp	if (argc > 0)
42722521Sdyson		CONFIG = argv[0];
42822521Sdyson	if (debug == 0) {
42922521Sdyson		FILE *fp;
4301541Srgrimes		if (daemon(0, 0) < 0) {
4311541Srgrimes			syslog(LOG_WARNING, "daemon(0,0) failed: %m");
43212769Sphk		}
433140728Sphk		/* From now on we don't want syslog messages going to stderr. */
4341541Srgrimes		closelog();
4351541Srgrimes		openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
43622521Sdyson		/*
43743311Sdillon		 * In case somebody has started inetd manually, we need to
4381541Srgrimes		 * clear the logname, so that old servers run as root do not
43965467Sbp		 * get the user's logname..
44065467Sbp		 */
4411541Srgrimes		if (setlogin("") < 0) {
4421541Srgrimes			syslog(LOG_WARNING, "cannot clear logname: %m");
4431541Srgrimes			/* no big deal if it fails.. */
44466356Sbp		}
44566356Sbp		pid = getpid();
44666356Sbp		fp = fopen(pid_file, "w");
44722521Sdyson		if (fp) {
448140728Sphk			fprintf(fp, "%ld\n", (long)pid);
44922521Sdyson			fclose(fp);
45022521Sdyson		} else {
451184413Strasz			syslog(LOG_WARNING, "%s: %m", pid_file);
4521541Srgrimes		}
45322521Sdyson	}
45422521Sdyson	sa.sa_flags = 0;
45522521Sdyson	sigemptyset(&sa.sa_mask);
45696755Strhodes	sigaddset(&sa.sa_mask, SIGALRM);
45722521Sdyson	sigaddset(&sa.sa_mask, SIGCHLD);
458184413Strasz	sigaddset(&sa.sa_mask, SIGHUP);
45922521Sdyson	sa.sa_handler = flag_retry;
46022521Sdyson	sigaction(SIGALRM, &sa, &saalrm);
46122521Sdyson	config();
46222521Sdyson	sa.sa_handler = flag_config;
46322521Sdyson	sigaction(SIGHUP, &sa, &sahup);
46422521Sdyson	sa.sa_handler = flag_reapchild;
46522521Sdyson	sigaction(SIGCHLD, &sa, &sachld);
46643305Sdillon	sa.sa_handler = SIG_IGN;
46743305Sdillon	sigaction(SIGPIPE, &sa, &sapipe);
46822521Sdyson
46922521Sdyson	{
47022607Smpp		/* space for daemons to overwrite environment for ps */
47122521Sdyson#define	DUMMYSIZE	100
47222521Sdyson		char dummy[DUMMYSIZE];
473193092Strasz
474193092Strasz		(void)memset(dummy, 'x', DUMMYSIZE - 1);
475193092Strasz		dummy[DUMMYSIZE - 1] = '\0';
476193092Strasz		(void)setenv("inetd_dummy", dummy, 1);
477193092Strasz	}
478193092Strasz
479193092Strasz	if (pipe(signalpipe) != 0) {
480193092Strasz		syslog(LOG_ERR, "pipe: %m");
481193092Strasz		exit(EX_OSERR);
482193092Strasz	}
483193092Strasz	FD_SET(signalpipe[0], &allsock);
484193092Strasz#ifdef SANITY_CHECK
485193092Strasz	nsock++;
486193092Strasz#endif
487193092Strasz	if (signalpipe[0] > maxsock)
488193092Strasz	    maxsock = signalpipe[0];
489193092Strasz	if (signalpipe[1] > maxsock)
490193092Strasz	    maxsock = signalpipe[1];
491193092Strasz
492193092Strasz	for (;;) {
493193092Strasz	    int n, ctrl;
494193092Strasz	    fd_set readable;
495193092Strasz
496193092Strasz#ifdef SANITY_CHECK
497193092Strasz	    if (nsock == 0) {
498193092Strasz		syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
49922521Sdyson		exit(EX_SOFTWARE);
500212043Srmacklem	    }
501212043Srmacklem#endif
502212043Srmacklem	    readable = allsock;
503212043Srmacklem	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
504212043Srmacklem		(fd_set *)0, (struct timeval *)0)) <= 0) {
505212043Srmacklem		    if (n < 0 && errno != EINTR) {
506212043Srmacklem			syslog(LOG_WARNING, "select: %m");
507212043Srmacklem			sleep(1);
508212043Srmacklem		    }
509212043Srmacklem		    continue;
510212043Srmacklem	    }
511212043Srmacklem	    /* handle any queued signal flags */
512212043Srmacklem	    if (FD_ISSET(signalpipe[0], &readable)) {
513212043Srmacklem		int nsig;
514212043Srmacklem		if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) {
515212043Srmacklem		    syslog(LOG_ERR, "ioctl: %m");
516212043Srmacklem		    exit(EX_OSERR);
517212043Srmacklem		}
518212043Srmacklem		while (--nsig >= 0) {
519212043Srmacklem		    char c;
520212043Srmacklem		    if (read(signalpipe[0], &c, 1) != 1) {
521212043Srmacklem			syslog(LOG_ERR, "read: %m");
522212043Srmacklem			exit(EX_OSERR);
523212043Srmacklem		    }
524212043Srmacklem		    if (debug)
525212043Srmacklem			warnx("handling signal flag %c", c);
52665467Sbp		    switch(c) {
52765467Sbp		    case 'A': /* sigalrm */
52865467Sbp			retry();
52965467Sbp			break;
53065467Sbp		    case 'C': /* sigchld */
531140728Sphk			reapchild();
53265467Sbp			break;
53365467Sbp		    case 'H': /* sighup */
53465467Sbp			config();
53565467Sbp			break;
53665467Sbp		    }
53765467Sbp		}
53865467Sbp	    }
53965467Sbp	    for (sep = servtab; n && sep; sep = sep->se_next)
54065467Sbp	        if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
54165467Sbp		    n--;
54265467Sbp		    if (debug)
54365467Sbp			    warnx("someone wants %s", sep->se_service);
54465467Sbp		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM) {
54565467Sbp			    i = 1;
54665467Sbp			    if (ioctl(sep->se_fd, FIONBIO, &i) < 0)
54765467Sbp				    syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m");
54865467Sbp			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
54965467Sbp				(socklen_t *)0);
55065467Sbp			    if (debug)
55165467Sbp				    warnx("accept, ctrl %d", ctrl);
55265467Sbp			    if (ctrl < 0) {
55365467Sbp				    if (errno != EINTR)
55465467Sbp					    syslog(LOG_WARNING,
55565467Sbp						"accept (for %s): %m",
55622521Sdyson						sep->se_service);
55722521Sdyson                                      if (sep->se_accept &&
55822521Sdyson                                          sep->se_socktype == SOCK_STREAM)
55922521Sdyson                                              close(ctrl);
56022597Smpp				    continue;
561169671Skib			    }
56222521Sdyson			    i = 0;
56366356Sbp			    if (ioctl(sep->se_fd, FIONBIO, &i) < 0)
56466356Sbp				    syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m");
565143642Sjeff			    if (ioctl(ctrl, FIONBIO, &i) < 0)
56666356Sbp				    syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m");
56766356Sbp			    if (cpmip(sep, ctrl) < 0) {
56822521Sdyson				close(ctrl);
56966356Sbp				continue;
570143513Sjeff			    }
571143513Sjeff		    } else
572143642Sjeff			    ctrl = sep->se_fd;
573143513Sjeff		    if (log && !ISWRAP(sep)) {
574143642Sjeff			    char pname[INET6_ADDRSTRLEN] = "unknown";
575143642Sjeff			    socklen_t sl;
576143642Sjeff			    sl = sizeof peermax;
577143642Sjeff			    if (getpeername(ctrl, (struct sockaddr *)
578143642Sjeff					    &peermax, &sl)) {
579143642Sjeff				    sl = sizeof peermax;
580143642Sjeff				    if (recvfrom(ctrl, buf, sizeof(buf),
581145424Sjeff					MSG_PEEK,
582116469Stjr					(struct sockaddr *)&peermax,
58366356Sbp					&sl) >= 0) {
584143642Sjeff				      getnameinfo((struct sockaddr *)&peermax,
585143642Sjeff						  peer.sa_len,
586143642Sjeff						  pname, sizeof(pname),
587143642Sjeff						  NULL, 0,
588143642Sjeff						  NI_NUMERICHOST|
589143642Sjeff						  NI_WITHSCOPEID);
590143642Sjeff				    }
591143642Sjeff			    } else {
592143642Sjeff			            getnameinfo((struct sockaddr *)&peermax,
59366356Sbp						peer.sa_len,
594143642Sjeff						pname, sizeof(pname),
595175294Sattilio						NULL, 0,
596150181Skan						NI_NUMERICHOST|
597150181Skan						NI_WITHSCOPEID);
598150181Skan			    }
599150181Skan			    syslog(LOG_INFO,"%s from %s", sep->se_service, pname);
600150181Skan		    }
601150181Skan		    (void) sigblock(SIGBLOCK);
602150181Skan		    pid = 0;
603150181Skan		    /*
604150181Skan		     * Fork for all external services, builtins which need to
605150181Skan		     * fork and anything we're wrapping (as wrapping might
606150181Skan		     * block or use hosts_options(5) twist).
607150181Skan		     */
608150181Skan		    dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep);
609150181Skan		    if (dofork) {
610150181Skan			    if (sep->se_count++ == 0)
611150181Skan				(void)gettimeofday(&sep->se_time, (struct timezone *)NULL);
612150181Skan			    else if (toomany > 0 && sep->se_count >= toomany) {
613150181Skan				struct timeval now;
614150181Skan
615150181Skan				(void)gettimeofday(&now, (struct timezone *)NULL);
616150181Skan				if (now.tv_sec - sep->se_time.tv_sec >
617175294Sattilio				    CNT_INTVL) {
618150181Skan					sep->se_time = now;
619150181Skan					sep->se_count = 1;
620143642Sjeff				} else {
621143642Sjeff					syslog(LOG_ERR,
622143642Sjeff			"%s/%s server failing (looping), service terminated",
623143642Sjeff					    sep->se_service, sep->se_proto);
624143642Sjeff					if (sep->se_accept &&
62522521Sdyson					    sep->se_socktype == SOCK_STREAM)
62622521Sdyson						close(ctrl);
62722521Sdyson					close_sep(sep);
62822521Sdyson					sigsetmask(0L);
62922521Sdyson					if (!timingout) {
63022521Sdyson						timingout = 1;
63122521Sdyson						alarm(RETRYTIME);
63222597Smpp					}
633140728Sphk					continue;
63422521Sdyson				}
63566356Sbp			    }
63666356Sbp			    pid = fork();
637172644Sdaichi		    }
638143642Sjeff		    if (pid < 0) {
63966570Sbp			    syslog(LOG_ERR, "fork: %m");
640143642Sjeff			    if (sep->se_accept &&
64166356Sbp				sep->se_socktype == SOCK_STREAM)
642172644Sdaichi				    close(ctrl);
643172644Sdaichi			    sigsetmask(0L);
644172644Sdaichi			    sleep(1);
645172644Sdaichi			    continue;
646172644Sdaichi		    }
64766356Sbp		    if (pid)
648143642Sjeff			addchild(sep, pid);
649172644Sdaichi		    sigsetmask(0L);
650172644Sdaichi		    if (pid == 0) {
651172644Sdaichi			    if (dofork) {
652172644Sdaichi				if (debug)
653172644Sdaichi					warnx("+ closing from %d", maxsock);
654175294Sattilio				for (tmpint = maxsock; tmpint > 2; tmpint--)
655172644Sdaichi					if (tmpint != ctrl)
656172644Sdaichi						(void) close(tmpint);
657172644Sdaichi				sigaction(SIGALRM, &saalrm, (struct sigaction *)0);
658172644Sdaichi				sigaction(SIGCHLD, &sachld, (struct sigaction *)0);
659172644Sdaichi				sigaction(SIGHUP, &sahup, (struct sigaction *)0);
660172644Sdaichi				/* SIGPIPE reset before exec */
661143642Sjeff			    }
662172644Sdaichi			    /*
663143642Sjeff			     * Call tcpmux to find the real service to exec.
664143642Sjeff			     */
66522521Sdyson			    if (sep->se_bi &&
66622521Sdyson				sep->se_bi->bi_fn == (bi_fn_t *) tcpmux) {
66766356Sbp				    sep = tcpmux(ctrl);
66866356Sbp				    if (sep == NULL) {
669182943Sed					    close(ctrl);
67066356Sbp					    _exit(0);
67198183Ssemenu				    }
67298183Ssemenu			    }
673218965Sbrucec			    if (ISWRAP(sep)) {
67498183Ssemenu				inetd_setproctitle("wrapping", ctrl);
67598183Ssemenu				service = sep->se_server_name ?
67666356Sbp				    sep->se_server_name : sep->se_service;
67766356Sbp				request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, NULL);
678140728Sphk				fromhost(&req);
6791541Srgrimes				deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
68030636Sroberto				allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
68198175Ssemenu				denied = !hosts_access(&req);
68292540Smckusick				if (denied) {
683141447Sphk				    syslog(deny_severity,
68498175Ssemenu				        "refused connection from %.500s, service %s (%s%s)",
68592540Smckusick				        eval_client(&req), service, sep->se_proto,
68692540Smckusick					(((struct sockaddr *)req.client->sin)->sa_family == AF_INET6 && !IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)req.client->sin)->sin6_addr)) ? "6" : "");
68792540Smckusick				    if (sep->se_socktype != SOCK_STREAM)
68892540Smckusick					recv(ctrl, buf, sizeof (buf), 0);
689140936Sphk				    if (dofork) {
69098175Ssemenu					sleep(1);
69192540Smckusick					_exit(0);
69292540Smckusick				    }
69392540Smckusick				}
69492540Smckusick				if (log) {
69598183Ssemenu				    syslog(allow_severity,
69692540Smckusick				        "connection from %.500s, service %s (%s%s)",
69792540Smckusick					eval_client(&req), service, sep->se_proto,
698140728Sphk					(((struct sockaddr *)req.client->sin)->sa_family == AF_INET6 && !IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)req.client->sin)->sin6_addr)) ? "6" : "");
69992540Smckusick				}
70092540Smckusick			    }
70130636Sroberto			    if (sep->se_bi) {
70230636Sroberto				(*sep->se_bi->bi_fn)(ctrl, sep);
70366356Sbp			    } else {
704155899Sjeff				if (debug)
705155899Sjeff					warnx("%d execl %s",
706143744Sjeff						getpid(), sep->se_server);
707143744Sjeff				dup2(ctrl, 0);
708143744Sjeff				close(ctrl);
709143744Sjeff				dup2(0, 1);
710193172Skib				dup2(0, 2);
711143744Sjeff				if ((pwd = getpwnam(sep->se_user)) == NULL) {
712143744Sjeff					syslog(LOG_ERR,
713155899Sjeff					    "%s/%s: %s: no such user",
714150181Skan						sep->se_service, sep->se_proto,
715193172Skib						sep->se_user);
716193172Skib					if (sep->se_socktype != SOCK_STREAM)
717149722Sssouhlal						recv(0, buf, sizeof (buf), 0);
718193172Skib					_exit(EX_NOUSER);
719182943Sed				}
720184205Sdes				grp = NULL;
72166356Sbp				if (   sep->se_group != NULL
7221541Srgrimes				    && (grp = getgrnam(sep->se_group)) == NULL
7231541Srgrimes				   ) {
7241541Srgrimes					syslog(LOG_ERR,
72512769Sphk					    "%s/%s: %s: no such group",
726140728Sphk						sep->se_service, sep->se_proto,
7271541Srgrimes						sep->se_group);
728140732Sphk					if (sep->se_socktype != SOCK_STREAM)
729155899Sjeff						recv(0, buf, sizeof (buf), 0);
730227696Skib					_exit(EX_NOUSER);
7311541Srgrimes				}
7321541Srgrimes				if (grp != NULL)
7331541Srgrimes					pwd->pw_gid = grp->gr_gid;
734156585Sjeff#ifdef LOGIN_CAP
735156585Sjeff				if ((lc = login_getclass(sep->se_class)) == NULL) {
736156585Sjeff					/* error syslogged by getclass */
737156585Sjeff					syslog(LOG_ERR,
738156585Sjeff					    "%s/%s: %s: login class error",
739156585Sjeff						sep->se_service, sep->se_proto,
740156585Sjeff						sep->se_class);
741156585Sjeff					if (sep->se_socktype != SOCK_STREAM)
742156585Sjeff						recv(0, buf, sizeof (buf), 0);
743156585Sjeff					_exit(EX_NOUSER);
744156585Sjeff				}
745156585Sjeff#endif
746156585Sjeff				if (setsid() < 0) {
747156585Sjeff					syslog(LOG_ERR,
748156585Sjeff						"%s: can't setsid(): %m",
749156585Sjeff						 sep->se_service);
750156585Sjeff					/* _exit(EX_OSERR); not fatal yet */
751156585Sjeff				}
752156585Sjeff#ifdef LOGIN_CAP
753156585Sjeff				if (setusercontext(lc, pwd, pwd->pw_uid,
754156585Sjeff				    LOGIN_SETALL) != 0) {
755156585Sjeff					syslog(LOG_ERR,
756156585Sjeff					 "%s: can't setusercontext(..%s..): %m",
757156585Sjeff					 sep->se_service, sep->se_user);
758156585Sjeff					_exit(EX_OSERR);
759166774Spjd				}
760166774Spjd#else
761166774Spjd				if (pwd->pw_uid) {
762166774Spjd					if (setlogin(sep->se_user) < 0) {
763166774Spjd						syslog(LOG_ERR,
764166774Spjd						 "%s: can't setlogin(%s): %m",
765166774Spjd						 sep->se_service, sep->se_user);
766166774Spjd						/* _exit(EX_OSERR); not yet */
767166774Spjd					}
768193175Skib					if (setgid(pwd->pw_gid) < 0) {
769193175Skib						syslog(LOG_ERR,
770193175Skib						  "%s: can't set gid %d: %m",
771193175Skib						  sep->se_service, pwd->pw_gid);
772193175Skib						_exit(EX_OSERR);
773193175Skib					}
774194601Skib					(void) initgroups(pwd->pw_name,
775193175Skib							pwd->pw_gid);
776193175Skib					if (setuid(pwd->pw_uid) < 0) {
777193175Skib						syslog(LOG_ERR,
778193175Skib						  "%s: can't set uid %d: %m",
779193175Skib						  sep->se_service, pwd->pw_uid);
780193175Skib						_exit(EX_OSERR);
781193175Skib					}
782193175Skib				}
783193175Skib#endif
784193175Skib				sigaction(SIGPIPE, &sapipe,
785227697Skib				    (struct sigaction *)0);
786194601Skib				execv(sep->se_server, sep->se_argv);
787193175Skib				syslog(LOG_ERR,
788193175Skib				    "cannot execute %s: %m", sep->se_server);
789193175Skib				if (sep->se_socktype != SOCK_STREAM)
790193175Skib					recv(0, buf, sizeof (buf), 0);
791193175Skib			    }
792193175Skib			    if (dofork)
793193175Skib				_exit(0);
794193175Skib		    }
795193175Skib		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM)
796193175Skib			    close(ctrl);
797193175Skib		}
798193175Skib	}
799227697Skib}
800193175Skib
801193175Skib/*
802193175Skib * Add a signal flag to the signal flag queue for later handling
803193175Skib */
804193175Skib
805193175Skibvoid
806193175Skibflag_signal(int c)
807193175Skib{
808193175Skib	char ch = c;
809227697Skib
810229431Skib	if (write(signalpipe[1], &ch, 1) != 1) {
811193175Skib		syslog(LOG_ERR, "write: %m");
812193175Skib		_exit(EX_OSERR);
813193175Skib	}
814193175Skib}
8151541Srgrimes
8161541Srgrimes/*
8171541Srgrimes * Record a new child pid for this service. If we've reached the
818138290Sphk * limit on children, then stop accepting incoming requests.
819138290Sphk */
820138290Sphk
821193092Straszvoid
822208128Skibaddchild(struct servtab *sep, pid_t pid)
823138290Sphk{
824138290Sphk	if (sep->se_maxchild <= 0)
825156585Sjeff		return;
826138290Sphk#ifdef SANITY_CHECK
827189961Spho	if (sep->se_numchild >= sep->se_maxchild) {
828169671Skib		syslog(LOG_ERR, "%s: %d >= %d",
829138290Sphk		    __FUNCTION__, sep->se_numchild, sep->se_maxchild);
830140776Sphk		exit(EX_SOFTWARE);
831138290Sphk	}
832138290Sphk#endif
833212043Srmacklem	sep->se_pids[sep->se_numchild++] = pid;
834138290Sphk	if (sep->se_numchild == sep->se_maxchild)
835138290Sphk		disable(sep);
836138290Sphk}
837138290Sphk
838193175Skib/*
839166774Spjd * Some child process has exited. See if it's on somebody's list.
8401541Srgrimes */
841
842void
843flag_reapchild(int signo __unused)
844{
845	flag_signal('C');
846}
847
848void
849reapchild(void)
850{
851	int k, status;
852	pid_t pid;
853	struct servtab *sep;
854
855	for (;;) {
856		pid = wait3(&status, WNOHANG, (struct rusage *)0);
857		if (pid <= 0)
858			break;
859		if (debug)
860			warnx("%d reaped, status %#x", pid, status);
861		for (sep = servtab; sep; sep = sep->se_next) {
862			for (k = 0; k < sep->se_numchild; k++)
863				if (sep->se_pids[k] == pid)
864					break;
865			if (k == sep->se_numchild)
866				continue;
867			if (sep->se_numchild == sep->se_maxchild)
868				enable(sep);
869			sep->se_pids[k] = sep->se_pids[--sep->se_numchild];
870			if (status)
871				syslog(LOG_WARNING,
872				    "%s[%d]: exit status 0x%x",
873				    sep->se_server, pid, status);
874			break;
875		}
876	}
877}
878
879void
880flag_config(int signo __unused)
881{
882	flag_signal('H');
883}
884
885void
886config(void)
887{
888	struct servtab *sep, *new, **sepp;
889	long omask;
890
891	if (!setconfig()) {
892		syslog(LOG_ERR, "%s: %m", CONFIG);
893		return;
894	}
895	for (sep = servtab; sep; sep = sep->se_next)
896		sep->se_checked = 0;
897	while ((new = getconfigent())) {
898		if (getpwnam(new->se_user) == NULL) {
899			syslog(LOG_ERR,
900				"%s/%s: no such user '%s', service ignored",
901				new->se_service, new->se_proto, new->se_user);
902			continue;
903		}
904		if (new->se_group && getgrnam(new->se_group) == NULL) {
905			syslog(LOG_ERR,
906				"%s/%s: no such group '%s', service ignored",
907				new->se_service, new->se_proto, new->se_group);
908			continue;
909		}
910#ifdef LOGIN_CAP
911		if (login_getclass(new->se_class) == NULL) {
912			/* error syslogged by getclass */
913			syslog(LOG_ERR,
914				"%s/%s: %s: login class error, service ignored",
915				new->se_service, new->se_proto, new->se_class);
916			continue;
917		}
918#endif
919		for (sep = servtab; sep; sep = sep->se_next)
920			if (strcmp(sep->se_service, new->se_service) == 0 &&
921			    strcmp(sep->se_proto, new->se_proto) == 0 &&
922			    sep->se_socktype == new->se_socktype &&
923			    sep->se_family == new->se_family)
924				break;
925		if (sep != 0) {
926			int i;
927
928#define SWAP(a, b) { __typeof__(a) c = a; a = b; b = c; }
929			omask = sigblock(SIGBLOCK);
930			if (sep->se_nomapped != new->se_nomapped) {
931				sep->se_nomapped = new->se_nomapped;
932				sep->se_reset = 1;
933			}
934			/* copy over outstanding child pids */
935			if (sep->se_maxchild > 0 && new->se_maxchild > 0) {
936				new->se_numchild = sep->se_numchild;
937				if (new->se_numchild > new->se_maxchild)
938					new->se_numchild = new->se_maxchild;
939				memcpy(new->se_pids, sep->se_pids,
940				    new->se_numchild * sizeof(*new->se_pids));
941			}
942			SWAP(sep->se_pids, new->se_pids);
943			sep->se_maxchild = new->se_maxchild;
944			sep->se_numchild = new->se_numchild;
945			sep->se_maxcpm = new->se_maxcpm;
946			sep->se_bi = new->se_bi;
947			/* might need to turn on or off service now */
948			if (sep->se_fd >= 0) {
949			      if (sep->se_maxchild > 0
950				  && sep->se_numchild == sep->se_maxchild) {
951				      if (FD_ISSET(sep->se_fd, &allsock))
952					  disable(sep);
953			      } else {
954				      if (!FD_ISSET(sep->se_fd, &allsock))
955					  enable(sep);
956			      }
957			}
958			sep->se_accept = new->se_accept;
959			SWAP(sep->se_user, new->se_user);
960			SWAP(sep->se_group, new->se_group);
961#ifdef LOGIN_CAP
962			SWAP(sep->se_class, new->se_class);
963#endif
964			SWAP(sep->se_server, new->se_server);
965			SWAP(sep->se_server_name, new->se_server_name);
966			for (i = 0; i < MAXARGV; i++)
967				SWAP(sep->se_argv[i], new->se_argv[i]);
968#ifdef IPSEC
969			SWAP(sep->se_policy, new->se_policy);
970			ipsecsetup(sep);
971#endif
972			sigsetmask(omask);
973			freeconfig(new);
974			if (debug)
975				print_service("REDO", sep);
976		} else {
977			sep = enter(new);
978			if (debug)
979				print_service("ADD ", sep);
980		}
981		sep->se_checked = 1;
982		if (ISMUX(sep)) {
983			sep->se_fd = -1;
984			continue;
985		}
986		switch (sep->se_family) {
987		case AF_INET:
988			if (no_v4bind != 0) {
989				sep->se_fd = -1;
990				continue;
991			}
992			break;
993#ifdef INET6
994		case AF_INET6:
995			if (no_v6bind != 0) {
996				sep->se_fd = -1;
997				continue;
998			}
999			break;
1000#endif
1001		}
1002		if (!sep->se_rpc) {
1003			if (sep->se_family != AF_UNIX) {
1004				sp = getservbyname(sep->se_service, sep->se_proto);
1005				if (sp == 0) {
1006					syslog(LOG_ERR, "%s/%s: unknown service",
1007					sep->se_service, sep->se_proto);
1008					sep->se_checked = 0;
1009					continue;
1010				}
1011			}
1012			switch (sep->se_family) {
1013			case AF_INET:
1014				if (sp->s_port != sep->se_ctrladdr4.sin_port) {
1015					sep->se_ctrladdr4.sin_port =
1016						sp->s_port;
1017					sep->se_reset = 1;
1018				}
1019				break;
1020#ifdef INET6
1021			case AF_INET6:
1022				if (sp->s_port !=
1023				    sep->se_ctrladdr6.sin6_port) {
1024					sep->se_ctrladdr6.sin6_port =
1025						sp->s_port;
1026					sep->se_reset = 1;
1027				}
1028				break;
1029#endif
1030			}
1031			if (sep->se_reset != 0 && sep->se_fd >= 0)
1032				close_sep(sep);
1033		} else {
1034			rpc = getrpcbyname(sep->se_service);
1035			if (rpc == 0) {
1036				syslog(LOG_ERR, "%s/%s unknown RPC service",
1037					sep->se_service, sep->se_proto);
1038				if (sep->se_fd != -1)
1039					(void) close(sep->se_fd);
1040				sep->se_fd = -1;
1041					continue;
1042			}
1043			if (rpc->r_number != sep->se_rpc_prog) {
1044				if (sep->se_rpc_prog)
1045					unregisterrpc(sep);
1046				sep->se_rpc_prog = rpc->r_number;
1047				if (sep->se_fd != -1)
1048					(void) close(sep->se_fd);
1049				sep->se_fd = -1;
1050			}
1051		}
1052		if (sep->se_fd == -1)
1053			setup(sep);
1054	}
1055	endconfig();
1056	/*
1057	 * Purge anything not looked at above.
1058	 */
1059	omask = sigblock(SIGBLOCK);
1060	sepp = &servtab;
1061	while ((sep = *sepp)) {
1062		if (sep->se_checked) {
1063			sepp = &sep->se_next;
1064			continue;
1065		}
1066		*sepp = sep->se_next;
1067		if (sep->se_fd >= 0)
1068			close_sep(sep);
1069		if (debug)
1070			print_service("FREE", sep);
1071		if (sep->se_rpc && sep->se_rpc_prog > 0)
1072			unregisterrpc(sep);
1073		freeconfig(sep);
1074		free(sep);
1075	}
1076	(void) sigsetmask(omask);
1077}
1078
1079void
1080unregisterrpc(struct servtab *sep)
1081{
1082        u_int i;
1083        struct servtab *sepp;
1084	long omask;
1085
1086	omask = sigblock(SIGBLOCK);
1087        for (sepp = servtab; sepp; sepp = sepp->se_next) {
1088                if (sepp == sep)
1089                        continue;
1090		if (sep->se_checked == 0 ||
1091                    !sepp->se_rpc ||
1092                    sep->se_rpc_prog != sepp->se_rpc_prog)
1093			continue;
1094                return;
1095        }
1096        if (debug)
1097                print_service("UNREG", sep);
1098        for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
1099                pmap_unset(sep->se_rpc_prog, i);
1100        if (sep->se_fd != -1)
1101                (void) close(sep->se_fd);
1102        sep->se_fd = -1;
1103	(void) sigsetmask(omask);
1104}
1105
1106void
1107flag_retry(int signo __unused)
1108{
1109	flag_signal('A');
1110}
1111
1112void
1113retry(void)
1114{
1115	struct servtab *sep;
1116
1117	timingout = 0;
1118	for (sep = servtab; sep; sep = sep->se_next)
1119		if (sep->se_fd == -1 && !ISMUX(sep))
1120			setup(sep);
1121}
1122
1123void
1124setup(struct servtab *sep)
1125{
1126	int on = 1;
1127
1128	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
1129		if (debug)
1130			warn("socket failed on %s/%s",
1131				sep->se_service, sep->se_proto);
1132		syslog(LOG_ERR, "%s/%s: socket: %m",
1133		    sep->se_service, sep->se_proto);
1134		return;
1135	}
1136#define	turnon(fd, opt) \
1137setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
1138	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
1139	    turnon(sep->se_fd, SO_DEBUG) < 0)
1140		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
1141	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
1142		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
1143#ifdef SO_PRIVSTATE
1144	if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
1145		syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
1146#endif
1147	/* tftpd opens a new connection then needs more infos */
1148	if ((sep->se_family == AF_INET6) &&
1149	    (strcmp(sep->se_proto, "udp") == 0) &&
1150	    (sep->se_accept == 0) &&
1151	    (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_PKTINFO,
1152			(char *)&on, sizeof (on)) < 0))
1153		syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m");
1154#ifdef IPV6_BINDV6ONLY
1155	if (sep->se_family == AF_INET6) {
1156		int flag = sep->se_nomapped ? 1 : 0;
1157		if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_BINDV6ONLY,
1158			       (char *)&flag, sizeof (flag)) < 0)
1159			syslog(LOG_ERR, "setsockopt (IPV6_BINDV6ONLY): %m");
1160	}
1161#endif /* IPV6_BINDV6ONLY */
1162#undef turnon
1163	if (sep->se_type == TTCP_TYPE)
1164		if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH,
1165		    (char *)&on, sizeof (on)) < 0)
1166			syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m");
1167#ifdef IPV6_FAITH
1168	if (sep->se_type == FAITH_TYPE) {
1169		if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on,
1170				sizeof(on)) < 0) {
1171			syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m");
1172		}
1173	}
1174#endif
1175#ifdef IPSEC
1176	ipsecsetup(sep);
1177#endif
1178	if (sep->se_family == AF_UNIX) {
1179		(void) unlink(sep->se_ctrladdr_un.sun_path);
1180		umask(0777); /* Make socket with conservative permissions */
1181	}
1182	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
1183	    sep->se_ctrladdr_size) < 0) {
1184		if (debug)
1185			warn("bind failed on %s/%s",
1186				sep->se_service, sep->se_proto);
1187		syslog(LOG_ERR, "%s/%s: bind: %m",
1188		    sep->se_service, sep->se_proto);
1189		(void) close(sep->se_fd);
1190		sep->se_fd = -1;
1191		if (!timingout) {
1192			timingout = 1;
1193			alarm(RETRYTIME);
1194		}
1195		if (sep->se_family == AF_UNIX)
1196			umask(mask);
1197		return;
1198	}
1199	if (sep->se_family == AF_UNIX) {
1200		/* Ick - fch{own,mod} don't work on Unix domain sockets */
1201		if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0)
1202			syslog(LOG_ERR, "chown socket: %m");
1203		if (chmod(sep->se_service, sep->se_sockmode) < 0)
1204			syslog(LOG_ERR, "chmod socket: %m");
1205		umask(mask);
1206	}
1207        if (sep->se_rpc) {
1208		u_int i;
1209		socklen_t len = sep->se_ctrladdr_size;
1210
1211		if (sep->se_family != AF_INET) {
1212                        syslog(LOG_ERR,
1213			       "%s/%s: unsupported address family for rpc",
1214                               sep->se_service, sep->se_proto);
1215                        (void) close(sep->se_fd);
1216                        sep->se_fd = -1;
1217                        return;
1218		}
1219                if (getsockname(sep->se_fd,
1220				(struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
1221                        syslog(LOG_ERR, "%s/%s: getsockname: %m",
1222                               sep->se_service, sep->se_proto);
1223                        (void) close(sep->se_fd);
1224                        sep->se_fd = -1;
1225                        return;
1226                }
1227                if (debug)
1228                        print_service("REG ", sep);
1229                for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
1230                        pmap_unset(sep->se_rpc_prog, i);
1231                        pmap_set(sep->se_rpc_prog, i,
1232                                 (sep->se_socktype == SOCK_DGRAM)
1233                                 ? IPPROTO_UDP : IPPROTO_TCP,
1234				 ntohs(sep->se_ctrladdr4.sin_port));
1235                }
1236        }
1237	if (sep->se_socktype == SOCK_STREAM)
1238		listen(sep->se_fd, 64);
1239	enable(sep);
1240	if (debug) {
1241		warnx("registered %s on %d",
1242			sep->se_server, sep->se_fd);
1243	}
1244}
1245
1246#ifdef IPSEC
1247void
1248ipsecsetup(sep)
1249	struct servtab *sep;
1250{
1251	char *buf;
1252	char *policy_in = NULL;
1253	char *policy_out = NULL;
1254	int level;
1255	int opt;
1256
1257	switch (sep->se_family) {
1258	case AF_INET:
1259		level = IPPROTO_IP;
1260		opt = IP_IPSEC_POLICY;
1261		break;
1262#ifdef INET6
1263	case AF_INET6:
1264		level = IPPROTO_IPV6;
1265		opt = IPV6_IPSEC_POLICY;
1266		break;
1267#endif
1268	default:
1269		return;
1270	}
1271
1272	if (!sep->se_policy || sep->se_policy[0] == '\0') {
1273		static char def_in[] = "in entrust", def_out[] = "out entrust";
1274		policy_in = def_in;
1275		policy_out = def_out;
1276	} else {
1277		if (!strncmp("in", sep->se_policy, 2))
1278			policy_in = sep->se_policy;
1279		else if (!strncmp("out", sep->se_policy, 3))
1280			policy_out = sep->se_policy;
1281		else {
1282			syslog(LOG_ERR, "invalid security policy \"%s\"",
1283				sep->se_policy);
1284			return;
1285		}
1286	}
1287
1288	if (policy_in != NULL) {
1289		buf = ipsec_set_policy(policy_in, strlen(policy_in));
1290		if (buf != NULL) {
1291			if (setsockopt(sep->se_fd, level, opt,
1292					buf, ipsec_get_policylen(buf)) < 0 &&
1293			    debug != 0)
1294				warnx("%s/%s: ipsec initialization failed; %s",
1295				      sep->se_service, sep->se_proto,
1296				      policy_in);
1297			free(buf);
1298		} else
1299			syslog(LOG_ERR, "invalid security policy \"%s\"",
1300				policy_in);
1301	}
1302	if (policy_out != NULL) {
1303		buf = ipsec_set_policy(policy_out, strlen(policy_out));
1304		if (buf != NULL) {
1305			if (setsockopt(sep->se_fd, level, opt,
1306					buf, ipsec_get_policylen(buf)) < 0 &&
1307			    debug != 0)
1308				warnx("%s/%s: ipsec initialization failed; %s",
1309				      sep->se_service, sep->se_proto,
1310				      policy_out);
1311			free(buf);
1312		} else
1313			syslog(LOG_ERR, "invalid security policy \"%s\"",
1314				policy_out);
1315	}
1316}
1317#endif
1318
1319/*
1320 * Finish with a service and its socket.
1321 */
1322void
1323close_sep(struct servtab *sep)
1324{
1325	if (sep->se_fd >= 0) {
1326		if (FD_ISSET(sep->se_fd, &allsock))
1327			disable(sep);
1328		(void) close(sep->se_fd);
1329		sep->se_fd = -1;
1330	}
1331	sep->se_count = 0;
1332	sep->se_numchild = 0;	/* forget about any existing children */
1333}
1334
1335int
1336matchservent(const char *name1, const char *name2, const char *proto)
1337{
1338	char **alias, *p;
1339	struct servent *se;
1340
1341	if (strcmp(proto, "unix") == 0) {
1342		if ((p = strrchr(name1, '/')) != NULL)
1343			name1 = p + 1;
1344		if ((p = strrchr(name2, '/')) != NULL)
1345			name2 = p + 1;
1346	}
1347	if (strcmp(name1, name2) == 0)
1348		return(1);
1349	if ((se = getservbyname(name1, proto)) != NULL) {
1350		if (strcmp(name2, se->s_name) == 0)
1351			return(1);
1352		for (alias = se->s_aliases; *alias; alias++)
1353			if (strcmp(name2, *alias) == 0)
1354				return(1);
1355	}
1356	return(0);
1357}
1358
1359struct servtab *
1360enter(struct servtab *cp)
1361{
1362	struct servtab *sep;
1363	long omask;
1364
1365	sep = (struct servtab *)malloc(sizeof (*sep));
1366	if (sep == (struct servtab *)0) {
1367		syslog(LOG_ERR, "malloc: %m");
1368		exit(EX_OSERR);
1369	}
1370	*sep = *cp;
1371	sep->se_fd = -1;
1372	omask = sigblock(SIGBLOCK);
1373	sep->se_next = servtab;
1374	servtab = sep;
1375	sigsetmask(omask);
1376	return (sep);
1377}
1378
1379void
1380enable(struct servtab *sep)
1381{
1382	if (debug)
1383		warnx(
1384		    "enabling %s, fd %d", sep->se_service, sep->se_fd);
1385#ifdef SANITY_CHECK
1386	if (sep->se_fd < 0) {
1387		syslog(LOG_ERR,
1388		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
1389		exit(EX_SOFTWARE);
1390	}
1391	if (ISMUX(sep)) {
1392		syslog(LOG_ERR,
1393		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
1394		exit(EX_SOFTWARE);
1395	}
1396	if (FD_ISSET(sep->se_fd, &allsock)) {
1397		syslog(LOG_ERR,
1398		    "%s: %s: not off", __FUNCTION__, sep->se_service);
1399		exit(EX_SOFTWARE);
1400	}
1401	nsock++;
1402#endif
1403	FD_SET(sep->se_fd, &allsock);
1404	if (sep->se_fd > maxsock)
1405		maxsock = sep->se_fd;
1406}
1407
1408void
1409disable(struct servtab *sep)
1410{
1411	if (debug)
1412		warnx(
1413		    "disabling %s, fd %d", sep->se_service, sep->se_fd);
1414#ifdef SANITY_CHECK
1415	if (sep->se_fd < 0) {
1416		syslog(LOG_ERR,
1417		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
1418		exit(EX_SOFTWARE);
1419	}
1420	if (ISMUX(sep)) {
1421		syslog(LOG_ERR,
1422		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
1423		exit(EX_SOFTWARE);
1424	}
1425	if (!FD_ISSET(sep->se_fd, &allsock)) {
1426		syslog(LOG_ERR,
1427		    "%s: %s: not on", __FUNCTION__, sep->se_service);
1428		exit(EX_SOFTWARE);
1429	}
1430	if (nsock == 0) {
1431		syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
1432		exit(EX_SOFTWARE);
1433	}
1434	nsock--;
1435#endif
1436	FD_CLR(sep->se_fd, &allsock);
1437	if (sep->se_fd == maxsock)
1438		maxsock--;
1439}
1440
1441FILE	*fconfig = NULL;
1442struct	servtab serv;
1443char	line[LINE_MAX];
1444
1445int
1446setconfig(void)
1447{
1448
1449	if (fconfig != NULL) {
1450		fseek(fconfig, 0L, SEEK_SET);
1451		return (1);
1452	}
1453	fconfig = fopen(CONFIG, "r");
1454	return (fconfig != NULL);
1455}
1456
1457void
1458endconfig(void)
1459{
1460	if (fconfig) {
1461		(void) fclose(fconfig);
1462		fconfig = NULL;
1463	}
1464}
1465
1466struct servtab *
1467getconfigent(void)
1468{
1469	struct servtab *sep = &serv;
1470	int argc;
1471	char *cp, *arg, *s;
1472	char *versp;
1473	static char TCPMUX_TOKEN[] = "tcpmux/";
1474#define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
1475#ifdef IPSEC
1476	char *policy = NULL;
1477#endif
1478	int v4bind = 0;
1479#ifdef INET6
1480	int v6bind = 0;
1481#endif
1482
1483more:
1484	while ((cp = nextline(fconfig)) != NULL) {
1485#ifdef IPSEC
1486		/* lines starting with #@ is not a comment, but the policy */
1487		if (cp[0] == '#' && cp[1] == '@') {
1488			char *p;
1489			for (p = cp + 2; p && *p && isspace(*p); p++)
1490				;
1491			if (*p == '\0') {
1492				if (policy)
1493					free(policy);
1494				policy = NULL;
1495			} else if (ipsec_get_policylen(p) >= 0) {
1496				if (policy)
1497					free(policy);
1498				policy = newstr(p);
1499			} else {
1500				syslog(LOG_ERR,
1501					"%s: invalid ipsec policy \"%s\"",
1502					CONFIG, p);
1503				exit(EX_CONFIG);
1504			}
1505		}
1506#endif
1507		if (*cp == '#' || *cp == '\0')
1508			continue;
1509		break;
1510	}
1511	if (cp == NULL)
1512		return ((struct servtab *)0);
1513	/*
1514	 * clear the static buffer, since some fields (se_ctrladdr,
1515	 * for example) don't get initialized here.
1516	 */
1517	memset(sep, 0, sizeof *sep);
1518	arg = skip(&cp);
1519	if (cp == NULL) {
1520		/* got an empty line containing just blanks/tabs. */
1521		goto more;
1522	}
1523	if (arg[0] == ':') { /* :user:group:perm: */
1524		char *user, *group, *perm;
1525		struct passwd *pw;
1526		struct group *gr;
1527		user = arg+1;
1528		if ((group = strchr(user, ':')) == NULL) {
1529			syslog(LOG_ERR, "no group after user '%s'", user);
1530			goto more;
1531		}
1532		*group++ = '\0';
1533		if ((perm = strchr(group, ':')) == NULL) {
1534			syslog(LOG_ERR, "no mode after group '%s'", group);
1535			goto more;
1536		}
1537		*perm++ = '\0';
1538		if ((pw = getpwnam(user)) == NULL) {
1539			syslog(LOG_ERR, "no such user '%s'", user);
1540			goto more;
1541		}
1542		sep->se_sockuid = pw->pw_uid;
1543		if ((gr = getgrnam(group)) == NULL) {
1544			syslog(LOG_ERR, "no such user '%s'", group);
1545			goto more;
1546		}
1547		sep->se_sockgid = gr->gr_gid;
1548		sep->se_sockmode = strtol(perm, &arg, 8);
1549		if (*arg != ':') {
1550			syslog(LOG_ERR, "bad mode '%s'", perm);
1551			goto more;
1552		}
1553		*arg++ = '\0';
1554	} else {
1555		sep->se_sockuid = euid;
1556		sep->se_sockgid = egid;
1557		sep->se_sockmode = 0200;
1558	}
1559	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
1560		char *c = arg + MUX_LEN;
1561		if (*c == '+') {
1562			sep->se_type = MUXPLUS_TYPE;
1563			c++;
1564		} else
1565			sep->se_type = MUX_TYPE;
1566		sep->se_service = newstr(c);
1567	} else {
1568		sep->se_service = newstr(arg);
1569		sep->se_type = NORM_TYPE;
1570	}
1571	arg = sskip(&cp);
1572	if (strcmp(arg, "stream") == 0)
1573		sep->se_socktype = SOCK_STREAM;
1574	else if (strcmp(arg, "dgram") == 0)
1575		sep->se_socktype = SOCK_DGRAM;
1576	else if (strcmp(arg, "rdm") == 0)
1577		sep->se_socktype = SOCK_RDM;
1578	else if (strcmp(arg, "seqpacket") == 0)
1579		sep->se_socktype = SOCK_SEQPACKET;
1580	else if (strcmp(arg, "raw") == 0)
1581		sep->se_socktype = SOCK_RAW;
1582	else
1583		sep->se_socktype = -1;
1584
1585	arg = sskip(&cp);
1586	if (strncmp(arg, "tcp", 3) == 0) {
1587		sep->se_proto = newstr(strsep(&arg, "/"));
1588		if (arg != NULL) {
1589			if (strcmp(arg, "ttcp") == 0)
1590				sep->se_type = TTCP_TYPE;
1591			else if (strcmp(arg, "faith") == 0)
1592				sep->se_type = FAITH_TYPE;
1593		}
1594	} else {
1595		if (sep->se_type == NORM_TYPE &&
1596		    strncmp(arg, "faith/", 6) == 0) {
1597			arg += 6;
1598			sep->se_type = FAITH_TYPE;
1599		}
1600		sep->se_proto = newstr(arg);
1601	}
1602        if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1603		if (no_v4bind != 0) {
1604			syslog(LOG_NOTICE, "IPv4 bind is ignored for %s",
1605			       sep->se_service);
1606			freeconfig(sep);
1607			goto more;
1608		}
1609                memmove(sep->se_proto, sep->se_proto + 4,
1610                    strlen(sep->se_proto) + 1 - 4);
1611                sep->se_rpc = 1;
1612                sep->se_rpc_prog = sep->se_rpc_lowvers =
1613			sep->se_rpc_lowvers = 0;
1614		memcpy(&sep->se_ctrladdr4, bind_sa4,
1615		       sizeof(sep->se_ctrladdr4));
1616                if ((versp = rindex(sep->se_service, '/'))) {
1617                        *versp++ = '\0';
1618                        switch (sscanf(versp, "%d-%d",
1619                                       &sep->se_rpc_lowvers,
1620                                       &sep->se_rpc_highvers)) {
1621                        case 2:
1622                                break;
1623                        case 1:
1624                                sep->se_rpc_highvers =
1625                                        sep->se_rpc_lowvers;
1626                                break;
1627                        default:
1628                                syslog(LOG_ERR,
1629					"bad RPC version specifier; %s",
1630					sep->se_service);
1631                                freeconfig(sep);
1632                                goto more;
1633                        }
1634                }
1635                else {
1636                        sep->se_rpc_lowvers =
1637                                sep->se_rpc_highvers = 1;
1638                }
1639        }
1640	sep->se_nomapped = 0;
1641	while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) {
1642#ifdef INET6
1643		if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') {
1644			if (no_v6bind != 0) {
1645				syslog(LOG_NOTICE, "IPv6 bind is ignored for %s",
1646				       sep->se_service);
1647				freeconfig(sep);
1648				goto more;
1649			}
1650			sep->se_proto[strlen(sep->se_proto) - 1] = '\0';
1651			v6bind = 1;
1652			continue;
1653		}
1654#endif
1655		if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') {
1656			sep->se_proto[strlen(sep->se_proto) - 1] = '\0';
1657			v4bind = 1;
1658			continue;
1659		}
1660		/* illegal version num */
1661		syslog(LOG_ERR,	"bad IP version for %s", sep->se_proto);
1662		freeconfig(sep);
1663		goto more;
1664	}
1665	if (strcmp(sep->se_proto, "unix") == 0) {
1666	        sep->se_family = AF_UNIX;
1667	} else
1668#ifdef INET6
1669	if (v6bind != 0) {
1670		sep->se_family = AF_INET6;
1671		if (v4bind == 0 || no_v4bind != 0)
1672			sep->se_nomapped = 1;
1673	} else
1674#endif
1675	{ /* default to v4 bind if not v6 bind */
1676		if (no_v4bind != 0) {
1677			syslog(LOG_NOTICE, "IPv4 bind is ignored for %s",
1678			       sep->se_service);
1679			freeconfig(sep);
1680			goto more;
1681		}
1682		sep->se_family = AF_INET;
1683	}
1684	/* init ctladdr */
1685	switch(sep->se_family) {
1686	case AF_INET:
1687		memcpy(&sep->se_ctrladdr4, bind_sa4,
1688		       sizeof(sep->se_ctrladdr4));
1689		sep->se_ctrladdr_size =	sizeof(sep->se_ctrladdr4);
1690		break;
1691#ifdef INET6
1692	case AF_INET6:
1693		memcpy(&sep->se_ctrladdr6, bind_sa6,
1694		       sizeof(sep->se_ctrladdr6));
1695		sep->se_ctrladdr_size =	sizeof(sep->se_ctrladdr6);
1696		break;
1697#endif
1698	case AF_UNIX:
1699		if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) {
1700			syslog(LOG_ERR,
1701			    "domain socket pathname too long for service %s",
1702			    sep->se_service);
1703			goto more;
1704		}
1705		memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr));
1706		sep->se_ctrladdr_un.sun_family = sep->se_family;
1707		sep->se_ctrladdr_un.sun_len = strlen(sep->se_service);
1708		strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service);
1709		sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un);
1710	}
1711	arg = sskip(&cp);
1712	if (!strncmp(arg, "wait", 4))
1713		sep->se_accept = 0;
1714	else if (!strncmp(arg, "nowait", 6))
1715		sep->se_accept = 1;
1716	else {
1717		syslog(LOG_ERR,
1718			"%s: bad wait/nowait for service %s",
1719			CONFIG, sep->se_service);
1720		goto more;
1721	}
1722	sep->se_maxchild = -1;
1723	sep->se_maxcpm = -1;
1724	if ((s = strchr(arg, '/')) != NULL) {
1725		char *eptr;
1726		u_long val;
1727
1728		val = strtoul(s + 1, &eptr, 10);
1729		if (eptr == s + 1 || val > MAX_MAXCHLD) {
1730			syslog(LOG_ERR,
1731				"%s: bad max-child for service %s",
1732				CONFIG, sep->se_service);
1733			goto more;
1734		}
1735		if (debug)
1736			if (!sep->se_accept && val != 1)
1737				warnx("maxchild=%lu for wait service %s"
1738				    " not recommended", val, sep->se_service);
1739		sep->se_maxchild = val;
1740		if (*eptr == '/')
1741			sep->se_maxcpm = strtol(eptr + 1, &eptr, 10);
1742		/*
1743		 * explicitly do not check for \0 for future expansion /
1744		 * backwards compatibility
1745		 */
1746	}
1747	if (ISMUX(sep)) {
1748		/*
1749		 * Silently enforce "nowait" mode for TCPMUX services
1750		 * since they don't have an assigned port to listen on.
1751		 */
1752		sep->se_accept = 1;
1753		if (strcmp(sep->se_proto, "tcp")) {
1754			syslog(LOG_ERR,
1755				"%s: bad protocol for tcpmux service %s",
1756				CONFIG, sep->se_service);
1757			goto more;
1758		}
1759		if (sep->se_socktype != SOCK_STREAM) {
1760			syslog(LOG_ERR,
1761				"%s: bad socket type for tcpmux service %s",
1762				CONFIG, sep->se_service);
1763			goto more;
1764		}
1765	}
1766	sep->se_user = newstr(sskip(&cp));
1767#ifdef LOGIN_CAP
1768	if ((s = strrchr(sep->se_user, '/')) != NULL) {
1769		*s = '\0';
1770		sep->se_class = newstr(s + 1);
1771	} else
1772		sep->se_class = newstr(RESOURCE_RC);
1773#endif
1774	if ((s = strrchr(sep->se_user, ':')) != NULL) {
1775		*s = '\0';
1776		sep->se_group = newstr(s + 1);
1777	} else
1778		sep->se_group = NULL;
1779	sep->se_server = newstr(sskip(&cp));
1780	if ((sep->se_server_name = rindex(sep->se_server, '/')))
1781		sep->se_server_name++;
1782	if (strcmp(sep->se_server, "internal") == 0) {
1783		struct biltin *bi;
1784
1785		for (bi = biltins; bi->bi_service; bi++)
1786			if (bi->bi_socktype == sep->se_socktype &&
1787			    matchservent(bi->bi_service, sep->se_service,
1788			    sep->se_proto))
1789				break;
1790		if (bi->bi_service == 0) {
1791			syslog(LOG_ERR, "internal service %s unknown",
1792				sep->se_service);
1793			goto more;
1794		}
1795		sep->se_accept = 1;	/* force accept mode for built-ins */
1796		sep->se_bi = bi;
1797	} else
1798		sep->se_bi = NULL;
1799	if (sep->se_maxcpm < 0)
1800		sep->se_maxcpm = maxcpm;
1801	if (sep->se_maxchild < 0) {	/* apply default max-children */
1802		if (sep->se_bi && sep->se_bi->bi_maxchild >= 0)
1803			sep->se_maxchild = sep->se_bi->bi_maxchild;
1804		else if (sep->se_accept)
1805			sep->se_maxchild = maxchild > 0 ? maxchild : 0;
1806		else
1807			sep->se_maxchild = 1;
1808	}
1809	if (sep->se_maxchild > 0) {
1810		sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids));
1811		if (sep->se_pids == NULL) {
1812			syslog(LOG_ERR, "malloc: %m");
1813			exit(EX_OSERR);
1814		}
1815	}
1816	argc = 0;
1817	for (arg = skip(&cp); cp; arg = skip(&cp))
1818		if (argc < MAXARGV) {
1819			sep->se_argv[argc++] = newstr(arg);
1820		} else {
1821			syslog(LOG_ERR,
1822				"%s: too many arguments for service %s",
1823				CONFIG, sep->se_service);
1824			goto more;
1825		}
1826	while (argc <= MAXARGV)
1827		sep->se_argv[argc++] = NULL;
1828#ifdef IPSEC
1829	sep->se_policy = policy ? newstr(policy) : NULL;
1830#endif
1831	return (sep);
1832}
1833
1834void
1835freeconfig(struct servtab *cp)
1836{
1837	int i;
1838
1839	if (cp->se_service)
1840		free(cp->se_service);
1841	if (cp->se_proto)
1842		free(cp->se_proto);
1843	if (cp->se_user)
1844		free(cp->se_user);
1845	if (cp->se_group)
1846		free(cp->se_group);
1847#ifdef LOGIN_CAP
1848	if (cp->se_class)
1849		free(cp->se_class);
1850#endif
1851	if (cp->se_server)
1852		free(cp->se_server);
1853	if (cp->se_pids)
1854		free(cp->se_pids);
1855	for (i = 0; i < MAXARGV; i++)
1856		if (cp->se_argv[i])
1857			free(cp->se_argv[i]);
1858#ifdef IPSEC
1859	if (cp->se_policy)
1860		free(cp->se_policy);
1861#endif
1862}
1863
1864
1865/*
1866 * Safe skip - if skip returns null, log a syntax error in the
1867 * configuration file and exit.
1868 */
1869char *
1870sskip(char **cpp)
1871{
1872	char *cp;
1873
1874	cp = skip(cpp);
1875	if (cp == NULL) {
1876		syslog(LOG_ERR, "%s: syntax error", CONFIG);
1877		exit(EX_DATAERR);
1878	}
1879	return (cp);
1880}
1881
1882char *
1883skip(char **cpp)
1884{
1885	char *cp = *cpp;
1886	char *start;
1887	char quote = '\0';
1888
1889again:
1890	while (*cp == ' ' || *cp == '\t')
1891		cp++;
1892	if (*cp == '\0') {
1893		int c;
1894
1895		c = getc(fconfig);
1896		(void) ungetc(c, fconfig);
1897		if (c == ' ' || c == '\t')
1898			if ((cp = nextline(fconfig)))
1899				goto again;
1900		*cpp = (char *)0;
1901		return ((char *)0);
1902	}
1903	if (*cp == '"' || *cp == '\'')
1904		quote = *cp++;
1905	start = cp;
1906	if (quote)
1907		while (*cp && *cp != quote)
1908			cp++;
1909	else
1910		while (*cp && *cp != ' ' && *cp != '\t')
1911			cp++;
1912	if (*cp != '\0')
1913		*cp++ = '\0';
1914	*cpp = cp;
1915	return (start);
1916}
1917
1918char *
1919nextline(FILE *fd)
1920{
1921	char *cp;
1922
1923	if (fgets(line, sizeof (line), fd) == NULL)
1924		return ((char *)0);
1925	cp = strchr(line, '\n');
1926	if (cp)
1927		*cp = '\0';
1928	return (line);
1929}
1930
1931char *
1932newstr(const char *cp)
1933{
1934	char *cr;
1935
1936	if ((cr = strdup(cp != NULL ? cp : "")))
1937		return (cr);
1938	syslog(LOG_ERR, "strdup: %m");
1939	exit(EX_OSERR);
1940}
1941
1942void
1943inetd_setproctitle(const char *a, int s)
1944{
1945	socklen_t size;
1946	struct sockaddr_storage ss;
1947	char buf[80], pbuf[INET6_ADDRSTRLEN];
1948
1949	size = sizeof(ss);
1950	if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
1951		getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf),
1952			    NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID);
1953		(void) sprintf(buf, "%s [%s]", a, pbuf);
1954	} else
1955		(void) sprintf(buf, "%s", a);
1956	setproctitle("%s", buf);
1957}
1958
1959int
1960check_loop(const struct sockaddr *sa, const struct servtab *sep)
1961{
1962	struct servtab *se2;
1963	char pname[INET6_ADDRSTRLEN];
1964
1965	for (se2 = servtab; se2; se2 = se2->se_next) {
1966		if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
1967			continue;
1968
1969		switch (se2->se_family) {
1970		case AF_INET:
1971			if (((const struct sockaddr_in *)sa)->sin_port ==
1972			    se2->se_ctrladdr4.sin_port)
1973				goto isloop;
1974			continue;
1975#ifdef INET6
1976		case AF_INET6:
1977			if (((const struct sockaddr_in *)sa)->sin_port ==
1978			    se2->se_ctrladdr4.sin_port)
1979				goto isloop;
1980			continue;
1981#endif
1982		default:
1983			continue;
1984		}
1985	isloop:
1986		getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0,
1987			    NI_NUMERICHOST|NI_WITHSCOPEID);
1988		syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s",
1989		       sep->se_service, sep->se_proto,
1990		       se2->se_service, se2->se_proto,
1991		       pname);
1992		return 1;
1993	}
1994	return 0;
1995}
1996
1997/*
1998 * print_service:
1999 *	Dump relevant information to stderr
2000 */
2001void
2002print_service(const char *action, const struct servtab *sep)
2003{
2004	fprintf(stderr,
2005	    "%s: %s proto=%s accept=%d max=%d user=%s group=%s"
2006#ifdef LOGIN_CAP
2007	    "class=%s"
2008#endif
2009	    " builtin=%p server=%s"
2010#ifdef IPSEC
2011	    " policy=\"%s\""
2012#endif
2013	    "\n",
2014	    action, sep->se_service, sep->se_proto,
2015	    sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group,
2016#ifdef LOGIN_CAP
2017	    sep->se_class,
2018#endif
2019	    (void *) sep->se_bi, sep->se_server
2020#ifdef IPSEC
2021	    , (sep->se_policy ? sep->se_policy : "")
2022#endif
2023	    );
2024}
2025
2026#define CPMHSIZE	256
2027#define CPMHMASK	(CPMHSIZE-1)
2028#define CHTGRAN		10
2029#define CHTSIZE		6
2030
2031typedef struct CTime {
2032	unsigned long 	ct_Ticks;
2033	int		ct_Count;
2034} CTime;
2035
2036typedef struct CHash {
2037	union {
2038		struct in_addr	c4_Addr;
2039		struct in6_addr	c6_Addr;
2040	} cu_Addr;
2041#define	ch_Addr4	cu_Addr.c4_Addr
2042#define	ch_Addr6	cu_Addr.c6_Addr
2043	int		ch_Family;
2044	time_t		ch_LTime;
2045	char		*ch_Service;
2046	CTime		ch_Times[CHTSIZE];
2047} CHash;
2048
2049CHash	CHashAry[CPMHSIZE];
2050
2051int
2052cpmip(const struct servtab *sep, int ctrl)
2053{
2054	struct sockaddr_storage rss;
2055	socklen_t rssLen = sizeof(rss);
2056	int r = 0;
2057
2058	/*
2059	 * If getpeername() fails, just let it through (if logging is
2060	 * enabled the condition is caught elsewhere)
2061	 */
2062
2063	if (sep->se_maxcpm > 0 &&
2064	    getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) {
2065		time_t t = time(NULL);
2066		int hv = 0xABC3D20F;
2067		int i;
2068		int cnt = 0;
2069		CHash *chBest = NULL;
2070		unsigned int ticks = t / CHTGRAN;
2071		struct sockaddr_in *sin4;
2072#ifdef INET6
2073		struct sockaddr_in6 *sin6;
2074#endif
2075
2076		sin4 = (struct sockaddr_in *)&rss;
2077#ifdef INET6
2078		sin6 = (struct sockaddr_in6 *)&rss;
2079#endif
2080		{
2081			char *p;
2082			int addrlen;
2083
2084			switch (rss.ss_family) {
2085			case AF_INET:
2086				p = (char *)&sin4->sin_addr;
2087				addrlen = sizeof(struct in_addr);
2088				break;
2089#ifdef INET6
2090			case AF_INET6:
2091				p = (char *)&sin6->sin6_addr;
2092				addrlen = sizeof(struct in6_addr);
2093				break;
2094#endif
2095			default:
2096				/* should not happen */
2097				return -1;
2098			}
2099
2100			for (i = 0; i < addrlen; ++i, ++p) {
2101				hv = (hv << 5) ^ (hv >> 23) ^ *p;
2102			}
2103			hv = (hv ^ (hv >> 16));
2104		}
2105		for (i = 0; i < 5; ++i) {
2106			CHash *ch = &CHashAry[(hv + i) & CPMHMASK];
2107
2108			if (rss.ss_family == AF_INET &&
2109			    ch->ch_Family == AF_INET &&
2110			    sin4->sin_addr.s_addr == ch->ch_Addr4.s_addr &&
2111			    ch->ch_Service && strcmp(sep->se_service,
2112			    ch->ch_Service) == 0) {
2113				chBest = ch;
2114				break;
2115			}
2116#ifdef INET6
2117			if (rss.ss_family == AF_INET6 &&
2118			    ch->ch_Family == AF_INET6 &&
2119			    IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
2120					       &ch->ch_Addr6) != 0 &&
2121			    ch->ch_Service && strcmp(sep->se_service,
2122			    ch->ch_Service) == 0) {
2123				chBest = ch;
2124				break;
2125			}
2126#endif
2127			if (chBest == NULL || ch->ch_LTime == 0 ||
2128			    ch->ch_LTime < chBest->ch_LTime) {
2129				chBest = ch;
2130			}
2131		}
2132		if ((rss.ss_family == AF_INET &&
2133		     (chBest->ch_Family != AF_INET ||
2134		      sin4->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) ||
2135		    chBest->ch_Service == NULL ||
2136		    strcmp(sep->se_service, chBest->ch_Service) != 0) {
2137			chBest->ch_Family = sin4->sin_family;
2138			chBest->ch_Addr4 = sin4->sin_addr;
2139			if (chBest->ch_Service)
2140				free(chBest->ch_Service);
2141			chBest->ch_Service = strdup(sep->se_service);
2142			bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
2143		}
2144#ifdef INET6
2145		if ((rss.ss_family == AF_INET6 &&
2146		     (chBest->ch_Family != AF_INET6 ||
2147		      IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
2148					 &chBest->ch_Addr6) == 0)) ||
2149		    chBest->ch_Service == NULL ||
2150		    strcmp(sep->se_service, chBest->ch_Service) != 0) {
2151			chBest->ch_Family = sin6->sin6_family;
2152			chBest->ch_Addr6 = sin6->sin6_addr;
2153			if (chBest->ch_Service)
2154				free(chBest->ch_Service);
2155			chBest->ch_Service = strdup(sep->se_service);
2156			bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
2157		}
2158#endif
2159		chBest->ch_LTime = t;
2160		{
2161			CTime *ct = &chBest->ch_Times[ticks % CHTSIZE];
2162			if (ct->ct_Ticks != ticks) {
2163				ct->ct_Ticks = ticks;
2164				ct->ct_Count = 0;
2165			}
2166			++ct->ct_Count;
2167		}
2168		for (i = 0; i < CHTSIZE; ++i) {
2169			CTime *ct = &chBest->ch_Times[i];
2170			if (ct->ct_Ticks <= ticks &&
2171			    ct->ct_Ticks >= ticks - CHTSIZE) {
2172				cnt += ct->ct_Count;
2173			}
2174		}
2175		if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) {
2176			char pname[INET6_ADDRSTRLEN];
2177
2178			getnameinfo((struct sockaddr *)&rss,
2179				    ((struct sockaddr *)&rss)->sa_len,
2180				    pname, sizeof(pname), NULL, 0,
2181				    NI_NUMERICHOST|NI_WITHSCOPEID);
2182			r = -1;
2183			syslog(LOG_ERR,
2184			    "%s from %s exceeded counts/min (limit %d/min)",
2185			    sep->se_service, pname,
2186			    sep->se_maxcpm);
2187		}
2188	}
2189	return(r);
2190}
2191