xref: /minix3/usr.sbin/inetd/inetd.c (revision c3b6f8f269dded933641674db559d1ecea71d5f1)
1*c3b6f8f2SDavid van Moolenbroek /*	$NetBSD: inetd.c,v 1.122 2014/04/05 23:36:10 khorben Exp $	*/
2*c3b6f8f2SDavid van Moolenbroek 
3*c3b6f8f2SDavid van Moolenbroek /*-
4*c3b6f8f2SDavid van Moolenbroek  * Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
5*c3b6f8f2SDavid van Moolenbroek  * All rights reserved.
6*c3b6f8f2SDavid van Moolenbroek  *
7*c3b6f8f2SDavid van Moolenbroek  * This code is derived from software contributed to The NetBSD Foundation
8*c3b6f8f2SDavid van Moolenbroek  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9*c3b6f8f2SDavid van Moolenbroek  * NASA Ames Research Center and by Matthias Scheler.
10*c3b6f8f2SDavid van Moolenbroek  *
11*c3b6f8f2SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
12*c3b6f8f2SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
13*c3b6f8f2SDavid van Moolenbroek  * are met:
14*c3b6f8f2SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
15*c3b6f8f2SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
16*c3b6f8f2SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
17*c3b6f8f2SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
18*c3b6f8f2SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
19*c3b6f8f2SDavid van Moolenbroek  *
20*c3b6f8f2SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21*c3b6f8f2SDavid van Moolenbroek  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22*c3b6f8f2SDavid van Moolenbroek  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23*c3b6f8f2SDavid van Moolenbroek  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24*c3b6f8f2SDavid van Moolenbroek  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25*c3b6f8f2SDavid van Moolenbroek  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26*c3b6f8f2SDavid van Moolenbroek  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27*c3b6f8f2SDavid van Moolenbroek  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28*c3b6f8f2SDavid van Moolenbroek  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29*c3b6f8f2SDavid van Moolenbroek  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30*c3b6f8f2SDavid van Moolenbroek  * POSSIBILITY OF SUCH DAMAGE.
31*c3b6f8f2SDavid van Moolenbroek  */
32*c3b6f8f2SDavid van Moolenbroek 
33*c3b6f8f2SDavid van Moolenbroek /*
34*c3b6f8f2SDavid van Moolenbroek  * Copyright (c) 1983, 1991, 1993, 1994
35*c3b6f8f2SDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
36*c3b6f8f2SDavid van Moolenbroek  *
37*c3b6f8f2SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
38*c3b6f8f2SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
39*c3b6f8f2SDavid van Moolenbroek  * are met:
40*c3b6f8f2SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
41*c3b6f8f2SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
42*c3b6f8f2SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
43*c3b6f8f2SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
44*c3b6f8f2SDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
45*c3b6f8f2SDavid van Moolenbroek  * 3. Neither the name of the University nor the names of its contributors
46*c3b6f8f2SDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
47*c3b6f8f2SDavid van Moolenbroek  *    without specific prior written permission.
48*c3b6f8f2SDavid van Moolenbroek  *
49*c3b6f8f2SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50*c3b6f8f2SDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51*c3b6f8f2SDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52*c3b6f8f2SDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53*c3b6f8f2SDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54*c3b6f8f2SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55*c3b6f8f2SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56*c3b6f8f2SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57*c3b6f8f2SDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58*c3b6f8f2SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59*c3b6f8f2SDavid van Moolenbroek  * SUCH DAMAGE.
60*c3b6f8f2SDavid van Moolenbroek  */
61*c3b6f8f2SDavid van Moolenbroek 
62*c3b6f8f2SDavid van Moolenbroek #include <sys/cdefs.h>
63*c3b6f8f2SDavid van Moolenbroek #ifndef lint
64*c3b6f8f2SDavid van Moolenbroek __COPYRIGHT("@(#) Copyright (c) 1983, 1991, 1993, 1994\
65*c3b6f8f2SDavid van Moolenbroek  The Regents of the University of California.  All rights reserved.");
66*c3b6f8f2SDavid van Moolenbroek #if 0
67*c3b6f8f2SDavid van Moolenbroek static char sccsid[] = "@(#)inetd.c	8.4 (Berkeley) 4/13/94";
68*c3b6f8f2SDavid van Moolenbroek #else
69*c3b6f8f2SDavid van Moolenbroek __RCSID("$NetBSD: inetd.c,v 1.122 2014/04/05 23:36:10 khorben Exp $");
70*c3b6f8f2SDavid van Moolenbroek #endif
71*c3b6f8f2SDavid van Moolenbroek #endif /* not lint */
72*c3b6f8f2SDavid van Moolenbroek 
73*c3b6f8f2SDavid van Moolenbroek /*
74*c3b6f8f2SDavid van Moolenbroek  * Inetd - Internet super-server
75*c3b6f8f2SDavid van Moolenbroek  *
76*c3b6f8f2SDavid van Moolenbroek  * This program invokes all internet services as needed.  Connection-oriented
77*c3b6f8f2SDavid van Moolenbroek  * services are invoked each time a connection is made, by creating a process.
78*c3b6f8f2SDavid van Moolenbroek  * This process is passed the connection as file descriptor 0 and is expected
79*c3b6f8f2SDavid van Moolenbroek  * to do a getpeername to find out the source host and port.
80*c3b6f8f2SDavid van Moolenbroek  *
81*c3b6f8f2SDavid van Moolenbroek  * Datagram oriented services are invoked when a datagram
82*c3b6f8f2SDavid van Moolenbroek  * arrives; a process is created and passed a pending message
83*c3b6f8f2SDavid van Moolenbroek  * on file descriptor 0.  Datagram servers may either connect
84*c3b6f8f2SDavid van Moolenbroek  * to their peer, freeing up the original socket for inetd
85*c3b6f8f2SDavid van Moolenbroek  * to receive further messages on, or ``take over the socket'',
86*c3b6f8f2SDavid van Moolenbroek  * processing all arriving datagrams and, eventually, timing
87*c3b6f8f2SDavid van Moolenbroek  * out.	 The first type of server is said to be ``multi-threaded'';
88*c3b6f8f2SDavid van Moolenbroek  * the second type of server ``single-threaded''.
89*c3b6f8f2SDavid van Moolenbroek  *
90*c3b6f8f2SDavid van Moolenbroek  * Inetd uses a configuration file which is read at startup
91*c3b6f8f2SDavid van Moolenbroek  * and, possibly, at some later time in response to a hangup signal.
92*c3b6f8f2SDavid van Moolenbroek  * The configuration file is ``free format'' with fields given in the
93*c3b6f8f2SDavid van Moolenbroek  * order shown below.  Continuation lines for an entry must being with
94*c3b6f8f2SDavid van Moolenbroek  * a space or tab.  All fields must be present in each entry.
95*c3b6f8f2SDavid van Moolenbroek  *
96*c3b6f8f2SDavid van Moolenbroek  *	service name			must be in /etc/services or must
97*c3b6f8f2SDavid van Moolenbroek  *					name a tcpmux service
98*c3b6f8f2SDavid van Moolenbroek  *	socket type[:accf[,arg]]	stream/dgram/raw/rdm/seqpacket,
99*c3b6f8f2SDavid van Moolenbroek 					only stream can name an accept filter
100*c3b6f8f2SDavid van Moolenbroek  *	protocol			must be in /etc/protocols
101*c3b6f8f2SDavid van Moolenbroek  *	wait/nowait[:max]		single-threaded/multi-threaded, max #
102*c3b6f8f2SDavid van Moolenbroek  *	user[:group]			user/group to run daemon as
103*c3b6f8f2SDavid van Moolenbroek  *	server program			full path name
104*c3b6f8f2SDavid van Moolenbroek  *	server program arguments	maximum of MAXARGS (20)
105*c3b6f8f2SDavid van Moolenbroek  *
106*c3b6f8f2SDavid van Moolenbroek  * For RPC services
107*c3b6f8f2SDavid van Moolenbroek  *      service name/version            must be in /etc/rpc
108*c3b6f8f2SDavid van Moolenbroek  *	socket type			stream/dgram/raw/rdm/seqpacket
109*c3b6f8f2SDavid van Moolenbroek  *	protocol			must be in /etc/protocols
110*c3b6f8f2SDavid van Moolenbroek  *	wait/nowait[:max]		single-threaded/multi-threaded
111*c3b6f8f2SDavid van Moolenbroek  *	user[:group]			user to run daemon as
112*c3b6f8f2SDavid van Moolenbroek  *	server program			full path name
113*c3b6f8f2SDavid van Moolenbroek  *	server program arguments	maximum of MAXARGS (20)
114*c3b6f8f2SDavid van Moolenbroek  *
115*c3b6f8f2SDavid van Moolenbroek  * For non-RPC services, the "service name" can be of the form
116*c3b6f8f2SDavid van Moolenbroek  * hostaddress:servicename, in which case the hostaddress is used
117*c3b6f8f2SDavid van Moolenbroek  * as the host portion of the address to listen on.  If hostaddress
118*c3b6f8f2SDavid van Moolenbroek  * consists of a single `*' character, INADDR_ANY is used.
119*c3b6f8f2SDavid van Moolenbroek  *
120*c3b6f8f2SDavid van Moolenbroek  * A line can also consist of just
121*c3b6f8f2SDavid van Moolenbroek  *	hostaddress:
122*c3b6f8f2SDavid van Moolenbroek  * where hostaddress is as in the preceding paragraph.  Such a line must
123*c3b6f8f2SDavid van Moolenbroek  * have no further fields; the specified hostaddress is remembered and
124*c3b6f8f2SDavid van Moolenbroek  * used for all further lines that have no hostaddress specified,
125*c3b6f8f2SDavid van Moolenbroek  * until the next such line (or EOF).  (This is why * is provided to
126*c3b6f8f2SDavid van Moolenbroek  * allow explicit specification of INADDR_ANY.)  A line
127*c3b6f8f2SDavid van Moolenbroek  *	*:
128*c3b6f8f2SDavid van Moolenbroek  * is implicitly in effect at the beginning of the file.
129*c3b6f8f2SDavid van Moolenbroek  *
130*c3b6f8f2SDavid van Moolenbroek  * The hostaddress specifier may (and often will) contain dots;
131*c3b6f8f2SDavid van Moolenbroek  * the service name must not.
132*c3b6f8f2SDavid van Moolenbroek  *
133*c3b6f8f2SDavid van Moolenbroek  * For RPC services, host-address specifiers are accepted and will
134*c3b6f8f2SDavid van Moolenbroek  * work to some extent; however, because of limitations in the
135*c3b6f8f2SDavid van Moolenbroek  * portmapper interface, it will not work to try to give more than
136*c3b6f8f2SDavid van Moolenbroek  * one line for any given RPC service, even if the host-address
137*c3b6f8f2SDavid van Moolenbroek  * specifiers are different.
138*c3b6f8f2SDavid van Moolenbroek  *
139*c3b6f8f2SDavid van Moolenbroek  * TCP services without official port numbers are handled with the
140*c3b6f8f2SDavid van Moolenbroek  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
141*c3b6f8f2SDavid van Moolenbroek  * requests. When a connection is made from a foreign host, the service
142*c3b6f8f2SDavid van Moolenbroek  * requested is passed to tcpmux, which looks it up in the servtab list
143*c3b6f8f2SDavid van Moolenbroek  * and returns the proper entry for the service. Tcpmux returns a
144*c3b6f8f2SDavid van Moolenbroek  * negative reply if the service doesn't exist, otherwise the invoked
145*c3b6f8f2SDavid van Moolenbroek  * server is expected to return the positive reply if the service type in
146*c3b6f8f2SDavid van Moolenbroek  * inetd.conf file has the prefix "tcpmux/". If the service type has the
147*c3b6f8f2SDavid van Moolenbroek  * prefix "tcpmux/+", tcpmux will return the positive reply for the
148*c3b6f8f2SDavid van Moolenbroek  * process; this is for compatibility with older server code, and also
149*c3b6f8f2SDavid van Moolenbroek  * allows you to invoke programs that use stdin/stdout without putting any
150*c3b6f8f2SDavid van Moolenbroek  * special server code in them. Services that use tcpmux are "nowait"
151*c3b6f8f2SDavid van Moolenbroek  * because they do not have a well-known port and hence cannot listen
152*c3b6f8f2SDavid van Moolenbroek  * for new requests.
153*c3b6f8f2SDavid van Moolenbroek  *
154*c3b6f8f2SDavid van Moolenbroek  * Comment lines are indicated by a `#' in column 1.
155*c3b6f8f2SDavid van Moolenbroek  *
156*c3b6f8f2SDavid van Moolenbroek  * #ifdef IPSEC
157*c3b6f8f2SDavid van Moolenbroek  * Comment lines that start with "#@" denote IPsec policy string, as described
158*c3b6f8f2SDavid van Moolenbroek  * in ipsec_set_policy(3).  This will affect all the following items in
159*c3b6f8f2SDavid van Moolenbroek  * inetd.conf(8).  To reset the policy, just use "#@" line.  By default,
160*c3b6f8f2SDavid van Moolenbroek  * there's no IPsec policy.
161*c3b6f8f2SDavid van Moolenbroek  * #endif
162*c3b6f8f2SDavid van Moolenbroek  */
163*c3b6f8f2SDavid van Moolenbroek 
164*c3b6f8f2SDavid van Moolenbroek /*
165*c3b6f8f2SDavid van Moolenbroek  * Here's the scoop concerning the user:group feature:
166*c3b6f8f2SDavid van Moolenbroek  *
167*c3b6f8f2SDavid van Moolenbroek  * 1) set-group-option off.
168*c3b6f8f2SDavid van Moolenbroek  *
169*c3b6f8f2SDavid van Moolenbroek  * 	a) user = root:	NO setuid() or setgid() is done
170*c3b6f8f2SDavid van Moolenbroek  *
171*c3b6f8f2SDavid van Moolenbroek  * 	b) other:	setuid()
172*c3b6f8f2SDavid van Moolenbroek  * 			setgid(primary group as found in passwd)
173*c3b6f8f2SDavid van Moolenbroek  * 			initgroups(name, primary group)
174*c3b6f8f2SDavid van Moolenbroek  *
175*c3b6f8f2SDavid van Moolenbroek  * 2) set-group-option on.
176*c3b6f8f2SDavid van Moolenbroek  *
177*c3b6f8f2SDavid van Moolenbroek  * 	a) user = root:	NO setuid()
178*c3b6f8f2SDavid van Moolenbroek  * 			setgid(specified group)
179*c3b6f8f2SDavid van Moolenbroek  * 			NO initgroups()
180*c3b6f8f2SDavid van Moolenbroek  *
181*c3b6f8f2SDavid van Moolenbroek  * 	b) other:	setuid()
182*c3b6f8f2SDavid van Moolenbroek  * 			setgid(specified group)
183*c3b6f8f2SDavid van Moolenbroek  * 			initgroups(name, specified group)
184*c3b6f8f2SDavid van Moolenbroek  *
185*c3b6f8f2SDavid van Moolenbroek  */
186*c3b6f8f2SDavid van Moolenbroek 
187*c3b6f8f2SDavid van Moolenbroek #include <sys/param.h>
188*c3b6f8f2SDavid van Moolenbroek #include <sys/stat.h>
189*c3b6f8f2SDavid van Moolenbroek #include <sys/ioctl.h>
190*c3b6f8f2SDavid van Moolenbroek #include <sys/socket.h>
191*c3b6f8f2SDavid van Moolenbroek #include <sys/un.h>
192*c3b6f8f2SDavid van Moolenbroek #include <sys/wait.h>
193*c3b6f8f2SDavid van Moolenbroek #include <sys/time.h>
194*c3b6f8f2SDavid van Moolenbroek #include <sys/resource.h>
195*c3b6f8f2SDavid van Moolenbroek #include <sys/event.h>
196*c3b6f8f2SDavid van Moolenbroek 
197*c3b6f8f2SDavid van Moolenbroek #ifndef NO_RPC
198*c3b6f8f2SDavid van Moolenbroek #define RPC
199*c3b6f8f2SDavid van Moolenbroek #endif
200*c3b6f8f2SDavid van Moolenbroek 
201*c3b6f8f2SDavid van Moolenbroek #include <net/if.h>
202*c3b6f8f2SDavid van Moolenbroek 
203*c3b6f8f2SDavid van Moolenbroek #include <netinet/in.h>
204*c3b6f8f2SDavid van Moolenbroek #include <arpa/inet.h>
205*c3b6f8f2SDavid van Moolenbroek #ifdef RPC
206*c3b6f8f2SDavid van Moolenbroek #include <rpc/rpc.h>
207*c3b6f8f2SDavid van Moolenbroek #include <rpc/rpcb_clnt.h>
208*c3b6f8f2SDavid van Moolenbroek #include <netconfig.h>
209*c3b6f8f2SDavid van Moolenbroek #endif
210*c3b6f8f2SDavid van Moolenbroek 
211*c3b6f8f2SDavid van Moolenbroek #include <ctype.h>
212*c3b6f8f2SDavid van Moolenbroek #include <errno.h>
213*c3b6f8f2SDavid van Moolenbroek #include <fcntl.h>
214*c3b6f8f2SDavid van Moolenbroek #include <grp.h>
215*c3b6f8f2SDavid van Moolenbroek #include <netdb.h>
216*c3b6f8f2SDavid van Moolenbroek #include <pwd.h>
217*c3b6f8f2SDavid van Moolenbroek #include <signal.h>
218*c3b6f8f2SDavid van Moolenbroek #include <stdio.h>
219*c3b6f8f2SDavid van Moolenbroek #include <stdlib.h>
220*c3b6f8f2SDavid van Moolenbroek #include <string.h>
221*c3b6f8f2SDavid van Moolenbroek #include <syslog.h>
222*c3b6f8f2SDavid van Moolenbroek #include <unistd.h>
223*c3b6f8f2SDavid van Moolenbroek #include <util.h>
224*c3b6f8f2SDavid van Moolenbroek #include <ifaddrs.h>
225*c3b6f8f2SDavid van Moolenbroek 
226*c3b6f8f2SDavid van Moolenbroek #include "pathnames.h"
227*c3b6f8f2SDavid van Moolenbroek 
228*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
229*c3b6f8f2SDavid van Moolenbroek #include <netipsec/ipsec.h>
230*c3b6f8f2SDavid van Moolenbroek #ifndef IPSEC_POLICY_IPSEC	/* no ipsec support on old ipsec */
231*c3b6f8f2SDavid van Moolenbroek #undef IPSEC
232*c3b6f8f2SDavid van Moolenbroek #endif
233*c3b6f8f2SDavid van Moolenbroek #include "ipsec.h"
234*c3b6f8f2SDavid van Moolenbroek #endif
235*c3b6f8f2SDavid van Moolenbroek 
236*c3b6f8f2SDavid van Moolenbroek #ifdef LIBWRAP
237*c3b6f8f2SDavid van Moolenbroek # include <tcpd.h>
238*c3b6f8f2SDavid van Moolenbroek #ifndef LIBWRAP_ALLOW_FACILITY
239*c3b6f8f2SDavid van Moolenbroek # define LIBWRAP_ALLOW_FACILITY LOG_AUTH
240*c3b6f8f2SDavid van Moolenbroek #endif
241*c3b6f8f2SDavid van Moolenbroek #ifndef LIBWRAP_ALLOW_SEVERITY
242*c3b6f8f2SDavid van Moolenbroek # define LIBWRAP_ALLOW_SEVERITY LOG_INFO
243*c3b6f8f2SDavid van Moolenbroek #endif
244*c3b6f8f2SDavid van Moolenbroek #ifndef LIBWRAP_DENY_FACILITY
245*c3b6f8f2SDavid van Moolenbroek # define LIBWRAP_DENY_FACILITY LOG_AUTH
246*c3b6f8f2SDavid van Moolenbroek #endif
247*c3b6f8f2SDavid van Moolenbroek #ifndef LIBWRAP_DENY_SEVERITY
248*c3b6f8f2SDavid van Moolenbroek # define LIBWRAP_DENY_SEVERITY LOG_WARNING
249*c3b6f8f2SDavid van Moolenbroek #endif
250*c3b6f8f2SDavid van Moolenbroek int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
251*c3b6f8f2SDavid van Moolenbroek int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
252*c3b6f8f2SDavid van Moolenbroek #endif
253*c3b6f8f2SDavid van Moolenbroek 
254*c3b6f8f2SDavid van Moolenbroek #define	TOOMANY		40		/* don't start more than TOOMANY */
255*c3b6f8f2SDavid van Moolenbroek #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
256*c3b6f8f2SDavid van Moolenbroek #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
257*c3b6f8f2SDavid van Moolenbroek 
258*c3b6f8f2SDavid van Moolenbroek #define	A_CNT(a)	(sizeof (a) / sizeof (a[0]))
259*c3b6f8f2SDavid van Moolenbroek 
260*c3b6f8f2SDavid van Moolenbroek int	debug;
261*c3b6f8f2SDavid van Moolenbroek #ifdef LIBWRAP
262*c3b6f8f2SDavid van Moolenbroek int	lflag;
263*c3b6f8f2SDavid van Moolenbroek #endif
264*c3b6f8f2SDavid van Moolenbroek int	maxsock;
265*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
266*c3b6f8f2SDavid van Moolenbroek int	kq;
267*c3b6f8f2SDavid van Moolenbroek #else /* __minix */
268*c3b6f8f2SDavid van Moolenbroek int	sig_pipe[2];
269*c3b6f8f2SDavid van Moolenbroek sigset_t sig_mask, old_mask;
270*c3b6f8f2SDavid van Moolenbroek #endif /* __minix */
271*c3b6f8f2SDavid van Moolenbroek int	options;
272*c3b6f8f2SDavid van Moolenbroek int	timingout;
273*c3b6f8f2SDavid van Moolenbroek const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
274*c3b6f8f2SDavid van Moolenbroek 
275*c3b6f8f2SDavid van Moolenbroek #ifndef OPEN_MAX
276*c3b6f8f2SDavid van Moolenbroek #define OPEN_MAX	64
277*c3b6f8f2SDavid van Moolenbroek #endif
278*c3b6f8f2SDavid van Moolenbroek 
279*c3b6f8f2SDavid van Moolenbroek /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
280*c3b6f8f2SDavid van Moolenbroek #define FD_MARGIN	(8)
281*c3b6f8f2SDavid van Moolenbroek rlim_t		rlim_ofile_cur = OPEN_MAX;
282*c3b6f8f2SDavid van Moolenbroek 
283*c3b6f8f2SDavid van Moolenbroek struct rlimit	rlim_ofile;
284*c3b6f8f2SDavid van Moolenbroek 
285*c3b6f8f2SDavid van Moolenbroek struct kevent	changebuf[64];
286*c3b6f8f2SDavid van Moolenbroek size_t		changes;
287*c3b6f8f2SDavid van Moolenbroek 
288*c3b6f8f2SDavid van Moolenbroek struct	servtab {
289*c3b6f8f2SDavid van Moolenbroek 	char	*se_hostaddr;		/* host address to listen on */
290*c3b6f8f2SDavid van Moolenbroek 	char	*se_service;		/* name of service */
291*c3b6f8f2SDavid van Moolenbroek 	int	se_socktype;		/* type of socket to use */
292*c3b6f8f2SDavid van Moolenbroek 	int	se_family;		/* address family */
293*c3b6f8f2SDavid van Moolenbroek 	char	*se_proto;		/* protocol used */
294*c3b6f8f2SDavid van Moolenbroek 	int	se_sndbuf;		/* sndbuf size */
295*c3b6f8f2SDavid van Moolenbroek 	int	se_rcvbuf;		/* rcvbuf size */
296*c3b6f8f2SDavid van Moolenbroek 	int	se_rpcprog;		/* rpc program number */
297*c3b6f8f2SDavid van Moolenbroek 	int	se_rpcversl;		/* rpc program lowest version */
298*c3b6f8f2SDavid van Moolenbroek 	int	se_rpcversh;		/* rpc program highest version */
299*c3b6f8f2SDavid van Moolenbroek #define isrpcservice(sep)	((sep)->se_rpcversl != 0)
300*c3b6f8f2SDavid van Moolenbroek 	pid_t	se_wait;		/* single threaded server */
301*c3b6f8f2SDavid van Moolenbroek 	short	se_checked;		/* looked at during merge */
302*c3b6f8f2SDavid van Moolenbroek 	char	*se_user;		/* user name to run as */
303*c3b6f8f2SDavid van Moolenbroek 	char	*se_group;		/* group name to run as */
304*c3b6f8f2SDavid van Moolenbroek 	struct	biltin *se_bi;		/* if built-in, description */
305*c3b6f8f2SDavid van Moolenbroek 	char	*se_server;		/* server program */
306*c3b6f8f2SDavid van Moolenbroek #define	MAXARGV 20
307*c3b6f8f2SDavid van Moolenbroek 	char	*se_argv[MAXARGV+1];	/* program arguments */
308*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
309*c3b6f8f2SDavid van Moolenbroek 	char	*se_policy;		/* IPsec poilcy string */
310*c3b6f8f2SDavid van Moolenbroek #endif
311*c3b6f8f2SDavid van Moolenbroek 	struct accept_filter_arg se_accf; /* accept filter for stream service */
312*c3b6f8f2SDavid van Moolenbroek 	int	se_fd;			/* open descriptor */
313*c3b6f8f2SDavid van Moolenbroek 	int	se_type;		/* type */
314*c3b6f8f2SDavid van Moolenbroek 	union {
315*c3b6f8f2SDavid van Moolenbroek 		struct	sockaddr se_un_ctrladdr;
316*c3b6f8f2SDavid van Moolenbroek 		struct	sockaddr_in se_un_ctrladdr_in;
317*c3b6f8f2SDavid van Moolenbroek 		struct	sockaddr_in6 se_un_ctrladdr_in6;
318*c3b6f8f2SDavid van Moolenbroek 		struct	sockaddr_un se_un_ctrladdr_un;
319*c3b6f8f2SDavid van Moolenbroek 	} se_un;			/* bound address */
320*c3b6f8f2SDavid van Moolenbroek #define se_ctrladdr	se_un.se_un_ctrladdr
321*c3b6f8f2SDavid van Moolenbroek #define se_ctrladdr_in	se_un.se_un_ctrladdr_in
322*c3b6f8f2SDavid van Moolenbroek #define se_ctrladdr_un	se_un.se_un_ctrladdr_un
323*c3b6f8f2SDavid van Moolenbroek 	int	se_ctrladdr_size;
324*c3b6f8f2SDavid van Moolenbroek 	int	se_max;			/* max # of instances of this service */
325*c3b6f8f2SDavid van Moolenbroek 	int	se_count;		/* number started since se_time */
326*c3b6f8f2SDavid van Moolenbroek 	struct	timeval se_time;	/* start of se_count */
327*c3b6f8f2SDavid van Moolenbroek 	struct	servtab *se_next;
328*c3b6f8f2SDavid van Moolenbroek } *servtab;
329*c3b6f8f2SDavid van Moolenbroek 
330*c3b6f8f2SDavid van Moolenbroek #define NORM_TYPE	0
331*c3b6f8f2SDavid van Moolenbroek #define MUX_TYPE	1
332*c3b6f8f2SDavid van Moolenbroek #define MUXPLUS_TYPE	2
333*c3b6f8f2SDavid van Moolenbroek #define FAITH_TYPE	3
334*c3b6f8f2SDavid van Moolenbroek #define ISMUX(sep)	(((sep)->se_type == MUX_TYPE) || \
335*c3b6f8f2SDavid van Moolenbroek 			 ((sep)->se_type == MUXPLUS_TYPE))
336*c3b6f8f2SDavid van Moolenbroek #define ISMUXPLUS(sep)	((sep)->se_type == MUXPLUS_TYPE)
337*c3b6f8f2SDavid van Moolenbroek 
338*c3b6f8f2SDavid van Moolenbroek 
339*c3b6f8f2SDavid van Moolenbroek static void	chargen_dg(int, struct servtab *);
340*c3b6f8f2SDavid van Moolenbroek static void	chargen_stream(int, struct servtab *);
341*c3b6f8f2SDavid van Moolenbroek static void	close_sep(struct servtab *);
342*c3b6f8f2SDavid van Moolenbroek static void	config(void);
343*c3b6f8f2SDavid van Moolenbroek static void	daytime_dg(int, struct servtab *);
344*c3b6f8f2SDavid van Moolenbroek static void	daytime_stream(int, struct servtab *);
345*c3b6f8f2SDavid van Moolenbroek static void	discard_dg(int, struct servtab *);
346*c3b6f8f2SDavid van Moolenbroek static void	discard_stream(int, struct servtab *);
347*c3b6f8f2SDavid van Moolenbroek static void	echo_dg(int, struct servtab *);
348*c3b6f8f2SDavid van Moolenbroek static void	echo_stream(int, struct servtab *);
349*c3b6f8f2SDavid van Moolenbroek static void	endconfig(void);
350*c3b6f8f2SDavid van Moolenbroek static struct servtab *enter(struct servtab *);
351*c3b6f8f2SDavid van Moolenbroek static void	freeconfig(struct servtab *);
352*c3b6f8f2SDavid van Moolenbroek static struct servtab *getconfigent(void);
353*c3b6f8f2SDavid van Moolenbroek __dead static void	goaway(void);
354*c3b6f8f2SDavid van Moolenbroek static void	machtime_dg(int, struct servtab *);
355*c3b6f8f2SDavid van Moolenbroek static void	machtime_stream(int, struct servtab *);
356*c3b6f8f2SDavid van Moolenbroek static char    *newstr(const char *);
357*c3b6f8f2SDavid van Moolenbroek static char    *nextline(FILE *);
358*c3b6f8f2SDavid van Moolenbroek static void	print_service(const char *, struct servtab *);
359*c3b6f8f2SDavid van Moolenbroek static void	reapchild(void);
360*c3b6f8f2SDavid van Moolenbroek static void	retry(void);
361*c3b6f8f2SDavid van Moolenbroek static void	run_service(int, struct servtab *, int);
362*c3b6f8f2SDavid van Moolenbroek static int	setconfig(void);
363*c3b6f8f2SDavid van Moolenbroek static void	setup(struct servtab *);
364*c3b6f8f2SDavid van Moolenbroek static char    *sskip(char **);
365*c3b6f8f2SDavid van Moolenbroek static char    *skip(char **);
366*c3b6f8f2SDavid van Moolenbroek static void	tcpmux(int, struct servtab *);
367*c3b6f8f2SDavid van Moolenbroek __dead static void	usage(void);
368*c3b6f8f2SDavid van Moolenbroek static void	register_rpc(struct servtab *);
369*c3b6f8f2SDavid van Moolenbroek static void	unregister_rpc(struct servtab *);
370*c3b6f8f2SDavid van Moolenbroek static void	bump_nofile(void);
371*c3b6f8f2SDavid van Moolenbroek static void	inetd_setproctitle(char *, int);
372*c3b6f8f2SDavid van Moolenbroek static void	initring(void);
373*c3b6f8f2SDavid van Moolenbroek static uint32_t	machtime(void);
374*c3b6f8f2SDavid van Moolenbroek static int	port_good_dg(struct sockaddr *);
375*c3b6f8f2SDavid van Moolenbroek static int 	dg_broadcast(struct in_addr *);
376*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
377*c3b6f8f2SDavid van Moolenbroek static int	my_kevent(const struct kevent *, size_t, struct kevent *,
378*c3b6f8f2SDavid van Moolenbroek 		size_t);
379*c3b6f8f2SDavid van Moolenbroek static struct kevent *	allocchange(void);
380*c3b6f8f2SDavid van Moolenbroek #endif /* !__minix */
381*c3b6f8f2SDavid van Moolenbroek static int	get_line(int, char *, int);
382*c3b6f8f2SDavid van Moolenbroek static void	spawn(struct servtab *, int);
383*c3b6f8f2SDavid van Moolenbroek 
384*c3b6f8f2SDavid van Moolenbroek struct biltin {
385*c3b6f8f2SDavid van Moolenbroek 	const char *bi_service;		/* internally provided service name */
386*c3b6f8f2SDavid van Moolenbroek 	int	bi_socktype;		/* type of socket supported */
387*c3b6f8f2SDavid van Moolenbroek 	short	bi_fork;		/* 1 if should fork before call */
388*c3b6f8f2SDavid van Moolenbroek 	short	bi_wait;		/* 1 if should wait for child */
389*c3b6f8f2SDavid van Moolenbroek 	void	(*bi_fn)(int, struct servtab *);
390*c3b6f8f2SDavid van Moolenbroek 					/* function which performs it */
391*c3b6f8f2SDavid van Moolenbroek } biltins[] = {
392*c3b6f8f2SDavid van Moolenbroek 	/* Echo received data */
393*c3b6f8f2SDavid van Moolenbroek 	{ "echo",	SOCK_STREAM,	1, 0,	echo_stream },
394*c3b6f8f2SDavid van Moolenbroek 	{ "echo",	SOCK_DGRAM,	0, 0,	echo_dg },
395*c3b6f8f2SDavid van Moolenbroek 
396*c3b6f8f2SDavid van Moolenbroek 	/* Internet /dev/null */
397*c3b6f8f2SDavid van Moolenbroek 	{ "discard",	SOCK_STREAM,	1, 0,	discard_stream },
398*c3b6f8f2SDavid van Moolenbroek 	{ "discard",	SOCK_DGRAM,	0, 0,	discard_dg },
399*c3b6f8f2SDavid van Moolenbroek 
400*c3b6f8f2SDavid van Moolenbroek 	/* Return 32 bit time since 1970 */
401*c3b6f8f2SDavid van Moolenbroek 	{ "time",	SOCK_STREAM,	0, 0,	machtime_stream },
402*c3b6f8f2SDavid van Moolenbroek 	{ "time",	SOCK_DGRAM,	0, 0,	machtime_dg },
403*c3b6f8f2SDavid van Moolenbroek 
404*c3b6f8f2SDavid van Moolenbroek 	/* Return human-readable time */
405*c3b6f8f2SDavid van Moolenbroek 	{ "daytime",	SOCK_STREAM,	0, 0,	daytime_stream },
406*c3b6f8f2SDavid van Moolenbroek 	{ "daytime",	SOCK_DGRAM,	0, 0,	daytime_dg },
407*c3b6f8f2SDavid van Moolenbroek 
408*c3b6f8f2SDavid van Moolenbroek 	/* Familiar character generator */
409*c3b6f8f2SDavid van Moolenbroek 	{ "chargen",	SOCK_STREAM,	1, 0,	chargen_stream },
410*c3b6f8f2SDavid van Moolenbroek 	{ "chargen",	SOCK_DGRAM,	0, 0,	chargen_dg },
411*c3b6f8f2SDavid van Moolenbroek 
412*c3b6f8f2SDavid van Moolenbroek 	{ "tcpmux",	SOCK_STREAM,	1, 0,	tcpmux },
413*c3b6f8f2SDavid van Moolenbroek 
414*c3b6f8f2SDavid van Moolenbroek 	{ NULL, 0, 0, 0, NULL }
415*c3b6f8f2SDavid van Moolenbroek };
416*c3b6f8f2SDavid van Moolenbroek 
417*c3b6f8f2SDavid van Moolenbroek /* list of "bad" ports. I.e. ports that are most obviously used for
418*c3b6f8f2SDavid van Moolenbroek  * "cycling packets" denial of service attacks. See /etc/services.
419*c3b6f8f2SDavid van Moolenbroek  * List must end with port number "0".
420*c3b6f8f2SDavid van Moolenbroek  */
421*c3b6f8f2SDavid van Moolenbroek 
422*c3b6f8f2SDavid van Moolenbroek u_int16_t bad_ports[] =  { 7, 9, 13, 19, 37, 0 };
423*c3b6f8f2SDavid van Moolenbroek 
424*c3b6f8f2SDavid van Moolenbroek 
425*c3b6f8f2SDavid van Moolenbroek #define NUMINT	(sizeof(intab) / sizeof(struct inent))
426*c3b6f8f2SDavid van Moolenbroek const char	*CONFIG = _PATH_INETDCONF;
427*c3b6f8f2SDavid van Moolenbroek 
428*c3b6f8f2SDavid van Moolenbroek static int my_signals[] =
429*c3b6f8f2SDavid van Moolenbroek     { SIGALRM, SIGHUP, SIGCHLD, SIGTERM, SIGINT, SIGPIPE };
430*c3b6f8f2SDavid van Moolenbroek 
431*c3b6f8f2SDavid van Moolenbroek #ifdef __minix
432*c3b6f8f2SDavid van Moolenbroek /*
433*c3b6f8f2SDavid van Moolenbroek  * NetBSD uses kqueue to catch signals, while (explicitly) ignoring them at the
434*c3b6f8f2SDavid van Moolenbroek  * process level.  We (MINIX3) do catch the signals at the process level,
435*c3b6f8f2SDavid van Moolenbroek  * instead sending them into select() using a pipe (djb's self-pipe trick).
436*c3b6f8f2SDavid van Moolenbroek  * That is safe, except it may interrupt system calls other than our select(),
437*c3b6f8f2SDavid van Moolenbroek  * so we also have to set appropriate signal masks (clearing them upon fork).
438*c3b6f8f2SDavid van Moolenbroek  */
439*c3b6f8f2SDavid van Moolenbroek static void
got_signal(int sig)440*c3b6f8f2SDavid van Moolenbroek got_signal(int sig)
441*c3b6f8f2SDavid van Moolenbroek {
442*c3b6f8f2SDavid van Moolenbroek 
443*c3b6f8f2SDavid van Moolenbroek 	(void) write(sig_pipe[1], &sig, sizeof(sig));
444*c3b6f8f2SDavid van Moolenbroek }
445*c3b6f8f2SDavid van Moolenbroek #endif /* __minix */
446*c3b6f8f2SDavid van Moolenbroek 
447*c3b6f8f2SDavid van Moolenbroek int
main(int argc,char * argv[])448*c3b6f8f2SDavid van Moolenbroek main(int argc, char *argv[])
449*c3b6f8f2SDavid van Moolenbroek {
450*c3b6f8f2SDavid van Moolenbroek 	int		ch, n, reload = 1;
451*c3b6f8f2SDavid van Moolenbroek 
452*c3b6f8f2SDavid van Moolenbroek 	while ((ch = getopt(argc, argv,
453*c3b6f8f2SDavid van Moolenbroek #ifdef LIBWRAP
454*c3b6f8f2SDavid van Moolenbroek 					"dl"
455*c3b6f8f2SDavid van Moolenbroek #else
456*c3b6f8f2SDavid van Moolenbroek 					"d"
457*c3b6f8f2SDavid van Moolenbroek #endif
458*c3b6f8f2SDavid van Moolenbroek 					   )) != -1)
459*c3b6f8f2SDavid van Moolenbroek 		switch(ch) {
460*c3b6f8f2SDavid van Moolenbroek 		case 'd':
461*c3b6f8f2SDavid van Moolenbroek 			debug = 1;
462*c3b6f8f2SDavid van Moolenbroek 			options |= SO_DEBUG;
463*c3b6f8f2SDavid van Moolenbroek 			break;
464*c3b6f8f2SDavid van Moolenbroek #ifdef LIBWRAP
465*c3b6f8f2SDavid van Moolenbroek 		case 'l':
466*c3b6f8f2SDavid van Moolenbroek 			lflag = 1;
467*c3b6f8f2SDavid van Moolenbroek 			break;
468*c3b6f8f2SDavid van Moolenbroek #endif
469*c3b6f8f2SDavid van Moolenbroek 		case '?':
470*c3b6f8f2SDavid van Moolenbroek 		default:
471*c3b6f8f2SDavid van Moolenbroek 			usage();
472*c3b6f8f2SDavid van Moolenbroek 		}
473*c3b6f8f2SDavid van Moolenbroek 	argc -= optind;
474*c3b6f8f2SDavid van Moolenbroek 	argv += optind;
475*c3b6f8f2SDavid van Moolenbroek 
476*c3b6f8f2SDavid van Moolenbroek 	if (argc > 0)
477*c3b6f8f2SDavid van Moolenbroek 		CONFIG = argv[0];
478*c3b6f8f2SDavid van Moolenbroek 
479*c3b6f8f2SDavid van Moolenbroek 	if (!debug)
480*c3b6f8f2SDavid van Moolenbroek 		daemon(0, 0);
481*c3b6f8f2SDavid van Moolenbroek 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
482*c3b6f8f2SDavid van Moolenbroek 	pidfile(NULL);
483*c3b6f8f2SDavid van Moolenbroek 
484*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
485*c3b6f8f2SDavid van Moolenbroek 	kq = kqueue();
486*c3b6f8f2SDavid van Moolenbroek 	if (kq < 0) {
487*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "kqueue: %m");
488*c3b6f8f2SDavid van Moolenbroek 		return (EXIT_FAILURE);
489*c3b6f8f2SDavid van Moolenbroek 	}
490*c3b6f8f2SDavid van Moolenbroek #else /* __minix */
491*c3b6f8f2SDavid van Moolenbroek 	if (pipe2(sig_pipe, O_CLOEXEC | O_NONBLOCK) != 0) {
492*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "pipe2: %m");
493*c3b6f8f2SDavid van Moolenbroek 		return (EXIT_FAILURE);
494*c3b6f8f2SDavid van Moolenbroek 	}
495*c3b6f8f2SDavid van Moolenbroek 
496*c3b6f8f2SDavid van Moolenbroek 	/* Block all signals until the first select() call.. just easier. */
497*c3b6f8f2SDavid van Moolenbroek 	sigfillset(&sig_mask);
498*c3b6f8f2SDavid van Moolenbroek 	(void) sigprocmask(SIG_SETMASK, &sig_mask, &old_mask);
499*c3b6f8f2SDavid van Moolenbroek 	sig_mask = old_mask;
500*c3b6f8f2SDavid van Moolenbroek #endif /* __minix */
501*c3b6f8f2SDavid van Moolenbroek 
502*c3b6f8f2SDavid van Moolenbroek 	if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
503*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "getrlimit: %m");
504*c3b6f8f2SDavid van Moolenbroek 	} else {
505*c3b6f8f2SDavid van Moolenbroek 		rlim_ofile_cur = rlim_ofile.rlim_cur;
506*c3b6f8f2SDavid van Moolenbroek 		if (rlim_ofile_cur == RLIM_INFINITY)	/* ! */
507*c3b6f8f2SDavid van Moolenbroek 			rlim_ofile_cur = OPEN_MAX;
508*c3b6f8f2SDavid van Moolenbroek 	}
509*c3b6f8f2SDavid van Moolenbroek 
510*c3b6f8f2SDavid van Moolenbroek 	for (n = 0; n < (int)A_CNT(my_signals); n++) {
511*c3b6f8f2SDavid van Moolenbroek 		int	signum;
512*c3b6f8f2SDavid van Moolenbroek 
513*c3b6f8f2SDavid van Moolenbroek 		signum = my_signals[n];
514*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
515*c3b6f8f2SDavid van Moolenbroek 		if (signum != SIGCHLD)
516*c3b6f8f2SDavid van Moolenbroek 			(void) signal(signum, SIG_IGN);
517*c3b6f8f2SDavid van Moolenbroek 
518*c3b6f8f2SDavid van Moolenbroek 		if (signum != SIGPIPE) {
519*c3b6f8f2SDavid van Moolenbroek 			struct kevent	*ev;
520*c3b6f8f2SDavid van Moolenbroek 
521*c3b6f8f2SDavid van Moolenbroek 			ev = allocchange();
522*c3b6f8f2SDavid van Moolenbroek 			EV_SET(ev, signum, EVFILT_SIGNAL, EV_ADD | EV_ENABLE,
523*c3b6f8f2SDavid van Moolenbroek 			    0, 0, 0);
524*c3b6f8f2SDavid van Moolenbroek 		}
525*c3b6f8f2SDavid van Moolenbroek #else /* __minix */
526*c3b6f8f2SDavid van Moolenbroek 		/* The above code ignores but does not "catch" SIGPIPE. */
527*c3b6f8f2SDavid van Moolenbroek 		if (signum != SIGPIPE)
528*c3b6f8f2SDavid van Moolenbroek 			(void) signal(signum, got_signal);
529*c3b6f8f2SDavid van Moolenbroek 		else
530*c3b6f8f2SDavid van Moolenbroek 			(void) signal(signum, SIG_IGN);
531*c3b6f8f2SDavid van Moolenbroek 		sigaddset(&sig_mask, signum);
532*c3b6f8f2SDavid van Moolenbroek #endif /* __minix */
533*c3b6f8f2SDavid van Moolenbroek 	}
534*c3b6f8f2SDavid van Moolenbroek 
535*c3b6f8f2SDavid van Moolenbroek 	for (;;) {
536*c3b6f8f2SDavid van Moolenbroek 		int		ctrl;
537*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
538*c3b6f8f2SDavid van Moolenbroek 		struct kevent	eventbuf[64], *ev;
539*c3b6f8f2SDavid van Moolenbroek #else
540*c3b6f8f2SDavid van Moolenbroek 		fd_set fds;
541*c3b6f8f2SDavid van Moolenbroek 		int sig, highfd;
542*c3b6f8f2SDavid van Moolenbroek #endif /* !__minix */
543*c3b6f8f2SDavid van Moolenbroek 		struct servtab	*sep;
544*c3b6f8f2SDavid van Moolenbroek 
545*c3b6f8f2SDavid van Moolenbroek 		if (reload) {
546*c3b6f8f2SDavid van Moolenbroek 			reload = 0;
547*c3b6f8f2SDavid van Moolenbroek 			config();
548*c3b6f8f2SDavid van Moolenbroek 		}
549*c3b6f8f2SDavid van Moolenbroek 
550*c3b6f8f2SDavid van Moolenbroek #ifdef __minix
551*c3b6f8f2SDavid van Moolenbroek 		FD_ZERO(&fds);
552*c3b6f8f2SDavid van Moolenbroek 		FD_SET(sig_pipe[0], &fds);
553*c3b6f8f2SDavid van Moolenbroek 		highfd = sig_pipe[0];
554*c3b6f8f2SDavid van Moolenbroek 
555*c3b6f8f2SDavid van Moolenbroek 		for (sep = servtab; sep != NULL; sep = sep->se_next)
556*c3b6f8f2SDavid van Moolenbroek 			if (sep->se_fd != -1 && (unsigned)sep->se_wait <= 1) {
557*c3b6f8f2SDavid van Moolenbroek 				FD_SET(sep->se_fd, &fds);
558*c3b6f8f2SDavid van Moolenbroek 				if (highfd < sep->se_fd)
559*c3b6f8f2SDavid van Moolenbroek 					highfd = sep->se_fd;
560*c3b6f8f2SDavid van Moolenbroek 			}
561*c3b6f8f2SDavid van Moolenbroek 
562*c3b6f8f2SDavid van Moolenbroek 		/*
563*c3b6f8f2SDavid van Moolenbroek 		 * Unblock all the signals we want to catch for the duration of
564*c3b6f8f2SDavid van Moolenbroek 		 * the select() call.  We do not yet have pselect(), but the
565*c3b6f8f2SDavid van Moolenbroek 		 * lack of atomicity does not affect correctness here, because
566*c3b6f8f2SDavid van Moolenbroek 		 * all the signals go through the pipe anyway--that is also why
567*c3b6f8f2SDavid van Moolenbroek 		 * we reissue the select() even if we did catch a signal.
568*c3b6f8f2SDavid van Moolenbroek 		 */
569*c3b6f8f2SDavid van Moolenbroek 		(void) sigprocmask(SIG_SETMASK, &old_mask, NULL);
570*c3b6f8f2SDavid van Moolenbroek 
571*c3b6f8f2SDavid van Moolenbroek 		while (select(highfd + 1, &fds, NULL, NULL, NULL) == -1 &&
572*c3b6f8f2SDavid van Moolenbroek 		    errno == EINTR);
573*c3b6f8f2SDavid van Moolenbroek 
574*c3b6f8f2SDavid van Moolenbroek 		(void) sigprocmask(SIG_SETMASK, &sig_mask, NULL);
575*c3b6f8f2SDavid van Moolenbroek 
576*c3b6f8f2SDavid van Moolenbroek 		if (FD_ISSET(sig_pipe[0], &fds)) {
577*c3b6f8f2SDavid van Moolenbroek 			while (read(sig_pipe[0], &sig, sizeof(sig)) != -1) {
578*c3b6f8f2SDavid van Moolenbroek 				switch (sig) {
579*c3b6f8f2SDavid van Moolenbroek #else /* !__minix */
580*c3b6f8f2SDavid van Moolenbroek 		n = my_kevent(changebuf, changes, eventbuf, A_CNT(eventbuf));
581*c3b6f8f2SDavid van Moolenbroek 		changes = 0;
582*c3b6f8f2SDavid van Moolenbroek 
583*c3b6f8f2SDavid van Moolenbroek 		for (ev = eventbuf; n > 0; ev++, n--) {
584*c3b6f8f2SDavid van Moolenbroek 			if (ev->filter == EVFILT_SIGNAL) {
585*c3b6f8f2SDavid van Moolenbroek 				switch (ev->ident) {
586*c3b6f8f2SDavid van Moolenbroek #endif /* !__minix */
587*c3b6f8f2SDavid van Moolenbroek 				case SIGALRM:
588*c3b6f8f2SDavid van Moolenbroek 					retry();
589*c3b6f8f2SDavid van Moolenbroek 					break;
590*c3b6f8f2SDavid van Moolenbroek 				case SIGCHLD:
591*c3b6f8f2SDavid van Moolenbroek 					reapchild();
592*c3b6f8f2SDavid van Moolenbroek 					break;
593*c3b6f8f2SDavid van Moolenbroek 				case SIGTERM:
594*c3b6f8f2SDavid van Moolenbroek 				case SIGINT:
595*c3b6f8f2SDavid van Moolenbroek 					goaway();
596*c3b6f8f2SDavid van Moolenbroek 					break;
597*c3b6f8f2SDavid van Moolenbroek 				case SIGHUP:
598*c3b6f8f2SDavid van Moolenbroek 					reload = 1;
599*c3b6f8f2SDavid van Moolenbroek 					break;
600*c3b6f8f2SDavid van Moolenbroek 				}
601*c3b6f8f2SDavid van Moolenbroek 				continue;
602*c3b6f8f2SDavid van Moolenbroek 			}
603*c3b6f8f2SDavid van Moolenbroek #ifdef __minix
604*c3b6f8f2SDavid van Moolenbroek 		}
605*c3b6f8f2SDavid van Moolenbroek 
606*c3b6f8f2SDavid van Moolenbroek 		for (sep = servtab; sep != NULL; sep = sep->se_next) {
607*c3b6f8f2SDavid van Moolenbroek 			if (sep->se_fd == -1 || (unsigned)sep->se_wait > 1 ||
608*c3b6f8f2SDavid van Moolenbroek 			    !FD_ISSET(sep->se_fd, &fds))
609*c3b6f8f2SDavid van Moolenbroek 				continue;
610*c3b6f8f2SDavid van Moolenbroek #else /* !__minix */
611*c3b6f8f2SDavid van Moolenbroek 			if (ev->filter != EVFILT_READ)
612*c3b6f8f2SDavid van Moolenbroek 				continue;
613*c3b6f8f2SDavid van Moolenbroek 			sep = (struct servtab *)ev->udata;
614*c3b6f8f2SDavid van Moolenbroek 			/* Paranoia */
615*c3b6f8f2SDavid van Moolenbroek 			if ((int)ev->ident != sep->se_fd)
616*c3b6f8f2SDavid van Moolenbroek 				continue;
617*c3b6f8f2SDavid van Moolenbroek #endif /* !__minix */
618*c3b6f8f2SDavid van Moolenbroek 			if (debug)
619*c3b6f8f2SDavid van Moolenbroek 				fprintf(stderr, "someone wants %s\n",
620*c3b6f8f2SDavid van Moolenbroek 				    sep->se_service);
621*c3b6f8f2SDavid van Moolenbroek 			if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
622*c3b6f8f2SDavid van Moolenbroek 				/* XXX here do the libwrap check-before-accept*/
623*c3b6f8f2SDavid van Moolenbroek 				ctrl = accept(sep->se_fd, NULL, NULL);
624*c3b6f8f2SDavid van Moolenbroek 				if (debug)
625*c3b6f8f2SDavid van Moolenbroek 					fprintf(stderr, "accept, ctrl %d\n",
626*c3b6f8f2SDavid van Moolenbroek 					    ctrl);
627*c3b6f8f2SDavid van Moolenbroek 				if (ctrl < 0) {
628*c3b6f8f2SDavid van Moolenbroek 					if (errno != EINTR)
629*c3b6f8f2SDavid van Moolenbroek 						syslog(LOG_WARNING,
630*c3b6f8f2SDavid van Moolenbroek 						    "accept (for %s): %m",
631*c3b6f8f2SDavid van Moolenbroek 						    sep->se_service);
632*c3b6f8f2SDavid van Moolenbroek 					continue;
633*c3b6f8f2SDavid van Moolenbroek 				}
634*c3b6f8f2SDavid van Moolenbroek 			} else
635*c3b6f8f2SDavid van Moolenbroek 				ctrl = sep->se_fd;
636*c3b6f8f2SDavid van Moolenbroek 			spawn(sep, ctrl);
637*c3b6f8f2SDavid van Moolenbroek 		}
638*c3b6f8f2SDavid van Moolenbroek 	}
639*c3b6f8f2SDavid van Moolenbroek }
640*c3b6f8f2SDavid van Moolenbroek 
641*c3b6f8f2SDavid van Moolenbroek static void
642*c3b6f8f2SDavid van Moolenbroek spawn(struct servtab *sep, int ctrl)
643*c3b6f8f2SDavid van Moolenbroek {
644*c3b6f8f2SDavid van Moolenbroek 	int dofork;
645*c3b6f8f2SDavid van Moolenbroek 	pid_t pid;
646*c3b6f8f2SDavid van Moolenbroek 
647*c3b6f8f2SDavid van Moolenbroek 	pid = 0;
648*c3b6f8f2SDavid van Moolenbroek #ifdef LIBWRAP_INTERNAL
649*c3b6f8f2SDavid van Moolenbroek 	dofork = 1;
650*c3b6f8f2SDavid van Moolenbroek #else
651*c3b6f8f2SDavid van Moolenbroek 	dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
652*c3b6f8f2SDavid van Moolenbroek #endif
653*c3b6f8f2SDavid van Moolenbroek 	if (dofork) {
654*c3b6f8f2SDavid van Moolenbroek 		if (sep->se_count++ == 0)
655*c3b6f8f2SDavid van Moolenbroek 			(void)gettimeofday(&sep->se_time, NULL);
656*c3b6f8f2SDavid van Moolenbroek 		else if (sep->se_count >= sep->se_max) {
657*c3b6f8f2SDavid van Moolenbroek 			struct timeval now;
658*c3b6f8f2SDavid van Moolenbroek 
659*c3b6f8f2SDavid van Moolenbroek 			(void)gettimeofday(&now, NULL);
660*c3b6f8f2SDavid van Moolenbroek 			if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
661*c3b6f8f2SDavid van Moolenbroek 				sep->se_time = now;
662*c3b6f8f2SDavid van Moolenbroek 				sep->se_count = 1;
663*c3b6f8f2SDavid van Moolenbroek 			} else {
664*c3b6f8f2SDavid van Moolenbroek 				syslog(LOG_ERR,
665*c3b6f8f2SDavid van Moolenbroek 				    "%s/%s max spawn rate (%d in %d seconds) "
666*c3b6f8f2SDavid van Moolenbroek 				    "exceeded; service not started",
667*c3b6f8f2SDavid van Moolenbroek 				    sep->se_service, sep->se_proto,
668*c3b6f8f2SDavid van Moolenbroek 				    sep->se_max, CNT_INTVL);
669*c3b6f8f2SDavid van Moolenbroek 				if (!sep->se_wait && sep->se_socktype ==
670*c3b6f8f2SDavid van Moolenbroek 				    SOCK_STREAM)
671*c3b6f8f2SDavid van Moolenbroek 					close(ctrl);
672*c3b6f8f2SDavid van Moolenbroek 				close_sep(sep);
673*c3b6f8f2SDavid van Moolenbroek 				if (!timingout) {
674*c3b6f8f2SDavid van Moolenbroek 					timingout = 1;
675*c3b6f8f2SDavid van Moolenbroek 					alarm(RETRYTIME);
676*c3b6f8f2SDavid van Moolenbroek 				}
677*c3b6f8f2SDavid van Moolenbroek 				return;
678*c3b6f8f2SDavid van Moolenbroek 			}
679*c3b6f8f2SDavid van Moolenbroek 		}
680*c3b6f8f2SDavid van Moolenbroek 		pid = fork();
681*c3b6f8f2SDavid van Moolenbroek 		if (pid < 0) {
682*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "fork: %m");
683*c3b6f8f2SDavid van Moolenbroek 			if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
684*c3b6f8f2SDavid van Moolenbroek 				close(ctrl);
685*c3b6f8f2SDavid van Moolenbroek 			sleep(1);
686*c3b6f8f2SDavid van Moolenbroek 			return;
687*c3b6f8f2SDavid van Moolenbroek 		}
688*c3b6f8f2SDavid van Moolenbroek 		if (pid != 0 && sep->se_wait) {
689*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
690*c3b6f8f2SDavid van Moolenbroek 			struct kevent	*ev;
691*c3b6f8f2SDavid van Moolenbroek 
692*c3b6f8f2SDavid van Moolenbroek 			sep->se_wait = pid;
693*c3b6f8f2SDavid van Moolenbroek 			ev = allocchange();
694*c3b6f8f2SDavid van Moolenbroek 			EV_SET(ev, sep->se_fd, EVFILT_READ,
695*c3b6f8f2SDavid van Moolenbroek 			    EV_DELETE, 0, 0, 0);
696*c3b6f8f2SDavid van Moolenbroek #endif /* !__minix */
697*c3b6f8f2SDavid van Moolenbroek 		}
698*c3b6f8f2SDavid van Moolenbroek 		if (pid == 0) {
699*c3b6f8f2SDavid van Moolenbroek 			size_t	n;
700*c3b6f8f2SDavid van Moolenbroek 
701*c3b6f8f2SDavid van Moolenbroek 			for (n = 0; n < A_CNT(my_signals); n++)
702*c3b6f8f2SDavid van Moolenbroek 				(void) signal(my_signals[n], SIG_DFL);
703*c3b6f8f2SDavid van Moolenbroek #ifdef __minix
704*c3b6f8f2SDavid van Moolenbroek 			close(sig_pipe[0]);
705*c3b6f8f2SDavid van Moolenbroek 			close(sig_pipe[1]);
706*c3b6f8f2SDavid van Moolenbroek 
707*c3b6f8f2SDavid van Moolenbroek 			(void) sigprocmask(SIG_SETMASK, &old_mask, NULL);
708*c3b6f8f2SDavid van Moolenbroek #endif /* __minix */
709*c3b6f8f2SDavid van Moolenbroek 			if (debug)
710*c3b6f8f2SDavid van Moolenbroek 				setsid();
711*c3b6f8f2SDavid van Moolenbroek 		}
712*c3b6f8f2SDavid van Moolenbroek 	}
713*c3b6f8f2SDavid van Moolenbroek 	if (pid == 0) {
714*c3b6f8f2SDavid van Moolenbroek 		run_service(ctrl, sep, dofork);
715*c3b6f8f2SDavid van Moolenbroek 		if (dofork)
716*c3b6f8f2SDavid van Moolenbroek 			exit(0);
717*c3b6f8f2SDavid van Moolenbroek 	}
718*c3b6f8f2SDavid van Moolenbroek 	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
719*c3b6f8f2SDavid van Moolenbroek 		close(ctrl);
720*c3b6f8f2SDavid van Moolenbroek }
721*c3b6f8f2SDavid van Moolenbroek 
722*c3b6f8f2SDavid van Moolenbroek static void
723*c3b6f8f2SDavid van Moolenbroek run_service(int ctrl, struct servtab *sep, int didfork)
724*c3b6f8f2SDavid van Moolenbroek {
725*c3b6f8f2SDavid van Moolenbroek 	struct passwd *pwd;
726*c3b6f8f2SDavid van Moolenbroek 	struct group *grp = NULL;	/* XXX gcc */
727*c3b6f8f2SDavid van Moolenbroek 	char buf[NI_MAXSERV];
728*c3b6f8f2SDavid van Moolenbroek 	struct servtab *s;
729*c3b6f8f2SDavid van Moolenbroek #ifdef LIBWRAP
730*c3b6f8f2SDavid van Moolenbroek 	char abuf[BUFSIZ];
731*c3b6f8f2SDavid van Moolenbroek 	struct request_info req;
732*c3b6f8f2SDavid van Moolenbroek 	int denied;
733*c3b6f8f2SDavid van Moolenbroek 	char *service = NULL;	/* XXX gcc */
734*c3b6f8f2SDavid van Moolenbroek #endif
735*c3b6f8f2SDavid van Moolenbroek 
736*c3b6f8f2SDavid van Moolenbroek #ifdef LIBWRAP
737*c3b6f8f2SDavid van Moolenbroek #ifndef LIBWRAP_INTERNAL
738*c3b6f8f2SDavid van Moolenbroek 	if (sep->se_bi == 0)
739*c3b6f8f2SDavid van Moolenbroek #endif
740*c3b6f8f2SDavid van Moolenbroek 	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
741*c3b6f8f2SDavid van Moolenbroek 		request_init(&req, RQ_DAEMON, sep->se_argv[0] ?
742*c3b6f8f2SDavid van Moolenbroek 		    sep->se_argv[0] : sep->se_service, RQ_FILE, ctrl, NULL);
743*c3b6f8f2SDavid van Moolenbroek 		fromhost(&req);
744*c3b6f8f2SDavid van Moolenbroek 		denied = !hosts_access(&req);
745*c3b6f8f2SDavid van Moolenbroek 		if (denied || lflag) {
746*c3b6f8f2SDavid van Moolenbroek 			if (getnameinfo(&sep->se_ctrladdr,
747*c3b6f8f2SDavid van Moolenbroek 			    (socklen_t)sep->se_ctrladdr.sa_len, NULL, 0,
748*c3b6f8f2SDavid van Moolenbroek 			    buf, sizeof(buf), 0) != 0) {
749*c3b6f8f2SDavid van Moolenbroek 				/* shouldn't happen */
750*c3b6f8f2SDavid van Moolenbroek 				(void)snprintf(buf, sizeof buf, "%d",
751*c3b6f8f2SDavid van Moolenbroek 				    ntohs(sep->se_ctrladdr_in.sin_port));
752*c3b6f8f2SDavid van Moolenbroek 			}
753*c3b6f8f2SDavid van Moolenbroek 			service = buf;
754*c3b6f8f2SDavid van Moolenbroek 			if (req.client->sin) {
755*c3b6f8f2SDavid van Moolenbroek 				sockaddr_snprintf(abuf, sizeof(abuf), "%a",
756*c3b6f8f2SDavid van Moolenbroek 				    req.client->sin);
757*c3b6f8f2SDavid van Moolenbroek 			} else {
758*c3b6f8f2SDavid van Moolenbroek 				strcpy(abuf, "(null)");
759*c3b6f8f2SDavid van Moolenbroek 			}
760*c3b6f8f2SDavid van Moolenbroek 		}
761*c3b6f8f2SDavid van Moolenbroek 		if (denied) {
762*c3b6f8f2SDavid van Moolenbroek 			syslog(deny_severity,
763*c3b6f8f2SDavid van Moolenbroek 			    "refused connection from %.500s(%s), service %s (%s)",
764*c3b6f8f2SDavid van Moolenbroek 			    eval_client(&req), abuf, service, sep->se_proto);
765*c3b6f8f2SDavid van Moolenbroek 			goto reject;
766*c3b6f8f2SDavid van Moolenbroek 		}
767*c3b6f8f2SDavid van Moolenbroek 		if (lflag) {
768*c3b6f8f2SDavid van Moolenbroek 			syslog(allow_severity,
769*c3b6f8f2SDavid van Moolenbroek 			    "connection from %.500s(%s), service %s (%s)",
770*c3b6f8f2SDavid van Moolenbroek 			    eval_client(&req), abuf, service, sep->se_proto);
771*c3b6f8f2SDavid van Moolenbroek 		}
772*c3b6f8f2SDavid van Moolenbroek 	}
773*c3b6f8f2SDavid van Moolenbroek #endif /* LIBWRAP */
774*c3b6f8f2SDavid van Moolenbroek 
775*c3b6f8f2SDavid van Moolenbroek 	if (sep->se_bi) {
776*c3b6f8f2SDavid van Moolenbroek 		if (didfork) {
777*c3b6f8f2SDavid van Moolenbroek 			for (s = servtab; s; s = s->se_next)
778*c3b6f8f2SDavid van Moolenbroek 				if (s->se_fd != -1 && s->se_fd != ctrl) {
779*c3b6f8f2SDavid van Moolenbroek 					close(s->se_fd);
780*c3b6f8f2SDavid van Moolenbroek 					s->se_fd = -1;
781*c3b6f8f2SDavid van Moolenbroek 				}
782*c3b6f8f2SDavid van Moolenbroek 		}
783*c3b6f8f2SDavid van Moolenbroek 		(*sep->se_bi->bi_fn)(ctrl, sep);
784*c3b6f8f2SDavid van Moolenbroek 	} else {
785*c3b6f8f2SDavid van Moolenbroek 		if ((pwd = getpwnam(sep->se_user)) == NULL) {
786*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "%s/%s: %s: No such user",
787*c3b6f8f2SDavid van Moolenbroek 			    sep->se_service, sep->se_proto, sep->se_user);
788*c3b6f8f2SDavid van Moolenbroek 			goto reject;
789*c3b6f8f2SDavid van Moolenbroek 		}
790*c3b6f8f2SDavid van Moolenbroek 		if (sep->se_group &&
791*c3b6f8f2SDavid van Moolenbroek 		    (grp = getgrnam(sep->se_group)) == NULL) {
792*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "%s/%s: %s: No such group",
793*c3b6f8f2SDavid van Moolenbroek 			    sep->se_service, sep->se_proto, sep->se_group);
794*c3b6f8f2SDavid van Moolenbroek 			goto reject;
795*c3b6f8f2SDavid van Moolenbroek 		}
796*c3b6f8f2SDavid van Moolenbroek 		if (pwd->pw_uid) {
797*c3b6f8f2SDavid van Moolenbroek 			if (sep->se_group)
798*c3b6f8f2SDavid van Moolenbroek 				pwd->pw_gid = grp->gr_gid;
799*c3b6f8f2SDavid van Moolenbroek 			if (setgid(pwd->pw_gid) < 0) {
800*c3b6f8f2SDavid van Moolenbroek 				syslog(LOG_ERR,
801*c3b6f8f2SDavid van Moolenbroek 				 "%s/%s: can't set gid %d: %m", sep->se_service,
802*c3b6f8f2SDavid van Moolenbroek 				    sep->se_proto, pwd->pw_gid);
803*c3b6f8f2SDavid van Moolenbroek 				goto reject;
804*c3b6f8f2SDavid van Moolenbroek 			}
805*c3b6f8f2SDavid van Moolenbroek 			(void) initgroups(pwd->pw_name,
806*c3b6f8f2SDavid van Moolenbroek 			    pwd->pw_gid);
807*c3b6f8f2SDavid van Moolenbroek 			if (setuid(pwd->pw_uid) < 0) {
808*c3b6f8f2SDavid van Moolenbroek 				syslog(LOG_ERR,
809*c3b6f8f2SDavid van Moolenbroek 				 "%s/%s: can't set uid %d: %m", sep->se_service,
810*c3b6f8f2SDavid van Moolenbroek 				    sep->se_proto, pwd->pw_uid);
811*c3b6f8f2SDavid van Moolenbroek 				goto reject;
812*c3b6f8f2SDavid van Moolenbroek 			}
813*c3b6f8f2SDavid van Moolenbroek 		} else if (sep->se_group) {
814*c3b6f8f2SDavid van Moolenbroek 			(void) setgid((gid_t)grp->gr_gid);
815*c3b6f8f2SDavid van Moolenbroek 		}
816*c3b6f8f2SDavid van Moolenbroek 		if (debug)
817*c3b6f8f2SDavid van Moolenbroek 			fprintf(stderr, "%d execl %s\n",
818*c3b6f8f2SDavid van Moolenbroek 			    getpid(), sep->se_server);
819*c3b6f8f2SDavid van Moolenbroek 		/* Set our control descriptor to not close-on-exec... */
820*c3b6f8f2SDavid van Moolenbroek 		if (fcntl(ctrl, F_SETFD, 0) < 0)
821*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "fcntl (%d, F_SETFD, 0): %m", ctrl);
822*c3b6f8f2SDavid van Moolenbroek 		/* ...and dup it to stdin, stdout, and stderr. */
823*c3b6f8f2SDavid van Moolenbroek 		if (ctrl != 0) {
824*c3b6f8f2SDavid van Moolenbroek 			dup2(ctrl, 0);
825*c3b6f8f2SDavid van Moolenbroek 			close(ctrl);
826*c3b6f8f2SDavid van Moolenbroek 			ctrl = 0;
827*c3b6f8f2SDavid van Moolenbroek 		}
828*c3b6f8f2SDavid van Moolenbroek 		dup2(0, 1);
829*c3b6f8f2SDavid van Moolenbroek 		dup2(0, 2);
830*c3b6f8f2SDavid van Moolenbroek 		if (rlim_ofile.rlim_cur != rlim_ofile_cur &&
831*c3b6f8f2SDavid van Moolenbroek 		    setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
832*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "setrlimit: %m");
833*c3b6f8f2SDavid van Moolenbroek 		execv(sep->se_server, sep->se_argv);
834*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "cannot execute %s: %m", sep->se_server);
835*c3b6f8f2SDavid van Moolenbroek 	reject:
836*c3b6f8f2SDavid van Moolenbroek 		if (sep->se_socktype != SOCK_STREAM)
837*c3b6f8f2SDavid van Moolenbroek 			recv(ctrl, buf, sizeof (buf), 0);
838*c3b6f8f2SDavid van Moolenbroek 		_exit(1);
839*c3b6f8f2SDavid van Moolenbroek 	}
840*c3b6f8f2SDavid van Moolenbroek }
841*c3b6f8f2SDavid van Moolenbroek 
842*c3b6f8f2SDavid van Moolenbroek static void
843*c3b6f8f2SDavid van Moolenbroek reapchild(void)
844*c3b6f8f2SDavid van Moolenbroek {
845*c3b6f8f2SDavid van Moolenbroek 	int status;
846*c3b6f8f2SDavid van Moolenbroek 	pid_t pid;
847*c3b6f8f2SDavid van Moolenbroek 	struct servtab *sep;
848*c3b6f8f2SDavid van Moolenbroek 
849*c3b6f8f2SDavid van Moolenbroek 	for (;;) {
850*c3b6f8f2SDavid van Moolenbroek 		pid = wait3(&status, WNOHANG, NULL);
851*c3b6f8f2SDavid van Moolenbroek 		if (pid <= 0)
852*c3b6f8f2SDavid van Moolenbroek 			break;
853*c3b6f8f2SDavid van Moolenbroek 		if (debug)
854*c3b6f8f2SDavid van Moolenbroek 			(void) fprintf(stderr, "%d reaped, status %#x\n",
855*c3b6f8f2SDavid van Moolenbroek 			    pid, status);
856*c3b6f8f2SDavid van Moolenbroek 		for (sep = servtab; sep != NULL; sep = sep->se_next)
857*c3b6f8f2SDavid van Moolenbroek 			if (sep->se_wait == pid) {
858*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
859*c3b6f8f2SDavid van Moolenbroek 				struct kevent	*ev;
860*c3b6f8f2SDavid van Moolenbroek #endif /* !__minix */
861*c3b6f8f2SDavid van Moolenbroek 
862*c3b6f8f2SDavid van Moolenbroek 				if (WIFEXITED(status) && WEXITSTATUS(status))
863*c3b6f8f2SDavid van Moolenbroek 					syslog(LOG_WARNING,
864*c3b6f8f2SDavid van Moolenbroek 					    "%s: exit status %u",
865*c3b6f8f2SDavid van Moolenbroek 					    sep->se_server, WEXITSTATUS(status));
866*c3b6f8f2SDavid van Moolenbroek 				else if (WIFSIGNALED(status))
867*c3b6f8f2SDavid van Moolenbroek 					syslog(LOG_WARNING,
868*c3b6f8f2SDavid van Moolenbroek 					    "%s: exit signal %u",
869*c3b6f8f2SDavid van Moolenbroek 					    sep->se_server, WTERMSIG(status));
870*c3b6f8f2SDavid van Moolenbroek 				sep->se_wait = 1;
871*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
872*c3b6f8f2SDavid van Moolenbroek 				ev = allocchange();
873*c3b6f8f2SDavid van Moolenbroek 				EV_SET(ev, sep->se_fd, EVFILT_READ,
874*c3b6f8f2SDavid van Moolenbroek 				    EV_ADD | EV_ENABLE, 0, 0, (intptr_t)sep);
875*c3b6f8f2SDavid van Moolenbroek #endif /* !__minix */
876*c3b6f8f2SDavid van Moolenbroek 				if (debug)
877*c3b6f8f2SDavid van Moolenbroek 					fprintf(stderr, "restored %s, fd %d\n",
878*c3b6f8f2SDavid van Moolenbroek 					    sep->se_service, sep->se_fd);
879*c3b6f8f2SDavid van Moolenbroek 			}
880*c3b6f8f2SDavid van Moolenbroek 	}
881*c3b6f8f2SDavid van Moolenbroek }
882*c3b6f8f2SDavid van Moolenbroek 
883*c3b6f8f2SDavid van Moolenbroek static void
884*c3b6f8f2SDavid van Moolenbroek config(void)
885*c3b6f8f2SDavid van Moolenbroek {
886*c3b6f8f2SDavid van Moolenbroek 	struct servtab *sep, *cp, **sepp;
887*c3b6f8f2SDavid van Moolenbroek 	size_t n;
888*c3b6f8f2SDavid van Moolenbroek 
889*c3b6f8f2SDavid van Moolenbroek 	if (!setconfig()) {
890*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "%s: %m", CONFIG);
891*c3b6f8f2SDavid van Moolenbroek 		return;
892*c3b6f8f2SDavid van Moolenbroek 	}
893*c3b6f8f2SDavid van Moolenbroek 	for (sep = servtab; sep != NULL; sep = sep->se_next)
894*c3b6f8f2SDavid van Moolenbroek 		sep->se_checked = 0;
895*c3b6f8f2SDavid van Moolenbroek 	while ((cp = getconfigent()) != NULL) {
896*c3b6f8f2SDavid van Moolenbroek 		for (sep = servtab; sep != NULL; sep = sep->se_next)
897*c3b6f8f2SDavid van Moolenbroek 			if (strcmp(sep->se_service, cp->se_service) == 0 &&
898*c3b6f8f2SDavid van Moolenbroek 			    strcmp(sep->se_hostaddr, cp->se_hostaddr) == 0 &&
899*c3b6f8f2SDavid van Moolenbroek 			    strcmp(sep->se_proto, cp->se_proto) == 0 &&
900*c3b6f8f2SDavid van Moolenbroek 			    ISMUX(sep) == ISMUX(cp))
901*c3b6f8f2SDavid van Moolenbroek 				break;
902*c3b6f8f2SDavid van Moolenbroek 		if (sep != NULL) {
903*c3b6f8f2SDavid van Moolenbroek 			int i;
904*c3b6f8f2SDavid van Moolenbroek 
905*c3b6f8f2SDavid van Moolenbroek #define SWAP(type, a, b) {type c = a; a = b; b = c;}
906*c3b6f8f2SDavid van Moolenbroek 
907*c3b6f8f2SDavid van Moolenbroek 			/*
908*c3b6f8f2SDavid van Moolenbroek 			 * sep->se_wait may be holding the pid of a daemon
909*c3b6f8f2SDavid van Moolenbroek 			 * that we're waiting for.  If so, don't overwrite
910*c3b6f8f2SDavid van Moolenbroek 			 * it unless the config file explicitly says don't
911*c3b6f8f2SDavid van Moolenbroek 			 * wait.
912*c3b6f8f2SDavid van Moolenbroek 			 */
913*c3b6f8f2SDavid van Moolenbroek 			if (cp->se_bi == 0 &&
914*c3b6f8f2SDavid van Moolenbroek 			    (sep->se_wait == 1 || cp->se_wait == 0))
915*c3b6f8f2SDavid van Moolenbroek 				sep->se_wait = cp->se_wait;
916*c3b6f8f2SDavid van Moolenbroek 			SWAP(char *, sep->se_user, cp->se_user);
917*c3b6f8f2SDavid van Moolenbroek 			SWAP(char *, sep->se_group, cp->se_group);
918*c3b6f8f2SDavid van Moolenbroek 			SWAP(char *, sep->se_server, cp->se_server);
919*c3b6f8f2SDavid van Moolenbroek 			for (i = 0; i < MAXARGV; i++)
920*c3b6f8f2SDavid van Moolenbroek 				SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
921*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
922*c3b6f8f2SDavid van Moolenbroek 			SWAP(char *, sep->se_policy, cp->se_policy);
923*c3b6f8f2SDavid van Moolenbroek #endif
924*c3b6f8f2SDavid van Moolenbroek 			SWAP(int, cp->se_type, sep->se_type);
925*c3b6f8f2SDavid van Moolenbroek 			SWAP(int, cp->se_max, sep->se_max);
926*c3b6f8f2SDavid van Moolenbroek #undef SWAP
927*c3b6f8f2SDavid van Moolenbroek 			if (isrpcservice(sep))
928*c3b6f8f2SDavid van Moolenbroek 				unregister_rpc(sep);
929*c3b6f8f2SDavid van Moolenbroek 			sep->se_rpcversl = cp->se_rpcversl;
930*c3b6f8f2SDavid van Moolenbroek 			sep->se_rpcversh = cp->se_rpcversh;
931*c3b6f8f2SDavid van Moolenbroek 			freeconfig(cp);
932*c3b6f8f2SDavid van Moolenbroek 			if (debug)
933*c3b6f8f2SDavid van Moolenbroek 				print_service("REDO", sep);
934*c3b6f8f2SDavid van Moolenbroek 		} else {
935*c3b6f8f2SDavid van Moolenbroek 			sep = enter(cp);
936*c3b6f8f2SDavid van Moolenbroek 			if (debug)
937*c3b6f8f2SDavid van Moolenbroek 				print_service("ADD ", sep);
938*c3b6f8f2SDavid van Moolenbroek 		}
939*c3b6f8f2SDavid van Moolenbroek 		sep->se_checked = 1;
940*c3b6f8f2SDavid van Moolenbroek 
941*c3b6f8f2SDavid van Moolenbroek 		switch (sep->se_family) {
942*c3b6f8f2SDavid van Moolenbroek 		case AF_LOCAL:
943*c3b6f8f2SDavid van Moolenbroek 			if (sep->se_fd != -1)
944*c3b6f8f2SDavid van Moolenbroek 				break;
945*c3b6f8f2SDavid van Moolenbroek 			n = strlen(sep->se_service);
946*c3b6f8f2SDavid van Moolenbroek 			if (n >= sizeof(sep->se_ctrladdr_un.sun_path)) {
947*c3b6f8f2SDavid van Moolenbroek 				syslog(LOG_ERR, "%s: address too long",
948*c3b6f8f2SDavid van Moolenbroek 				    sep->se_service);
949*c3b6f8f2SDavid van Moolenbroek 				sep->se_checked = 0;
950*c3b6f8f2SDavid van Moolenbroek 				continue;
951*c3b6f8f2SDavid van Moolenbroek 			}
952*c3b6f8f2SDavid van Moolenbroek 			(void)unlink(sep->se_service);
953*c3b6f8f2SDavid van Moolenbroek 			strlcpy(sep->se_ctrladdr_un.sun_path,
954*c3b6f8f2SDavid van Moolenbroek 			    sep->se_service, n);
955*c3b6f8f2SDavid van Moolenbroek 			sep->se_ctrladdr_un.sun_family = AF_LOCAL;
956*c3b6f8f2SDavid van Moolenbroek 			sep->se_ctrladdr_size = (int)(n +
957*c3b6f8f2SDavid van Moolenbroek 			    sizeof(sep->se_ctrladdr_un) -
958*c3b6f8f2SDavid van Moolenbroek 			    sizeof(sep->se_ctrladdr_un.sun_path));
959*c3b6f8f2SDavid van Moolenbroek 			if (!ISMUX(sep))
960*c3b6f8f2SDavid van Moolenbroek 				setup(sep);
961*c3b6f8f2SDavid van Moolenbroek 			break;
962*c3b6f8f2SDavid van Moolenbroek 		case AF_INET:
963*c3b6f8f2SDavid van Moolenbroek #ifdef INET6
964*c3b6f8f2SDavid van Moolenbroek 		case AF_INET6:
965*c3b6f8f2SDavid van Moolenbroek #endif
966*c3b6f8f2SDavid van Moolenbroek 		    {
967*c3b6f8f2SDavid van Moolenbroek 			struct addrinfo hints, *res;
968*c3b6f8f2SDavid van Moolenbroek 			char *host;
969*c3b6f8f2SDavid van Moolenbroek 			const char *port;
970*c3b6f8f2SDavid van Moolenbroek 			int error;
971*c3b6f8f2SDavid van Moolenbroek 			int s;
972*c3b6f8f2SDavid van Moolenbroek 
973*c3b6f8f2SDavid van Moolenbroek 			/* check if the family is supported */
974*c3b6f8f2SDavid van Moolenbroek 			s = socket(sep->se_family, SOCK_DGRAM, 0);
975*c3b6f8f2SDavid van Moolenbroek 			if (s < 0) {
976*c3b6f8f2SDavid van Moolenbroek 				syslog(LOG_WARNING,
977*c3b6f8f2SDavid van Moolenbroek 				    "%s/%s: %s: the address family is not "
978*c3b6f8f2SDavid van Moolenbroek 				    "supported by the kernel",
979*c3b6f8f2SDavid van Moolenbroek 				    sep->se_service, sep->se_proto,
980*c3b6f8f2SDavid van Moolenbroek 				    sep->se_hostaddr);
981*c3b6f8f2SDavid van Moolenbroek 				sep->se_checked = 0;
982*c3b6f8f2SDavid van Moolenbroek 				continue;
983*c3b6f8f2SDavid van Moolenbroek 			}
984*c3b6f8f2SDavid van Moolenbroek 			close(s);
985*c3b6f8f2SDavid van Moolenbroek 
986*c3b6f8f2SDavid van Moolenbroek 			memset(&hints, 0, sizeof(hints));
987*c3b6f8f2SDavid van Moolenbroek 			hints.ai_family = sep->se_family;
988*c3b6f8f2SDavid van Moolenbroek 			hints.ai_socktype = sep->se_socktype;
989*c3b6f8f2SDavid van Moolenbroek 			hints.ai_flags = AI_PASSIVE;
990*c3b6f8f2SDavid van Moolenbroek 			if (!strcmp(sep->se_hostaddr, "*"))
991*c3b6f8f2SDavid van Moolenbroek 				host = NULL;
992*c3b6f8f2SDavid van Moolenbroek 			else
993*c3b6f8f2SDavid van Moolenbroek 				host = sep->se_hostaddr;
994*c3b6f8f2SDavid van Moolenbroek 			if (isrpcservice(sep) || ISMUX(sep))
995*c3b6f8f2SDavid van Moolenbroek 				port = "0";
996*c3b6f8f2SDavid van Moolenbroek 			else
997*c3b6f8f2SDavid van Moolenbroek 				port = sep->se_service;
998*c3b6f8f2SDavid van Moolenbroek 			error = getaddrinfo(host, port, &hints, &res);
999*c3b6f8f2SDavid van Moolenbroek 			if (error) {
1000*c3b6f8f2SDavid van Moolenbroek 				if (error == EAI_SERVICE) {
1001*c3b6f8f2SDavid van Moolenbroek 					/* gai_strerror not friendly enough */
1002*c3b6f8f2SDavid van Moolenbroek 					syslog(LOG_WARNING, "%s/%s: "
1003*c3b6f8f2SDavid van Moolenbroek 					    "unknown service",
1004*c3b6f8f2SDavid van Moolenbroek 					    sep->se_service, sep->se_proto);
1005*c3b6f8f2SDavid van Moolenbroek 				} else {
1006*c3b6f8f2SDavid van Moolenbroek 					syslog(LOG_ERR, "%s/%s: %s: %s",
1007*c3b6f8f2SDavid van Moolenbroek 					    sep->se_service, sep->se_proto,
1008*c3b6f8f2SDavid van Moolenbroek 					    sep->se_hostaddr,
1009*c3b6f8f2SDavid van Moolenbroek 					    gai_strerror(error));
1010*c3b6f8f2SDavid van Moolenbroek 				}
1011*c3b6f8f2SDavid van Moolenbroek 				sep->se_checked = 0;
1012*c3b6f8f2SDavid van Moolenbroek 				continue;
1013*c3b6f8f2SDavid van Moolenbroek 			}
1014*c3b6f8f2SDavid van Moolenbroek 			if (res->ai_next) {
1015*c3b6f8f2SDavid van Moolenbroek 				syslog(LOG_ERR,
1016*c3b6f8f2SDavid van Moolenbroek 					"%s/%s: %s: resolved to multiple addr",
1017*c3b6f8f2SDavid van Moolenbroek 				    sep->se_service, sep->se_proto,
1018*c3b6f8f2SDavid van Moolenbroek 				    sep->se_hostaddr);
1019*c3b6f8f2SDavid van Moolenbroek 				sep->se_checked = 0;
1020*c3b6f8f2SDavid van Moolenbroek 				freeaddrinfo(res);
1021*c3b6f8f2SDavid van Moolenbroek 				continue;
1022*c3b6f8f2SDavid van Moolenbroek 			}
1023*c3b6f8f2SDavid van Moolenbroek 			memcpy(&sep->se_ctrladdr, res->ai_addr,
1024*c3b6f8f2SDavid van Moolenbroek 				res->ai_addrlen);
1025*c3b6f8f2SDavid van Moolenbroek 			if (ISMUX(sep)) {
1026*c3b6f8f2SDavid van Moolenbroek 				sep->se_fd = -1;
1027*c3b6f8f2SDavid van Moolenbroek 				freeaddrinfo(res);
1028*c3b6f8f2SDavid van Moolenbroek 				continue;
1029*c3b6f8f2SDavid van Moolenbroek 			}
1030*c3b6f8f2SDavid van Moolenbroek 			sep->se_ctrladdr_size = res->ai_addrlen;
1031*c3b6f8f2SDavid van Moolenbroek 			freeaddrinfo(res);
1032*c3b6f8f2SDavid van Moolenbroek #ifdef RPC
1033*c3b6f8f2SDavid van Moolenbroek 			if (isrpcservice(sep)) {
1034*c3b6f8f2SDavid van Moolenbroek 				struct rpcent *rp;
1035*c3b6f8f2SDavid van Moolenbroek 
1036*c3b6f8f2SDavid van Moolenbroek 				sep->se_rpcprog = atoi(sep->se_service);
1037*c3b6f8f2SDavid van Moolenbroek 				if (sep->se_rpcprog == 0) {
1038*c3b6f8f2SDavid van Moolenbroek 					rp = getrpcbyname(sep->se_service);
1039*c3b6f8f2SDavid van Moolenbroek 					if (rp == 0) {
1040*c3b6f8f2SDavid van Moolenbroek 						syslog(LOG_ERR,
1041*c3b6f8f2SDavid van Moolenbroek 						    "%s/%s: unknown service",
1042*c3b6f8f2SDavid van Moolenbroek 						    sep->se_service,
1043*c3b6f8f2SDavid van Moolenbroek 						    sep->se_proto);
1044*c3b6f8f2SDavid van Moolenbroek 						sep->se_checked = 0;
1045*c3b6f8f2SDavid van Moolenbroek 						continue;
1046*c3b6f8f2SDavid van Moolenbroek 					}
1047*c3b6f8f2SDavid van Moolenbroek 					sep->se_rpcprog = rp->r_number;
1048*c3b6f8f2SDavid van Moolenbroek 				}
1049*c3b6f8f2SDavid van Moolenbroek 				if (sep->se_fd == -1 && !ISMUX(sep))
1050*c3b6f8f2SDavid van Moolenbroek 					setup(sep);
1051*c3b6f8f2SDavid van Moolenbroek 				if (sep->se_fd != -1)
1052*c3b6f8f2SDavid van Moolenbroek 					register_rpc(sep);
1053*c3b6f8f2SDavid van Moolenbroek 			} else
1054*c3b6f8f2SDavid van Moolenbroek #endif
1055*c3b6f8f2SDavid van Moolenbroek 			{
1056*c3b6f8f2SDavid van Moolenbroek 				if (sep->se_fd >= 0)
1057*c3b6f8f2SDavid van Moolenbroek 					close_sep(sep);
1058*c3b6f8f2SDavid van Moolenbroek 				if (sep->se_fd == -1 && !ISMUX(sep))
1059*c3b6f8f2SDavid van Moolenbroek 					setup(sep);
1060*c3b6f8f2SDavid van Moolenbroek 			}
1061*c3b6f8f2SDavid van Moolenbroek 		    }
1062*c3b6f8f2SDavid van Moolenbroek 		}
1063*c3b6f8f2SDavid van Moolenbroek 	}
1064*c3b6f8f2SDavid van Moolenbroek 	endconfig();
1065*c3b6f8f2SDavid van Moolenbroek 	/*
1066*c3b6f8f2SDavid van Moolenbroek 	 * Purge anything not looked at above.
1067*c3b6f8f2SDavid van Moolenbroek 	 */
1068*c3b6f8f2SDavid van Moolenbroek 	sepp = &servtab;
1069*c3b6f8f2SDavid van Moolenbroek 	while ((sep = *sepp) != NULL) {
1070*c3b6f8f2SDavid van Moolenbroek 		if (sep->se_checked) {
1071*c3b6f8f2SDavid van Moolenbroek 			sepp = &sep->se_next;
1072*c3b6f8f2SDavid van Moolenbroek 			continue;
1073*c3b6f8f2SDavid van Moolenbroek 		}
1074*c3b6f8f2SDavid van Moolenbroek 		*sepp = sep->se_next;
1075*c3b6f8f2SDavid van Moolenbroek 		if (sep->se_fd >= 0)
1076*c3b6f8f2SDavid van Moolenbroek 			close_sep(sep);
1077*c3b6f8f2SDavid van Moolenbroek 		if (isrpcservice(sep))
1078*c3b6f8f2SDavid van Moolenbroek 			unregister_rpc(sep);
1079*c3b6f8f2SDavid van Moolenbroek 		if (sep->se_family == AF_LOCAL)
1080*c3b6f8f2SDavid van Moolenbroek 			(void)unlink(sep->se_service);
1081*c3b6f8f2SDavid van Moolenbroek 		if (debug)
1082*c3b6f8f2SDavid van Moolenbroek 			print_service("FREE", sep);
1083*c3b6f8f2SDavid van Moolenbroek 		freeconfig(sep);
1084*c3b6f8f2SDavid van Moolenbroek 		free(sep);
1085*c3b6f8f2SDavid van Moolenbroek 	}
1086*c3b6f8f2SDavid van Moolenbroek }
1087*c3b6f8f2SDavid van Moolenbroek 
1088*c3b6f8f2SDavid van Moolenbroek static void
1089*c3b6f8f2SDavid van Moolenbroek retry(void)
1090*c3b6f8f2SDavid van Moolenbroek {
1091*c3b6f8f2SDavid van Moolenbroek 	struct servtab *sep;
1092*c3b6f8f2SDavid van Moolenbroek 
1093*c3b6f8f2SDavid van Moolenbroek 	timingout = 0;
1094*c3b6f8f2SDavid van Moolenbroek 	for (sep = servtab; sep != NULL; sep = sep->se_next) {
1095*c3b6f8f2SDavid van Moolenbroek 		if (sep->se_fd == -1 && !ISMUX(sep)) {
1096*c3b6f8f2SDavid van Moolenbroek 			switch (sep->se_family) {
1097*c3b6f8f2SDavid van Moolenbroek 			case AF_LOCAL:
1098*c3b6f8f2SDavid van Moolenbroek 			case AF_INET:
1099*c3b6f8f2SDavid van Moolenbroek #ifdef INET6
1100*c3b6f8f2SDavid van Moolenbroek 			case AF_INET6:
1101*c3b6f8f2SDavid van Moolenbroek #endif
1102*c3b6f8f2SDavid van Moolenbroek 				setup(sep);
1103*c3b6f8f2SDavid van Moolenbroek 				if (sep->se_fd >= 0 && isrpcservice(sep))
1104*c3b6f8f2SDavid van Moolenbroek 					register_rpc(sep);
1105*c3b6f8f2SDavid van Moolenbroek 				break;
1106*c3b6f8f2SDavid van Moolenbroek 			}
1107*c3b6f8f2SDavid van Moolenbroek 		}
1108*c3b6f8f2SDavid van Moolenbroek 	}
1109*c3b6f8f2SDavid van Moolenbroek }
1110*c3b6f8f2SDavid van Moolenbroek 
1111*c3b6f8f2SDavid van Moolenbroek static void
1112*c3b6f8f2SDavid van Moolenbroek goaway(void)
1113*c3b6f8f2SDavid van Moolenbroek {
1114*c3b6f8f2SDavid van Moolenbroek 	struct servtab *sep;
1115*c3b6f8f2SDavid van Moolenbroek 
1116*c3b6f8f2SDavid van Moolenbroek 	for (sep = servtab; sep != NULL; sep = sep->se_next) {
1117*c3b6f8f2SDavid van Moolenbroek 		if (sep->se_fd == -1)
1118*c3b6f8f2SDavid van Moolenbroek 			continue;
1119*c3b6f8f2SDavid van Moolenbroek 
1120*c3b6f8f2SDavid van Moolenbroek 		switch (sep->se_family) {
1121*c3b6f8f2SDavid van Moolenbroek 		case AF_LOCAL:
1122*c3b6f8f2SDavid van Moolenbroek 			(void)unlink(sep->se_service);
1123*c3b6f8f2SDavid van Moolenbroek 			break;
1124*c3b6f8f2SDavid van Moolenbroek 		case AF_INET:
1125*c3b6f8f2SDavid van Moolenbroek #ifdef INET6
1126*c3b6f8f2SDavid van Moolenbroek 		case AF_INET6:
1127*c3b6f8f2SDavid van Moolenbroek #endif
1128*c3b6f8f2SDavid van Moolenbroek 			if (sep->se_wait == 1 && isrpcservice(sep))
1129*c3b6f8f2SDavid van Moolenbroek 				unregister_rpc(sep);
1130*c3b6f8f2SDavid van Moolenbroek 			break;
1131*c3b6f8f2SDavid van Moolenbroek 		}
1132*c3b6f8f2SDavid van Moolenbroek 		(void)close(sep->se_fd);
1133*c3b6f8f2SDavid van Moolenbroek 		sep->se_fd = -1;
1134*c3b6f8f2SDavid van Moolenbroek 	}
1135*c3b6f8f2SDavid van Moolenbroek 	exit(0);
1136*c3b6f8f2SDavid van Moolenbroek }
1137*c3b6f8f2SDavid van Moolenbroek 
1138*c3b6f8f2SDavid van Moolenbroek static void
1139*c3b6f8f2SDavid van Moolenbroek setup(struct servtab *sep)
1140*c3b6f8f2SDavid van Moolenbroek {
1141*c3b6f8f2SDavid van Moolenbroek 	int		on = 1;
1142*c3b6f8f2SDavid van Moolenbroek #ifdef INET6
1143*c3b6f8f2SDavid van Moolenbroek 	int		off = 0;
1144*c3b6f8f2SDavid van Moolenbroek #endif
1145*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
1146*c3b6f8f2SDavid van Moolenbroek 	struct kevent	*ev;
1147*c3b6f8f2SDavid van Moolenbroek #endif /* !__minix */
1148*c3b6f8f2SDavid van Moolenbroek 
1149*c3b6f8f2SDavid van Moolenbroek 	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
1150*c3b6f8f2SDavid van Moolenbroek 		if (debug)
1151*c3b6f8f2SDavid van Moolenbroek 			fprintf(stderr, "socket failed on %s/%s: %s\n",
1152*c3b6f8f2SDavid van Moolenbroek 			    sep->se_service, sep->se_proto, strerror(errno));
1153*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "%s/%s: socket: %m",
1154*c3b6f8f2SDavid van Moolenbroek 		    sep->se_service, sep->se_proto);
1155*c3b6f8f2SDavid van Moolenbroek 		return;
1156*c3b6f8f2SDavid van Moolenbroek 	}
1157*c3b6f8f2SDavid van Moolenbroek 	/* Set all listening sockets to close-on-exec. */
1158*c3b6f8f2SDavid van Moolenbroek 	if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) {
1159*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "%s/%s: fcntl(F_SETFD, FD_CLOEXEC): %m",
1160*c3b6f8f2SDavid van Moolenbroek 		    sep->se_service, sep->se_proto);
1161*c3b6f8f2SDavid van Moolenbroek 		close(sep->se_fd);
1162*c3b6f8f2SDavid van Moolenbroek 		sep->se_fd = -1;
1163*c3b6f8f2SDavid van Moolenbroek 		return;
1164*c3b6f8f2SDavid van Moolenbroek 	}
1165*c3b6f8f2SDavid van Moolenbroek 
1166*c3b6f8f2SDavid van Moolenbroek #define	turnon(fd, opt) \
1167*c3b6f8f2SDavid van Moolenbroek setsockopt(fd, SOL_SOCKET, opt, &on, (socklen_t)sizeof(on))
1168*c3b6f8f2SDavid van Moolenbroek 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
1169*c3b6f8f2SDavid van Moolenbroek 	    turnon(sep->se_fd, SO_DEBUG) < 0)
1170*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
1171*c3b6f8f2SDavid van Moolenbroek 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
1172*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
1173*c3b6f8f2SDavid van Moolenbroek #undef turnon
1174*c3b6f8f2SDavid van Moolenbroek 
1175*c3b6f8f2SDavid van Moolenbroek 	/* Set the socket buffer sizes, if specified. */
1176*c3b6f8f2SDavid van Moolenbroek 	if (sep->se_sndbuf != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
1177*c3b6f8f2SDavid van Moolenbroek 	    SO_SNDBUF, &sep->se_sndbuf, (socklen_t)sizeof(sep->se_sndbuf)) < 0)
1178*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "setsockopt (SO_SNDBUF %d): %m",
1179*c3b6f8f2SDavid van Moolenbroek 		    sep->se_sndbuf);
1180*c3b6f8f2SDavid van Moolenbroek 	if (sep->se_rcvbuf != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
1181*c3b6f8f2SDavid van Moolenbroek 	    SO_RCVBUF, &sep->se_rcvbuf, (socklen_t)sizeof(sep->se_rcvbuf)) < 0)
1182*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "setsockopt (SO_RCVBUF %d): %m",
1183*c3b6f8f2SDavid van Moolenbroek 		    sep->se_rcvbuf);
1184*c3b6f8f2SDavid van Moolenbroek #ifdef INET6
1185*c3b6f8f2SDavid van Moolenbroek 	if (sep->se_family == AF_INET6) {
1186*c3b6f8f2SDavid van Moolenbroek 		int *v;
1187*c3b6f8f2SDavid van Moolenbroek 		v = (sep->se_type == FAITH_TYPE) ? &on : &off;
1188*c3b6f8f2SDavid van Moolenbroek 		if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH,
1189*c3b6f8f2SDavid van Moolenbroek 		    v, (socklen_t)sizeof(*v)) < 0)
1190*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m");
1191*c3b6f8f2SDavid van Moolenbroek 	}
1192*c3b6f8f2SDavid van Moolenbroek #endif
1193*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
1194*c3b6f8f2SDavid van Moolenbroek 	if (ipsecsetup(sep->se_family, sep->se_fd, sep->se_policy) < 0 &&
1195*c3b6f8f2SDavid van Moolenbroek 	    sep->se_policy) {
1196*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "%s/%s: ipsec setup failed",
1197*c3b6f8f2SDavid van Moolenbroek 		    sep->se_service, sep->se_proto);
1198*c3b6f8f2SDavid van Moolenbroek 		(void)close(sep->se_fd);
1199*c3b6f8f2SDavid van Moolenbroek 		sep->se_fd = -1;
1200*c3b6f8f2SDavid van Moolenbroek 		return;
1201*c3b6f8f2SDavid van Moolenbroek 	}
1202*c3b6f8f2SDavid van Moolenbroek #endif
1203*c3b6f8f2SDavid van Moolenbroek 
1204*c3b6f8f2SDavid van Moolenbroek 	if (bind(sep->se_fd, &sep->se_ctrladdr,
1205*c3b6f8f2SDavid van Moolenbroek 	    (socklen_t)sep->se_ctrladdr_size) < 0) {
1206*c3b6f8f2SDavid van Moolenbroek 		if (debug)
1207*c3b6f8f2SDavid van Moolenbroek 			fprintf(stderr, "bind failed on %s/%s: %s\n",
1208*c3b6f8f2SDavid van Moolenbroek 			    sep->se_service, sep->se_proto, strerror(errno));
1209*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "%s/%s: bind: %m",
1210*c3b6f8f2SDavid van Moolenbroek 		    sep->se_service, sep->se_proto);
1211*c3b6f8f2SDavid van Moolenbroek 		(void) close(sep->se_fd);
1212*c3b6f8f2SDavid van Moolenbroek 		sep->se_fd = -1;
1213*c3b6f8f2SDavid van Moolenbroek 		if (!timingout) {
1214*c3b6f8f2SDavid van Moolenbroek 			timingout = 1;
1215*c3b6f8f2SDavid van Moolenbroek 			alarm(RETRYTIME);
1216*c3b6f8f2SDavid van Moolenbroek 		}
1217*c3b6f8f2SDavid van Moolenbroek 		return;
1218*c3b6f8f2SDavid van Moolenbroek 	}
1219*c3b6f8f2SDavid van Moolenbroek 	if (sep->se_socktype == SOCK_STREAM)
1220*c3b6f8f2SDavid van Moolenbroek 		listen(sep->se_fd, 10);
1221*c3b6f8f2SDavid van Moolenbroek 
1222*c3b6f8f2SDavid van Moolenbroek 	/* Set the accept filter, if specified. To be done after listen.*/
1223*c3b6f8f2SDavid van Moolenbroek 	if (sep->se_accf.af_name[0] != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
1224*c3b6f8f2SDavid van Moolenbroek 	    SO_ACCEPTFILTER, &sep->se_accf,
1225*c3b6f8f2SDavid van Moolenbroek 	    (socklen_t)sizeof(sep->se_accf)) < 0)
1226*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "setsockopt(SO_ACCEPTFILTER %s): %m",
1227*c3b6f8f2SDavid van Moolenbroek 		    sep->se_accf.af_name);
1228*c3b6f8f2SDavid van Moolenbroek 
1229*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
1230*c3b6f8f2SDavid van Moolenbroek 	ev = allocchange();
1231*c3b6f8f2SDavid van Moolenbroek 	EV_SET(ev, sep->se_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0,
1232*c3b6f8f2SDavid van Moolenbroek 	    (intptr_t)sep);
1233*c3b6f8f2SDavid van Moolenbroek #endif /* !__minix */
1234*c3b6f8f2SDavid van Moolenbroek 	if (sep->se_fd > maxsock) {
1235*c3b6f8f2SDavid van Moolenbroek 		maxsock = sep->se_fd;
1236*c3b6f8f2SDavid van Moolenbroek 		if (maxsock > (int)(rlim_ofile_cur - FD_MARGIN))
1237*c3b6f8f2SDavid van Moolenbroek 			bump_nofile();
1238*c3b6f8f2SDavid van Moolenbroek 	}
1239*c3b6f8f2SDavid van Moolenbroek 	if (debug)
1240*c3b6f8f2SDavid van Moolenbroek 		fprintf(stderr, "registered %s on %d\n",
1241*c3b6f8f2SDavid van Moolenbroek 		    sep->se_server, sep->se_fd);
1242*c3b6f8f2SDavid van Moolenbroek }
1243*c3b6f8f2SDavid van Moolenbroek 
1244*c3b6f8f2SDavid van Moolenbroek /*
1245*c3b6f8f2SDavid van Moolenbroek  * Finish with a service and its socket.
1246*c3b6f8f2SDavid van Moolenbroek  */
1247*c3b6f8f2SDavid van Moolenbroek static void
1248*c3b6f8f2SDavid van Moolenbroek close_sep(struct servtab *sep)
1249*c3b6f8f2SDavid van Moolenbroek {
1250*c3b6f8f2SDavid van Moolenbroek 	if (sep->se_fd >= 0) {
1251*c3b6f8f2SDavid van Moolenbroek 		(void) close(sep->se_fd);
1252*c3b6f8f2SDavid van Moolenbroek 		sep->se_fd = -1;
1253*c3b6f8f2SDavid van Moolenbroek 	}
1254*c3b6f8f2SDavid van Moolenbroek 	sep->se_count = 0;
1255*c3b6f8f2SDavid van Moolenbroek }
1256*c3b6f8f2SDavid van Moolenbroek 
1257*c3b6f8f2SDavid van Moolenbroek static void
1258*c3b6f8f2SDavid van Moolenbroek register_rpc(struct servtab *sep)
1259*c3b6f8f2SDavid van Moolenbroek {
1260*c3b6f8f2SDavid van Moolenbroek #ifdef RPC
1261*c3b6f8f2SDavid van Moolenbroek 	struct netbuf nbuf;
1262*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr_storage ss;
1263*c3b6f8f2SDavid van Moolenbroek 	struct netconfig *nconf;
1264*c3b6f8f2SDavid van Moolenbroek 	socklen_t socklen;
1265*c3b6f8f2SDavid van Moolenbroek 	int n;
1266*c3b6f8f2SDavid van Moolenbroek 
1267*c3b6f8f2SDavid van Moolenbroek 	if ((nconf = getnetconfigent(sep->se_proto+4)) == NULL) {
1268*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "%s: getnetconfigent failed",
1269*c3b6f8f2SDavid van Moolenbroek 		    sep->se_proto);
1270*c3b6f8f2SDavid van Moolenbroek 		return;
1271*c3b6f8f2SDavid van Moolenbroek 	}
1272*c3b6f8f2SDavid van Moolenbroek 	socklen = sizeof ss;
1273*c3b6f8f2SDavid van Moolenbroek 	if (getsockname(sep->se_fd, (struct sockaddr *)(void *)&ss, &socklen) < 0) {
1274*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "%s/%s: getsockname: %m",
1275*c3b6f8f2SDavid van Moolenbroek 		    sep->se_service, sep->se_proto);
1276*c3b6f8f2SDavid van Moolenbroek 		return;
1277*c3b6f8f2SDavid van Moolenbroek 	}
1278*c3b6f8f2SDavid van Moolenbroek 
1279*c3b6f8f2SDavid van Moolenbroek 	nbuf.buf = &ss;
1280*c3b6f8f2SDavid van Moolenbroek 	nbuf.len = ss.ss_len;
1281*c3b6f8f2SDavid van Moolenbroek 	nbuf.maxlen = sizeof (struct sockaddr_storage);
1282*c3b6f8f2SDavid van Moolenbroek 	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1283*c3b6f8f2SDavid van Moolenbroek 		if (debug)
1284*c3b6f8f2SDavid van Moolenbroek 			fprintf(stderr, "rpcb_set: %u %d %s %s\n",
1285*c3b6f8f2SDavid van Moolenbroek 			    sep->se_rpcprog, n, nconf->nc_netid,
1286*c3b6f8f2SDavid van Moolenbroek 			    taddr2uaddr(nconf, &nbuf));
1287*c3b6f8f2SDavid van Moolenbroek 		(void)rpcb_unset((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf);
1288*c3b6f8f2SDavid van Moolenbroek 		if (!rpcb_set((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf, &nbuf))
1289*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "rpcb_set: %u %d %s %s%s",
1290*c3b6f8f2SDavid van Moolenbroek 			    sep->se_rpcprog, n, nconf->nc_netid,
1291*c3b6f8f2SDavid van Moolenbroek 			    taddr2uaddr(nconf, &nbuf), clnt_spcreateerror(""));
1292*c3b6f8f2SDavid van Moolenbroek 	}
1293*c3b6f8f2SDavid van Moolenbroek #endif /* RPC */
1294*c3b6f8f2SDavid van Moolenbroek }
1295*c3b6f8f2SDavid van Moolenbroek 
1296*c3b6f8f2SDavid van Moolenbroek static void
1297*c3b6f8f2SDavid van Moolenbroek unregister_rpc(struct servtab *sep)
1298*c3b6f8f2SDavid van Moolenbroek {
1299*c3b6f8f2SDavid van Moolenbroek #ifdef RPC
1300*c3b6f8f2SDavid van Moolenbroek 	int n;
1301*c3b6f8f2SDavid van Moolenbroek 	struct netconfig *nconf;
1302*c3b6f8f2SDavid van Moolenbroek 
1303*c3b6f8f2SDavid van Moolenbroek 	if ((nconf = getnetconfigent(sep->se_proto+4)) == NULL) {
1304*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "%s: getnetconfigent failed",
1305*c3b6f8f2SDavid van Moolenbroek 		    sep->se_proto);
1306*c3b6f8f2SDavid van Moolenbroek 		return;
1307*c3b6f8f2SDavid van Moolenbroek 	}
1308*c3b6f8f2SDavid van Moolenbroek 
1309*c3b6f8f2SDavid van Moolenbroek 	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1310*c3b6f8f2SDavid van Moolenbroek 		if (debug)
1311*c3b6f8f2SDavid van Moolenbroek 			fprintf(stderr, "rpcb_unset(%u, %d, %s)\n",
1312*c3b6f8f2SDavid van Moolenbroek 			    sep->se_rpcprog, n, nconf->nc_netid);
1313*c3b6f8f2SDavid van Moolenbroek 		if (!rpcb_unset((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf))
1314*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "rpcb_unset(%u, %d, %s) failed\n",
1315*c3b6f8f2SDavid van Moolenbroek 			    sep->se_rpcprog, n, nconf->nc_netid);
1316*c3b6f8f2SDavid van Moolenbroek 	}
1317*c3b6f8f2SDavid van Moolenbroek #endif /* RPC */
1318*c3b6f8f2SDavid van Moolenbroek }
1319*c3b6f8f2SDavid van Moolenbroek 
1320*c3b6f8f2SDavid van Moolenbroek 
1321*c3b6f8f2SDavid van Moolenbroek static struct servtab *
1322*c3b6f8f2SDavid van Moolenbroek enter(struct servtab *cp)
1323*c3b6f8f2SDavid van Moolenbroek {
1324*c3b6f8f2SDavid van Moolenbroek 	struct servtab *sep;
1325*c3b6f8f2SDavid van Moolenbroek 
1326*c3b6f8f2SDavid van Moolenbroek 	sep = malloc(sizeof (*sep));
1327*c3b6f8f2SDavid van Moolenbroek 	if (sep == NULL) {
1328*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "Out of memory.");
1329*c3b6f8f2SDavid van Moolenbroek 		exit(1);
1330*c3b6f8f2SDavid van Moolenbroek 	}
1331*c3b6f8f2SDavid van Moolenbroek 	*sep = *cp;
1332*c3b6f8f2SDavid van Moolenbroek 	sep->se_fd = -1;
1333*c3b6f8f2SDavid van Moolenbroek 	sep->se_rpcprog = -1;
1334*c3b6f8f2SDavid van Moolenbroek 	sep->se_next = servtab;
1335*c3b6f8f2SDavid van Moolenbroek 	servtab = sep;
1336*c3b6f8f2SDavid van Moolenbroek 	return (sep);
1337*c3b6f8f2SDavid van Moolenbroek }
1338*c3b6f8f2SDavid van Moolenbroek 
1339*c3b6f8f2SDavid van Moolenbroek FILE	*fconfig = NULL;
1340*c3b6f8f2SDavid van Moolenbroek struct	servtab serv;
1341*c3b6f8f2SDavid van Moolenbroek char	line[LINE_MAX];
1342*c3b6f8f2SDavid van Moolenbroek char    *defhost;
1343*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
1344*c3b6f8f2SDavid van Moolenbroek static char *policy = NULL;
1345*c3b6f8f2SDavid van Moolenbroek #endif
1346*c3b6f8f2SDavid van Moolenbroek 
1347*c3b6f8f2SDavid van Moolenbroek static int
1348*c3b6f8f2SDavid van Moolenbroek setconfig(void)
1349*c3b6f8f2SDavid van Moolenbroek {
1350*c3b6f8f2SDavid van Moolenbroek 	if (defhost)
1351*c3b6f8f2SDavid van Moolenbroek 		free(defhost);
1352*c3b6f8f2SDavid van Moolenbroek 	defhost = newstr("*");
1353*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
1354*c3b6f8f2SDavid van Moolenbroek 	if (policy)
1355*c3b6f8f2SDavid van Moolenbroek 		free(policy);
1356*c3b6f8f2SDavid van Moolenbroek 	policy = NULL;
1357*c3b6f8f2SDavid van Moolenbroek #endif
1358*c3b6f8f2SDavid van Moolenbroek 	if (fconfig != NULL) {
1359*c3b6f8f2SDavid van Moolenbroek 		fseek(fconfig, 0L, SEEK_SET);
1360*c3b6f8f2SDavid van Moolenbroek 		return (1);
1361*c3b6f8f2SDavid van Moolenbroek 	}
1362*c3b6f8f2SDavid van Moolenbroek 	fconfig = fopen(CONFIG, "r");
1363*c3b6f8f2SDavid van Moolenbroek 	return (fconfig != NULL);
1364*c3b6f8f2SDavid van Moolenbroek }
1365*c3b6f8f2SDavid van Moolenbroek 
1366*c3b6f8f2SDavid van Moolenbroek static void
1367*c3b6f8f2SDavid van Moolenbroek endconfig(void)
1368*c3b6f8f2SDavid van Moolenbroek {
1369*c3b6f8f2SDavid van Moolenbroek 	if (fconfig != NULL) {
1370*c3b6f8f2SDavid van Moolenbroek 		(void) fclose(fconfig);
1371*c3b6f8f2SDavid van Moolenbroek 		fconfig = NULL;
1372*c3b6f8f2SDavid van Moolenbroek 	}
1373*c3b6f8f2SDavid van Moolenbroek 	if (defhost != NULL) {
1374*c3b6f8f2SDavid van Moolenbroek 		free(defhost);
1375*c3b6f8f2SDavid van Moolenbroek 		defhost = NULL;
1376*c3b6f8f2SDavid van Moolenbroek 	}
1377*c3b6f8f2SDavid van Moolenbroek }
1378*c3b6f8f2SDavid van Moolenbroek 
1379*c3b6f8f2SDavid van Moolenbroek static struct servtab *
1380*c3b6f8f2SDavid van Moolenbroek getconfigent(void)
1381*c3b6f8f2SDavid van Moolenbroek {
1382*c3b6f8f2SDavid van Moolenbroek 	struct servtab *sep = &serv;
1383*c3b6f8f2SDavid van Moolenbroek 	int argc, val;
1384*c3b6f8f2SDavid van Moolenbroek 	char *cp, *cp0, *arg, *buf0, *buf1, *sz0, *sz1;
1385*c3b6f8f2SDavid van Moolenbroek 	static char TCPMUX_TOKEN[] = "tcpmux/";
1386*c3b6f8f2SDavid van Moolenbroek #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
1387*c3b6f8f2SDavid van Moolenbroek 	char *hostdelim;
1388*c3b6f8f2SDavid van Moolenbroek 
1389*c3b6f8f2SDavid van Moolenbroek more:
1390*c3b6f8f2SDavid van Moolenbroek 	while ((cp = nextline(fconfig)) != NULL) {
1391*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
1392*c3b6f8f2SDavid van Moolenbroek 		/* lines starting with #@ is not a comment, but the policy */
1393*c3b6f8f2SDavid van Moolenbroek 		if (cp[0] == '#' && cp[1] == '@') {
1394*c3b6f8f2SDavid van Moolenbroek 			char *p;
1395*c3b6f8f2SDavid van Moolenbroek 			for (p = cp + 2; p && *p && isspace((unsigned char)*p); p++)
1396*c3b6f8f2SDavid van Moolenbroek 				;
1397*c3b6f8f2SDavid van Moolenbroek 			if (*p == '\0') {
1398*c3b6f8f2SDavid van Moolenbroek 				if (policy)
1399*c3b6f8f2SDavid van Moolenbroek 					free(policy);
1400*c3b6f8f2SDavid van Moolenbroek 				policy = NULL;
1401*c3b6f8f2SDavid van Moolenbroek 			} else {
1402*c3b6f8f2SDavid van Moolenbroek 				if (ipsecsetup_test(p) < 0) {
1403*c3b6f8f2SDavid van Moolenbroek 					syslog(LOG_ERR,
1404*c3b6f8f2SDavid van Moolenbroek 						"%s: invalid ipsec policy \"%s\"",
1405*c3b6f8f2SDavid van Moolenbroek 						CONFIG, p);
1406*c3b6f8f2SDavid van Moolenbroek 					exit(1);
1407*c3b6f8f2SDavid van Moolenbroek 				} else {
1408*c3b6f8f2SDavid van Moolenbroek 					if (policy)
1409*c3b6f8f2SDavid van Moolenbroek 						free(policy);
1410*c3b6f8f2SDavid van Moolenbroek 					policy = newstr(p);
1411*c3b6f8f2SDavid van Moolenbroek 				}
1412*c3b6f8f2SDavid van Moolenbroek 			}
1413*c3b6f8f2SDavid van Moolenbroek 		}
1414*c3b6f8f2SDavid van Moolenbroek #endif
1415*c3b6f8f2SDavid van Moolenbroek 		if (*cp == '#' || *cp == '\0')
1416*c3b6f8f2SDavid van Moolenbroek 			continue;
1417*c3b6f8f2SDavid van Moolenbroek 		break;
1418*c3b6f8f2SDavid van Moolenbroek 	}
1419*c3b6f8f2SDavid van Moolenbroek 	if (cp == NULL)
1420*c3b6f8f2SDavid van Moolenbroek 		return (NULL);
1421*c3b6f8f2SDavid van Moolenbroek 	/*
1422*c3b6f8f2SDavid van Moolenbroek 	 * clear the static buffer, since some fields (se_ctrladdr,
1423*c3b6f8f2SDavid van Moolenbroek 	 * for example) don't get initialized here.
1424*c3b6f8f2SDavid van Moolenbroek 	 */
1425*c3b6f8f2SDavid van Moolenbroek 	memset(sep, 0, sizeof *sep);
1426*c3b6f8f2SDavid van Moolenbroek 	arg = skip(&cp);
1427*c3b6f8f2SDavid van Moolenbroek 	if (cp == NULL) {
1428*c3b6f8f2SDavid van Moolenbroek 		/* got an empty line containing just blanks/tabs. */
1429*c3b6f8f2SDavid van Moolenbroek 		goto more;
1430*c3b6f8f2SDavid van Moolenbroek 	}
1431*c3b6f8f2SDavid van Moolenbroek 	/* Check for a host name. */
1432*c3b6f8f2SDavid van Moolenbroek 	hostdelim = strrchr(arg, ':');
1433*c3b6f8f2SDavid van Moolenbroek 	if (hostdelim) {
1434*c3b6f8f2SDavid van Moolenbroek 		*hostdelim = '\0';
1435*c3b6f8f2SDavid van Moolenbroek 		if (arg[0] == '[' && hostdelim > arg && hostdelim[-1] == ']') {
1436*c3b6f8f2SDavid van Moolenbroek 			hostdelim[-1] = '\0';
1437*c3b6f8f2SDavid van Moolenbroek 			sep->se_hostaddr = newstr(arg + 1);
1438*c3b6f8f2SDavid van Moolenbroek 		} else
1439*c3b6f8f2SDavid van Moolenbroek 			sep->se_hostaddr = newstr(arg);
1440*c3b6f8f2SDavid van Moolenbroek 		arg = hostdelim + 1;
1441*c3b6f8f2SDavid van Moolenbroek 		/*
1442*c3b6f8f2SDavid van Moolenbroek 		 * If the line is of the form `host:', then just change the
1443*c3b6f8f2SDavid van Moolenbroek 		 * default host for the following lines.
1444*c3b6f8f2SDavid van Moolenbroek 		 */
1445*c3b6f8f2SDavid van Moolenbroek 		if (*arg == '\0') {
1446*c3b6f8f2SDavid van Moolenbroek 			arg = skip(&cp);
1447*c3b6f8f2SDavid van Moolenbroek 			if (cp == NULL) {
1448*c3b6f8f2SDavid van Moolenbroek 				free(defhost);
1449*c3b6f8f2SDavid van Moolenbroek 				defhost = sep->se_hostaddr;
1450*c3b6f8f2SDavid van Moolenbroek 				goto more;
1451*c3b6f8f2SDavid van Moolenbroek 			}
1452*c3b6f8f2SDavid van Moolenbroek 		}
1453*c3b6f8f2SDavid van Moolenbroek 	} else
1454*c3b6f8f2SDavid van Moolenbroek 		sep->se_hostaddr = newstr(defhost);
1455*c3b6f8f2SDavid van Moolenbroek 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
1456*c3b6f8f2SDavid van Moolenbroek 		char *c = arg + MUX_LEN;
1457*c3b6f8f2SDavid van Moolenbroek 		if (*c == '+') {
1458*c3b6f8f2SDavid van Moolenbroek 			sep->se_type = MUXPLUS_TYPE;
1459*c3b6f8f2SDavid van Moolenbroek 			c++;
1460*c3b6f8f2SDavid van Moolenbroek 		} else
1461*c3b6f8f2SDavid van Moolenbroek 			sep->se_type = MUX_TYPE;
1462*c3b6f8f2SDavid van Moolenbroek 		sep->se_service = newstr(c);
1463*c3b6f8f2SDavid van Moolenbroek 	} else {
1464*c3b6f8f2SDavid van Moolenbroek 		sep->se_service = newstr(arg);
1465*c3b6f8f2SDavid van Moolenbroek 		sep->se_type = NORM_TYPE;
1466*c3b6f8f2SDavid van Moolenbroek 	}
1467*c3b6f8f2SDavid van Moolenbroek 
1468*c3b6f8f2SDavid van Moolenbroek 	arg = sskip(&cp);
1469*c3b6f8f2SDavid van Moolenbroek 	if (strncmp(arg, "stream", sizeof("stream") - 1) == 0) {
1470*c3b6f8f2SDavid van Moolenbroek 		char *accf, *accf_arg;
1471*c3b6f8f2SDavid van Moolenbroek 
1472*c3b6f8f2SDavid van Moolenbroek 		sep->se_socktype = SOCK_STREAM;
1473*c3b6f8f2SDavid van Moolenbroek 
1474*c3b6f8f2SDavid van Moolenbroek 		/* one and only one accept filter */
1475*c3b6f8f2SDavid van Moolenbroek 		accf = strchr(arg, ':');
1476*c3b6f8f2SDavid van Moolenbroek 		if (accf) {
1477*c3b6f8f2SDavid van Moolenbroek 	    		if (accf != strrchr(arg, ':') ||/* more than one */
1478*c3b6f8f2SDavid van Moolenbroek 	    		    *(accf + 1) == '\0') {	/* nothing beyond */
1479*c3b6f8f2SDavid van Moolenbroek 				sep->se_socktype = -1;
1480*c3b6f8f2SDavid van Moolenbroek 			} else {
1481*c3b6f8f2SDavid van Moolenbroek 				accf++;			/* skip delimiter */
1482*c3b6f8f2SDavid van Moolenbroek 				strlcpy(sep->se_accf.af_name, accf,
1483*c3b6f8f2SDavid van Moolenbroek 					sizeof(sep->se_accf.af_name));
1484*c3b6f8f2SDavid van Moolenbroek 				accf_arg = strchr(accf, ',');
1485*c3b6f8f2SDavid van Moolenbroek 				if (accf_arg) {	/* zero or one arg, no more */
1486*c3b6f8f2SDavid van Moolenbroek 					if (strrchr(accf, ',') != accf_arg) {
1487*c3b6f8f2SDavid van Moolenbroek 						sep->se_socktype = -1;
1488*c3b6f8f2SDavid van Moolenbroek 					} else {
1489*c3b6f8f2SDavid van Moolenbroek 						accf_arg++;
1490*c3b6f8f2SDavid van Moolenbroek 						strlcpy(sep->se_accf.af_arg,
1491*c3b6f8f2SDavid van Moolenbroek 							accf_arg,
1492*c3b6f8f2SDavid van Moolenbroek 							sizeof(sep->se_accf.af_arg));
1493*c3b6f8f2SDavid van Moolenbroek 					}
1494*c3b6f8f2SDavid van Moolenbroek 				}
1495*c3b6f8f2SDavid van Moolenbroek 			}
1496*c3b6f8f2SDavid van Moolenbroek 		}
1497*c3b6f8f2SDavid van Moolenbroek 	}
1498*c3b6f8f2SDavid van Moolenbroek 
1499*c3b6f8f2SDavid van Moolenbroek 	else if (strcmp(arg, "dgram") == 0)
1500*c3b6f8f2SDavid van Moolenbroek 		sep->se_socktype = SOCK_DGRAM;
1501*c3b6f8f2SDavid van Moolenbroek 	else if (strcmp(arg, "rdm") == 0)
1502*c3b6f8f2SDavid van Moolenbroek 		sep->se_socktype = SOCK_RDM;
1503*c3b6f8f2SDavid van Moolenbroek 	else if (strcmp(arg, "seqpacket") == 0)
1504*c3b6f8f2SDavid van Moolenbroek 		sep->se_socktype = SOCK_SEQPACKET;
1505*c3b6f8f2SDavid van Moolenbroek 	else if (strcmp(arg, "raw") == 0)
1506*c3b6f8f2SDavid van Moolenbroek 		sep->se_socktype = SOCK_RAW;
1507*c3b6f8f2SDavid van Moolenbroek 	else
1508*c3b6f8f2SDavid van Moolenbroek 		sep->se_socktype = -1;
1509*c3b6f8f2SDavid van Moolenbroek 
1510*c3b6f8f2SDavid van Moolenbroek 	arg = sskip(&cp);
1511*c3b6f8f2SDavid van Moolenbroek 	if (sep->se_type == NORM_TYPE &&
1512*c3b6f8f2SDavid van Moolenbroek 	    strncmp(arg, "faith/", strlen("faith/")) == 0) {
1513*c3b6f8f2SDavid van Moolenbroek 		arg += strlen("faith/");
1514*c3b6f8f2SDavid van Moolenbroek 		sep->se_type = FAITH_TYPE;
1515*c3b6f8f2SDavid van Moolenbroek 	}
1516*c3b6f8f2SDavid van Moolenbroek 	sep->se_proto = newstr(arg);
1517*c3b6f8f2SDavid van Moolenbroek 
1518*c3b6f8f2SDavid van Moolenbroek #define	MALFORMED(arg) \
1519*c3b6f8f2SDavid van Moolenbroek do { \
1520*c3b6f8f2SDavid van Moolenbroek 	syslog(LOG_ERR, "%s: malformed buffer size option `%s'", \
1521*c3b6f8f2SDavid van Moolenbroek 	    sep->se_service, (arg)); \
1522*c3b6f8f2SDavid van Moolenbroek 	goto more; \
1523*c3b6f8f2SDavid van Moolenbroek 	/*NOTREACHED*/ \
1524*c3b6f8f2SDavid van Moolenbroek } while (/*CONSTCOND*/0)
1525*c3b6f8f2SDavid van Moolenbroek 
1526*c3b6f8f2SDavid van Moolenbroek #define	GETVAL(arg) \
1527*c3b6f8f2SDavid van Moolenbroek do { \
1528*c3b6f8f2SDavid van Moolenbroek 	if (!isdigit((unsigned char)*(arg))) \
1529*c3b6f8f2SDavid van Moolenbroek 		MALFORMED(arg); \
1530*c3b6f8f2SDavid van Moolenbroek 	val = (int)strtol((arg), &cp0, 10); \
1531*c3b6f8f2SDavid van Moolenbroek 	if (cp0 != NULL) { \
1532*c3b6f8f2SDavid van Moolenbroek 		if (cp0[1] != '\0') \
1533*c3b6f8f2SDavid van Moolenbroek 			MALFORMED((arg)); \
1534*c3b6f8f2SDavid van Moolenbroek 		if (cp0[0] == 'k') \
1535*c3b6f8f2SDavid van Moolenbroek 			val *= 1024; \
1536*c3b6f8f2SDavid van Moolenbroek 		if (cp0[0] == 'm') \
1537*c3b6f8f2SDavid van Moolenbroek 			val *= 1024 * 1024; \
1538*c3b6f8f2SDavid van Moolenbroek 	} \
1539*c3b6f8f2SDavid van Moolenbroek 	if (val < 1) { \
1540*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "%s: invalid buffer size `%s'", \
1541*c3b6f8f2SDavid van Moolenbroek 		    sep->se_service, (arg)); \
1542*c3b6f8f2SDavid van Moolenbroek 		goto more; \
1543*c3b6f8f2SDavid van Moolenbroek 	} \
1544*c3b6f8f2SDavid van Moolenbroek 	/*NOTREACHED*/ \
1545*c3b6f8f2SDavid van Moolenbroek } while (/*CONSTCOND*/0)
1546*c3b6f8f2SDavid van Moolenbroek 
1547*c3b6f8f2SDavid van Moolenbroek #define	ASSIGN(arg) \
1548*c3b6f8f2SDavid van Moolenbroek do { \
1549*c3b6f8f2SDavid van Moolenbroek 	if (strcmp((arg), "sndbuf") == 0) \
1550*c3b6f8f2SDavid van Moolenbroek 		sep->se_sndbuf = val; \
1551*c3b6f8f2SDavid van Moolenbroek 	else if (strcmp((arg), "rcvbuf") == 0) \
1552*c3b6f8f2SDavid van Moolenbroek 		sep->se_rcvbuf = val; \
1553*c3b6f8f2SDavid van Moolenbroek 	else \
1554*c3b6f8f2SDavid van Moolenbroek 		MALFORMED((arg)); \
1555*c3b6f8f2SDavid van Moolenbroek } while (/*CONSTCOND*/0)
1556*c3b6f8f2SDavid van Moolenbroek 
1557*c3b6f8f2SDavid van Moolenbroek 	/*
1558*c3b6f8f2SDavid van Moolenbroek 	 * Extract the send and receive buffer sizes before parsing
1559*c3b6f8f2SDavid van Moolenbroek 	 * the protocol.
1560*c3b6f8f2SDavid van Moolenbroek 	 */
1561*c3b6f8f2SDavid van Moolenbroek 	sep->se_sndbuf = sep->se_rcvbuf = 0;
1562*c3b6f8f2SDavid van Moolenbroek 	buf0 = buf1 = sz0 = sz1 = NULL;
1563*c3b6f8f2SDavid van Moolenbroek 	if ((buf0 = strchr(sep->se_proto, ',')) != NULL) {
1564*c3b6f8f2SDavid van Moolenbroek 		/* Not meaningful for Tcpmux services. */
1565*c3b6f8f2SDavid van Moolenbroek 		if (ISMUX(sep)) {
1566*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "%s: can't specify buffer sizes for "
1567*c3b6f8f2SDavid van Moolenbroek 			    "tcpmux services", sep->se_service);
1568*c3b6f8f2SDavid van Moolenbroek 			goto more;
1569*c3b6f8f2SDavid van Moolenbroek 		}
1570*c3b6f8f2SDavid van Moolenbroek 
1571*c3b6f8f2SDavid van Moolenbroek 		/* Skip the , */
1572*c3b6f8f2SDavid van Moolenbroek 		*buf0++ = '\0';
1573*c3b6f8f2SDavid van Moolenbroek 
1574*c3b6f8f2SDavid van Moolenbroek 		/* Check to see if another socket buffer size was specified. */
1575*c3b6f8f2SDavid van Moolenbroek 		if ((buf1 = strchr(buf0, ',')) != NULL) {
1576*c3b6f8f2SDavid van Moolenbroek 			/* Skip the , */
1577*c3b6f8f2SDavid van Moolenbroek 			*buf1++ = '\0';
1578*c3b6f8f2SDavid van Moolenbroek 
1579*c3b6f8f2SDavid van Moolenbroek 			/* Make sure a 3rd one wasn't specified. */
1580*c3b6f8f2SDavid van Moolenbroek 			if (strchr(buf1, ',') != NULL) {
1581*c3b6f8f2SDavid van Moolenbroek 				syslog(LOG_ERR, "%s: too many buffer sizes",
1582*c3b6f8f2SDavid van Moolenbroek 				    sep->se_service);
1583*c3b6f8f2SDavid van Moolenbroek 				goto more;
1584*c3b6f8f2SDavid van Moolenbroek 			}
1585*c3b6f8f2SDavid van Moolenbroek 
1586*c3b6f8f2SDavid van Moolenbroek 			/* Locate the size. */
1587*c3b6f8f2SDavid van Moolenbroek 			if ((sz1 = strchr(buf1, '=')) == NULL)
1588*c3b6f8f2SDavid van Moolenbroek 				MALFORMED(buf1);
1589*c3b6f8f2SDavid van Moolenbroek 
1590*c3b6f8f2SDavid van Moolenbroek 			/* Skip the = */
1591*c3b6f8f2SDavid van Moolenbroek 			*sz1++ = '\0';
1592*c3b6f8f2SDavid van Moolenbroek 		}
1593*c3b6f8f2SDavid van Moolenbroek 
1594*c3b6f8f2SDavid van Moolenbroek 		/* Locate the size. */
1595*c3b6f8f2SDavid van Moolenbroek 		if ((sz0 = strchr(buf0, '=')) == NULL)
1596*c3b6f8f2SDavid van Moolenbroek 			MALFORMED(buf0);
1597*c3b6f8f2SDavid van Moolenbroek 
1598*c3b6f8f2SDavid van Moolenbroek 		/* Skip the = */
1599*c3b6f8f2SDavid van Moolenbroek 		*sz0++ = '\0';
1600*c3b6f8f2SDavid van Moolenbroek 
1601*c3b6f8f2SDavid van Moolenbroek 		GETVAL(sz0);
1602*c3b6f8f2SDavid van Moolenbroek 		ASSIGN(buf0);
1603*c3b6f8f2SDavid van Moolenbroek 
1604*c3b6f8f2SDavid van Moolenbroek 		if (buf1 != NULL) {
1605*c3b6f8f2SDavid van Moolenbroek 			GETVAL(sz1);
1606*c3b6f8f2SDavid van Moolenbroek 			ASSIGN(buf1);
1607*c3b6f8f2SDavid van Moolenbroek 		}
1608*c3b6f8f2SDavid van Moolenbroek 	}
1609*c3b6f8f2SDavid van Moolenbroek 
1610*c3b6f8f2SDavid van Moolenbroek #undef ASSIGN
1611*c3b6f8f2SDavid van Moolenbroek #undef GETVAL
1612*c3b6f8f2SDavid van Moolenbroek #undef MALFORMED
1613*c3b6f8f2SDavid van Moolenbroek 
1614*c3b6f8f2SDavid van Moolenbroek 	if (strcmp(sep->se_proto, "unix") == 0) {
1615*c3b6f8f2SDavid van Moolenbroek 		sep->se_family = AF_LOCAL;
1616*c3b6f8f2SDavid van Moolenbroek 	} else {
1617*c3b6f8f2SDavid van Moolenbroek 		val = (int)strlen(sep->se_proto);
1618*c3b6f8f2SDavid van Moolenbroek 		if (!val) {
1619*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "%s: invalid protocol specified",
1620*c3b6f8f2SDavid van Moolenbroek 			    sep->se_service);
1621*c3b6f8f2SDavid van Moolenbroek 			goto more;
1622*c3b6f8f2SDavid van Moolenbroek 		}
1623*c3b6f8f2SDavid van Moolenbroek 		val = sep->se_proto[val - 1];
1624*c3b6f8f2SDavid van Moolenbroek 		switch (val) {
1625*c3b6f8f2SDavid van Moolenbroek 		case '4':	/*tcp4 or udp4*/
1626*c3b6f8f2SDavid van Moolenbroek 			sep->se_family = AF_INET;
1627*c3b6f8f2SDavid van Moolenbroek 			break;
1628*c3b6f8f2SDavid van Moolenbroek #ifdef INET6
1629*c3b6f8f2SDavid van Moolenbroek 		case '6':	/*tcp6 or udp6*/
1630*c3b6f8f2SDavid van Moolenbroek 			sep->se_family = AF_INET6;
1631*c3b6f8f2SDavid van Moolenbroek 			break;
1632*c3b6f8f2SDavid van Moolenbroek #endif
1633*c3b6f8f2SDavid van Moolenbroek 		default:
1634*c3b6f8f2SDavid van Moolenbroek 			sep->se_family = AF_INET;	/*will become AF_INET6*/
1635*c3b6f8f2SDavid van Moolenbroek 			break;
1636*c3b6f8f2SDavid van Moolenbroek 		}
1637*c3b6f8f2SDavid van Moolenbroek 		if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1638*c3b6f8f2SDavid van Moolenbroek #ifdef RPC
1639*c3b6f8f2SDavid van Moolenbroek 			char *cp1, *ccp;
1640*c3b6f8f2SDavid van Moolenbroek 			cp1 = strchr(sep->se_service, '/');
1641*c3b6f8f2SDavid van Moolenbroek 			if (cp1 == 0) {
1642*c3b6f8f2SDavid van Moolenbroek 				syslog(LOG_ERR, "%s: no rpc version",
1643*c3b6f8f2SDavid van Moolenbroek 				    sep->se_service);
1644*c3b6f8f2SDavid van Moolenbroek 				goto more;
1645*c3b6f8f2SDavid van Moolenbroek 			}
1646*c3b6f8f2SDavid van Moolenbroek 			*cp1++ = '\0';
1647*c3b6f8f2SDavid van Moolenbroek 			sep->se_rpcversl = sep->se_rpcversh =
1648*c3b6f8f2SDavid van Moolenbroek 			    (int)strtol(cp1, &ccp, 0);
1649*c3b6f8f2SDavid van Moolenbroek 			if (ccp == cp1) {
1650*c3b6f8f2SDavid van Moolenbroek 		badafterall:
1651*c3b6f8f2SDavid van Moolenbroek 				syslog(LOG_ERR, "%s/%s: bad rpc version",
1652*c3b6f8f2SDavid van Moolenbroek 				    sep->se_service, cp1);
1653*c3b6f8f2SDavid van Moolenbroek 				goto more;
1654*c3b6f8f2SDavid van Moolenbroek 			}
1655*c3b6f8f2SDavid van Moolenbroek 			if (*ccp == '-') {
1656*c3b6f8f2SDavid van Moolenbroek 				cp1 = ccp + 1;
1657*c3b6f8f2SDavid van Moolenbroek 				sep->se_rpcversh = (int)strtol(cp1, &ccp, 0);
1658*c3b6f8f2SDavid van Moolenbroek 				if (ccp == cp1)
1659*c3b6f8f2SDavid van Moolenbroek 					goto badafterall;
1660*c3b6f8f2SDavid van Moolenbroek 			}
1661*c3b6f8f2SDavid van Moolenbroek #else
1662*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "%s: rpc services not suported",
1663*c3b6f8f2SDavid van Moolenbroek 			    sep->se_service);
1664*c3b6f8f2SDavid van Moolenbroek 			goto more;
1665*c3b6f8f2SDavid van Moolenbroek #endif /* RPC */
1666*c3b6f8f2SDavid van Moolenbroek 		}
1667*c3b6f8f2SDavid van Moolenbroek 	}
1668*c3b6f8f2SDavid van Moolenbroek 	arg = sskip(&cp);
1669*c3b6f8f2SDavid van Moolenbroek 	{
1670*c3b6f8f2SDavid van Moolenbroek 		char *cp1;
1671*c3b6f8f2SDavid van Moolenbroek 		if ((cp1 = strchr(arg, ':')) == NULL)
1672*c3b6f8f2SDavid van Moolenbroek 			cp1 = strchr(arg, '.');
1673*c3b6f8f2SDavid van Moolenbroek 		if (cp1 != NULL) {
1674*c3b6f8f2SDavid van Moolenbroek 			*cp1++ = '\0';
1675*c3b6f8f2SDavid van Moolenbroek 			sep->se_max = atoi(cp1);
1676*c3b6f8f2SDavid van Moolenbroek 		} else
1677*c3b6f8f2SDavid van Moolenbroek 			sep->se_max = TOOMANY;
1678*c3b6f8f2SDavid van Moolenbroek 	}
1679*c3b6f8f2SDavid van Moolenbroek 	sep->se_wait = strcmp(arg, "wait") == 0;
1680*c3b6f8f2SDavid van Moolenbroek 	if (ISMUX(sep)) {
1681*c3b6f8f2SDavid van Moolenbroek 		/*
1682*c3b6f8f2SDavid van Moolenbroek 		 * Silently enforce "nowait" for TCPMUX services since
1683*c3b6f8f2SDavid van Moolenbroek 		 * they don't have an assigned port to listen on.
1684*c3b6f8f2SDavid van Moolenbroek 		 */
1685*c3b6f8f2SDavid van Moolenbroek 		sep->se_wait = 0;
1686*c3b6f8f2SDavid van Moolenbroek 
1687*c3b6f8f2SDavid van Moolenbroek 		if (strncmp(sep->se_proto, "tcp", 3)) {
1688*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR,
1689*c3b6f8f2SDavid van Moolenbroek 			    "%s: bad protocol for tcpmux service %s",
1690*c3b6f8f2SDavid van Moolenbroek 			    CONFIG, sep->se_service);
1691*c3b6f8f2SDavid van Moolenbroek 			goto more;
1692*c3b6f8f2SDavid van Moolenbroek 		}
1693*c3b6f8f2SDavid van Moolenbroek 		if (sep->se_socktype != SOCK_STREAM) {
1694*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR,
1695*c3b6f8f2SDavid van Moolenbroek 			    "%s: bad socket type for tcpmux service %s",
1696*c3b6f8f2SDavid van Moolenbroek 			    CONFIG, sep->se_service);
1697*c3b6f8f2SDavid van Moolenbroek 			goto more;
1698*c3b6f8f2SDavid van Moolenbroek 		}
1699*c3b6f8f2SDavid van Moolenbroek 	}
1700*c3b6f8f2SDavid van Moolenbroek 	sep->se_user = newstr(sskip(&cp));
1701*c3b6f8f2SDavid van Moolenbroek 	if ((sep->se_group = strchr(sep->se_user, ':')) != NULL)
1702*c3b6f8f2SDavid van Moolenbroek 		*sep->se_group++ = '\0';
1703*c3b6f8f2SDavid van Moolenbroek 	else if ((sep->se_group = strchr(sep->se_user, '.')) != NULL)
1704*c3b6f8f2SDavid van Moolenbroek 		*sep->se_group++ = '\0';
1705*c3b6f8f2SDavid van Moolenbroek 
1706*c3b6f8f2SDavid van Moolenbroek 	sep->se_server = newstr(sskip(&cp));
1707*c3b6f8f2SDavid van Moolenbroek 	if (strcmp(sep->se_server, "internal") == 0) {
1708*c3b6f8f2SDavid van Moolenbroek 		struct biltin *bi;
1709*c3b6f8f2SDavid van Moolenbroek 
1710*c3b6f8f2SDavid van Moolenbroek 		for (bi = biltins; bi->bi_service; bi++)
1711*c3b6f8f2SDavid van Moolenbroek 			if (bi->bi_socktype == sep->se_socktype &&
1712*c3b6f8f2SDavid van Moolenbroek 			    strcmp(bi->bi_service, sep->se_service) == 0)
1713*c3b6f8f2SDavid van Moolenbroek 				break;
1714*c3b6f8f2SDavid van Moolenbroek 		if (bi->bi_service == 0) {
1715*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "internal service %s unknown",
1716*c3b6f8f2SDavid van Moolenbroek 			    sep->se_service);
1717*c3b6f8f2SDavid van Moolenbroek 			goto more;
1718*c3b6f8f2SDavid van Moolenbroek 		}
1719*c3b6f8f2SDavid van Moolenbroek 		sep->se_bi = bi;
1720*c3b6f8f2SDavid van Moolenbroek 		sep->se_wait = bi->bi_wait;
1721*c3b6f8f2SDavid van Moolenbroek 	} else
1722*c3b6f8f2SDavid van Moolenbroek 		sep->se_bi = NULL;
1723*c3b6f8f2SDavid van Moolenbroek 	argc = 0;
1724*c3b6f8f2SDavid van Moolenbroek 	for (arg = skip(&cp); cp; arg = skip(&cp)) {
1725*c3b6f8f2SDavid van Moolenbroek 		if (argc < MAXARGV)
1726*c3b6f8f2SDavid van Moolenbroek 			sep->se_argv[argc++] = newstr(arg);
1727*c3b6f8f2SDavid van Moolenbroek 	}
1728*c3b6f8f2SDavid van Moolenbroek 	while (argc <= MAXARGV)
1729*c3b6f8f2SDavid van Moolenbroek 		sep->se_argv[argc++] = NULL;
1730*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
1731*c3b6f8f2SDavid van Moolenbroek 	sep->se_policy = policy ? newstr(policy) : NULL;
1732*c3b6f8f2SDavid van Moolenbroek #endif
1733*c3b6f8f2SDavid van Moolenbroek 	return (sep);
1734*c3b6f8f2SDavid van Moolenbroek }
1735*c3b6f8f2SDavid van Moolenbroek 
1736*c3b6f8f2SDavid van Moolenbroek static void
1737*c3b6f8f2SDavid van Moolenbroek freeconfig(struct servtab *cp)
1738*c3b6f8f2SDavid van Moolenbroek {
1739*c3b6f8f2SDavid van Moolenbroek 	int i;
1740*c3b6f8f2SDavid van Moolenbroek 
1741*c3b6f8f2SDavid van Moolenbroek 	if (cp->se_hostaddr)
1742*c3b6f8f2SDavid van Moolenbroek 		free(cp->se_hostaddr);
1743*c3b6f8f2SDavid van Moolenbroek 	if (cp->se_service)
1744*c3b6f8f2SDavid van Moolenbroek 		free(cp->se_service);
1745*c3b6f8f2SDavid van Moolenbroek 	if (cp->se_proto)
1746*c3b6f8f2SDavid van Moolenbroek 		free(cp->se_proto);
1747*c3b6f8f2SDavid van Moolenbroek 	if (cp->se_user)
1748*c3b6f8f2SDavid van Moolenbroek 		free(cp->se_user);
1749*c3b6f8f2SDavid van Moolenbroek 	/* Note: se_group is part of the newstr'ed se_user */
1750*c3b6f8f2SDavid van Moolenbroek 	if (cp->se_server)
1751*c3b6f8f2SDavid van Moolenbroek 		free(cp->se_server);
1752*c3b6f8f2SDavid van Moolenbroek 	for (i = 0; i < MAXARGV; i++)
1753*c3b6f8f2SDavid van Moolenbroek 		if (cp->se_argv[i])
1754*c3b6f8f2SDavid van Moolenbroek 			free(cp->se_argv[i]);
1755*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
1756*c3b6f8f2SDavid van Moolenbroek 	if (cp->se_policy)
1757*c3b6f8f2SDavid van Moolenbroek 		free(cp->se_policy);
1758*c3b6f8f2SDavid van Moolenbroek #endif
1759*c3b6f8f2SDavid van Moolenbroek }
1760*c3b6f8f2SDavid van Moolenbroek 
1761*c3b6f8f2SDavid van Moolenbroek 
1762*c3b6f8f2SDavid van Moolenbroek /*
1763*c3b6f8f2SDavid van Moolenbroek  * Safe skip - if skip returns null, log a syntax error in the
1764*c3b6f8f2SDavid van Moolenbroek  * configuration file and exit.
1765*c3b6f8f2SDavid van Moolenbroek  */
1766*c3b6f8f2SDavid van Moolenbroek static char *
1767*c3b6f8f2SDavid van Moolenbroek sskip(char **cpp)
1768*c3b6f8f2SDavid van Moolenbroek {
1769*c3b6f8f2SDavid van Moolenbroek 	char *cp;
1770*c3b6f8f2SDavid van Moolenbroek 
1771*c3b6f8f2SDavid van Moolenbroek 	cp = skip(cpp);
1772*c3b6f8f2SDavid van Moolenbroek 	if (cp == NULL) {
1773*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "%s: syntax error", CONFIG);
1774*c3b6f8f2SDavid van Moolenbroek 		exit(1);
1775*c3b6f8f2SDavid van Moolenbroek 	}
1776*c3b6f8f2SDavid van Moolenbroek 	return (cp);
1777*c3b6f8f2SDavid van Moolenbroek }
1778*c3b6f8f2SDavid van Moolenbroek 
1779*c3b6f8f2SDavid van Moolenbroek static char *
1780*c3b6f8f2SDavid van Moolenbroek skip(char **cpp)
1781*c3b6f8f2SDavid van Moolenbroek {
1782*c3b6f8f2SDavid van Moolenbroek 	char *cp = *cpp;
1783*c3b6f8f2SDavid van Moolenbroek 	char *start;
1784*c3b6f8f2SDavid van Moolenbroek 	char quote;
1785*c3b6f8f2SDavid van Moolenbroek 
1786*c3b6f8f2SDavid van Moolenbroek 	if (*cpp == NULL)
1787*c3b6f8f2SDavid van Moolenbroek 		return (NULL);
1788*c3b6f8f2SDavid van Moolenbroek 
1789*c3b6f8f2SDavid van Moolenbroek again:
1790*c3b6f8f2SDavid van Moolenbroek 	while (*cp == ' ' || *cp == '\t')
1791*c3b6f8f2SDavid van Moolenbroek 		cp++;
1792*c3b6f8f2SDavid van Moolenbroek 	if (*cp == '\0') {
1793*c3b6f8f2SDavid van Moolenbroek 		int c;
1794*c3b6f8f2SDavid van Moolenbroek 
1795*c3b6f8f2SDavid van Moolenbroek 		c = getc(fconfig);
1796*c3b6f8f2SDavid van Moolenbroek 		(void) ungetc(c, fconfig);
1797*c3b6f8f2SDavid van Moolenbroek 		if (c == ' ' || c == '\t')
1798*c3b6f8f2SDavid van Moolenbroek 			if ((cp = nextline(fconfig)) != NULL)
1799*c3b6f8f2SDavid van Moolenbroek 				goto again;
1800*c3b6f8f2SDavid van Moolenbroek 		*cpp = NULL;
1801*c3b6f8f2SDavid van Moolenbroek 		return (NULL);
1802*c3b6f8f2SDavid van Moolenbroek 	}
1803*c3b6f8f2SDavid van Moolenbroek 	start = cp;
1804*c3b6f8f2SDavid van Moolenbroek 	quote = '\0';
1805*c3b6f8f2SDavid van Moolenbroek 	while (*cp && (quote || (*cp != ' ' && *cp != '\t'))) {
1806*c3b6f8f2SDavid van Moolenbroek 		if (*cp == '\'' || *cp == '"') {
1807*c3b6f8f2SDavid van Moolenbroek 			if (quote && *cp != quote)
1808*c3b6f8f2SDavid van Moolenbroek 				cp++;
1809*c3b6f8f2SDavid van Moolenbroek 			else {
1810*c3b6f8f2SDavid van Moolenbroek 				if (quote)
1811*c3b6f8f2SDavid van Moolenbroek 					quote = '\0';
1812*c3b6f8f2SDavid van Moolenbroek 				else
1813*c3b6f8f2SDavid van Moolenbroek 					quote = *cp;
1814*c3b6f8f2SDavid van Moolenbroek 				memmove(cp, cp+1, strlen(cp));
1815*c3b6f8f2SDavid van Moolenbroek 			}
1816*c3b6f8f2SDavid van Moolenbroek 		} else
1817*c3b6f8f2SDavid van Moolenbroek 			cp++;
1818*c3b6f8f2SDavid van Moolenbroek 	}
1819*c3b6f8f2SDavid van Moolenbroek 	if (*cp != '\0')
1820*c3b6f8f2SDavid van Moolenbroek 		*cp++ = '\0';
1821*c3b6f8f2SDavid van Moolenbroek 	*cpp = cp;
1822*c3b6f8f2SDavid van Moolenbroek 	return (start);
1823*c3b6f8f2SDavid van Moolenbroek }
1824*c3b6f8f2SDavid van Moolenbroek 
1825*c3b6f8f2SDavid van Moolenbroek static char *
1826*c3b6f8f2SDavid van Moolenbroek nextline(FILE *fd)
1827*c3b6f8f2SDavid van Moolenbroek {
1828*c3b6f8f2SDavid van Moolenbroek 	char *cp;
1829*c3b6f8f2SDavid van Moolenbroek 
1830*c3b6f8f2SDavid van Moolenbroek 	if (fgets(line, (int)sizeof(line), fd) == NULL)
1831*c3b6f8f2SDavid van Moolenbroek 		return (NULL);
1832*c3b6f8f2SDavid van Moolenbroek 	cp = strchr(line, '\n');
1833*c3b6f8f2SDavid van Moolenbroek 	if (cp)
1834*c3b6f8f2SDavid van Moolenbroek 		*cp = '\0';
1835*c3b6f8f2SDavid van Moolenbroek 	return (line);
1836*c3b6f8f2SDavid van Moolenbroek }
1837*c3b6f8f2SDavid van Moolenbroek 
1838*c3b6f8f2SDavid van Moolenbroek static char *
1839*c3b6f8f2SDavid van Moolenbroek newstr(const char *cp)
1840*c3b6f8f2SDavid van Moolenbroek {
1841*c3b6f8f2SDavid van Moolenbroek 	char *dp;
1842*c3b6f8f2SDavid van Moolenbroek 	if ((dp = strdup((cp != NULL) ? cp : "")) != NULL)
1843*c3b6f8f2SDavid van Moolenbroek 		return (dp);
1844*c3b6f8f2SDavid van Moolenbroek 	syslog(LOG_ERR, "strdup: %m");
1845*c3b6f8f2SDavid van Moolenbroek 	exit(1);
1846*c3b6f8f2SDavid van Moolenbroek 	/*NOTREACHED*/
1847*c3b6f8f2SDavid van Moolenbroek }
1848*c3b6f8f2SDavid van Moolenbroek 
1849*c3b6f8f2SDavid van Moolenbroek static void
1850*c3b6f8f2SDavid van Moolenbroek inetd_setproctitle(char *a, int s)
1851*c3b6f8f2SDavid van Moolenbroek {
1852*c3b6f8f2SDavid van Moolenbroek 	socklen_t size;
1853*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr_storage ss;
1854*c3b6f8f2SDavid van Moolenbroek 	char hbuf[NI_MAXHOST];
1855*c3b6f8f2SDavid van Moolenbroek 	const char *hp;
1856*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr *sa;
1857*c3b6f8f2SDavid van Moolenbroek 
1858*c3b6f8f2SDavid van Moolenbroek 	size = sizeof(ss);
1859*c3b6f8f2SDavid van Moolenbroek 	sa = (struct sockaddr *)(void *)&ss;
1860*c3b6f8f2SDavid van Moolenbroek 	if (getpeername(s, sa, &size) == 0) {
1861*c3b6f8f2SDavid van Moolenbroek 		if (getnameinfo(sa, size, hbuf, (socklen_t)sizeof(hbuf), NULL,
1862*c3b6f8f2SDavid van Moolenbroek 		    0, niflags) != 0)
1863*c3b6f8f2SDavid van Moolenbroek 			hp = "?";
1864*c3b6f8f2SDavid van Moolenbroek 		else
1865*c3b6f8f2SDavid van Moolenbroek 			hp = hbuf;
1866*c3b6f8f2SDavid van Moolenbroek 		setproctitle("-%s [%s]", a, hp);
1867*c3b6f8f2SDavid van Moolenbroek 	} else
1868*c3b6f8f2SDavid van Moolenbroek 		setproctitle("-%s", a);
1869*c3b6f8f2SDavid van Moolenbroek }
1870*c3b6f8f2SDavid van Moolenbroek 
1871*c3b6f8f2SDavid van Moolenbroek static void
1872*c3b6f8f2SDavid van Moolenbroek bump_nofile(void)
1873*c3b6f8f2SDavid van Moolenbroek {
1874*c3b6f8f2SDavid van Moolenbroek #define FD_CHUNK	32
1875*c3b6f8f2SDavid van Moolenbroek 	struct rlimit rl;
1876*c3b6f8f2SDavid van Moolenbroek 
1877*c3b6f8f2SDavid van Moolenbroek 	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1878*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "getrlimit: %m");
1879*c3b6f8f2SDavid van Moolenbroek 		return;
1880*c3b6f8f2SDavid van Moolenbroek 	}
1881*c3b6f8f2SDavid van Moolenbroek 	rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1882*c3b6f8f2SDavid van Moolenbroek 	if (rl.rlim_cur <= rlim_ofile_cur) {
1883*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR,
1884*c3b6f8f2SDavid van Moolenbroek 		    "bump_nofile: cannot extend file limit, max = %d",
1885*c3b6f8f2SDavid van Moolenbroek 		    (int)rl.rlim_cur);
1886*c3b6f8f2SDavid van Moolenbroek 		return;
1887*c3b6f8f2SDavid van Moolenbroek 	}
1888*c3b6f8f2SDavid van Moolenbroek 
1889*c3b6f8f2SDavid van Moolenbroek 	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1890*c3b6f8f2SDavid van Moolenbroek 		syslog(LOG_ERR, "setrlimit: %m");
1891*c3b6f8f2SDavid van Moolenbroek 		return;
1892*c3b6f8f2SDavid van Moolenbroek 	}
1893*c3b6f8f2SDavid van Moolenbroek 
1894*c3b6f8f2SDavid van Moolenbroek 	rlim_ofile_cur = rl.rlim_cur;
1895*c3b6f8f2SDavid van Moolenbroek 	return;
1896*c3b6f8f2SDavid van Moolenbroek }
1897*c3b6f8f2SDavid van Moolenbroek 
1898*c3b6f8f2SDavid van Moolenbroek /*
1899*c3b6f8f2SDavid van Moolenbroek  * Internet services provided internally by inetd:
1900*c3b6f8f2SDavid van Moolenbroek  */
1901*c3b6f8f2SDavid van Moolenbroek #define	BUFSIZE	4096
1902*c3b6f8f2SDavid van Moolenbroek 
1903*c3b6f8f2SDavid van Moolenbroek /* ARGSUSED */
1904*c3b6f8f2SDavid van Moolenbroek static void
1905*c3b6f8f2SDavid van Moolenbroek echo_stream(int s, struct servtab *sep)	/* Echo service -- echo data back */
1906*c3b6f8f2SDavid van Moolenbroek {
1907*c3b6f8f2SDavid van Moolenbroek 	char buffer[BUFSIZE];
1908*c3b6f8f2SDavid van Moolenbroek 	ssize_t i;
1909*c3b6f8f2SDavid van Moolenbroek 
1910*c3b6f8f2SDavid van Moolenbroek 	inetd_setproctitle(sep->se_service, s);
1911*c3b6f8f2SDavid van Moolenbroek 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1912*c3b6f8f2SDavid van Moolenbroek 	    write(s, buffer, (size_t)i) > 0)
1913*c3b6f8f2SDavid van Moolenbroek 		;
1914*c3b6f8f2SDavid van Moolenbroek }
1915*c3b6f8f2SDavid van Moolenbroek 
1916*c3b6f8f2SDavid van Moolenbroek /* ARGSUSED */
1917*c3b6f8f2SDavid van Moolenbroek static void
1918*c3b6f8f2SDavid van Moolenbroek echo_dg(int s, struct servtab *sep)	/* Echo service -- echo data back */
1919*c3b6f8f2SDavid van Moolenbroek {
1920*c3b6f8f2SDavid van Moolenbroek 	char buffer[BUFSIZE];
1921*c3b6f8f2SDavid van Moolenbroek 	ssize_t i;
1922*c3b6f8f2SDavid van Moolenbroek 	socklen_t size;
1923*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr_storage ss;
1924*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr *sa;
1925*c3b6f8f2SDavid van Moolenbroek 
1926*c3b6f8f2SDavid van Moolenbroek 	sa = (struct sockaddr *)(void *)&ss;
1927*c3b6f8f2SDavid van Moolenbroek 	size = sizeof(ss);
1928*c3b6f8f2SDavid van Moolenbroek 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, sa, &size)) < 0)
1929*c3b6f8f2SDavid van Moolenbroek 		return;
1930*c3b6f8f2SDavid van Moolenbroek 	if (port_good_dg(sa))
1931*c3b6f8f2SDavid van Moolenbroek 		(void) sendto(s, buffer, (size_t)i, 0, sa, size);
1932*c3b6f8f2SDavid van Moolenbroek }
1933*c3b6f8f2SDavid van Moolenbroek 
1934*c3b6f8f2SDavid van Moolenbroek /* ARGSUSED */
1935*c3b6f8f2SDavid van Moolenbroek static void
1936*c3b6f8f2SDavid van Moolenbroek discard_stream(int s, struct servtab *sep) /* Discard service -- ignore data */
1937*c3b6f8f2SDavid van Moolenbroek {
1938*c3b6f8f2SDavid van Moolenbroek 	char buffer[BUFSIZE];
1939*c3b6f8f2SDavid van Moolenbroek 
1940*c3b6f8f2SDavid van Moolenbroek 	inetd_setproctitle(sep->se_service, s);
1941*c3b6f8f2SDavid van Moolenbroek 	while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1942*c3b6f8f2SDavid van Moolenbroek 			errno == EINTR)
1943*c3b6f8f2SDavid van Moolenbroek 		;
1944*c3b6f8f2SDavid van Moolenbroek }
1945*c3b6f8f2SDavid van Moolenbroek 
1946*c3b6f8f2SDavid van Moolenbroek /* ARGSUSED */
1947*c3b6f8f2SDavid van Moolenbroek static void
1948*c3b6f8f2SDavid van Moolenbroek discard_dg(int s, struct servtab *sep)	/* Discard service -- ignore data */
1949*c3b6f8f2SDavid van Moolenbroek 
1950*c3b6f8f2SDavid van Moolenbroek {
1951*c3b6f8f2SDavid van Moolenbroek 	char buffer[BUFSIZE];
1952*c3b6f8f2SDavid van Moolenbroek 
1953*c3b6f8f2SDavid van Moolenbroek 	(void) read(s, buffer, sizeof(buffer));
1954*c3b6f8f2SDavid van Moolenbroek }
1955*c3b6f8f2SDavid van Moolenbroek 
1956*c3b6f8f2SDavid van Moolenbroek #define LINESIZ 72
1957*c3b6f8f2SDavid van Moolenbroek char ring[128];
1958*c3b6f8f2SDavid van Moolenbroek char *endring;
1959*c3b6f8f2SDavid van Moolenbroek 
1960*c3b6f8f2SDavid van Moolenbroek static void
1961*c3b6f8f2SDavid van Moolenbroek initring(void)
1962*c3b6f8f2SDavid van Moolenbroek {
1963*c3b6f8f2SDavid van Moolenbroek 	int i;
1964*c3b6f8f2SDavid van Moolenbroek 
1965*c3b6f8f2SDavid van Moolenbroek 	endring = ring;
1966*c3b6f8f2SDavid van Moolenbroek 
1967*c3b6f8f2SDavid van Moolenbroek 	for (i = 0; i <= 128; ++i)
1968*c3b6f8f2SDavid van Moolenbroek 		if (isprint(i))
1969*c3b6f8f2SDavid van Moolenbroek 			*endring++ = i;
1970*c3b6f8f2SDavid van Moolenbroek }
1971*c3b6f8f2SDavid van Moolenbroek 
1972*c3b6f8f2SDavid van Moolenbroek /* ARGSUSED */
1973*c3b6f8f2SDavid van Moolenbroek static void
1974*c3b6f8f2SDavid van Moolenbroek chargen_stream(int s,struct servtab *sep)	/* Character generator */
1975*c3b6f8f2SDavid van Moolenbroek {
1976*c3b6f8f2SDavid van Moolenbroek 	size_t len;
1977*c3b6f8f2SDavid van Moolenbroek 	char *rs, text[LINESIZ+2];
1978*c3b6f8f2SDavid van Moolenbroek 
1979*c3b6f8f2SDavid van Moolenbroek 	inetd_setproctitle(sep->se_service, s);
1980*c3b6f8f2SDavid van Moolenbroek 
1981*c3b6f8f2SDavid van Moolenbroek 	if (!endring) {
1982*c3b6f8f2SDavid van Moolenbroek 		initring();
1983*c3b6f8f2SDavid van Moolenbroek 		rs = ring;
1984*c3b6f8f2SDavid van Moolenbroek 	}
1985*c3b6f8f2SDavid van Moolenbroek 
1986*c3b6f8f2SDavid van Moolenbroek 	text[LINESIZ] = '\r';
1987*c3b6f8f2SDavid van Moolenbroek 	text[LINESIZ + 1] = '\n';
1988*c3b6f8f2SDavid van Moolenbroek 	for (rs = ring;;) {
1989*c3b6f8f2SDavid van Moolenbroek 		if ((len = endring - rs) >= LINESIZ)
1990*c3b6f8f2SDavid van Moolenbroek 			memmove(text, rs, LINESIZ);
1991*c3b6f8f2SDavid van Moolenbroek 		else {
1992*c3b6f8f2SDavid van Moolenbroek 			memmove(text, rs, len);
1993*c3b6f8f2SDavid van Moolenbroek 			memmove(text + len, ring, LINESIZ - len);
1994*c3b6f8f2SDavid van Moolenbroek 		}
1995*c3b6f8f2SDavid van Moolenbroek 		if (++rs == endring)
1996*c3b6f8f2SDavid van Moolenbroek 			rs = ring;
1997*c3b6f8f2SDavid van Moolenbroek 		if (write(s, text, sizeof(text)) != sizeof(text))
1998*c3b6f8f2SDavid van Moolenbroek 			break;
1999*c3b6f8f2SDavid van Moolenbroek 	}
2000*c3b6f8f2SDavid van Moolenbroek }
2001*c3b6f8f2SDavid van Moolenbroek 
2002*c3b6f8f2SDavid van Moolenbroek /* ARGSUSED */
2003*c3b6f8f2SDavid van Moolenbroek static void
2004*c3b6f8f2SDavid van Moolenbroek chargen_dg(int s, struct servtab *sep)		/* Character generator */
2005*c3b6f8f2SDavid van Moolenbroek {
2006*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr_storage ss;
2007*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr *sa;
2008*c3b6f8f2SDavid van Moolenbroek 	static char *rs;
2009*c3b6f8f2SDavid van Moolenbroek 	size_t len;
2010*c3b6f8f2SDavid van Moolenbroek 	socklen_t size;
2011*c3b6f8f2SDavid van Moolenbroek 	char text[LINESIZ+2];
2012*c3b6f8f2SDavid van Moolenbroek 
2013*c3b6f8f2SDavid van Moolenbroek 	if (endring == 0) {
2014*c3b6f8f2SDavid van Moolenbroek 		initring();
2015*c3b6f8f2SDavid van Moolenbroek 		rs = ring;
2016*c3b6f8f2SDavid van Moolenbroek 	}
2017*c3b6f8f2SDavid van Moolenbroek 
2018*c3b6f8f2SDavid van Moolenbroek 	sa = (struct sockaddr *)(void *)&ss;
2019*c3b6f8f2SDavid van Moolenbroek 	size = sizeof(ss);
2020*c3b6f8f2SDavid van Moolenbroek 	if (recvfrom(s, text, sizeof(text), 0, sa, &size) < 0)
2021*c3b6f8f2SDavid van Moolenbroek 		return;
2022*c3b6f8f2SDavid van Moolenbroek 
2023*c3b6f8f2SDavid van Moolenbroek 	if (!port_good_dg(sa))
2024*c3b6f8f2SDavid van Moolenbroek 		return;
2025*c3b6f8f2SDavid van Moolenbroek 
2026*c3b6f8f2SDavid van Moolenbroek 	if ((len = endring - rs) >= LINESIZ)
2027*c3b6f8f2SDavid van Moolenbroek 		memmove(text, rs, LINESIZ);
2028*c3b6f8f2SDavid van Moolenbroek 	else {
2029*c3b6f8f2SDavid van Moolenbroek 		memmove(text, rs, len);
2030*c3b6f8f2SDavid van Moolenbroek 		memmove(text + len, ring, LINESIZ - len);
2031*c3b6f8f2SDavid van Moolenbroek 	}
2032*c3b6f8f2SDavid van Moolenbroek 	if (++rs == endring)
2033*c3b6f8f2SDavid van Moolenbroek 		rs = ring;
2034*c3b6f8f2SDavid van Moolenbroek 	text[LINESIZ] = '\r';
2035*c3b6f8f2SDavid van Moolenbroek 	text[LINESIZ + 1] = '\n';
2036*c3b6f8f2SDavid van Moolenbroek 	(void) sendto(s, text, sizeof(text), 0, sa, size);
2037*c3b6f8f2SDavid van Moolenbroek }
2038*c3b6f8f2SDavid van Moolenbroek 
2039*c3b6f8f2SDavid van Moolenbroek /*
2040*c3b6f8f2SDavid van Moolenbroek  * Return a machine readable date and time, in the form of the
2041*c3b6f8f2SDavid van Moolenbroek  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
2042*c3b6f8f2SDavid van Moolenbroek  * returns the number of seconds since midnight, Jan 1, 1970,
2043*c3b6f8f2SDavid van Moolenbroek  * we must add 2208988800 seconds to this figure to make up for
2044*c3b6f8f2SDavid van Moolenbroek  * some seventy years Bell Labs was asleep.
2045*c3b6f8f2SDavid van Moolenbroek  */
2046*c3b6f8f2SDavid van Moolenbroek 
2047*c3b6f8f2SDavid van Moolenbroek static uint32_t
2048*c3b6f8f2SDavid van Moolenbroek machtime(void)
2049*c3b6f8f2SDavid van Moolenbroek {
2050*c3b6f8f2SDavid van Moolenbroek 	struct timeval tv;
2051*c3b6f8f2SDavid van Moolenbroek 
2052*c3b6f8f2SDavid van Moolenbroek 	if (gettimeofday(&tv, NULL) < 0) {
2053*c3b6f8f2SDavid van Moolenbroek 		if (debug)
2054*c3b6f8f2SDavid van Moolenbroek 			fprintf(stderr, "Unable to get time of day\n");
2055*c3b6f8f2SDavid van Moolenbroek 		return (0);
2056*c3b6f8f2SDavid van Moolenbroek 	}
2057*c3b6f8f2SDavid van Moolenbroek #define	OFFSET ((uint32_t)25567 * 24*60*60)
2058*c3b6f8f2SDavid van Moolenbroek 	return (htonl((uint32_t)(tv.tv_sec + OFFSET)));
2059*c3b6f8f2SDavid van Moolenbroek #undef OFFSET
2060*c3b6f8f2SDavid van Moolenbroek }
2061*c3b6f8f2SDavid van Moolenbroek 
2062*c3b6f8f2SDavid van Moolenbroek /* ARGSUSED */
2063*c3b6f8f2SDavid van Moolenbroek static void
2064*c3b6f8f2SDavid van Moolenbroek machtime_stream(int s, struct servtab *sep)
2065*c3b6f8f2SDavid van Moolenbroek {
2066*c3b6f8f2SDavid van Moolenbroek 	uint32_t result;
2067*c3b6f8f2SDavid van Moolenbroek 
2068*c3b6f8f2SDavid van Moolenbroek 	result = machtime();
2069*c3b6f8f2SDavid van Moolenbroek 	(void) write(s, &result, sizeof(result));
2070*c3b6f8f2SDavid van Moolenbroek }
2071*c3b6f8f2SDavid van Moolenbroek 
2072*c3b6f8f2SDavid van Moolenbroek /* ARGSUSED */
2073*c3b6f8f2SDavid van Moolenbroek void
2074*c3b6f8f2SDavid van Moolenbroek machtime_dg(int s, struct servtab *sep)
2075*c3b6f8f2SDavid van Moolenbroek {
2076*c3b6f8f2SDavid van Moolenbroek 	uint32_t result;
2077*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr_storage ss;
2078*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr *sa;
2079*c3b6f8f2SDavid van Moolenbroek 	socklen_t size;
2080*c3b6f8f2SDavid van Moolenbroek 
2081*c3b6f8f2SDavid van Moolenbroek 	sa = (struct sockaddr *)(void *)&ss;
2082*c3b6f8f2SDavid van Moolenbroek 	size = sizeof(ss);
2083*c3b6f8f2SDavid van Moolenbroek 	if (recvfrom(s, &result, sizeof(result), 0, sa, &size) < 0)
2084*c3b6f8f2SDavid van Moolenbroek 		return;
2085*c3b6f8f2SDavid van Moolenbroek 	if (!port_good_dg(sa))
2086*c3b6f8f2SDavid van Moolenbroek 		return;
2087*c3b6f8f2SDavid van Moolenbroek 	result = machtime();
2088*c3b6f8f2SDavid van Moolenbroek 	(void)sendto(s, &result, sizeof(result), 0, sa, size);
2089*c3b6f8f2SDavid van Moolenbroek }
2090*c3b6f8f2SDavid van Moolenbroek 
2091*c3b6f8f2SDavid van Moolenbroek /* ARGSUSED */
2092*c3b6f8f2SDavid van Moolenbroek static void
2093*c3b6f8f2SDavid van Moolenbroek daytime_stream(int s,struct servtab *sep)
2094*c3b6f8f2SDavid van Moolenbroek /* Return human-readable time of day */
2095*c3b6f8f2SDavid van Moolenbroek {
2096*c3b6f8f2SDavid van Moolenbroek 	char buffer[256];
2097*c3b6f8f2SDavid van Moolenbroek 	time_t clk;
2098*c3b6f8f2SDavid van Moolenbroek 	int len;
2099*c3b6f8f2SDavid van Moolenbroek 
2100*c3b6f8f2SDavid van Moolenbroek 	clk = time((time_t *) 0);
2101*c3b6f8f2SDavid van Moolenbroek 
2102*c3b6f8f2SDavid van Moolenbroek 	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clk));
2103*c3b6f8f2SDavid van Moolenbroek 	(void) write(s, buffer, len);
2104*c3b6f8f2SDavid van Moolenbroek }
2105*c3b6f8f2SDavid van Moolenbroek 
2106*c3b6f8f2SDavid van Moolenbroek /* ARGSUSED */
2107*c3b6f8f2SDavid van Moolenbroek void
2108*c3b6f8f2SDavid van Moolenbroek daytime_dg(int s, struct servtab *sep)
2109*c3b6f8f2SDavid van Moolenbroek /* Return human-readable time of day */
2110*c3b6f8f2SDavid van Moolenbroek {
2111*c3b6f8f2SDavid van Moolenbroek 	char buffer[256];
2112*c3b6f8f2SDavid van Moolenbroek 	time_t clk;
2113*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr_storage ss;
2114*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr *sa;
2115*c3b6f8f2SDavid van Moolenbroek 	socklen_t size;
2116*c3b6f8f2SDavid van Moolenbroek 	int len;
2117*c3b6f8f2SDavid van Moolenbroek 
2118*c3b6f8f2SDavid van Moolenbroek 	clk = time((time_t *) 0);
2119*c3b6f8f2SDavid van Moolenbroek 
2120*c3b6f8f2SDavid van Moolenbroek 	sa = (struct sockaddr *)(void *)&ss;
2121*c3b6f8f2SDavid van Moolenbroek 	size = sizeof(ss);
2122*c3b6f8f2SDavid van Moolenbroek 	if (recvfrom(s, buffer, sizeof(buffer), 0, sa, &size) < 0)
2123*c3b6f8f2SDavid van Moolenbroek 		return;
2124*c3b6f8f2SDavid van Moolenbroek 	if (!port_good_dg(sa))
2125*c3b6f8f2SDavid van Moolenbroek 		return;
2126*c3b6f8f2SDavid van Moolenbroek 	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clk));
2127*c3b6f8f2SDavid van Moolenbroek 	(void) sendto(s, buffer, len, 0, sa, size);
2128*c3b6f8f2SDavid van Moolenbroek }
2129*c3b6f8f2SDavid van Moolenbroek 
2130*c3b6f8f2SDavid van Moolenbroek /*
2131*c3b6f8f2SDavid van Moolenbroek  * print_service:
2132*c3b6f8f2SDavid van Moolenbroek  *	Dump relevant information to stderr
2133*c3b6f8f2SDavid van Moolenbroek  */
2134*c3b6f8f2SDavid van Moolenbroek static void
2135*c3b6f8f2SDavid van Moolenbroek print_service(const char *action, struct servtab *sep)
2136*c3b6f8f2SDavid van Moolenbroek {
2137*c3b6f8f2SDavid van Moolenbroek 
2138*c3b6f8f2SDavid van Moolenbroek 	if (isrpcservice(sep))
2139*c3b6f8f2SDavid van Moolenbroek 		fprintf(stderr,
2140*c3b6f8f2SDavid van Moolenbroek 		    "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, user:group=%s:%s builtin=%lx server=%s"
2141*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
2142*c3b6f8f2SDavid van Moolenbroek 		    " policy=\"%s\""
2143*c3b6f8f2SDavid van Moolenbroek #endif
2144*c3b6f8f2SDavid van Moolenbroek 		    "\n",
2145*c3b6f8f2SDavid van Moolenbroek 		    action, sep->se_service,
2146*c3b6f8f2SDavid van Moolenbroek 		    sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
2147*c3b6f8f2SDavid van Moolenbroek 		    sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
2148*c3b6f8f2SDavid van Moolenbroek 		    (long)sep->se_bi, sep->se_server
2149*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
2150*c3b6f8f2SDavid van Moolenbroek 		    , (sep->se_policy ? sep->se_policy : "")
2151*c3b6f8f2SDavid van Moolenbroek #endif
2152*c3b6f8f2SDavid van Moolenbroek 		    );
2153*c3b6f8f2SDavid van Moolenbroek 	else
2154*c3b6f8f2SDavid van Moolenbroek 		fprintf(stderr,
2155*c3b6f8f2SDavid van Moolenbroek 		    "%s: %s proto=%s%s, wait.max=%d.%d, user:group=%s:%s builtin=%lx server=%s"
2156*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
2157*c3b6f8f2SDavid van Moolenbroek 		    " policy=%s"
2158*c3b6f8f2SDavid van Moolenbroek #endif
2159*c3b6f8f2SDavid van Moolenbroek 		    "\n",
2160*c3b6f8f2SDavid van Moolenbroek 		    action, sep->se_service,
2161*c3b6f8f2SDavid van Moolenbroek 		    sep->se_type == FAITH_TYPE ? "faith/" : "",
2162*c3b6f8f2SDavid van Moolenbroek 		    sep->se_proto,
2163*c3b6f8f2SDavid van Moolenbroek 		    sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
2164*c3b6f8f2SDavid van Moolenbroek 		    (long)sep->se_bi, sep->se_server
2165*c3b6f8f2SDavid van Moolenbroek #ifdef IPSEC
2166*c3b6f8f2SDavid van Moolenbroek 		    , (sep->se_policy ? sep->se_policy : "")
2167*c3b6f8f2SDavid van Moolenbroek #endif
2168*c3b6f8f2SDavid van Moolenbroek 		    );
2169*c3b6f8f2SDavid van Moolenbroek }
2170*c3b6f8f2SDavid van Moolenbroek 
2171*c3b6f8f2SDavid van Moolenbroek static void
2172*c3b6f8f2SDavid van Moolenbroek usage(void)
2173*c3b6f8f2SDavid van Moolenbroek {
2174*c3b6f8f2SDavid van Moolenbroek #ifdef LIBWRAP
2175*c3b6f8f2SDavid van Moolenbroek 	(void)fprintf(stderr, "usage: %s [-dl] [conf]\n", getprogname());
2176*c3b6f8f2SDavid van Moolenbroek #else
2177*c3b6f8f2SDavid van Moolenbroek 	(void)fprintf(stderr, "usage: %s [-d] [conf]\n", getprogname());
2178*c3b6f8f2SDavid van Moolenbroek #endif
2179*c3b6f8f2SDavid van Moolenbroek 	exit(1);
2180*c3b6f8f2SDavid van Moolenbroek }
2181*c3b6f8f2SDavid van Moolenbroek 
2182*c3b6f8f2SDavid van Moolenbroek 
2183*c3b6f8f2SDavid van Moolenbroek /*
2184*c3b6f8f2SDavid van Moolenbroek  *  Based on TCPMUX.C by Mark K. Lottor November 1988
2185*c3b6f8f2SDavid van Moolenbroek  *  sri-nic::ps:<mkl>tcpmux.c
2186*c3b6f8f2SDavid van Moolenbroek  */
2187*c3b6f8f2SDavid van Moolenbroek 
2188*c3b6f8f2SDavid van Moolenbroek static int		/* # of characters upto \r,\n or \0 */
2189*c3b6f8f2SDavid van Moolenbroek get_line(int fd,	char *buf, int len)
2190*c3b6f8f2SDavid van Moolenbroek {
2191*c3b6f8f2SDavid van Moolenbroek 	int count = 0;
2192*c3b6f8f2SDavid van Moolenbroek 	ssize_t n;
2193*c3b6f8f2SDavid van Moolenbroek 
2194*c3b6f8f2SDavid van Moolenbroek 	do {
2195*c3b6f8f2SDavid van Moolenbroek 		n = read(fd, buf, len-count);
2196*c3b6f8f2SDavid van Moolenbroek 		if (n == 0)
2197*c3b6f8f2SDavid van Moolenbroek 			return (count);
2198*c3b6f8f2SDavid van Moolenbroek 		if (n < 0)
2199*c3b6f8f2SDavid van Moolenbroek 			return (-1);
2200*c3b6f8f2SDavid van Moolenbroek 		while (--n >= 0) {
2201*c3b6f8f2SDavid van Moolenbroek 			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
2202*c3b6f8f2SDavid van Moolenbroek 				return (count);
2203*c3b6f8f2SDavid van Moolenbroek 			count++;
2204*c3b6f8f2SDavid van Moolenbroek 			buf++;
2205*c3b6f8f2SDavid van Moolenbroek 		}
2206*c3b6f8f2SDavid van Moolenbroek 	} while (count < len);
2207*c3b6f8f2SDavid van Moolenbroek 	return (count);
2208*c3b6f8f2SDavid van Moolenbroek }
2209*c3b6f8f2SDavid van Moolenbroek 
2210*c3b6f8f2SDavid van Moolenbroek #define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
2211*c3b6f8f2SDavid van Moolenbroek 
2212*c3b6f8f2SDavid van Moolenbroek #define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
2213*c3b6f8f2SDavid van Moolenbroek 
2214*c3b6f8f2SDavid van Moolenbroek static void
2215*c3b6f8f2SDavid van Moolenbroek tcpmux(int ctrl, struct servtab *sep)
2216*c3b6f8f2SDavid van Moolenbroek {
2217*c3b6f8f2SDavid van Moolenbroek 	char service[MAX_SERV_LEN+1];
2218*c3b6f8f2SDavid van Moolenbroek 	int len;
2219*c3b6f8f2SDavid van Moolenbroek 
2220*c3b6f8f2SDavid van Moolenbroek 	/* Get requested service name */
2221*c3b6f8f2SDavid van Moolenbroek 	if ((len = get_line(ctrl, service, MAX_SERV_LEN)) < 0) {
2222*c3b6f8f2SDavid van Moolenbroek 		strwrite(ctrl, "-Error reading service name\r\n");
2223*c3b6f8f2SDavid van Moolenbroek 		goto reject;
2224*c3b6f8f2SDavid van Moolenbroek 	}
2225*c3b6f8f2SDavid van Moolenbroek 	service[len] = '\0';
2226*c3b6f8f2SDavid van Moolenbroek 
2227*c3b6f8f2SDavid van Moolenbroek 	if (debug)
2228*c3b6f8f2SDavid van Moolenbroek 		fprintf(stderr, "tcpmux: someone wants %s\n", service);
2229*c3b6f8f2SDavid van Moolenbroek 
2230*c3b6f8f2SDavid van Moolenbroek 	/*
2231*c3b6f8f2SDavid van Moolenbroek 	 * Help is a required command, and lists available services,
2232*c3b6f8f2SDavid van Moolenbroek 	 * one per line.
2233*c3b6f8f2SDavid van Moolenbroek 	 */
2234*c3b6f8f2SDavid van Moolenbroek 	if (!strcasecmp(service, "help")) {
2235*c3b6f8f2SDavid van Moolenbroek 		strwrite(ctrl, "+Available services:\r\n");
2236*c3b6f8f2SDavid van Moolenbroek 		strwrite(ctrl, "help\r\n");
2237*c3b6f8f2SDavid van Moolenbroek 		for (sep = servtab; sep != NULL; sep = sep->se_next) {
2238*c3b6f8f2SDavid van Moolenbroek 			if (!ISMUX(sep))
2239*c3b6f8f2SDavid van Moolenbroek 				continue;
2240*c3b6f8f2SDavid van Moolenbroek 			(void)write(ctrl, sep->se_service,
2241*c3b6f8f2SDavid van Moolenbroek 			    strlen(sep->se_service));
2242*c3b6f8f2SDavid van Moolenbroek 			strwrite(ctrl, "\r\n");
2243*c3b6f8f2SDavid van Moolenbroek 		}
2244*c3b6f8f2SDavid van Moolenbroek 		goto reject;
2245*c3b6f8f2SDavid van Moolenbroek 	}
2246*c3b6f8f2SDavid van Moolenbroek 
2247*c3b6f8f2SDavid van Moolenbroek 	/* Try matching a service in inetd.conf with the request */
2248*c3b6f8f2SDavid van Moolenbroek 	for (sep = servtab; sep != NULL; sep = sep->se_next) {
2249*c3b6f8f2SDavid van Moolenbroek 		if (!ISMUX(sep))
2250*c3b6f8f2SDavid van Moolenbroek 			continue;
2251*c3b6f8f2SDavid van Moolenbroek 		if (!strcasecmp(service, sep->se_service)) {
2252*c3b6f8f2SDavid van Moolenbroek 			if (ISMUXPLUS(sep))
2253*c3b6f8f2SDavid van Moolenbroek 				strwrite(ctrl, "+Go\r\n");
2254*c3b6f8f2SDavid van Moolenbroek 			run_service(ctrl, sep, 1 /* forked */);
2255*c3b6f8f2SDavid van Moolenbroek 			return;
2256*c3b6f8f2SDavid van Moolenbroek 		}
2257*c3b6f8f2SDavid van Moolenbroek 	}
2258*c3b6f8f2SDavid van Moolenbroek 	strwrite(ctrl, "-Service not available\r\n");
2259*c3b6f8f2SDavid van Moolenbroek reject:
2260*c3b6f8f2SDavid van Moolenbroek 	_exit(1);
2261*c3b6f8f2SDavid van Moolenbroek }
2262*c3b6f8f2SDavid van Moolenbroek 
2263*c3b6f8f2SDavid van Moolenbroek /*
2264*c3b6f8f2SDavid van Moolenbroek  * check if the address/port where send data to is one of the obvious ports
2265*c3b6f8f2SDavid van Moolenbroek  * that are used for denial of service attacks like two echo ports
2266*c3b6f8f2SDavid van Moolenbroek  * just echoing data between them
2267*c3b6f8f2SDavid van Moolenbroek  */
2268*c3b6f8f2SDavid van Moolenbroek static int
2269*c3b6f8f2SDavid van Moolenbroek port_good_dg(struct sockaddr *sa)
2270*c3b6f8f2SDavid van Moolenbroek {
2271*c3b6f8f2SDavid van Moolenbroek 	struct in_addr in;
2272*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr_in *sin;
2273*c3b6f8f2SDavid van Moolenbroek #ifdef INET6
2274*c3b6f8f2SDavid van Moolenbroek 	struct in6_addr *in6;
2275*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr_in6 *sin6;
2276*c3b6f8f2SDavid van Moolenbroek #endif
2277*c3b6f8f2SDavid van Moolenbroek 	u_int16_t port;
2278*c3b6f8f2SDavid van Moolenbroek 	int i;
2279*c3b6f8f2SDavid van Moolenbroek 	char hbuf[NI_MAXHOST];
2280*c3b6f8f2SDavid van Moolenbroek 
2281*c3b6f8f2SDavid van Moolenbroek 	switch (sa->sa_family) {
2282*c3b6f8f2SDavid van Moolenbroek 	case AF_INET:
2283*c3b6f8f2SDavid van Moolenbroek 		sin = (struct sockaddr_in *)(void *)sa;
2284*c3b6f8f2SDavid van Moolenbroek 		in.s_addr = ntohl(sin->sin_addr.s_addr);
2285*c3b6f8f2SDavid van Moolenbroek 		port = ntohs(sin->sin_port);
2286*c3b6f8f2SDavid van Moolenbroek #ifdef INET6
2287*c3b6f8f2SDavid van Moolenbroek 	v4chk:
2288*c3b6f8f2SDavid van Moolenbroek #endif
2289*c3b6f8f2SDavid van Moolenbroek 		if (IN_MULTICAST(in.s_addr))
2290*c3b6f8f2SDavid van Moolenbroek 			goto bad;
2291*c3b6f8f2SDavid van Moolenbroek 		switch ((in.s_addr & 0xff000000) >> 24) {
2292*c3b6f8f2SDavid van Moolenbroek 		case 0: case 127: case 255:
2293*c3b6f8f2SDavid van Moolenbroek 			goto bad;
2294*c3b6f8f2SDavid van Moolenbroek 		}
2295*c3b6f8f2SDavid van Moolenbroek 		if (dg_broadcast(&in))
2296*c3b6f8f2SDavid van Moolenbroek 			goto bad;
2297*c3b6f8f2SDavid van Moolenbroek 		break;
2298*c3b6f8f2SDavid van Moolenbroek #ifdef INET6
2299*c3b6f8f2SDavid van Moolenbroek 	case AF_INET6:
2300*c3b6f8f2SDavid van Moolenbroek 		sin6 = (struct sockaddr_in6 *)(void *)sa;
2301*c3b6f8f2SDavid van Moolenbroek 		in6 = &sin6->sin6_addr;
2302*c3b6f8f2SDavid van Moolenbroek 		port = ntohs(sin6->sin6_port);
2303*c3b6f8f2SDavid van Moolenbroek 		if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
2304*c3b6f8f2SDavid van Moolenbroek 			goto bad;
2305*c3b6f8f2SDavid van Moolenbroek 		if (IN6_IS_ADDR_V4MAPPED(in6) || IN6_IS_ADDR_V4COMPAT(in6)) {
2306*c3b6f8f2SDavid van Moolenbroek 			memcpy(&in, &in6->s6_addr[12], sizeof(in));
2307*c3b6f8f2SDavid van Moolenbroek 			in.s_addr = ntohl(in.s_addr);
2308*c3b6f8f2SDavid van Moolenbroek 			goto v4chk;
2309*c3b6f8f2SDavid van Moolenbroek 		}
2310*c3b6f8f2SDavid van Moolenbroek 		break;
2311*c3b6f8f2SDavid van Moolenbroek #endif
2312*c3b6f8f2SDavid van Moolenbroek 	default:
2313*c3b6f8f2SDavid van Moolenbroek 		/* XXX unsupported af, is it safe to assume it to be safe? */
2314*c3b6f8f2SDavid van Moolenbroek 		return (1);
2315*c3b6f8f2SDavid van Moolenbroek 	}
2316*c3b6f8f2SDavid van Moolenbroek 
2317*c3b6f8f2SDavid van Moolenbroek 	for (i = 0; bad_ports[i] != 0; i++) {
2318*c3b6f8f2SDavid van Moolenbroek 		if (port == bad_ports[i])
2319*c3b6f8f2SDavid van Moolenbroek 			goto bad;
2320*c3b6f8f2SDavid van Moolenbroek 	}
2321*c3b6f8f2SDavid van Moolenbroek 
2322*c3b6f8f2SDavid van Moolenbroek 	return (1);
2323*c3b6f8f2SDavid van Moolenbroek 
2324*c3b6f8f2SDavid van Moolenbroek bad:
2325*c3b6f8f2SDavid van Moolenbroek 	if (getnameinfo(sa, sa->sa_len, hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
2326*c3b6f8f2SDavid van Moolenbroek 	    niflags) != 0)
2327*c3b6f8f2SDavid van Moolenbroek 		strlcpy(hbuf, "?", sizeof(hbuf));
2328*c3b6f8f2SDavid van Moolenbroek 	syslog(LOG_WARNING,"Possible DoS attack from %s, Port %d",
2329*c3b6f8f2SDavid van Moolenbroek 		hbuf, port);
2330*c3b6f8f2SDavid van Moolenbroek 	return (0);
2331*c3b6f8f2SDavid van Moolenbroek }
2332*c3b6f8f2SDavid van Moolenbroek 
2333*c3b6f8f2SDavid van Moolenbroek /* XXX need optimization */
2334*c3b6f8f2SDavid van Moolenbroek static int
2335*c3b6f8f2SDavid van Moolenbroek dg_broadcast(struct in_addr *in)
2336*c3b6f8f2SDavid van Moolenbroek {
2337*c3b6f8f2SDavid van Moolenbroek 	struct ifaddrs *ifa, *ifap;
2338*c3b6f8f2SDavid van Moolenbroek 	struct sockaddr_in *sin;
2339*c3b6f8f2SDavid van Moolenbroek 
2340*c3b6f8f2SDavid van Moolenbroek 	if (getifaddrs(&ifap) < 0)
2341*c3b6f8f2SDavid van Moolenbroek 		return (0);
2342*c3b6f8f2SDavid van Moolenbroek 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
2343*c3b6f8f2SDavid van Moolenbroek 		if (ifa->ifa_addr->sa_family != AF_INET ||
2344*c3b6f8f2SDavid van Moolenbroek 		    (ifa->ifa_flags & IFF_BROADCAST) == 0)
2345*c3b6f8f2SDavid van Moolenbroek 			continue;
2346*c3b6f8f2SDavid van Moolenbroek 		sin = (struct sockaddr_in *)(void *)ifa->ifa_broadaddr;
2347*c3b6f8f2SDavid van Moolenbroek 		if (sin->sin_addr.s_addr == in->s_addr) {
2348*c3b6f8f2SDavid van Moolenbroek 			freeifaddrs(ifap);
2349*c3b6f8f2SDavid van Moolenbroek 			return (1);
2350*c3b6f8f2SDavid van Moolenbroek 		}
2351*c3b6f8f2SDavid van Moolenbroek 	}
2352*c3b6f8f2SDavid van Moolenbroek 	freeifaddrs(ifap);
2353*c3b6f8f2SDavid van Moolenbroek 	return (0);
2354*c3b6f8f2SDavid van Moolenbroek }
2355*c3b6f8f2SDavid van Moolenbroek 
2356*c3b6f8f2SDavid van Moolenbroek #ifndef __minix
2357*c3b6f8f2SDavid van Moolenbroek static int
2358*c3b6f8f2SDavid van Moolenbroek my_kevent(const struct kevent *changelist, size_t nchanges,
2359*c3b6f8f2SDavid van Moolenbroek     struct kevent *eventlist, size_t nevents)
2360*c3b6f8f2SDavid van Moolenbroek {
2361*c3b6f8f2SDavid van Moolenbroek 	int	result;
2362*c3b6f8f2SDavid van Moolenbroek 
2363*c3b6f8f2SDavid van Moolenbroek 	while ((result = kevent(kq, changelist, nchanges, eventlist, nevents,
2364*c3b6f8f2SDavid van Moolenbroek 	    NULL)) < 0)
2365*c3b6f8f2SDavid van Moolenbroek 		if (errno != EINTR) {
2366*c3b6f8f2SDavid van Moolenbroek 			syslog(LOG_ERR, "kevent: %m");
2367*c3b6f8f2SDavid van Moolenbroek 			exit(EXIT_FAILURE);
2368*c3b6f8f2SDavid van Moolenbroek 		}
2369*c3b6f8f2SDavid van Moolenbroek 
2370*c3b6f8f2SDavid van Moolenbroek 	return (result);
2371*c3b6f8f2SDavid van Moolenbroek }
2372*c3b6f8f2SDavid van Moolenbroek 
2373*c3b6f8f2SDavid van Moolenbroek static struct kevent *
2374*c3b6f8f2SDavid van Moolenbroek allocchange(void)
2375*c3b6f8f2SDavid van Moolenbroek {
2376*c3b6f8f2SDavid van Moolenbroek 	if (changes == A_CNT(changebuf)) {
2377*c3b6f8f2SDavid van Moolenbroek 		(void) my_kevent(changebuf, A_CNT(changebuf), NULL, 0);
2378*c3b6f8f2SDavid van Moolenbroek 		changes = 0;
2379*c3b6f8f2SDavid van Moolenbroek 	}
2380*c3b6f8f2SDavid van Moolenbroek 
2381*c3b6f8f2SDavid van Moolenbroek 	return (&changebuf[changes++]);
2382*c3b6f8f2SDavid van Moolenbroek }
2383*c3b6f8f2SDavid van Moolenbroek #endif /* !__minix */
2384