Home | History | Annotate | Line # | Download | only in inetd
inetd.c revision 1.130
      1  1.130    rillig /*	$NetBSD: inetd.c,v 1.130 2021/08/30 17:32:23 rillig Exp $	*/
      2   1.42   thorpej 
      3   1.42   thorpej /*-
      4   1.87      tron  * Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
      5   1.42   thorpej  * All rights reserved.
      6   1.42   thorpej  *
      7   1.42   thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8   1.42   thorpej  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9   1.87      tron  * NASA Ames Research Center and by Matthias Scheler.
     10   1.42   thorpej  *
     11   1.42   thorpej  * Redistribution and use in source and binary forms, with or without
     12   1.42   thorpej  * modification, are permitted provided that the following conditions
     13   1.42   thorpej  * are met:
     14   1.42   thorpej  * 1. Redistributions of source code must retain the above copyright
     15   1.42   thorpej  *    notice, this list of conditions and the following disclaimer.
     16   1.42   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     17   1.42   thorpej  *    notice, this list of conditions and the following disclaimer in the
     18   1.42   thorpej  *    documentation and/or other materials provided with the distribution.
     19   1.42   thorpej  *
     20   1.42   thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21   1.42   thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22   1.42   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23   1.42   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24   1.42   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25   1.42   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26   1.42   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27   1.42   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28   1.42   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29   1.42   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30   1.42   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     31   1.42   thorpej  */
     32   1.20   mycroft 
     33    1.1       cgd /*
     34   1.23   mycroft  * Copyright (c) 1983, 1991, 1993, 1994
     35   1.23   mycroft  *	The Regents of the University of California.  All rights reserved.
     36    1.1       cgd  *
     37    1.1       cgd  * Redistribution and use in source and binary forms, with or without
     38    1.1       cgd  * modification, are permitted provided that the following conditions
     39    1.1       cgd  * are met:
     40    1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     41    1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     42    1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     43    1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     44    1.1       cgd  *    documentation and/or other materials provided with the distribution.
     45   1.93       agc  * 3. Neither the name of the University nor the names of its contributors
     46    1.1       cgd  *    may be used to endorse or promote products derived from this software
     47    1.1       cgd  *    without specific prior written permission.
     48    1.1       cgd  *
     49    1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     50    1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     51    1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     52    1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     53    1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     54    1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     55    1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     56    1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     57    1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     58    1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     59    1.1       cgd  * SUCH DAMAGE.
     60    1.1       cgd  */
     61    1.1       cgd 
     62   1.36       mrg #include <sys/cdefs.h>
     63    1.1       cgd #ifndef lint
     64  1.106     lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1991, 1993, 1994\
     65  1.106     lukem  The Regents of the University of California.  All rights reserved.");
     66   1.23   mycroft #if 0
     67   1.23   mycroft static char sccsid[] = "@(#)inetd.c	8.4 (Berkeley) 4/13/94";
     68   1.23   mycroft #else
     69  1.130    rillig __RCSID("$NetBSD: inetd.c,v 1.130 2021/08/30 17:32:23 rillig Exp $");
     70   1.23   mycroft #endif
     71    1.1       cgd #endif /* not lint */
     72    1.1       cgd 
     73    1.1       cgd /*
     74    1.1       cgd  * Inetd - Internet super-server
     75    1.1       cgd  *
     76   1.23   mycroft  * This program invokes all internet services as needed.  Connection-oriented
     77   1.23   mycroft  * services are invoked each time a connection is made, by creating a process.
     78   1.23   mycroft  * This process is passed the connection as file descriptor 0 and is expected
     79   1.23   mycroft  * to do a getpeername to find out the source host and port.
     80    1.1       cgd  *
     81    1.1       cgd  * Datagram oriented services are invoked when a datagram
     82    1.1       cgd  * arrives; a process is created and passed a pending message
     83    1.1       cgd  * on file descriptor 0.  Datagram servers may either connect
     84    1.1       cgd  * to their peer, freeing up the original socket for inetd
     85    1.1       cgd  * to receive further messages on, or ``take over the socket'',
     86    1.1       cgd  * processing all arriving datagrams and, eventually, timing
     87    1.1       cgd  * out.	 The first type of server is said to be ``multi-threaded'';
     88   1.16     mouse  * the second type of server ``single-threaded''.
     89    1.1       cgd  *
     90    1.1       cgd  * Inetd uses a configuration file which is read at startup
     91    1.1       cgd  * and, possibly, at some later time in response to a hangup signal.
     92    1.1       cgd  * The configuration file is ``free format'' with fields given in the
     93    1.1       cgd  * order shown below.  Continuation lines for an entry must being with
     94    1.1       cgd  * a space or tab.  All fields must be present in each entry.
     95    1.1       cgd  *
     96   1.23   mycroft  *	service name			must be in /etc/services or must
     97   1.23   mycroft  *					name a tcpmux service
     98  1.107       tls  *	socket type[:accf[,arg]]	stream/dgram/raw/rdm/seqpacket,
     99  1.107       tls 					only stream can name an accept filter
    100    1.1       cgd  *	protocol			must be in /etc/protocols
    101  1.115    tsarna  *	wait/nowait[:max]		single-threaded/multi-threaded, max #
    102   1.55        ad  *	user[:group]			user/group to run daemon as
    103    1.1       cgd  *	server program			full path name
    104  1.125    martin  *	server program arguments	maximum of MAXARGV (64)
    105    1.1       cgd  *
    106    1.2    brezak  * For RPC services
    107    1.2    brezak  *      service name/version            must be in /etc/rpc
    108    1.2    brezak  *	socket type			stream/dgram/raw/rdm/seqpacket
    109    1.2    brezak  *	protocol			must be in /etc/protocols
    110  1.115    tsarna  *	wait/nowait[:max]		single-threaded/multi-threaded
    111   1.55        ad  *	user[:group]			user to run daemon as
    112    1.2    brezak  *	server program			full path name
    113  1.125    martin  *	server program arguments	maximum of MAXARGV (64)
    114    1.5        pk  *
    115   1.16     mouse  * For non-RPC services, the "service name" can be of the form
    116   1.16     mouse  * hostaddress:servicename, in which case the hostaddress is used
    117   1.16     mouse  * as the host portion of the address to listen on.  If hostaddress
    118   1.16     mouse  * consists of a single `*' character, INADDR_ANY is used.
    119   1.16     mouse  *
    120   1.16     mouse  * A line can also consist of just
    121   1.16     mouse  *	hostaddress:
    122   1.16     mouse  * where hostaddress is as in the preceding paragraph.  Such a line must
    123   1.16     mouse  * have no further fields; the specified hostaddress is remembered and
    124   1.16     mouse  * used for all further lines that have no hostaddress specified,
    125   1.16     mouse  * until the next such line (or EOF).  (This is why * is provided to
    126   1.16     mouse  * allow explicit specification of INADDR_ANY.)  A line
    127   1.16     mouse  *	*:
    128   1.16     mouse  * is implicitly in effect at the beginning of the file.
    129   1.16     mouse  *
    130   1.16     mouse  * The hostaddress specifier may (and often will) contain dots;
    131   1.16     mouse  * the service name must not.
    132   1.16     mouse  *
    133   1.16     mouse  * For RPC services, host-address specifiers are accepted and will
    134   1.16     mouse  * work to some extent; however, because of limitations in the
    135   1.16     mouse  * portmapper interface, it will not work to try to give more than
    136   1.16     mouse  * one line for any given RPC service, even if the host-address
    137   1.16     mouse  * specifiers are different.
    138   1.16     mouse  *
    139   1.23   mycroft  * TCP services without official port numbers are handled with the
    140   1.23   mycroft  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
    141   1.23   mycroft  * requests. When a connection is made from a foreign host, the service
    142   1.23   mycroft  * requested is passed to tcpmux, which looks it up in the servtab list
    143   1.23   mycroft  * and returns the proper entry for the service. Tcpmux returns a
    144   1.23   mycroft  * negative reply if the service doesn't exist, otherwise the invoked
    145   1.23   mycroft  * server is expected to return the positive reply if the service type in
    146   1.23   mycroft  * inetd.conf file has the prefix "tcpmux/". If the service type has the
    147   1.23   mycroft  * prefix "tcpmux/+", tcpmux will return the positive reply for the
    148   1.23   mycroft  * process; this is for compatibility with older server code, and also
    149   1.23   mycroft  * allows you to invoke programs that use stdin/stdout without putting any
    150   1.23   mycroft  * special server code in them. Services that use tcpmux are "nowait"
    151   1.23   mycroft  * because they do not have a well-known port and hence cannot listen
    152   1.23   mycroft  * for new requests.
    153   1.23   mycroft  *
    154    1.1       cgd  * Comment lines are indicated by a `#' in column 1.
    155   1.49    itojun  *
    156   1.49    itojun  * #ifdef IPSEC
    157   1.49    itojun  * Comment lines that start with "#@" denote IPsec policy string, as described
    158   1.49    itojun  * in ipsec_set_policy(3).  This will affect all the following items in
    159   1.49    itojun  * inetd.conf(8).  To reset the policy, just use "#@" line.  By default,
    160   1.49    itojun  * there's no IPsec policy.
    161   1.49    itojun  * #endif
    162    1.1       cgd  */
    163    1.5        pk 
    164    1.5        pk /*
    165   1.55        ad  * Here's the scoop concerning the user:group feature:
    166    1.5        pk  *
    167    1.5        pk  * 1) set-group-option off.
    168   1.16     mouse  *
    169    1.5        pk  * 	a) user = root:	NO setuid() or setgid() is done
    170   1.16     mouse  *
    171    1.5        pk  * 	b) other:	setuid()
    172    1.5        pk  * 			setgid(primary group as found in passwd)
    173    1.5        pk  * 			initgroups(name, primary group)
    174   1.16     mouse  *
    175    1.5        pk  * 2) set-group-option on.
    176   1.16     mouse  *
    177    1.5        pk  * 	a) user = root:	NO setuid()
    178    1.5        pk  * 			setgid(specified group)
    179    1.5        pk  * 			NO initgroups()
    180   1.16     mouse  *
    181    1.5        pk  * 	b) other:	setuid()
    182    1.5        pk  * 			setgid(specified group)
    183    1.5        pk  * 			initgroups(name, specified group)
    184   1.16     mouse  *
    185    1.5        pk  */
    186    1.5        pk 
    187    1.5        pk #include <sys/param.h>
    188    1.5        pk #include <sys/stat.h>
    189    1.5        pk #include <sys/ioctl.h>
    190    1.5        pk #include <sys/wait.h>
    191    1.5        pk #include <sys/resource.h>
    192   1.85      tron #include <sys/event.h>
    193  1.127  christos #include <sys/socket.h>
    194  1.127  christos 
    195    1.5        pk 
    196   1.53  sommerfe #ifndef NO_RPC
    197    1.5        pk #define RPC
    198   1.53  sommerfe #endif
    199    1.1       cgd 
    200   1.82    itojun #include <net/if.h>
    201   1.82    itojun 
    202   1.23   mycroft #ifdef RPC
    203   1.23   mycroft #include <rpc/rpc.h>
    204   1.62      fvdl #include <rpc/rpcb_clnt.h>
    205   1.62      fvdl #include <netconfig.h>
    206   1.23   mycroft #endif
    207    1.1       cgd 
    208   1.42   thorpej #include <ctype.h>
    209  1.127  christos #include <err.h>
    210    1.1       cgd #include <errno.h>
    211   1.30   mycroft #include <fcntl.h>
    212  1.127  christos #include <glob.h>
    213   1.23   mycroft #include <grp.h>
    214  1.127  christos #include <libgen.h>
    215    1.1       cgd #include <pwd.h>
    216   1.23   mycroft #include <signal.h>
    217    1.1       cgd #include <stdio.h>
    218    1.9       cgd #include <stdlib.h>
    219    1.1       cgd #include <string.h>
    220   1.23   mycroft #include <syslog.h>
    221   1.23   mycroft #include <unistd.h>
    222   1.48   thorpej #include <util.h>
    223   1.82    itojun #include <ifaddrs.h>
    224   1.23   mycroft 
    225  1.127  christos #include "inetd.h"
    226   1.49    itojun 
    227   1.12       mrg #ifdef LIBWRAP
    228   1.12       mrg # include <tcpd.h>
    229   1.13       mrg #ifndef LIBWRAP_ALLOW_FACILITY
    230   1.17     mouse # define LIBWRAP_ALLOW_FACILITY LOG_AUTH
    231   1.13       mrg #endif
    232   1.13       mrg #ifndef LIBWRAP_ALLOW_SEVERITY
    233   1.13       mrg # define LIBWRAP_ALLOW_SEVERITY LOG_INFO
    234   1.13       mrg #endif
    235   1.13       mrg #ifndef LIBWRAP_DENY_FACILITY
    236   1.17     mouse # define LIBWRAP_DENY_FACILITY LOG_AUTH
    237   1.13       mrg #endif
    238   1.13       mrg #ifndef LIBWRAP_DENY_SEVERITY
    239   1.13       mrg # define LIBWRAP_DENY_SEVERITY LOG_WARNING
    240   1.13       mrg #endif
    241   1.13       mrg int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
    242   1.13       mrg int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
    243   1.12       mrg #endif
    244   1.12       mrg 
    245  1.127  christos #define	CNT_INTVL	((time_t)60)	/* servers in CNT_INTVL sec. */
    246    1.1       cgd #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
    247    1.1       cgd 
    248   1.12       mrg int	debug;
    249   1.12       mrg #ifdef LIBWRAP
    250   1.12       mrg int	lflag;
    251   1.12       mrg #endif
    252   1.88      tron int	maxsock;
    253   1.85      tron int	kq;
    254    1.1       cgd int	options;
    255    1.1       cgd int	timingout;
    256   1.57    itojun const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
    257    1.5        pk 
    258    1.5        pk #ifndef OPEN_MAX
    259    1.5        pk #define OPEN_MAX	64
    260    1.5        pk #endif
    261    1.5        pk 
    262    1.5        pk /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
    263    1.5        pk #define FD_MARGIN	(8)
    264   1.70   mycroft rlim_t		rlim_ofile_cur = OPEN_MAX;
    265    1.5        pk 
    266    1.5        pk struct rlimit	rlim_ofile;
    267    1.1       cgd 
    268   1.87      tron struct kevent	changebuf[64];
    269   1.87      tron size_t		changes;
    270   1.87      tron 
    271  1.127  christos struct servtab *servtab;
    272   1.23   mycroft 
    273   1.87      tron static void	chargen_dg(int, struct servtab *);
    274   1.87      tron static void	chargen_stream(int, struct servtab *);
    275   1.87      tron static void	close_sep(struct servtab *);
    276   1.87      tron static void	config(void);
    277   1.87      tron static void	daytime_dg(int, struct servtab *);
    278   1.87      tron static void	daytime_stream(int, struct servtab *);
    279   1.87      tron static void	discard_dg(int, struct servtab *);
    280   1.87      tron static void	discard_stream(int, struct servtab *);
    281   1.87      tron static void	echo_dg(int, struct servtab *);
    282   1.87      tron static void	echo_stream(int, struct servtab *);
    283   1.87      tron static void	endconfig(void);
    284  1.127  christos static struct servtab	*enter(struct servtab *);
    285  1.127  christos static struct servtab	*getconfigent(char **);
    286  1.119     joerg __dead static void	goaway(void);
    287   1.87      tron static void	machtime_dg(int, struct servtab *);
    288   1.87      tron static void	machtime_stream(int, struct servtab *);
    289  1.127  christos #ifdef DEBUG_ENABLE
    290  1.110  christos static void	print_service(const char *, struct servtab *);
    291  1.127  christos #endif
    292   1.87      tron static void	reapchild(void);
    293   1.87      tron static void	retry(void);
    294  1.105  dholland static void	run_service(int, struct servtab *, int);
    295   1.87      tron static void	setup(struct servtab *);
    296  1.127  christos static char	*skip(char **);
    297   1.87      tron static void	tcpmux(int, struct servtab *);
    298  1.119     joerg __dead static void	usage(void);
    299   1.87      tron static void	register_rpc(struct servtab *);
    300   1.87      tron static void	unregister_rpc(struct servtab *);
    301   1.87      tron static void	bump_nofile(void);
    302   1.87      tron static void	inetd_setproctitle(char *, int);
    303   1.87      tron static void	initring(void);
    304   1.87      tron static uint32_t	machtime(void);
    305   1.87      tron static int	port_good_dg(struct sockaddr *);
    306  1.127  christos static int	dg_broadcast(struct in_addr *);
    307  1.127  christos static int	my_kevent(const struct kevent *, size_t, struct kevent *, size_t);
    308  1.127  christos static struct kevent	*allocchange(void);
    309  1.113       roy static int	get_line(int, char *, int);
    310   1.87      tron static void	spawn(struct servtab *, int);
    311  1.127  christos static struct servtab	init_servtab(void);
    312  1.127  christos static int	rl_process(struct servtab *, int);
    313  1.127  christos static struct se_ip_list_node	*rl_add(struct servtab *, char *);
    314  1.127  christos static void	rl_reset(struct servtab *, time_t);
    315  1.127  christos static struct se_ip_list_node	*rl_try_get_ip(struct servtab *, char *);
    316  1.127  christos static void	include_configs(char *);
    317  1.127  christos static int	glob_error(const char *, int);
    318  1.127  christos static void	read_glob_configs(char *);
    319  1.127  christos static void	prepare_next_config(const char*);
    320  1.127  christos static bool	is_same_service(const struct servtab *, const struct servtab *);
    321  1.127  christos static char	*gen_file_pattern(const char *, const char *);
    322  1.127  christos static bool	check_no_reinclude(const char *);
    323  1.127  christos static void	include_matched_path(char *);
    324  1.127  christos static void	purge_unchecked(void);
    325  1.127  christos static void	config_root(void);
    326  1.127  christos static void	clear_ip_list(struct servtab *);
    327  1.127  christos static time_t	rl_time(void);
    328  1.127  christos static void	rl_get_name(struct servtab *, int, char *);
    329  1.127  christos static void	rl_drop_connection(struct servtab *, int);
    330    1.1       cgd 
    331    1.1       cgd struct biltin {
    332  1.110  christos 	const char *bi_service;		/* internally provided service name */
    333    1.1       cgd 	int	bi_socktype;		/* type of socket supported */
    334    1.1       cgd 	short	bi_fork;		/* 1 if should fork before call */
    335    1.1       cgd 	short	bi_wait;		/* 1 if should wait for child */
    336   1.86      tron 	void	(*bi_fn)(int, struct servtab *);
    337   1.36       mrg 					/* function which performs it */
    338    1.1       cgd } biltins[] = {
    339    1.1       cgd 	/* Echo received data */
    340   1.23   mycroft 	{ "echo",	SOCK_STREAM,	1, 0,	echo_stream },
    341   1.23   mycroft 	{ "echo",	SOCK_DGRAM,	0, 0,	echo_dg },
    342    1.1       cgd 
    343    1.1       cgd 	/* Internet /dev/null */
    344   1.23   mycroft 	{ "discard",	SOCK_STREAM,	1, 0,	discard_stream },
    345   1.23   mycroft 	{ "discard",	SOCK_DGRAM,	0, 0,	discard_dg },
    346    1.1       cgd 
    347   1.35       mrg 	/* Return 32 bit time since 1970 */
    348   1.23   mycroft 	{ "time",	SOCK_STREAM,	0, 0,	machtime_stream },
    349   1.23   mycroft 	{ "time",	SOCK_DGRAM,	0, 0,	machtime_dg },
    350    1.1       cgd 
    351    1.1       cgd 	/* Return human-readable time */
    352   1.23   mycroft 	{ "daytime",	SOCK_STREAM,	0, 0,	daytime_stream },
    353   1.23   mycroft 	{ "daytime",	SOCK_DGRAM,	0, 0,	daytime_dg },
    354    1.1       cgd 
    355    1.1       cgd 	/* Familiar character generator */
    356   1.23   mycroft 	{ "chargen",	SOCK_STREAM,	1, 0,	chargen_stream },
    357   1.23   mycroft 	{ "chargen",	SOCK_DGRAM,	0, 0,	chargen_dg },
    358   1.23   mycroft 
    359   1.30   mycroft 	{ "tcpmux",	SOCK_STREAM,	1, 0,	tcpmux },
    360   1.23   mycroft 
    361  1.110  christos 	{ NULL, 0, 0, 0, NULL }
    362    1.1       cgd };
    363    1.1       cgd 
    364   1.47       hwr /* list of "bad" ports. I.e. ports that are most obviously used for
    365   1.47       hwr  * "cycling packets" denial of service attacks. See /etc/services.
    366   1.47       hwr  * List must end with port number "0".
    367   1.47       hwr  */
    368   1.47       hwr 
    369   1.79    itojun u_int16_t bad_ports[] =  { 7, 9, 13, 19, 37, 0 };
    370   1.47       hwr 
    371   1.47       hwr 
    372    1.1       cgd #define NUMINT	(sizeof(intab) / sizeof(struct inent))
    373  1.110  christos const char	*CONFIG = _PATH_INETDCONF;
    374    1.5        pk 
    375   1.88      tron static int my_signals[] =
    376   1.88      tron     { SIGALRM, SIGHUP, SIGCHLD, SIGTERM, SIGINT, SIGPIPE };
    377   1.87      tron 
    378   1.36       mrg int
    379   1.87      tron main(int argc, char *argv[])
    380    1.1       cgd {
    381   1.87      tron 	int		ch, n, reload = 1;
    382    1.1       cgd 
    383   1.12       mrg 	while ((ch = getopt(argc, argv,
    384   1.12       mrg #ifdef LIBWRAP
    385   1.12       mrg 					"dl"
    386   1.12       mrg #else
    387   1.12       mrg 					"d"
    388   1.12       mrg #endif
    389   1.38     lukem 					   )) != -1)
    390    1.1       cgd 		switch(ch) {
    391    1.1       cgd 		case 'd':
    392    1.1       cgd 			debug = 1;
    393    1.1       cgd 			options |= SO_DEBUG;
    394    1.1       cgd 			break;
    395   1.12       mrg #ifdef LIBWRAP
    396   1.12       mrg 		case 'l':
    397   1.12       mrg 			lflag = 1;
    398   1.12       mrg 			break;
    399   1.12       mrg #endif
    400    1.1       cgd 		case '?':
    401    1.1       cgd 		default:
    402   1.23   mycroft 			usage();
    403    1.1       cgd 		}
    404    1.1       cgd 	argc -= optind;
    405    1.1       cgd 	argv += optind;
    406    1.1       cgd 
    407    1.1       cgd 	if (argc > 0)
    408    1.1       cgd 		CONFIG = argv[0];
    409    1.5        pk 
    410   1.87      tron 	if (!debug)
    411    1.1       cgd 		daemon(0, 0);
    412   1.72     lukem 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
    413   1.48   thorpej 	pidfile(NULL);
    414    1.5        pk 
    415   1.85      tron 	kq = kqueue();
    416   1.85      tron 	if (kq < 0) {
    417   1.85      tron 		syslog(LOG_ERR, "kqueue: %m");
    418   1.85      tron 		return (EXIT_FAILURE);
    419   1.85      tron 	}
    420   1.85      tron 
    421    1.6        pk 	if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
    422    1.5        pk 		syslog(LOG_ERR, "getrlimit: %m");
    423    1.5        pk 	} else {
    424    1.5        pk 		rlim_ofile_cur = rlim_ofile.rlim_cur;
    425    1.6        pk 		if (rlim_ofile_cur == RLIM_INFINITY)	/* ! */
    426    1.6        pk 			rlim_ofile_cur = OPEN_MAX;
    427    1.5        pk 	}
    428    1.5        pk 
    429  1.127  christos 	for (n = 0; n < (int)__arraycount(my_signals); n++) {
    430   1.88      tron 		int	signum;
    431   1.88      tron 
    432   1.88      tron 		signum = my_signals[n];
    433  1.100  christos 		if (signum != SIGCHLD)
    434  1.100  christos 			(void) signal(signum, SIG_IGN);
    435   1.88      tron 
    436   1.88      tron 		if (signum != SIGPIPE) {
    437   1.88      tron 			struct kevent	*ev;
    438   1.88      tron 
    439   1.88      tron 			ev = allocchange();
    440   1.88      tron 			EV_SET(ev, signum, EVFILT_SIGNAL, EV_ADD | EV_ENABLE,
    441   1.94      fvdl 			    0, 0, 0);
    442   1.88      tron 		}
    443   1.87      tron 	}
    444    1.1       cgd 
    445    1.1       cgd 	for (;;) {
    446   1.87      tron 		int		ctrl;
    447   1.88      tron 		struct kevent	eventbuf[64], *ev;
    448   1.87      tron 		struct servtab	*sep;
    449   1.87      tron 
    450   1.87      tron 		if (reload) {
    451   1.87      tron 			reload = 0;
    452  1.127  christos 			config_root();
    453   1.87      tron 		}
    454    1.1       cgd 
    455  1.127  christos 		n = my_kevent(changebuf, changes, eventbuf, __arraycount(eventbuf));
    456   1.87      tron 		changes = 0;
    457   1.87      tron 
    458   1.87      tron 		for (ev = eventbuf; n > 0; ev++, n--) {
    459   1.87      tron 			if (ev->filter == EVFILT_SIGNAL) {
    460   1.87      tron 				switch (ev->ident) {
    461   1.87      tron 				case SIGALRM:
    462   1.87      tron 					retry();
    463   1.87      tron 					break;
    464   1.87      tron 				case SIGCHLD:
    465   1.87      tron 					reapchild();
    466   1.87      tron 					break;
    467   1.87      tron 				case SIGTERM:
    468   1.87      tron 				case SIGINT:
    469   1.87      tron 					goaway();
    470   1.87      tron 					break;
    471   1.87      tron 				case SIGHUP:
    472   1.87      tron 					reload = 1;
    473   1.87      tron 					break;
    474   1.87      tron 				}
    475   1.85      tron 				continue;
    476   1.87      tron 			}
    477   1.87      tron 			if (ev->filter != EVFILT_READ)
    478   1.87      tron 				continue;
    479   1.87      tron 			sep = (struct servtab *)ev->udata;
    480   1.85      tron 			/* Paranoia */
    481  1.102    rillig 			if ((int)ev->ident != sep->se_fd)
    482   1.79    itojun 				continue;
    483  1.127  christos 			DPRINTF(SERV_FMT ": service requested" , SERV_PARAMS(sep));
    484   1.79    itojun 			if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
    485   1.96    rumble 				/* XXX here do the libwrap check-before-accept*/
    486   1.85      tron 				ctrl = accept(sep->se_fd, NULL, NULL);
    487  1.130    rillig 				DPRINTF(SERV_FMT ": accept, ctrl fd %d",
    488  1.127  christos 				    SERV_PARAMS(sep), ctrl);
    489   1.79    itojun 				if (ctrl < 0) {
    490   1.79    itojun 					if (errno != EINTR)
    491   1.79    itojun 						syslog(LOG_WARNING,
    492  1.127  christos 						    SERV_FMT ": accept: %m",
    493  1.127  christos 						    SERV_PARAMS(sep));
    494   1.79    itojun 					continue;
    495   1.79    itojun 				}
    496   1.79    itojun 			} else
    497   1.79    itojun 				ctrl = sep->se_fd;
    498   1.79    itojun 			spawn(sep, ctrl);
    499   1.79    itojun 		}
    500   1.79    itojun 	}
    501   1.79    itojun }
    502   1.79    itojun 
    503   1.87      tron static void
    504   1.87      tron spawn(struct servtab *sep, int ctrl)
    505   1.79    itojun {
    506   1.79    itojun 	int dofork;
    507   1.79    itojun 	pid_t pid;
    508   1.79    itojun 
    509   1.79    itojun 	pid = 0;
    510   1.28   mycroft #ifdef LIBWRAP_INTERNAL
    511   1.79    itojun 	dofork = 1;
    512   1.26   mycroft #else
    513   1.79    itojun 	dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
    514   1.26   mycroft #endif
    515   1.79    itojun 	if (dofork) {
    516  1.127  christos 		if (rl_process(sep, ctrl)) {
    517  1.127  christos 			return;
    518    1.5        pk 		}
    519   1.79    itojun 		pid = fork();
    520   1.79    itojun 		if (pid < 0) {
    521   1.79    itojun 			syslog(LOG_ERR, "fork: %m");
    522   1.79    itojun 			if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    523   1.79    itojun 				close(ctrl);
    524   1.79    itojun 			sleep(1);
    525   1.79    itojun 			return;
    526   1.79    itojun 		}
    527   1.79    itojun 		if (pid != 0 && sep->se_wait) {
    528   1.87      tron 			struct kevent	*ev;
    529   1.85      tron 
    530   1.79    itojun 			sep->se_wait = pid;
    531   1.87      tron 			ev = allocchange();
    532   1.87      tron 			EV_SET(ev, sep->se_fd, EVFILT_READ,
    533   1.85      tron 			    EV_DELETE, 0, 0, 0);
    534   1.79    itojun 		}
    535    1.5        pk 		if (pid == 0) {
    536  1.102    rillig 			size_t	n;
    537   1.88      tron 
    538  1.127  christos 			for (n = 0; n < __arraycount(my_signals); n++)
    539   1.88      tron 				(void) signal(my_signals[n], SIG_DFL);
    540   1.79    itojun 			if (debug)
    541   1.79    itojun 				setsid();
    542   1.30   mycroft 		}
    543   1.30   mycroft 	}
    544   1.79    itojun 	if (pid == 0) {
    545  1.105  dholland 		run_service(ctrl, sep, dofork);
    546   1.79    itojun 		if (dofork)
    547   1.79    itojun 			exit(0);
    548   1.79    itojun 	}
    549   1.79    itojun 	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
    550   1.79    itojun 		close(ctrl);
    551   1.30   mycroft }
    552   1.30   mycroft 
    553   1.87      tron static void
    554  1.105  dholland run_service(int ctrl, struct servtab *sep, int didfork)
    555   1.30   mycroft {
    556   1.30   mycroft 	struct passwd *pwd;
    557   1.36       mrg 	struct group *grp = NULL;	/* XXX gcc */
    558   1.57    itojun 	char buf[NI_MAXSERV];
    559  1.105  dholland 	struct servtab *s;
    560   1.30   mycroft #ifdef LIBWRAP
    561  1.109  christos 	char abuf[BUFSIZ];
    562   1.30   mycroft 	struct request_info req;
    563   1.30   mycroft 	int denied;
    564   1.40  christos 	char *service = NULL;	/* XXX gcc */
    565   1.30   mycroft #endif
    566   1.30   mycroft 
    567   1.20   mycroft #ifdef LIBWRAP
    568   1.28   mycroft #ifndef LIBWRAP_INTERNAL
    569   1.30   mycroft 	if (sep->se_bi == 0)
    570   1.28   mycroft #endif
    571   1.34   mycroft 	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
    572   1.30   mycroft 		request_init(&req, RQ_DAEMON, sep->se_argv[0] ?
    573   1.30   mycroft 		    sep->se_argv[0] : sep->se_service, RQ_FILE, ctrl, NULL);
    574   1.30   mycroft 		fromhost(&req);
    575   1.30   mycroft 		denied = !hosts_access(&req);
    576   1.30   mycroft 		if (denied || lflag) {
    577   1.52    itojun 			if (getnameinfo(&sep->se_ctrladdr,
    578  1.110  christos 			    (socklen_t)sep->se_ctrladdr.sa_len, NULL, 0,
    579  1.110  christos 			    buf, sizeof(buf), 0) != 0) {
    580   1.52    itojun 				/* shouldn't happen */
    581   1.30   mycroft 				(void)snprintf(buf, sizeof buf, "%d",
    582   1.30   mycroft 				    ntohs(sep->se_ctrladdr_in.sin_port));
    583   1.52    itojun 			}
    584   1.52    itojun 			service = buf;
    585  1.116  dholland 			if (req.client->sin) {
    586  1.116  dholland 				sockaddr_snprintf(abuf, sizeof(abuf), "%a",
    587  1.116  dholland 				    req.client->sin);
    588  1.116  dholland 			} else {
    589  1.116  dholland 				strcpy(abuf, "(null)");
    590  1.116  dholland 			}
    591   1.30   mycroft 		}
    592   1.30   mycroft 		if (denied) {
    593   1.30   mycroft 			syslog(deny_severity,
    594  1.109  christos 			    "refused connection from %.500s(%s), service %s (%s)",
    595  1.109  christos 			    eval_client(&req), abuf, service, sep->se_proto);
    596   1.30   mycroft 			goto reject;
    597   1.30   mycroft 		}
    598   1.30   mycroft 		if (lflag) {
    599   1.30   mycroft 			syslog(allow_severity,
    600  1.109  christos 			    "connection from %.500s(%s), service %s (%s)",
    601  1.109  christos 			    eval_client(&req), abuf, service, sep->se_proto);
    602   1.30   mycroft 		}
    603   1.30   mycroft 	}
    604   1.30   mycroft #endif /* LIBWRAP */
    605   1.30   mycroft 
    606   1.30   mycroft 	if (sep->se_bi) {
    607  1.105  dholland 		if (didfork) {
    608  1.105  dholland 			for (s = servtab; s; s = s->se_next)
    609  1.110  christos 				if (s->se_fd != -1 && s->se_fd != ctrl) {
    610  1.105  dholland 					close(s->se_fd);
    611  1.110  christos 					s->se_fd = -1;
    612  1.110  christos 				}
    613  1.105  dholland 		}
    614   1.30   mycroft 		(*sep->se_bi->bi_fn)(ctrl, sep);
    615   1.30   mycroft 	} else {
    616   1.30   mycroft 		if ((pwd = getpwnam(sep->se_user)) == NULL) {
    617   1.30   mycroft 			syslog(LOG_ERR, "%s/%s: %s: No such user",
    618   1.30   mycroft 			    sep->se_service, sep->se_proto, sep->se_user);
    619   1.30   mycroft 			goto reject;
    620   1.30   mycroft 		}
    621   1.30   mycroft 		if (sep->se_group &&
    622   1.30   mycroft 		    (grp = getgrnam(sep->se_group)) == NULL) {
    623   1.30   mycroft 			syslog(LOG_ERR, "%s/%s: %s: No such group",
    624   1.30   mycroft 			    sep->se_service, sep->se_proto, sep->se_group);
    625   1.30   mycroft 			goto reject;
    626   1.30   mycroft 		}
    627   1.30   mycroft 		if (pwd->pw_uid) {
    628   1.30   mycroft 			if (sep->se_group)
    629   1.30   mycroft 				pwd->pw_gid = grp->gr_gid;
    630   1.30   mycroft 			if (setgid(pwd->pw_gid) < 0) {
    631   1.30   mycroft 				syslog(LOG_ERR,
    632   1.30   mycroft 				 "%s/%s: can't set gid %d: %m", sep->se_service,
    633   1.30   mycroft 				    sep->se_proto, pwd->pw_gid);
    634   1.30   mycroft 				goto reject;
    635   1.20   mycroft 			}
    636   1.30   mycroft 			(void) initgroups(pwd->pw_name,
    637   1.30   mycroft 			    pwd->pw_gid);
    638   1.30   mycroft 			if (setuid(pwd->pw_uid) < 0) {
    639   1.30   mycroft 				syslog(LOG_ERR,
    640   1.30   mycroft 				 "%s/%s: can't set uid %d: %m", sep->se_service,
    641   1.30   mycroft 				    sep->se_proto, pwd->pw_uid);
    642   1.22   mycroft 				goto reject;
    643   1.20   mycroft 			}
    644   1.30   mycroft 		} else if (sep->se_group) {
    645   1.30   mycroft 			(void) setgid((gid_t)grp->gr_gid);
    646   1.30   mycroft 		}
    647  1.130    rillig 		DPRINTF("%d execl %s",
    648  1.127  christos 		    getpid(), sep->se_server);
    649   1.30   mycroft 		/* Set our control descriptor to not close-on-exec... */
    650   1.30   mycroft 		if (fcntl(ctrl, F_SETFD, 0) < 0)
    651  1.110  christos 			syslog(LOG_ERR, "fcntl (%d, F_SETFD, 0): %m", ctrl);
    652   1.30   mycroft 		/* ...and dup it to stdin, stdout, and stderr. */
    653   1.30   mycroft 		if (ctrl != 0) {
    654   1.30   mycroft 			dup2(ctrl, 0);
    655   1.30   mycroft 			close(ctrl);
    656   1.30   mycroft 			ctrl = 0;
    657   1.30   mycroft 		}
    658   1.30   mycroft 		dup2(0, 1);
    659   1.30   mycroft 		dup2(0, 2);
    660   1.30   mycroft 		if (rlim_ofile.rlim_cur != rlim_ofile_cur &&
    661   1.30   mycroft 		    setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
    662   1.30   mycroft 			syslog(LOG_ERR, "setrlimit: %m");
    663   1.30   mycroft 		execv(sep->se_server, sep->se_argv);
    664   1.30   mycroft 		syslog(LOG_ERR, "cannot execute %s: %m", sep->se_server);
    665   1.30   mycroft 	reject:
    666   1.30   mycroft 		if (sep->se_socktype != SOCK_STREAM)
    667   1.30   mycroft 			recv(ctrl, buf, sizeof (buf), 0);
    668  1.127  christos 		_exit(EXIT_FAILURE);
    669    1.1       cgd 	}
    670    1.1       cgd }
    671    1.1       cgd 
    672   1.87      tron static void
    673   1.87      tron reapchild(void)
    674    1.1       cgd {
    675    1.1       cgd 	int status;
    676   1.23   mycroft 	pid_t pid;
    677   1.23   mycroft 	struct servtab *sep;
    678    1.1       cgd 
    679    1.1       cgd 	for (;;) {
    680   1.85      tron 		pid = wait3(&status, WNOHANG, NULL);
    681    1.1       cgd 		if (pid <= 0)
    682    1.1       cgd 			break;
    683  1.127  christos 		DPRINTF("%d reaped, status %#x", pid, status);
    684   1.85      tron 		for (sep = servtab; sep != NULL; sep = sep->se_next)
    685    1.1       cgd 			if (sep->se_wait == pid) {
    686   1.87      tron 				struct kevent	*ev;
    687   1.85      tron 
    688    1.5        pk 				if (WIFEXITED(status) && WEXITSTATUS(status))
    689    1.1       cgd 					syslog(LOG_WARNING,
    690  1.122   khorben 					    "%s: exit status %u",
    691    1.5        pk 					    sep->se_server, WEXITSTATUS(status));
    692    1.5        pk 				else if (WIFSIGNALED(status))
    693    1.5        pk 					syslog(LOG_WARNING,
    694  1.122   khorben 					    "%s: exit signal %u",
    695    1.5        pk 					    sep->se_server, WTERMSIG(status));
    696    1.5        pk 				sep->se_wait = 1;
    697   1.87      tron 				ev = allocchange();
    698   1.87      tron 				EV_SET(ev, sep->se_fd, EVFILT_READ,
    699   1.85      tron 				    EV_ADD | EV_ENABLE, 0, 0, (intptr_t)sep);
    700  1.127  christos 				DPRINTF("restored %s, fd %d",
    701  1.127  christos 				    sep->se_service, sep->se_fd);
    702    1.1       cgd 			}
    703    1.1       cgd 	}
    704    1.1       cgd }
    705    1.1       cgd 
    706  1.127  christos size_t	line_number;
    707  1.127  christos 
    708  1.130    rillig /*
    709  1.127  christos  * Recursively merge loaded service definitions with any defined
    710  1.130    rillig  * in the current or included config files.
    711  1.127  christos  */
    712   1.87      tron static void
    713   1.87      tron config(void)
    714    1.1       cgd {
    715  1.127  christos 	struct servtab *sep, *cp;
    716  1.127  christos 	/*
    717  1.130    rillig 	 * Current position in line, used with key-values notation,
    718  1.130    rillig 	 * saves cp across getconfigent calls.
    719  1.127  christos 	 */
    720  1.127  christos 	char *current_pos;
    721  1.102    rillig 	size_t n;
    722  1.130    rillig 
    723  1.127  christos 	/* open config file from beginning */
    724  1.127  christos 	fconfig = fopen(CONFIG, "r");
    725  1.127  christos 	if(fconfig == NULL) {
    726    1.1       cgd 		syslog(LOG_ERR, "%s: %m", CONFIG);
    727    1.1       cgd 		return;
    728    1.1       cgd 	}
    729  1.127  christos 
    730  1.127  christos 	/* First call to nextline will advance line_number to 1 */
    731  1.127  christos 	line_number = 0;
    732  1.130    rillig 
    733  1.127  christos 	/* Start parsing at the beginning of the first line */
    734  1.127  christos 	current_pos = nextline(fconfig);
    735  1.127  christos 
    736  1.127  christos 	while ((cp = getconfigent(&current_pos)) != NULL) {
    737  1.127  christos 		/* Find an already existing service definition */
    738   1.85      tron 		for (sep = servtab; sep != NULL; sep = sep->se_next)
    739  1.127  christos 			if (is_same_service(sep, cp))
    740    1.1       cgd 				break;
    741   1.87      tron 		if (sep != NULL) {
    742    1.1       cgd 			int i;
    743    1.1       cgd 
    744  1.101       mrg #define SWAP(type, a, b) {type c = a; a = b; b = c;}
    745    1.5        pk 
    746    1.1       cgd 			/*
    747    1.1       cgd 			 * sep->se_wait may be holding the pid of a daemon
    748    1.1       cgd 			 * that we're waiting for.  If so, don't overwrite
    749   1.16     mouse 			 * it unless the config file explicitly says don't
    750    1.1       cgd 			 * wait.
    751    1.1       cgd 			 */
    752   1.16     mouse 			if (cp->se_bi == 0 &&
    753    1.1       cgd 			    (sep->se_wait == 1 || cp->se_wait == 0))
    754    1.1       cgd 				sep->se_wait = cp->se_wait;
    755   1.11   mycroft 			SWAP(char *, sep->se_user, cp->se_user);
    756   1.11   mycroft 			SWAP(char *, sep->se_group, cp->se_group);
    757   1.11   mycroft 			SWAP(char *, sep->se_server, cp->se_server);
    758    1.1       cgd 			for (i = 0; i < MAXARGV; i++)
    759    1.5        pk 				SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
    760   1.49    itojun #ifdef IPSEC
    761   1.49    itojun 			SWAP(char *, sep->se_policy, cp->se_policy);
    762   1.49    itojun #endif
    763   1.24   mycroft 			SWAP(int, cp->se_type, sep->se_type);
    764  1.127  christos 			SWAP(size_t, cp->se_service_max, sep->se_service_max);
    765  1.127  christos 			SWAP(size_t, cp->se_ip_max, sep->se_ip_max);
    766    1.5        pk #undef SWAP
    767    1.5        pk 			if (isrpcservice(sep))
    768    1.5        pk 				unregister_rpc(sep);
    769    1.5        pk 			sep->se_rpcversl = cp->se_rpcversl;
    770    1.5        pk 			sep->se_rpcversh = cp->se_rpcversh;
    771    1.1       cgd 			freeconfig(cp);
    772  1.127  christos #ifdef DEBUG_ENABLE
    773    1.1       cgd 			if (debug)
    774    1.1       cgd 				print_service("REDO", sep);
    775  1.127  christos #endif
    776    1.1       cgd 		} else {
    777    1.1       cgd 			sep = enter(cp);
    778  1.127  christos #ifdef DEBUG_ENABLE
    779    1.1       cgd 			if (debug)
    780    1.1       cgd 				print_service("ADD ", sep);
    781  1.127  christos #endif
    782    1.1       cgd 		}
    783    1.1       cgd 		sep->se_checked = 1;
    784    1.2    brezak 
    785  1.130    rillig 		/*
    786  1.127  christos 		 * Remainder of config(void) checks validity of servtab options
    787  1.130    rillig 		 * and sets up the service by setting up sockets (in setup(servtab)).
    788  1.127  christos 		 */
    789    1.5        pk 		switch (sep->se_family) {
    790   1.44     lukem 		case AF_LOCAL:
    791    1.5        pk 			if (sep->se_fd != -1)
    792    1.5        pk 				break;
    793   1.38     lukem 			n = strlen(sep->se_service);
    794  1.121  christos 			if (n >= sizeof(sep->se_ctrladdr_un.sun_path)) {
    795  1.127  christos 				syslog(LOG_ERR, "%s/%s: address too long",
    796  1.127  christos 				    sep->se_service, sep->se_proto);
    797   1.38     lukem 				sep->se_checked = 0;
    798   1.38     lukem 				continue;
    799   1.38     lukem 			}
    800    1.5        pk 			(void)unlink(sep->se_service);
    801  1.121  christos 			strlcpy(sep->se_ctrladdr_un.sun_path,
    802  1.123     elric 			    sep->se_service, n + 1);
    803   1.44     lukem 			sep->se_ctrladdr_un.sun_family = AF_LOCAL;
    804  1.110  christos 			sep->se_ctrladdr_size = (int)(n +
    805   1.23   mycroft 			    sizeof(sep->se_ctrladdr_un) -
    806  1.110  christos 			    sizeof(sep->se_ctrladdr_un.sun_path));
    807   1.23   mycroft 			if (!ISMUX(sep))
    808   1.23   mycroft 				setup(sep);
    809    1.5        pk 			break;
    810    1.5        pk 		case AF_INET:
    811   1.58    itojun #ifdef INET6
    812   1.49    itojun 		case AF_INET6:
    813   1.58    itojun #endif
    814   1.49    itojun 		    {
    815   1.49    itojun 			struct addrinfo hints, *res;
    816  1.110  christos 			char *host;
    817  1.110  christos 			const char *port;
    818   1.49    itojun 			int error;
    819   1.68    itojun 			int s;
    820   1.68    itojun 
    821   1.68    itojun 			/* check if the family is supported */
    822   1.68    itojun 			s = socket(sep->se_family, SOCK_DGRAM, 0);
    823   1.68    itojun 			if (s < 0) {
    824   1.68    itojun 				syslog(LOG_WARNING,
    825   1.96    rumble 				    "%s/%s: %s: the address family is not "
    826   1.96    rumble 				    "supported by the kernel",
    827   1.68    itojun 				    sep->se_service, sep->se_proto,
    828   1.68    itojun 				    sep->se_hostaddr);
    829   1.68    itojun 				sep->se_checked = 0;
    830   1.68    itojun 				continue;
    831   1.68    itojun 			}
    832   1.68    itojun 			close(s);
    833   1.49    itojun 
    834   1.49    itojun 			memset(&hints, 0, sizeof(hints));
    835   1.49    itojun 			hints.ai_family = sep->se_family;
    836   1.49    itojun 			hints.ai_socktype = sep->se_socktype;
    837   1.65    itojun 			hints.ai_flags = AI_PASSIVE;
    838   1.65    itojun 			if (!strcmp(sep->se_hostaddr, "*"))
    839   1.49    itojun 				host = NULL;
    840   1.65    itojun 			else
    841   1.49    itojun 				host = sep->se_hostaddr;
    842   1.49    itojun 			if (isrpcservice(sep) || ISMUX(sep))
    843   1.49    itojun 				port = "0";
    844   1.49    itojun 			else
    845  1.130    rillig 				port = sep->se_service;
    846   1.49    itojun 			error = getaddrinfo(host, port, &hints, &res);
    847   1.49    itojun 			if (error) {
    848   1.68    itojun 				if (error == EAI_SERVICE) {
    849   1.68    itojun 					/* gai_strerror not friendly enough */
    850  1.127  christos 					syslog(LOG_WARNING, SERV_FMT ": "
    851   1.65    itojun 					    "unknown service",
    852  1.127  christos 					    SERV_PARAMS(sep));
    853   1.60    itojun 				} else {
    854  1.127  christos 					syslog(LOG_ERR, SERV_FMT ": %s: %s",
    855  1.127  christos 					    SERV_PARAMS(sep),
    856   1.60    itojun 					    sep->se_hostaddr,
    857   1.60    itojun 					    gai_strerror(error));
    858   1.60    itojun 				}
    859   1.49    itojun 				sep->se_checked = 0;
    860   1.49    itojun 				continue;
    861   1.49    itojun 			}
    862   1.49    itojun 			if (res->ai_next) {
    863   1.50    itojun 				syslog(LOG_ERR,
    864  1.127  christos 					SERV_FMT ": %s: resolved to multiple addr",
    865  1.127  christos 				    SERV_PARAMS(sep),
    866   1.49    itojun 				    sep->se_hostaddr);
    867   1.49    itojun 				sep->se_checked = 0;
    868   1.49    itojun 				freeaddrinfo(res);
    869   1.49    itojun 				continue;
    870   1.16     mouse 			}
    871   1.49    itojun 			memcpy(&sep->se_ctrladdr, res->ai_addr,
    872   1.49    itojun 				res->ai_addrlen);
    873   1.23   mycroft 			if (ISMUX(sep)) {
    874   1.23   mycroft 				sep->se_fd = -1;
    875   1.49    itojun 				freeaddrinfo(res);
    876   1.23   mycroft 				continue;
    877   1.23   mycroft 			}
    878   1.49    itojun 			sep->se_ctrladdr_size = res->ai_addrlen;
    879   1.49    itojun 			freeaddrinfo(res);
    880   1.53  sommerfe #ifdef RPC
    881    1.5        pk 			if (isrpcservice(sep)) {
    882    1.5        pk 				struct rpcent *rp;
    883    1.5        pk 
    884    1.5        pk 				sep->se_rpcprog = atoi(sep->se_service);
    885    1.5        pk 				if (sep->se_rpcprog == 0) {
    886    1.5        pk 					rp = getrpcbyname(sep->se_service);
    887    1.5        pk 					if (rp == 0) {
    888    1.5        pk 						syslog(LOG_ERR,
    889  1.130    rillig 						    SERV_FMT
    890  1.127  christos 						    ": unknown service",
    891  1.127  christos 						    SERV_PARAMS(sep));
    892   1.23   mycroft 						sep->se_checked = 0;
    893    1.5        pk 						continue;
    894    1.5        pk 					}
    895    1.5        pk 					sep->se_rpcprog = rp->r_number;
    896    1.5        pk 				}
    897   1.23   mycroft 				if (sep->se_fd == -1 && !ISMUX(sep))
    898    1.5        pk 					setup(sep);
    899    1.5        pk 				if (sep->se_fd != -1)
    900    1.5        pk 					register_rpc(sep);
    901   1.53  sommerfe 			} else
    902   1.53  sommerfe #endif
    903   1.53  sommerfe 			{
    904   1.49    itojun 				if (sep->se_fd >= 0)
    905   1.49    itojun 					close_sep(sep);
    906   1.23   mycroft 				if (sep->se_fd == -1 && !ISMUX(sep))
    907    1.5        pk 					setup(sep);
    908    1.5        pk 			}
    909   1.49    itojun 		    }
    910    1.5        pk 		}
    911    1.1       cgd 	}
    912    1.1       cgd 	endconfig();
    913    1.1       cgd }
    914    1.1       cgd 
    915   1.87      tron static void
    916   1.87      tron retry(void)
    917    1.5        pk {
    918   1.23   mycroft 	struct servtab *sep;
    919    1.2    brezak 
    920    1.5        pk 	timingout = 0;
    921   1.85      tron 	for (sep = servtab; sep != NULL; sep = sep->se_next) {
    922   1.23   mycroft 		if (sep->se_fd == -1 && !ISMUX(sep)) {
    923    1.5        pk 			switch (sep->se_family) {
    924   1.44     lukem 			case AF_LOCAL:
    925    1.5        pk 			case AF_INET:
    926   1.58    itojun #ifdef INET6
    927   1.49    itojun 			case AF_INET6:
    928   1.58    itojun #endif
    929    1.5        pk 				setup(sep);
    930  1.110  christos 				if (sep->se_fd >= 0 && isrpcservice(sep))
    931    1.5        pk 					register_rpc(sep);
    932    1.5        pk 				break;
    933    1.5        pk 			}
    934    1.5        pk 		}
    935    1.5        pk 	}
    936    1.2    brezak }
    937    1.2    brezak 
    938   1.87      tron static void
    939   1.87      tron goaway(void)
    940    1.1       cgd {
    941   1.36       mrg 	struct servtab *sep;
    942    1.1       cgd 
    943   1.85      tron 	for (sep = servtab; sep != NULL; sep = sep->se_next) {
    944    1.1       cgd 		if (sep->se_fd == -1)
    945    1.5        pk 			continue;
    946  1.130    rillig 
    947    1.5        pk 		switch (sep->se_family) {
    948   1.44     lukem 		case AF_LOCAL:
    949    1.5        pk 			(void)unlink(sep->se_service);
    950    1.5        pk 			break;
    951    1.5        pk 		case AF_INET:
    952   1.58    itojun #ifdef INET6
    953   1.49    itojun 		case AF_INET6:
    954   1.58    itojun #endif
    955    1.5        pk 			if (sep->se_wait == 1 && isrpcservice(sep))
    956    1.5        pk 				unregister_rpc(sep);
    957    1.5        pk 			break;
    958    1.5        pk 		}
    959    1.5        pk 		(void)close(sep->se_fd);
    960  1.110  christos 		sep->se_fd = -1;
    961    1.5        pk 	}
    962    1.5        pk 	exit(0);
    963    1.1       cgd }
    964    1.1       cgd 
    965   1.87      tron static void
    966   1.87      tron setup(struct servtab *sep)
    967    1.1       cgd {
    968   1.97        pk 	int		on = 1;
    969   1.97        pk #ifdef INET6
    970   1.97        pk 	int		off = 0;
    971   1.97        pk #endif
    972   1.87      tron 	struct kevent	*ev;
    973    1.1       cgd 
    974    1.5        pk 	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
    975  1.130    rillig 		DPRINTF("socket failed on " SERV_FMT ": %s",
    976  1.127  christos 		    SERV_PARAMS(sep), strerror(errno));
    977    1.1       cgd 		syslog(LOG_ERR, "%s/%s: socket: %m",
    978    1.1       cgd 		    sep->se_service, sep->se_proto);
    979    1.1       cgd 		return;
    980    1.1       cgd 	}
    981   1.46   mycroft 	/* Set all listening sockets to close-on-exec. */
    982   1.84   mycroft 	if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) {
    983  1.127  christos 		syslog(LOG_ERR, SERV_FMT ": fcntl(F_SETFD, FD_CLOEXEC): %m",
    984  1.127  christos 		    SERV_PARAMS(sep));
    985   1.84   mycroft 		close(sep->se_fd);
    986  1.110  christos 		sep->se_fd = -1;
    987   1.84   mycroft 		return;
    988   1.84   mycroft 	}
    989   1.42   thorpej 
    990    1.1       cgd #define	turnon(fd, opt) \
    991  1.110  christos setsockopt(fd, SOL_SOCKET, opt, &on, (socklen_t)sizeof(on))
    992    1.1       cgd 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
    993    1.1       cgd 	    turnon(sep->se_fd, SO_DEBUG) < 0)
    994    1.1       cgd 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
    995    1.1       cgd 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
    996    1.1       cgd 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
    997    1.1       cgd #undef turnon
    998   1.42   thorpej 
    999   1.42   thorpej 	/* Set the socket buffer sizes, if specified. */
   1000   1.42   thorpej 	if (sep->se_sndbuf != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
   1001  1.110  christos 	    SO_SNDBUF, &sep->se_sndbuf, (socklen_t)sizeof(sep->se_sndbuf)) < 0)
   1002   1.42   thorpej 		syslog(LOG_ERR, "setsockopt (SO_SNDBUF %d): %m",
   1003   1.42   thorpej 		    sep->se_sndbuf);
   1004   1.42   thorpej 	if (sep->se_rcvbuf != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
   1005  1.110  christos 	    SO_RCVBUF, &sep->se_rcvbuf, (socklen_t)sizeof(sep->se_rcvbuf)) < 0)
   1006   1.42   thorpej 		syslog(LOG_ERR, "setsockopt (SO_RCVBUF %d): %m",
   1007   1.42   thorpej 		    sep->se_rcvbuf);
   1008   1.90    itojun #ifdef INET6
   1009   1.90    itojun 	if (sep->se_family == AF_INET6) {
   1010   1.90    itojun 		int *v;
   1011   1.90    itojun 		v = (sep->se_type == FAITH_TYPE) ? &on : &off;
   1012   1.90    itojun 		if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH,
   1013  1.110  christos 		    v, (socklen_t)sizeof(*v)) < 0)
   1014   1.90    itojun 			syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m");
   1015   1.90    itojun 	}
   1016   1.90    itojun #endif
   1017   1.49    itojun #ifdef IPSEC
   1018  1.124     ozaki 	/* Avoid setting a policy if a policy specifier doesn't exist. */
   1019  1.124     ozaki 	if (sep->se_policy != NULL) {
   1020  1.124     ozaki 		int e = ipsecsetup(sep->se_family, sep->se_fd, sep->se_policy);
   1021  1.124     ozaki 		if (e < 0) {
   1022  1.127  christos 			syslog(LOG_ERR, SERV_FMT ": ipsec setup failed",
   1023  1.127  christos 			    SERV_PARAMS(sep));
   1024  1.124     ozaki 			(void)close(sep->se_fd);
   1025  1.124     ozaki 			sep->se_fd = -1;
   1026  1.124     ozaki 			return;
   1027  1.124     ozaki 		}
   1028   1.50    itojun 	}
   1029   1.49    itojun #endif
   1030   1.42   thorpej 
   1031  1.127  christos 	if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
   1032  1.127  christos 		DPRINTF(SERV_FMT ": bind failed: %s",
   1033  1.127  christos 			SERV_PARAMS(sep), strerror(errno));
   1034  1.127  christos 		syslog(LOG_ERR, SERV_FMT ": bind: %m",
   1035  1.127  christos 		    SERV_PARAMS(sep));
   1036    1.1       cgd 		(void) close(sep->se_fd);
   1037    1.1       cgd 		sep->se_fd = -1;
   1038    1.1       cgd 		if (!timingout) {
   1039    1.1       cgd 			timingout = 1;
   1040    1.1       cgd 			alarm(RETRYTIME);
   1041    1.1       cgd 		}
   1042    1.1       cgd 		return;
   1043    1.1       cgd 	}
   1044    1.1       cgd 	if (sep->se_socktype == SOCK_STREAM)
   1045    1.1       cgd 		listen(sep->se_fd, 10);
   1046    1.5        pk 
   1047  1.107       tls 	/* Set the accept filter, if specified. To be done after listen.*/
   1048  1.107       tls 	if (sep->se_accf.af_name[0] != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
   1049  1.110  christos 	    SO_ACCEPTFILTER, &sep->se_accf,
   1050  1.110  christos 	    (socklen_t)sizeof(sep->se_accf)) < 0)
   1051  1.107       tls 		syslog(LOG_ERR, "setsockopt(SO_ACCEPTFILTER %s): %m",
   1052  1.107       tls 		    sep->se_accf.af_name);
   1053  1.107       tls 
   1054   1.87      tron 	ev = allocchange();
   1055   1.87      tron 	EV_SET(ev, sep->se_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0,
   1056   1.85      tron 	    (intptr_t)sep);
   1057    1.5        pk 	if (sep->se_fd > maxsock) {
   1058    1.1       cgd 		maxsock = sep->se_fd;
   1059  1.111     lukem 		if (maxsock > (int)(rlim_ofile_cur - FD_MARGIN))
   1060    1.5        pk 			bump_nofile();
   1061    1.5        pk 	}
   1062  1.127  christos 	DPRINTF(SERV_FMT ": registered on fd %d", SERV_PARAMS(sep), sep->se_fd);
   1063   1.23   mycroft }
   1064   1.23   mycroft 
   1065   1.23   mycroft /*
   1066   1.23   mycroft  * Finish with a service and its socket.
   1067   1.23   mycroft  */
   1068   1.87      tron static void
   1069   1.87      tron close_sep(struct servtab *sep)
   1070  1.130    rillig {
   1071  1.127  christos 
   1072   1.23   mycroft 	if (sep->se_fd >= 0) {
   1073   1.23   mycroft 		(void) close(sep->se_fd);
   1074   1.23   mycroft 		sep->se_fd = -1;
   1075   1.23   mycroft 	}
   1076   1.23   mycroft 	sep->se_count = 0;
   1077  1.127  christos 	if (sep->se_ip_max != SERVTAB_UNSPEC_SIZE_T) {
   1078  1.127  christos 		clear_ip_list(sep);
   1079  1.127  christos 	}
   1080    1.5        pk }
   1081    1.5        pk 
   1082   1.87      tron static void
   1083   1.87      tron register_rpc(struct servtab *sep)
   1084    1.5        pk {
   1085    1.5        pk #ifdef RPC
   1086   1.62      fvdl 	struct netbuf nbuf;
   1087   1.49    itojun 	struct sockaddr_storage ss;
   1088   1.62      fvdl 	struct netconfig *nconf;
   1089  1.102    rillig 	socklen_t socklen;
   1090  1.102    rillig 	int n;
   1091    1.5        pk 
   1092   1.62      fvdl 	if ((nconf = getnetconfigent(sep->se_proto+4)) == NULL) {
   1093   1.62      fvdl 		syslog(LOG_ERR, "%s: getnetconfigent failed",
   1094    1.5        pk 		    sep->se_proto);
   1095    1.5        pk 		return;
   1096    1.5        pk 	}
   1097  1.102    rillig 	socklen = sizeof ss;
   1098  1.110  christos 	if (getsockname(sep->se_fd, (struct sockaddr *)(void *)&ss, &socklen) < 0) {
   1099  1.127  christos 		syslog(LOG_ERR, SERV_FMT ": getsockname: %m",
   1100  1.127  christos 		    SERV_PARAMS(sep));
   1101    1.5        pk 		return;
   1102    1.5        pk 	}
   1103    1.5        pk 
   1104   1.62      fvdl 	nbuf.buf = &ss;
   1105   1.62      fvdl 	nbuf.len = ss.ss_len;
   1106   1.62      fvdl 	nbuf.maxlen = sizeof (struct sockaddr_storage);
   1107    1.5        pk 	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
   1108  1.127  christos 		DPRINTF("rpcb_set: %u %d %s %s",
   1109  1.127  christos 		    sep->se_rpcprog, n, nconf->nc_netid,
   1110  1.127  christos 		    taddr2uaddr(nconf, &nbuf));
   1111  1.110  christos 		(void)rpcb_unset((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf);
   1112  1.110  christos 		if (!rpcb_set((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf, &nbuf))
   1113   1.62      fvdl 			syslog(LOG_ERR, "rpcb_set: %u %d %s %s%s",
   1114   1.62      fvdl 			    sep->se_rpcprog, n, nconf->nc_netid,
   1115   1.62      fvdl 			    taddr2uaddr(nconf, &nbuf), clnt_spcreateerror(""));
   1116    1.5        pk 	}
   1117    1.5        pk #endif /* RPC */
   1118    1.5        pk }
   1119    1.5        pk 
   1120   1.87      tron static void
   1121   1.87      tron unregister_rpc(struct servtab *sep)
   1122    1.5        pk {
   1123    1.5        pk #ifdef RPC
   1124    1.5        pk 	int n;
   1125   1.62      fvdl 	struct netconfig *nconf;
   1126   1.62      fvdl 
   1127   1.62      fvdl 	if ((nconf = getnetconfigent(sep->se_proto+4)) == NULL) {
   1128   1.62      fvdl 		syslog(LOG_ERR, "%s: getnetconfigent failed",
   1129   1.62      fvdl 		    sep->se_proto);
   1130   1.62      fvdl 		return;
   1131   1.62      fvdl 	}
   1132    1.5        pk 
   1133    1.5        pk 	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
   1134  1.127  christos 		DPRINTF("rpcb_unset(%u, %d, %s)",
   1135  1.127  christos 		    sep->se_rpcprog, n, nconf->nc_netid);
   1136  1.110  christos 		if (!rpcb_unset((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf))
   1137   1.62      fvdl 			syslog(LOG_ERR, "rpcb_unset(%u, %d, %s) failed\n",
   1138   1.62      fvdl 			    sep->se_rpcprog, n, nconf->nc_netid);
   1139    1.5        pk 	}
   1140    1.5        pk #endif /* RPC */
   1141    1.1       cgd }
   1142    1.1       cgd 
   1143    1.5        pk 
   1144   1.87      tron static struct servtab *
   1145   1.87      tron enter(struct servtab *cp)
   1146    1.1       cgd {
   1147   1.23   mycroft 	struct servtab *sep;
   1148    1.1       cgd 
   1149  1.110  christos 	sep = malloc(sizeof (*sep));
   1150   1.85      tron 	if (sep == NULL) {
   1151    1.1       cgd 		syslog(LOG_ERR, "Out of memory.");
   1152  1.127  christos 		exit(EXIT_FAILURE);
   1153    1.1       cgd 	}
   1154    1.1       cgd 	*sep = *cp;
   1155    1.1       cgd 	sep->se_fd = -1;
   1156    1.5        pk 	sep->se_rpcprog = -1;
   1157    1.1       cgd 	sep->se_next = servtab;
   1158    1.1       cgd 	servtab = sep;
   1159    1.1       cgd 	return (sep);
   1160    1.1       cgd }
   1161    1.1       cgd 
   1162  1.127  christos FILE	*fconfig;
   1163  1.127  christos /* Temporary storage for new servtab */
   1164  1.127  christos static struct	servtab serv;
   1165  1.127  christos /* Current line from current config file */
   1166  1.127  christos static char	line[LINE_MAX];
   1167   1.16     mouse char    *defhost;
   1168   1.59    itojun #ifdef IPSEC
   1169  1.127  christos char *policy;
   1170   1.59    itojun #endif
   1171    1.1       cgd 
   1172   1.87      tron static void
   1173   1.87      tron endconfig(void)
   1174    1.1       cgd {
   1175   1.87      tron 	if (fconfig != NULL) {
   1176    1.1       cgd 		(void) fclose(fconfig);
   1177    1.1       cgd 		fconfig = NULL;
   1178    1.1       cgd 	}
   1179   1.87      tron 	if (defhost != NULL) {
   1180   1.16     mouse 		free(defhost);
   1181   1.87      tron 		defhost = NULL;
   1182   1.16     mouse 	}
   1183  1.127  christos 
   1184  1.127  christos #ifdef IPSEC
   1185  1.127  christos 	if (policy != NULL) {
   1186  1.127  christos 		free(policy);
   1187  1.127  christos 		policy = NULL;
   1188  1.127  christos 	}
   1189  1.127  christos #endif
   1190  1.127  christos 
   1191    1.1       cgd }
   1192    1.1       cgd 
   1193  1.127  christos #define LOG_EARLY_ENDCONF() \
   1194  1.127  christos 	ERR("Exiting %s early. Some services will be unavailable", CONFIG)
   1195  1.127  christos 
   1196  1.127  christos #define LOG_TOO_FEW_ARGS() \
   1197  1.127  christos 	ERR("Expected more arguments")
   1198  1.127  christos 
   1199  1.127  christos /* Parse the next service and apply any directives, and returns it as servtab */
   1200   1.87      tron static struct servtab *
   1201  1.127  christos getconfigent(char **current_pos)
   1202    1.1       cgd {
   1203   1.23   mycroft 	struct servtab *sep = &serv;
   1204  1.130    rillig 	int argc, val;
   1205   1.42   thorpej 	char *cp, *cp0, *arg, *buf0, *buf1, *sz0, *sz1;
   1206   1.23   mycroft 	static char TCPMUX_TOKEN[] = "tcpmux/";
   1207   1.23   mycroft #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
   1208   1.16     mouse 	char *hostdelim;
   1209    1.5        pk 
   1210  1.130    rillig 	/*
   1211  1.130    rillig 	 * Pre-condition: current_pos points into line,
   1212  1.127  christos 	 * line contains config line. Continue where the last getconfigent left off.
   1213  1.130    rillig 	 * Allows for multiple service definitions per line.
   1214  1.127  christos 	 */
   1215  1.127  christos 	cp = *current_pos;
   1216  1.127  christos 
   1217  1.127  christos 	if (false) {
   1218  1.130    rillig 		/*
   1219  1.130    rillig 		 * Go to the next line, but only after attemting to read the current
   1220  1.130    rillig 		 * one! Keep reading until we find a valid definition or EOF.
   1221  1.127  christos 		 */
   1222  1.130    rillig more:
   1223  1.127  christos 		cp = nextline(fconfig);
   1224  1.127  christos 	}
   1225  1.127  christos 
   1226  1.127  christos 	if (cp == NULL) {
   1227  1.127  christos 		/* EOF or I/O error, let config() know to exit the file */
   1228  1.127  christos 		return NULL;
   1229  1.127  christos 	}
   1230  1.127  christos 
   1231  1.127  christos 	/* Comments and IPsec policies */
   1232  1.127  christos 	if (cp[0] == '#') {
   1233   1.49    itojun #ifdef IPSEC
   1234   1.49    itojun 		/* lines starting with #@ is not a comment, but the policy */
   1235  1.127  christos 		if (cp[1] == '@') {
   1236   1.49    itojun 			char *p;
   1237   1.98       dsl 			for (p = cp + 2; p && *p && isspace((unsigned char)*p); p++)
   1238   1.49    itojun 				;
   1239   1.49    itojun 			if (*p == '\0') {
   1240   1.49    itojun 				if (policy)
   1241   1.49    itojun 					free(policy);
   1242   1.49    itojun 				policy = NULL;
   1243   1.49    itojun 			} else {
   1244   1.58    itojun 				if (ipsecsetup_test(p) < 0) {
   1245  1.127  christos 					ERR("Invalid IPsec policy \"%s\"", p);
   1246  1.127  christos 					LOG_EARLY_ENDCONF();
   1247  1.130    rillig 					/*
   1248  1.130    rillig 					* Stop reading the current config to prevent services
   1249  1.127  christos 					* from being run without IPsec.
   1250  1.127  christos 					*/
   1251  1.127  christos 					return NULL;
   1252   1.58    itojun 				} else {
   1253   1.58    itojun 					if (policy)
   1254   1.58    itojun 						free(policy);
   1255   1.58    itojun 					policy = newstr(p);
   1256   1.58    itojun 				}
   1257   1.49    itojun 			}
   1258   1.49    itojun 		}
   1259   1.49    itojun #endif
   1260  1.127  christos 
   1261  1.127  christos 		goto more;
   1262    1.5        pk 	}
   1263  1.127  christos 
   1264  1.127  christos 	/* Parse next token: listen-addr/hostname, service-spec, .include */
   1265   1.23   mycroft 	arg = skip(&cp);
   1266  1.127  christos 
   1267   1.23   mycroft 	if (cp == NULL) {
   1268   1.23   mycroft 		goto more;
   1269   1.23   mycroft 	}
   1270  1.127  christos 
   1271  1.127  christos 	if(arg[0] == '.') {
   1272  1.127  christos 		if (strcmp(&arg[1], "include") == 0) {
   1273  1.127  christos 			/* include directive */
   1274  1.127  christos 			arg = skip(&cp);
   1275  1.127  christos 			if(arg == NULL) {
   1276  1.127  christos 				LOG_TOO_FEW_ARGS();
   1277  1.127  christos 				return NULL;
   1278  1.127  christos 			}
   1279  1.127  christos 			include_configs(arg);
   1280  1.127  christos 			goto more;
   1281  1.127  christos 		} else {
   1282  1.127  christos 			ERR("Unknown directive '%s'", &arg[1]);
   1283  1.127  christos 			goto more;
   1284  1.127  christos 		}
   1285  1.127  christos 	}
   1286  1.130    rillig 
   1287  1.127  christos 	/* After this point, we might need to store data in a servtab */
   1288  1.127  christos 	*sep = init_servtab();
   1289  1.127  christos 
   1290   1.23   mycroft 	/* Check for a host name. */
   1291   1.23   mycroft 	hostdelim = strrchr(arg, ':');
   1292   1.16     mouse 	if (hostdelim) {
   1293   1.16     mouse 		*hostdelim = '\0';
   1294   1.69    itojun 		if (arg[0] == '[' && hostdelim > arg && hostdelim[-1] == ']') {
   1295   1.69    itojun 			hostdelim[-1] = '\0';
   1296   1.69    itojun 			sep->se_hostaddr = newstr(arg + 1);
   1297   1.69    itojun 		} else
   1298   1.69    itojun 			sep->se_hostaddr = newstr(arg);
   1299   1.23   mycroft 		arg = hostdelim + 1;
   1300   1.23   mycroft 		/*
   1301   1.23   mycroft 		 * If the line is of the form `host:', then just change the
   1302   1.23   mycroft 		 * default host for the following lines.
   1303   1.23   mycroft 		 */
   1304   1.23   mycroft 		if (*arg == '\0') {
   1305   1.23   mycroft 			arg = skip(&cp);
   1306   1.23   mycroft 			if (cp == NULL) {
   1307   1.23   mycroft 				free(defhost);
   1308   1.23   mycroft 				defhost = sep->se_hostaddr;
   1309   1.23   mycroft 				goto more;
   1310   1.23   mycroft 			}
   1311   1.23   mycroft 		}
   1312  1.127  christos 	} else {
   1313  1.127  christos 		/* No host address found, set it to NULL to indicate absence */
   1314  1.127  christos 		sep->se_hostaddr = NULL;
   1315  1.127  christos 	}
   1316   1.23   mycroft 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
   1317   1.23   mycroft 		char *c = arg + MUX_LEN;
   1318   1.23   mycroft 		if (*c == '+') {
   1319   1.23   mycroft 			sep->se_type = MUXPLUS_TYPE;
   1320   1.23   mycroft 			c++;
   1321   1.16     mouse 		} else
   1322   1.23   mycroft 			sep->se_type = MUX_TYPE;
   1323   1.23   mycroft 		sep->se_service = newstr(c);
   1324   1.23   mycroft 	} else {
   1325   1.23   mycroft 		sep->se_service = newstr(arg);
   1326   1.23   mycroft 		sep->se_type = NORM_TYPE;
   1327   1.16     mouse 	}
   1328    1.5        pk 
   1329  1.127  christos 	DPRINTCONF("Found service definition '%s'", sep->se_service);
   1330  1.127  christos 
   1331  1.127  christos 	/* on/off/socktype */
   1332  1.127  christos 	arg = skip(&cp);
   1333  1.127  christos 	if (arg == NULL) {
   1334  1.127  christos 		LOG_TOO_FEW_ARGS();
   1335  1.127  christos 		freeconfig(sep);
   1336  1.127  christos 		goto more;
   1337  1.127  christos 	}
   1338  1.127  christos 
   1339  1.127  christos 	/* Check for new v2 syntax */
   1340  1.127  christos 	if (strcmp(arg, "on") == 0 || strncmp(arg, "on#", 3) == 0) {
   1341  1.127  christos 
   1342  1.127  christos 		if (arg[2] == '#') {
   1343  1.127  christos 			cp = nextline(fconfig);
   1344  1.127  christos 		}
   1345  1.107       tls 
   1346  1.127  christos 		switch(parse_syntax_v2(sep, &cp)) {
   1347  1.127  christos 		case V2_SUCCESS:
   1348  1.127  christos 			*current_pos = cp;
   1349  1.127  christos 			return sep;
   1350  1.127  christos 		case V2_SKIP:
   1351  1.127  christos 			/* Skip invalid definitions, freeconfig is called in parse_v2.c */
   1352  1.127  christos 			*current_pos = cp;
   1353  1.127  christos 			freeconfig(sep);
   1354  1.127  christos 			goto more;
   1355  1.127  christos 		case V2_ERROR:
   1356  1.130    rillig 			/*
   1357  1.127  christos 			 * Unrecoverable error, stop reading. freeconfig is called
   1358  1.130    rillig 			 * in parse_v2.c
   1359  1.127  christos 			 */
   1360  1.127  christos 			LOG_EARLY_ENDCONF();
   1361  1.127  christos 			freeconfig(sep);
   1362  1.127  christos 			return NULL;
   1363  1.127  christos 		}
   1364  1.127  christos 	} else if (strcmp(arg, "off") == 0 || strncmp(arg, "off#", 4) == 0) {
   1365  1.130    rillig 
   1366  1.127  christos 		if (arg[3] == '#') {
   1367  1.127  christos 			cp = nextline(fconfig);
   1368  1.127  christos 		}
   1369  1.107       tls 
   1370  1.127  christos 		/* Parse syntax the same as with 'on', but ignore the result */
   1371  1.127  christos 		switch(parse_syntax_v2(sep, &cp)) {
   1372  1.127  christos 		case V2_SUCCESS:
   1373  1.127  christos 		case V2_SKIP:
   1374  1.127  christos 			*current_pos = cp;
   1375  1.127  christos 			freeconfig(sep);
   1376  1.127  christos 			goto more;
   1377  1.127  christos 		case V2_ERROR:
   1378  1.127  christos 			/* Unrecoverable error, stop reading */
   1379  1.127  christos 			LOG_EARLY_ENDCONF();
   1380  1.127  christos 			freeconfig(sep);
   1381  1.127  christos 			return NULL;
   1382  1.127  christos 		}
   1383  1.127  christos 	} else {
   1384  1.127  christos 		/* continue parsing v1 */
   1385  1.127  christos 		parse_socktype(arg, sep);
   1386  1.127  christos 		if (sep->se_socktype == SOCK_STREAM) {
   1387  1.127  christos 			parse_accept_filter(arg, sep);
   1388  1.127  christos 		}
   1389  1.127  christos 		if (sep->se_hostaddr == NULL) {
   1390  1.127  christos 			/* Set host to current default */
   1391  1.127  christos 			sep->se_hostaddr = newstr(defhost);
   1392  1.107       tls 		}
   1393  1.107       tls 	}
   1394    1.5        pk 
   1395  1.127  christos 	/* protocol */
   1396  1.127  christos 	arg = skip(&cp);
   1397  1.127  christos 	if (arg == NULL) {
   1398  1.127  christos 		LOG_TOO_FEW_ARGS();
   1399  1.127  christos 		freeconfig(sep);
   1400  1.127  christos 		goto more;
   1401  1.127  christos 	}
   1402   1.66    itojun 	if (sep->se_type == NORM_TYPE &&
   1403   1.66    itojun 	    strncmp(arg, "faith/", strlen("faith/")) == 0) {
   1404   1.66    itojun 		arg += strlen("faith/");
   1405   1.66    itojun 		sep->se_type = FAITH_TYPE;
   1406   1.66    itojun 	}
   1407   1.66    itojun 	sep->se_proto = newstr(arg);
   1408   1.42   thorpej 
   1409   1.42   thorpej #define	MALFORMED(arg) \
   1410   1.42   thorpej do { \
   1411  1.127  christos 	ERR("%s: malformed buffer size option `%s'", \
   1412   1.42   thorpej 	    sep->se_service, (arg)); \
   1413  1.127  christos 	freeconfig(sep); \
   1414   1.42   thorpej 	goto more; \
   1415  1.110  christos 	/*NOTREACHED*/ \
   1416  1.110  christos } while (/*CONSTCOND*/0)
   1417   1.42   thorpej 
   1418   1.42   thorpej #define	GETVAL(arg) \
   1419   1.42   thorpej do { \
   1420   1.98       dsl 	if (!isdigit((unsigned char)*(arg))) \
   1421   1.42   thorpej 		MALFORMED(arg); \
   1422  1.110  christos 	val = (int)strtol((arg), &cp0, 10); \
   1423   1.42   thorpej 	if (cp0 != NULL) { \
   1424   1.42   thorpej 		if (cp0[1] != '\0') \
   1425   1.42   thorpej 			MALFORMED((arg)); \
   1426   1.42   thorpej 		if (cp0[0] == 'k') \
   1427   1.42   thorpej 			val *= 1024; \
   1428   1.42   thorpej 		if (cp0[0] == 'm') \
   1429   1.42   thorpej 			val *= 1024 * 1024; \
   1430   1.42   thorpej 	} \
   1431   1.42   thorpej 	if (val < 1) { \
   1432  1.127  christos 		ERR("%s: invalid buffer size `%s'", \
   1433   1.42   thorpej 		    sep->se_service, (arg)); \
   1434  1.127  christos 		freeconfig(sep); \
   1435   1.42   thorpej 		goto more; \
   1436   1.42   thorpej 	} \
   1437  1.110  christos 	/*NOTREACHED*/ \
   1438  1.110  christos } while (/*CONSTCOND*/0)
   1439   1.42   thorpej 
   1440   1.42   thorpej #define	ASSIGN(arg) \
   1441   1.42   thorpej do { \
   1442   1.42   thorpej 	if (strcmp((arg), "sndbuf") == 0) \
   1443   1.42   thorpej 		sep->se_sndbuf = val; \
   1444   1.42   thorpej 	else if (strcmp((arg), "rcvbuf") == 0) \
   1445   1.42   thorpej 		sep->se_rcvbuf = val; \
   1446   1.42   thorpej 	else \
   1447   1.42   thorpej 		MALFORMED((arg)); \
   1448  1.110  christos } while (/*CONSTCOND*/0)
   1449   1.42   thorpej 
   1450   1.42   thorpej 	/*
   1451   1.42   thorpej 	 * Extract the send and receive buffer sizes before parsing
   1452   1.42   thorpej 	 * the protocol.
   1453   1.42   thorpej 	 */
   1454   1.42   thorpej 	sep->se_sndbuf = sep->se_rcvbuf = 0;
   1455   1.42   thorpej 	buf0 = buf1 = sz0 = sz1 = NULL;
   1456   1.42   thorpej 	if ((buf0 = strchr(sep->se_proto, ',')) != NULL) {
   1457   1.42   thorpej 		/* Not meaningful for Tcpmux services. */
   1458   1.64    itojun 		if (ISMUX(sep)) {
   1459  1.127  christos 			ERR("%s: can't specify buffer sizes for "
   1460   1.42   thorpej 			    "tcpmux services", sep->se_service);
   1461   1.42   thorpej 			goto more;
   1462   1.42   thorpej 		}
   1463   1.42   thorpej 
   1464   1.42   thorpej 		/* Skip the , */
   1465   1.42   thorpej 		*buf0++ = '\0';
   1466   1.42   thorpej 
   1467   1.42   thorpej 		/* Check to see if another socket buffer size was specified. */
   1468   1.42   thorpej 		if ((buf1 = strchr(buf0, ',')) != NULL) {
   1469   1.42   thorpej 			/* Skip the , */
   1470   1.42   thorpej 			*buf1++ = '\0';
   1471   1.42   thorpej 
   1472   1.42   thorpej 			/* Make sure a 3rd one wasn't specified. */
   1473   1.42   thorpej 			if (strchr(buf1, ',') != NULL) {
   1474  1.127  christos 				ERR("%s: too many buffer sizes", sep->se_service);
   1475   1.42   thorpej 				goto more;
   1476   1.42   thorpej 			}
   1477   1.42   thorpej 
   1478   1.42   thorpej 			/* Locate the size. */
   1479   1.42   thorpej 			if ((sz1 = strchr(buf1, '=')) == NULL)
   1480   1.42   thorpej 				MALFORMED(buf1);
   1481   1.42   thorpej 
   1482   1.42   thorpej 			/* Skip the = */
   1483   1.42   thorpej 			*sz1++ = '\0';
   1484   1.42   thorpej 		}
   1485   1.42   thorpej 
   1486   1.42   thorpej 		/* Locate the size. */
   1487   1.42   thorpej 		if ((sz0 = strchr(buf0, '=')) == NULL)
   1488   1.42   thorpej 			MALFORMED(buf0);
   1489   1.42   thorpej 
   1490   1.42   thorpej 		/* Skip the = */
   1491   1.42   thorpej 		*sz0++ = '\0';
   1492   1.42   thorpej 
   1493   1.42   thorpej 		GETVAL(sz0);
   1494   1.42   thorpej 		ASSIGN(buf0);
   1495   1.42   thorpej 
   1496   1.42   thorpej 		if (buf1 != NULL) {
   1497   1.42   thorpej 			GETVAL(sz1);
   1498   1.42   thorpej 			ASSIGN(buf1);
   1499   1.42   thorpej 		}
   1500   1.42   thorpej 	}
   1501   1.42   thorpej 
   1502   1.42   thorpej #undef ASSIGN
   1503   1.42   thorpej #undef GETVAL
   1504   1.42   thorpej #undef MALFORMED
   1505   1.42   thorpej 
   1506  1.127  christos 	if (parse_protocol(sep)) {
   1507  1.127  christos 		freeconfig(sep);
   1508  1.127  christos 		goto more;
   1509  1.127  christos 	}
   1510  1.127  christos 
   1511  1.127  christos 	/* wait/nowait:max */
   1512  1.127  christos 	arg = skip(&cp);
   1513  1.127  christos 	if (arg == NULL) {
   1514  1.127  christos 		LOG_TOO_FEW_ARGS();
   1515  1.127  christos 		freeconfig(sep);
   1516  1.127  christos 		goto more;
   1517    1.5        pk 	}
   1518  1.127  christos 
   1519  1.127  christos 	/* Rate limiting parsing */ {
   1520  1.110  christos 		char *cp1;
   1521  1.110  christos 		if ((cp1 = strchr(arg, ':')) == NULL)
   1522  1.110  christos 			cp1 = strchr(arg, '.');
   1523  1.110  christos 		if (cp1 != NULL) {
   1524  1.127  christos 			int rstatus;
   1525  1.110  christos 			*cp1++ = '\0';
   1526  1.130    rillig 			sep->se_service_max = (size_t)strtou(cp1, NULL, 10, 0,
   1527  1.127  christos 			    SERVTAB_COUNT_MAX, &rstatus);
   1528  1.127  christos 
   1529  1.127  christos 			if (rstatus != 0) {
   1530  1.127  christos 				if (rstatus != ERANGE) {
   1531  1.127  christos 					/* For compatibility with atoi parsing */
   1532  1.127  christos 					sep->se_service_max = 0;
   1533  1.127  christos 				}
   1534  1.127  christos 
   1535  1.127  christos 				WRN("Improper \"max\" value '%s', "
   1536  1.130    rillig 				    "using '%zu' instead: %s",
   1537  1.127  christos 				    cp1,
   1538  1.127  christos 				    sep->se_service_max,
   1539  1.127  christos 				    strerror(rstatus));
   1540  1.127  christos 			}
   1541  1.127  christos 
   1542    1.5        pk 		} else
   1543  1.127  christos 			sep->se_service_max = TOOMANY;
   1544  1.127  christos 	}
   1545  1.127  christos 	if (parse_wait(sep, strcmp(arg, "wait") == 0)) {
   1546  1.127  christos 		freeconfig(sep);
   1547  1.127  christos 		goto more;
   1548  1.127  christos 	}
   1549  1.127  christos 
   1550  1.127  christos 	/* Parse user:group token */
   1551  1.127  christos 	arg = skip(&cp);
   1552  1.127  christos 	if(arg == NULL) {
   1553  1.127  christos 		LOG_TOO_FEW_ARGS();
   1554  1.127  christos 		freeconfig(sep);
   1555  1.127  christos 		goto more;
   1556  1.127  christos 	}
   1557  1.127  christos 	char* separator = strchr(arg, ':');
   1558  1.127  christos 	if (separator == NULL) {
   1559  1.127  christos 		/* Backwards compatibility, allow dot instead of colon */
   1560  1.127  christos 		separator = strchr(arg, '.');
   1561    1.5        pk 	}
   1562   1.23   mycroft 
   1563  1.127  christos 	if (separator == NULL) {
   1564  1.127  christos 		/* Only user was specified */
   1565  1.127  christos 		sep->se_group = NULL;
   1566  1.127  christos 	} else {
   1567  1.127  christos 		*separator = '\0';
   1568  1.127  christos 		sep->se_group = newstr(separator + 1);
   1569   1.23   mycroft 	}
   1570   1.55        ad 
   1571  1.127  christos 	sep->se_user = newstr(arg);
   1572    1.1       cgd 
   1573  1.127  christos 	/* Parser server-program (path to binary or "internal") */
   1574  1.127  christos 	arg = skip(&cp);
   1575  1.127  christos 	if (arg == NULL) {
   1576  1.127  christos 		LOG_TOO_FEW_ARGS();
   1577  1.127  christos 		freeconfig(sep);
   1578  1.127  christos 		goto more;
   1579  1.127  christos 	}
   1580  1.127  christos 	if (parse_server(sep, arg)) {
   1581  1.127  christos 		freeconfig(sep);
   1582  1.127  christos 		goto more;
   1583  1.127  christos 	}
   1584  1.130    rillig 
   1585    1.1       cgd 	argc = 0;
   1586    1.5        pk 	for (arg = skip(&cp); cp; arg = skip(&cp)) {
   1587    1.1       cgd 		if (argc < MAXARGV)
   1588    1.1       cgd 			sep->se_argv[argc++] = newstr(arg);
   1589    1.5        pk 	}
   1590    1.1       cgd 	while (argc <= MAXARGV)
   1591    1.1       cgd 		sep->se_argv[argc++] = NULL;
   1592   1.49    itojun #ifdef IPSEC
   1593   1.49    itojun 	sep->se_policy = policy ? newstr(policy) : NULL;
   1594   1.49    itojun #endif
   1595  1.127  christos 	/* getconfigent read a positional service def, move to next line */
   1596  1.127  christos 	*current_pos = nextline(fconfig);
   1597    1.1       cgd 	return (sep);
   1598    1.1       cgd }
   1599    1.1       cgd 
   1600  1.127  christos void
   1601   1.87      tron freeconfig(struct servtab *cp)
   1602    1.1       cgd {
   1603    1.1       cgd 	int i;
   1604    1.1       cgd 
   1605   1.16     mouse 	if (cp->se_hostaddr)
   1606   1.16     mouse 		free(cp->se_hostaddr);
   1607    1.1       cgd 	if (cp->se_service)
   1608    1.1       cgd 		free(cp->se_service);
   1609    1.1       cgd 	if (cp->se_proto)
   1610    1.1       cgd 		free(cp->se_proto);
   1611    1.1       cgd 	if (cp->se_user)
   1612    1.1       cgd 		free(cp->se_user);
   1613  1.127  christos 	if(cp->se_group)
   1614  1.127  christos 		free(cp->se_group);
   1615    1.1       cgd 	if (cp->se_server)
   1616    1.1       cgd 		free(cp->se_server);
   1617    1.1       cgd 	for (i = 0; i < MAXARGV; i++)
   1618    1.1       cgd 		if (cp->se_argv[i])
   1619    1.1       cgd 			free(cp->se_argv[i]);
   1620   1.49    itojun #ifdef IPSEC
   1621   1.49    itojun 	if (cp->se_policy)
   1622   1.49    itojun 		free(cp->se_policy);
   1623   1.49    itojun #endif
   1624    1.1       cgd }
   1625    1.1       cgd 
   1626   1.23   mycroft /*
   1627  1.127  christos  * Get next token *in the current service definition* from config file.
   1628  1.127  christos  * Allows multi-line parse if single space or single tab-indented.
   1629  1.127  christos  * Things in quotes are considered single token.
   1630  1.127  christos  * Advances cp to next token.
   1631   1.23   mycroft  */
   1632   1.87      tron static char *
   1633   1.87      tron skip(char **cpp)
   1634    1.1       cgd {
   1635   1.23   mycroft 	char *cp = *cpp;
   1636    1.1       cgd 	char *start;
   1637   1.95      cube 	char quote;
   1638    1.1       cgd 
   1639    1.5        pk 	if (*cpp == NULL)
   1640   1.85      tron 		return (NULL);
   1641    1.5        pk 
   1642    1.1       cgd again:
   1643    1.1       cgd 	while (*cp == ' ' || *cp == '\t')
   1644    1.1       cgd 		cp++;
   1645    1.1       cgd 	if (*cp == '\0') {
   1646    1.1       cgd 		int c;
   1647    1.1       cgd 
   1648    1.1       cgd 		c = getc(fconfig);
   1649    1.1       cgd 		(void) ungetc(c, fconfig);
   1650  1.130    rillig 		if (c == ' ' || c == '\t')
   1651  1.110  christos 			if ((cp = nextline(fconfig)) != NULL)
   1652    1.1       cgd 				goto again;
   1653   1.85      tron 		*cpp = NULL;
   1654   1.85      tron 		return (NULL);
   1655    1.1       cgd 	}
   1656    1.1       cgd 	start = cp;
   1657  1.127  christos 	/* Parse shell-style quotes */
   1658   1.95      cube 	quote = '\0';
   1659   1.95      cube 	while (*cp && (quote || (*cp != ' ' && *cp != '\t'))) {
   1660   1.95      cube 		if (*cp == '\'' || *cp == '"') {
   1661   1.95      cube 			if (quote && *cp != quote)
   1662   1.95      cube 				cp++;
   1663   1.95      cube 			else {
   1664   1.95      cube 				if (quote)
   1665   1.95      cube 					quote = '\0';
   1666   1.95      cube 				else
   1667   1.95      cube 					quote = *cp;
   1668   1.95      cube 				memmove(cp, cp+1, strlen(cp));
   1669   1.95      cube 			}
   1670   1.95      cube 		} else
   1671   1.95      cube 			cp++;
   1672   1.95      cube 	}
   1673    1.1       cgd 	if (*cp != '\0')
   1674    1.1       cgd 		*cp++ = '\0';
   1675    1.1       cgd 	*cpp = cp;
   1676    1.1       cgd 	return (start);
   1677    1.1       cgd }
   1678    1.1       cgd 
   1679  1.127  christos char *
   1680   1.87      tron nextline(FILE *fd)
   1681    1.1       cgd {
   1682    1.1       cgd 	char *cp;
   1683    1.1       cgd 
   1684  1.127  christos 	if (fgets(line, (int)sizeof(line), fd) == NULL) {
   1685  1.127  christos 		if (ferror(fd)) {
   1686  1.127  christos 			ERR("Error when reading next line: %s", strerror(errno));
   1687  1.127  christos 		}
   1688  1.127  christos 		return NULL;
   1689  1.127  christos 	}
   1690   1.23   mycroft 	cp = strchr(line, '\n');
   1691    1.1       cgd 	if (cp)
   1692    1.1       cgd 		*cp = '\0';
   1693  1.127  christos 	line_number++;
   1694  1.127  christos 	return line;
   1695    1.1       cgd }
   1696    1.1       cgd 
   1697  1.127  christos char *
   1698  1.110  christos newstr(const char *cp)
   1699    1.1       cgd {
   1700  1.110  christos 	char *dp;
   1701  1.110  christos 	if ((dp = strdup((cp != NULL) ? cp : "")) != NULL)
   1702  1.110  christos 		return (dp);
   1703    1.1       cgd 	syslog(LOG_ERR, "strdup: %m");
   1704  1.127  christos 	exit(EXIT_FAILURE);
   1705  1.110  christos 	/*NOTREACHED*/
   1706    1.1       cgd }
   1707    1.1       cgd 
   1708   1.87      tron static void
   1709   1.87      tron inetd_setproctitle(char *a, int s)
   1710    1.1       cgd {
   1711   1.77  christos 	socklen_t size;
   1712   1.49    itojun 	struct sockaddr_storage ss;
   1713  1.110  christos 	char hbuf[NI_MAXHOST];
   1714  1.110  christos 	const char *hp;
   1715  1.110  christos 	struct sockaddr *sa;
   1716    1.1       cgd 
   1717   1.49    itojun 	size = sizeof(ss);
   1718  1.110  christos 	sa = (struct sockaddr *)(void *)&ss;
   1719  1.110  christos 	if (getpeername(s, sa, &size) == 0) {
   1720  1.110  christos 		if (getnameinfo(sa, size, hbuf, (socklen_t)sizeof(hbuf), NULL,
   1721  1.110  christos 		    0, niflags) != 0)
   1722   1.99  christos 			hp = "?";
   1723  1.110  christos 		else
   1724  1.110  christos 			hp = hbuf;
   1725   1.99  christos 		setproctitle("-%s [%s]", a, hp);
   1726   1.49    itojun 	} else
   1727   1.77  christos 		setproctitle("-%s", a);
   1728    1.5        pk }
   1729    1.5        pk 
   1730   1.87      tron static void
   1731   1.87      tron bump_nofile(void)
   1732    1.5        pk {
   1733    1.5        pk #define FD_CHUNK	32
   1734    1.5        pk 	struct rlimit rl;
   1735    1.5        pk 
   1736    1.6        pk 	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
   1737    1.5        pk 		syslog(LOG_ERR, "getrlimit: %m");
   1738   1.36       mrg 		return;
   1739    1.5        pk 	}
   1740    1.5        pk 	rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
   1741    1.5        pk 	if (rl.rlim_cur <= rlim_ofile_cur) {
   1742    1.5        pk 		syslog(LOG_ERR,
   1743   1.23   mycroft 		    "bump_nofile: cannot extend file limit, max = %d",
   1744   1.36       mrg 		    (int)rl.rlim_cur);
   1745   1.36       mrg 		return;
   1746    1.5        pk 	}
   1747    1.5        pk 
   1748    1.6        pk 	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
   1749    1.5        pk 		syslog(LOG_ERR, "setrlimit: %m");
   1750   1.36       mrg 		return;
   1751    1.5        pk 	}
   1752    1.5        pk 
   1753    1.5        pk 	rlim_ofile_cur = rl.rlim_cur;
   1754   1.36       mrg 	return;
   1755    1.5        pk }
   1756    1.5        pk 
   1757    1.1       cgd /*
   1758    1.1       cgd  * Internet services provided internally by inetd:
   1759    1.1       cgd  */
   1760    1.5        pk #define	BUFSIZE	4096
   1761    1.1       cgd 
   1762    1.1       cgd /* ARGSUSED */
   1763   1.87      tron static void
   1764   1.87      tron echo_stream(int s, struct servtab *sep)	/* Echo service -- echo data back */
   1765    1.1       cgd {
   1766    1.1       cgd 	char buffer[BUFSIZE];
   1767  1.110  christos 	ssize_t i;
   1768    1.1       cgd 
   1769    1.9       cgd 	inetd_setproctitle(sep->se_service, s);
   1770    1.1       cgd 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
   1771  1.110  christos 	    write(s, buffer, (size_t)i) > 0)
   1772    1.1       cgd 		;
   1773    1.1       cgd }
   1774    1.1       cgd 
   1775    1.1       cgd /* ARGSUSED */
   1776   1.87      tron static void
   1777   1.87      tron echo_dg(int s, struct servtab *sep)	/* Echo service -- echo data back */
   1778    1.1       cgd {
   1779    1.1       cgd 	char buffer[BUFSIZE];
   1780  1.110  christos 	ssize_t i;
   1781   1.78    itojun 	socklen_t size;
   1782   1.54    itojun 	struct sockaddr_storage ss;
   1783   1.54    itojun 	struct sockaddr *sa;
   1784    1.1       cgd 
   1785  1.110  christos 	sa = (struct sockaddr *)(void *)&ss;
   1786   1.54    itojun 	size = sizeof(ss);
   1787   1.54    itojun 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, sa, &size)) < 0)
   1788    1.1       cgd 		return;
   1789   1.54    itojun 	if (port_good_dg(sa))
   1790  1.110  christos 		(void) sendto(s, buffer, (size_t)i, 0, sa, size);
   1791    1.1       cgd }
   1792    1.1       cgd 
   1793    1.1       cgd /* ARGSUSED */
   1794   1.87      tron static void
   1795   1.87      tron discard_stream(int s, struct servtab *sep) /* Discard service -- ignore data */
   1796    1.1       cgd {
   1797    1.1       cgd 	char buffer[BUFSIZE];
   1798    1.1       cgd 
   1799    1.9       cgd 	inetd_setproctitle(sep->se_service, s);
   1800    1.5        pk 	while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
   1801    1.5        pk 			errno == EINTR)
   1802    1.5        pk 		;
   1803    1.1       cgd }
   1804    1.1       cgd 
   1805    1.1       cgd /* ARGSUSED */
   1806   1.87      tron static void
   1807   1.87      tron discard_dg(int s, struct servtab *sep)	/* Discard service -- ignore data */
   1808  1.130    rillig 
   1809    1.1       cgd {
   1810    1.1       cgd 	char buffer[BUFSIZE];
   1811    1.1       cgd 
   1812    1.1       cgd 	(void) read(s, buffer, sizeof(buffer));
   1813    1.1       cgd }
   1814    1.1       cgd 
   1815    1.1       cgd #define LINESIZ 72
   1816    1.1       cgd char ring[128];
   1817    1.1       cgd char *endring;
   1818    1.1       cgd 
   1819   1.87      tron static void
   1820   1.87      tron initring(void)
   1821    1.1       cgd {
   1822   1.23   mycroft 	int i;
   1823    1.1       cgd 
   1824    1.1       cgd 	endring = ring;
   1825    1.1       cgd 
   1826    1.1       cgd 	for (i = 0; i <= 128; ++i)
   1827    1.1       cgd 		if (isprint(i))
   1828    1.1       cgd 			*endring++ = i;
   1829    1.1       cgd }
   1830    1.1       cgd 
   1831    1.1       cgd /* ARGSUSED */
   1832   1.87      tron static void
   1833   1.87      tron chargen_stream(int s,struct servtab *sep)	/* Character generator */
   1834    1.1       cgd {
   1835  1.110  christos 	size_t len;
   1836   1.23   mycroft 	char *rs, text[LINESIZ+2];
   1837    1.1       cgd 
   1838    1.9       cgd 	inetd_setproctitle(sep->se_service, s);
   1839    1.1       cgd 
   1840    1.1       cgd 	if (!endring) {
   1841    1.1       cgd 		initring();
   1842    1.1       cgd 		rs = ring;
   1843    1.1       cgd 	}
   1844    1.1       cgd 
   1845    1.1       cgd 	text[LINESIZ] = '\r';
   1846    1.1       cgd 	text[LINESIZ + 1] = '\n';
   1847    1.1       cgd 	for (rs = ring;;) {
   1848    1.1       cgd 		if ((len = endring - rs) >= LINESIZ)
   1849   1.23   mycroft 			memmove(text, rs, LINESIZ);
   1850    1.1       cgd 		else {
   1851   1.23   mycroft 			memmove(text, rs, len);
   1852   1.23   mycroft 			memmove(text + len, ring, LINESIZ - len);
   1853    1.1       cgd 		}
   1854    1.1       cgd 		if (++rs == endring)
   1855    1.1       cgd 			rs = ring;
   1856    1.1       cgd 		if (write(s, text, sizeof(text)) != sizeof(text))
   1857    1.1       cgd 			break;
   1858    1.1       cgd 	}
   1859    1.1       cgd }
   1860    1.1       cgd 
   1861    1.1       cgd /* ARGSUSED */
   1862   1.87      tron static void
   1863   1.87      tron chargen_dg(int s, struct servtab *sep)		/* Character generator */
   1864    1.1       cgd {
   1865   1.54    itojun 	struct sockaddr_storage ss;
   1866   1.54    itojun 	struct sockaddr *sa;
   1867    1.1       cgd 	static char *rs;
   1868  1.110  christos 	size_t len;
   1869   1.78    itojun 	socklen_t size;
   1870    1.1       cgd 	char text[LINESIZ+2];
   1871    1.1       cgd 
   1872    1.1       cgd 	if (endring == 0) {
   1873    1.1       cgd 		initring();
   1874    1.1       cgd 		rs = ring;
   1875    1.1       cgd 	}
   1876    1.1       cgd 
   1877  1.110  christos 	sa = (struct sockaddr *)(void *)&ss;
   1878   1.54    itojun 	size = sizeof(ss);
   1879   1.54    itojun 	if (recvfrom(s, text, sizeof(text), 0, sa, &size) < 0)
   1880    1.1       cgd 		return;
   1881    1.1       cgd 
   1882   1.54    itojun 	if (!port_good_dg(sa))
   1883   1.47       hwr 		return;
   1884   1.47       hwr 
   1885    1.1       cgd 	if ((len = endring - rs) >= LINESIZ)
   1886   1.23   mycroft 		memmove(text, rs, LINESIZ);
   1887    1.1       cgd 	else {
   1888   1.23   mycroft 		memmove(text, rs, len);
   1889   1.23   mycroft 		memmove(text + len, ring, LINESIZ - len);
   1890    1.1       cgd 	}
   1891    1.1       cgd 	if (++rs == endring)
   1892    1.1       cgd 		rs = ring;
   1893    1.1       cgd 	text[LINESIZ] = '\r';
   1894    1.1       cgd 	text[LINESIZ + 1] = '\n';
   1895   1.54    itojun 	(void) sendto(s, text, sizeof(text), 0, sa, size);
   1896    1.1       cgd }
   1897    1.1       cgd 
   1898    1.1       cgd /*
   1899    1.1       cgd  * Return a machine readable date and time, in the form of the
   1900    1.1       cgd  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
   1901    1.1       cgd  * returns the number of seconds since midnight, Jan 1, 1970,
   1902    1.1       cgd  * we must add 2208988800 seconds to this figure to make up for
   1903    1.1       cgd  * some seventy years Bell Labs was asleep.
   1904    1.1       cgd  */
   1905    1.1       cgd 
   1906   1.87      tron static uint32_t
   1907   1.87      tron machtime(void)
   1908    1.1       cgd {
   1909    1.1       cgd 	struct timeval tv;
   1910    1.1       cgd 
   1911   1.85      tron 	if (gettimeofday(&tv, NULL) < 0) {
   1912  1.127  christos 		DPRINTF("Unable to get time of day");
   1913   1.75       abs 		return (0);
   1914    1.1       cgd 	}
   1915   1.75       abs #define	OFFSET ((uint32_t)25567 * 24*60*60)
   1916   1.75       abs 	return (htonl((uint32_t)(tv.tv_sec + OFFSET)));
   1917   1.23   mycroft #undef OFFSET
   1918    1.1       cgd }
   1919    1.1       cgd 
   1920    1.1       cgd /* ARGSUSED */
   1921   1.87      tron static void
   1922   1.87      tron machtime_stream(int s, struct servtab *sep)
   1923    1.1       cgd {
   1924   1.75       abs 	uint32_t result;
   1925    1.1       cgd 
   1926    1.1       cgd 	result = machtime();
   1927  1.110  christos 	(void) write(s, &result, sizeof(result));
   1928    1.1       cgd }
   1929    1.1       cgd 
   1930    1.1       cgd /* ARGSUSED */
   1931   1.23   mycroft void
   1932   1.87      tron machtime_dg(int s, struct servtab *sep)
   1933    1.1       cgd {
   1934   1.75       abs 	uint32_t result;
   1935   1.54    itojun 	struct sockaddr_storage ss;
   1936   1.54    itojun 	struct sockaddr *sa;
   1937   1.78    itojun 	socklen_t size;
   1938    1.1       cgd 
   1939  1.110  christos 	sa = (struct sockaddr *)(void *)&ss;
   1940   1.54    itojun 	size = sizeof(ss);
   1941  1.110  christos 	if (recvfrom(s, &result, sizeof(result), 0, sa, &size) < 0)
   1942    1.1       cgd 		return;
   1943   1.54    itojun 	if (!port_good_dg(sa))
   1944   1.47       hwr 		return;
   1945    1.1       cgd 	result = machtime();
   1946  1.110  christos 	(void)sendto(s, &result, sizeof(result), 0, sa, size);
   1947    1.1       cgd }
   1948    1.1       cgd 
   1949    1.1       cgd /* ARGSUSED */
   1950   1.87      tron static void
   1951   1.87      tron daytime_stream(int s,struct servtab *sep)
   1952   1.87      tron /* Return human-readable time of day */
   1953    1.1       cgd {
   1954    1.1       cgd 	char buffer[256];
   1955  1.110  christos 	time_t clk;
   1956   1.12       mrg 	int len;
   1957    1.1       cgd 
   1958  1.110  christos 	clk = time((time_t *) 0);
   1959    1.1       cgd 
   1960  1.110  christos 	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clk));
   1961   1.12       mrg 	(void) write(s, buffer, len);
   1962    1.1       cgd }
   1963    1.1       cgd 
   1964    1.1       cgd /* ARGSUSED */
   1965   1.23   mycroft void
   1966   1.87      tron daytime_dg(int s, struct servtab *sep)
   1967   1.87      tron /* Return human-readable time of day */
   1968    1.1       cgd {
   1969    1.1       cgd 	char buffer[256];
   1970  1.110  christos 	time_t clk;
   1971   1.54    itojun 	struct sockaddr_storage ss;
   1972   1.54    itojun 	struct sockaddr *sa;
   1973   1.78    itojun 	socklen_t size;
   1974   1.78    itojun 	int len;
   1975    1.1       cgd 
   1976  1.110  christos 	clk = time((time_t *) 0);
   1977    1.1       cgd 
   1978  1.110  christos 	sa = (struct sockaddr *)(void *)&ss;
   1979   1.54    itojun 	size = sizeof(ss);
   1980   1.54    itojun 	if (recvfrom(s, buffer, sizeof(buffer), 0, sa, &size) < 0)
   1981    1.1       cgd 		return;
   1982   1.54    itojun 	if (!port_good_dg(sa))
   1983   1.47       hwr 		return;
   1984  1.110  christos 	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clk));
   1985   1.54    itojun 	(void) sendto(s, buffer, len, 0, sa, size);
   1986    1.1       cgd }
   1987    1.1       cgd 
   1988  1.127  christos #ifdef DEBUG_ENABLE
   1989    1.1       cgd /*
   1990    1.1       cgd  * print_service:
   1991    1.1       cgd  *	Dump relevant information to stderr
   1992    1.1       cgd  */
   1993   1.87      tron static void
   1994  1.110  christos print_service(const char *action, struct servtab *sep)
   1995    1.1       cgd {
   1996   1.78    itojun 
   1997    1.5        pk 	if (isrpcservice(sep))
   1998    1.5        pk 		fprintf(stderr,
   1999  1.127  christos 		    "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%zu, user:group=%s:%s builtin=%lx server=%s"
   2000   1.49    itojun #ifdef IPSEC
   2001   1.49    itojun 		    " policy=\"%s\""
   2002   1.49    itojun #endif
   2003   1.49    itojun 		    "\n",
   2004    1.5        pk 		    action, sep->se_service,
   2005    1.5        pk 		    sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
   2006  1.127  christos 		    sep->se_wait, sep->se_service_max, sep->se_user, sep->se_group,
   2007   1.49    itojun 		    (long)sep->se_bi, sep->se_server
   2008   1.49    itojun #ifdef IPSEC
   2009   1.49    itojun 		    , (sep->se_policy ? sep->se_policy : "")
   2010   1.49    itojun #endif
   2011   1.49    itojun 		    );
   2012    1.5        pk 	else
   2013    1.5        pk 		fprintf(stderr,
   2014  1.127  christos 		    "%s: %s:%s proto=%s%s, wait.max=%d.%zu, user:group=%s:%s builtin=%lx server=%s"
   2015   1.49    itojun #ifdef IPSEC
   2016   1.49    itojun 		    " policy=%s"
   2017   1.49    itojun #endif
   2018   1.49    itojun 		    "\n",
   2019  1.127  christos 		    action, sep->se_hostaddr, sep->se_service,
   2020   1.66    itojun 		    sep->se_type == FAITH_TYPE ? "faith/" : "",
   2021   1.66    itojun 		    sep->se_proto,
   2022  1.127  christos 		    sep->se_wait, sep->se_service_max, sep->se_user, sep->se_group,
   2023   1.49    itojun 		    (long)sep->se_bi, sep->se_server
   2024   1.49    itojun #ifdef IPSEC
   2025   1.49    itojun 		    , (sep->se_policy ? sep->se_policy : "")
   2026   1.49    itojun #endif
   2027   1.49    itojun 		    );
   2028    1.5        pk }
   2029  1.127  christos #endif
   2030    1.5        pk 
   2031   1.87      tron static void
   2032   1.87      tron usage(void)
   2033   1.23   mycroft {
   2034   1.23   mycroft #ifdef LIBWRAP
   2035   1.73       cgd 	(void)fprintf(stderr, "usage: %s [-dl] [conf]\n", getprogname());
   2036   1.23   mycroft #else
   2037   1.73       cgd 	(void)fprintf(stderr, "usage: %s [-d] [conf]\n", getprogname());
   2038   1.23   mycroft #endif
   2039  1.127  christos 	exit(EXIT_FAILURE);
   2040   1.23   mycroft }
   2041   1.23   mycroft 
   2042   1.23   mycroft 
   2043   1.23   mycroft /*
   2044   1.23   mycroft  *  Based on TCPMUX.C by Mark K. Lottor November 1988
   2045   1.23   mycroft  *  sri-nic::ps:<mkl>tcpmux.c
   2046   1.23   mycroft  */
   2047   1.23   mycroft 
   2048   1.23   mycroft static int		/* # of characters upto \r,\n or \0 */
   2049  1.113       roy get_line(int fd,	char *buf, int len)
   2050   1.23   mycroft {
   2051  1.110  christos 	int count = 0;
   2052  1.110  christos 	ssize_t n;
   2053   1.23   mycroft 
   2054   1.23   mycroft 	do {
   2055   1.23   mycroft 		n = read(fd, buf, len-count);
   2056   1.23   mycroft 		if (n == 0)
   2057   1.23   mycroft 			return (count);
   2058   1.23   mycroft 		if (n < 0)
   2059   1.23   mycroft 			return (-1);
   2060   1.23   mycroft 		while (--n >= 0) {
   2061   1.23   mycroft 			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
   2062   1.23   mycroft 				return (count);
   2063   1.23   mycroft 			count++;
   2064   1.23   mycroft 			buf++;
   2065   1.23   mycroft 		}
   2066   1.23   mycroft 	} while (count < len);
   2067   1.23   mycroft 	return (count);
   2068   1.23   mycroft }
   2069   1.23   mycroft 
   2070   1.23   mycroft #define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
   2071   1.23   mycroft 
   2072   1.23   mycroft #define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
   2073   1.23   mycroft 
   2074   1.87      tron static void
   2075   1.87      tron tcpmux(int ctrl, struct servtab *sep)
   2076   1.23   mycroft {
   2077   1.23   mycroft 	char service[MAX_SERV_LEN+1];
   2078   1.23   mycroft 	int len;
   2079   1.23   mycroft 
   2080   1.23   mycroft 	/* Get requested service name */
   2081  1.113       roy 	if ((len = get_line(ctrl, service, MAX_SERV_LEN)) < 0) {
   2082   1.30   mycroft 		strwrite(ctrl, "-Error reading service name\r\n");
   2083   1.30   mycroft 		goto reject;
   2084   1.23   mycroft 	}
   2085   1.23   mycroft 	service[len] = '\0';
   2086   1.23   mycroft 
   2087  1.127  christos 	DPRINTF("tcpmux: %s: service requested", service);
   2088   1.23   mycroft 
   2089   1.23   mycroft 	/*
   2090   1.23   mycroft 	 * Help is a required command, and lists available services,
   2091   1.23   mycroft 	 * one per line.
   2092   1.23   mycroft 	 */
   2093   1.23   mycroft 	if (!strcasecmp(service, "help")) {
   2094   1.31   mycroft 		strwrite(ctrl, "+Available services:\r\n");
   2095   1.31   mycroft 		strwrite(ctrl, "help\r\n");
   2096   1.85      tron 		for (sep = servtab; sep != NULL; sep = sep->se_next) {
   2097   1.23   mycroft 			if (!ISMUX(sep))
   2098   1.23   mycroft 				continue;
   2099   1.30   mycroft 			(void)write(ctrl, sep->se_service,
   2100   1.30   mycroft 			    strlen(sep->se_service));
   2101   1.30   mycroft 			strwrite(ctrl, "\r\n");
   2102   1.23   mycroft 		}
   2103   1.30   mycroft 		goto reject;
   2104   1.23   mycroft 	}
   2105   1.23   mycroft 
   2106   1.23   mycroft 	/* Try matching a service in inetd.conf with the request */
   2107   1.85      tron 	for (sep = servtab; sep != NULL; sep = sep->se_next) {
   2108   1.23   mycroft 		if (!ISMUX(sep))
   2109   1.23   mycroft 			continue;
   2110   1.23   mycroft 		if (!strcasecmp(service, sep->se_service)) {
   2111   1.30   mycroft 			if (ISMUXPLUS(sep))
   2112   1.30   mycroft 				strwrite(ctrl, "+Go\r\n");
   2113  1.105  dholland 			run_service(ctrl, sep, 1 /* forked */);
   2114   1.30   mycroft 			return;
   2115   1.23   mycroft 		}
   2116   1.23   mycroft 	}
   2117   1.30   mycroft 	strwrite(ctrl, "-Service not available\r\n");
   2118   1.30   mycroft reject:
   2119  1.127  christos 	_exit(EXIT_FAILURE);
   2120   1.23   mycroft }
   2121   1.23   mycroft 
   2122   1.47       hwr /*
   2123   1.71    itojun  * check if the address/port where send data to is one of the obvious ports
   2124   1.47       hwr  * that are used for denial of service attacks like two echo ports
   2125   1.47       hwr  * just echoing data between them
   2126   1.47       hwr  */
   2127   1.87      tron static int
   2128   1.87      tron port_good_dg(struct sockaddr *sa)
   2129   1.47       hwr {
   2130   1.71    itojun 	struct in_addr in;
   2131  1.110  christos 	struct sockaddr_in *sin;
   2132   1.71    itojun #ifdef INET6
   2133   1.71    itojun 	struct in6_addr *in6;
   2134  1.110  christos 	struct sockaddr_in6 *sin6;
   2135   1.71    itojun #endif
   2136   1.47       hwr 	u_int16_t port;
   2137  1.110  christos 	int i;
   2138   1.57    itojun 	char hbuf[NI_MAXHOST];
   2139   1.47       hwr 
   2140   1.54    itojun 	switch (sa->sa_family) {
   2141   1.54    itojun 	case AF_INET:
   2142  1.110  christos 		sin = (struct sockaddr_in *)(void *)sa;
   2143  1.110  christos 		in.s_addr = ntohl(sin->sin_addr.s_addr);
   2144  1.110  christos 		port = ntohs(sin->sin_port);
   2145   1.97        pk #ifdef INET6
   2146   1.71    itojun 	v4chk:
   2147   1.97        pk #endif
   2148   1.71    itojun 		if (IN_MULTICAST(in.s_addr))
   2149   1.71    itojun 			goto bad;
   2150   1.71    itojun 		switch ((in.s_addr & 0xff000000) >> 24) {
   2151   1.71    itojun 		case 0: case 127: case 255:
   2152   1.71    itojun 			goto bad;
   2153   1.71    itojun 		}
   2154   1.82    itojun 		if (dg_broadcast(&in))
   2155   1.82    itojun 			goto bad;
   2156   1.54    itojun 		break;
   2157   1.58    itojun #ifdef INET6
   2158   1.54    itojun 	case AF_INET6:
   2159  1.110  christos 		sin6 = (struct sockaddr_in6 *)(void *)sa;
   2160  1.110  christos 		in6 = &sin6->sin6_addr;
   2161  1.110  christos 		port = ntohs(sin6->sin6_port);
   2162   1.71    itojun 		if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
   2163   1.71    itojun 			goto bad;
   2164   1.71    itojun 		if (IN6_IS_ADDR_V4MAPPED(in6) || IN6_IS_ADDR_V4COMPAT(in6)) {
   2165   1.71    itojun 			memcpy(&in, &in6->s6_addr[12], sizeof(in));
   2166   1.71    itojun 			in.s_addr = ntohl(in.s_addr);
   2167   1.71    itojun 			goto v4chk;
   2168   1.71    itojun 		}
   2169   1.54    itojun 		break;
   2170   1.58    itojun #endif
   2171   1.54    itojun 	default:
   2172   1.54    itojun 		/* XXX unsupported af, is it safe to assume it to be safe? */
   2173   1.87      tron 		return (1);
   2174   1.54    itojun 	}
   2175   1.47       hwr 
   2176   1.71    itojun 	for (i = 0; bad_ports[i] != 0; i++) {
   2177   1.71    itojun 		if (port == bad_ports[i])
   2178   1.71    itojun 			goto bad;
   2179   1.71    itojun 	}
   2180   1.47       hwr 
   2181   1.71    itojun 	return (1);
   2182   1.71    itojun 
   2183   1.71    itojun bad:
   2184  1.110  christos 	if (getnameinfo(sa, sa->sa_len, hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
   2185   1.80    itojun 	    niflags) != 0)
   2186   1.92    itojun 		strlcpy(hbuf, "?", sizeof(hbuf));
   2187   1.71    itojun 	syslog(LOG_WARNING,"Possible DoS attack from %s, Port %d",
   2188   1.71    itojun 		hbuf, port);
   2189   1.82    itojun 	return (0);
   2190   1.82    itojun }
   2191   1.82    itojun 
   2192   1.82    itojun /* XXX need optimization */
   2193   1.87      tron static int
   2194   1.87      tron dg_broadcast(struct in_addr *in)
   2195   1.82    itojun {
   2196   1.82    itojun 	struct ifaddrs *ifa, *ifap;
   2197   1.82    itojun 	struct sockaddr_in *sin;
   2198   1.82    itojun 
   2199   1.82    itojun 	if (getifaddrs(&ifap) < 0)
   2200   1.82    itojun 		return (0);
   2201   1.82    itojun 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
   2202   1.82    itojun 		if (ifa->ifa_addr->sa_family != AF_INET ||
   2203   1.82    itojun 		    (ifa->ifa_flags & IFF_BROADCAST) == 0)
   2204   1.82    itojun 			continue;
   2205  1.110  christos 		sin = (struct sockaddr_in *)(void *)ifa->ifa_broadaddr;
   2206   1.82    itojun 		if (sin->sin_addr.s_addr == in->s_addr) {
   2207   1.82    itojun 			freeifaddrs(ifap);
   2208   1.82    itojun 			return (1);
   2209   1.82    itojun 		}
   2210   1.82    itojun 	}
   2211   1.82    itojun 	freeifaddrs(ifap);
   2212   1.71    itojun 	return (0);
   2213   1.85      tron }
   2214   1.85      tron 
   2215   1.85      tron static int
   2216   1.85      tron my_kevent(const struct kevent *changelist, size_t nchanges,
   2217   1.85      tron     struct kevent *eventlist, size_t nevents)
   2218   1.85      tron {
   2219   1.85      tron 	int	result;
   2220   1.85      tron 
   2221   1.85      tron 	while ((result = kevent(kq, changelist, nchanges, eventlist, nevents,
   2222   1.85      tron 	    NULL)) < 0)
   2223   1.85      tron 		if (errno != EINTR) {
   2224   1.85      tron 			syslog(LOG_ERR, "kevent: %m");
   2225   1.85      tron 			exit(EXIT_FAILURE);
   2226   1.85      tron 		}
   2227   1.85      tron 
   2228   1.85      tron 	return (result);
   2229   1.87      tron }
   2230   1.87      tron 
   2231   1.87      tron static struct kevent *
   2232   1.87      tron allocchange(void)
   2233   1.87      tron {
   2234  1.127  christos 	if (changes == __arraycount(changebuf)) {
   2235  1.127  christos 		(void) my_kevent(changebuf, __arraycount(changebuf), NULL, 0);
   2236   1.87      tron 		changes = 0;
   2237   1.87      tron 	}
   2238   1.87      tron 
   2239   1.87      tron 	return (&changebuf[changes++]);
   2240   1.47       hwr }
   2241  1.127  christos 
   2242  1.127  christos static void
   2243  1.127  christos config_root()
   2244  1.127  christos {
   2245  1.127  christos 	struct servtab *sep;
   2246  1.127  christos 	/* Uncheck services */
   2247  1.127  christos 	for (sep = servtab; sep != NULL; sep = sep->se_next) {
   2248  1.127  christos 		sep->se_checked = 0;
   2249  1.127  christos 	}
   2250  1.127  christos 	defhost = newstr("*");
   2251  1.127  christos #ifdef IPSEC
   2252  1.127  christos 	policy = NULL;
   2253  1.127  christos #endif
   2254  1.127  christos 	fconfig = NULL;
   2255  1.127  christos 	config();
   2256  1.127  christos 	purge_unchecked();
   2257  1.127  christos }
   2258  1.127  christos 
   2259  1.130    rillig static void
   2260  1.130    rillig purge_unchecked(void)
   2261  1.127  christos {
   2262  1.127  christos 	struct servtab *sep, **sepp = &servtab;
   2263  1.127  christos 	int servtab_count = 0;
   2264  1.127  christos 	while ((sep = *sepp) != NULL) {
   2265  1.127  christos 		if (sep->se_checked) {
   2266  1.127  christos 			sepp = &sep->se_next;
   2267  1.127  christos 			servtab_count++;
   2268  1.127  christos 			continue;
   2269  1.127  christos 		}
   2270  1.127  christos 		*sepp = sep->se_next;
   2271  1.127  christos 		if (sep->se_fd >= 0)
   2272  1.127  christos 			close_sep(sep);
   2273  1.127  christos 		if (isrpcservice(sep))
   2274  1.127  christos 			unregister_rpc(sep);
   2275  1.127  christos 		if (sep->se_family == AF_LOCAL)
   2276  1.127  christos 			(void)unlink(sep->se_service);
   2277  1.127  christos #ifdef DEBUG_ENABLE
   2278  1.127  christos 		if (debug)
   2279  1.127  christos 			print_service("FREE", sep);
   2280  1.127  christos #endif
   2281  1.127  christos 		freeconfig(sep);
   2282  1.127  christos 		free(sep);
   2283  1.127  christos 	}
   2284  1.127  christos 	DPRINTF("%d service(s) loaded.", servtab_count);
   2285  1.127  christos }
   2286  1.127  christos 
   2287  1.127  christos static bool
   2288  1.130    rillig is_same_service(const struct servtab *sep, const struct servtab *cp)
   2289  1.127  christos {
   2290  1.130    rillig 	return
   2291  1.127  christos 	    strcmp(sep->se_service, cp->se_service) == 0 &&
   2292  1.127  christos 	    strcmp(sep->se_hostaddr, cp->se_hostaddr) == 0 &&
   2293  1.127  christos 	    strcmp(sep->se_proto, cp->se_proto) == 0 &&
   2294  1.127  christos 	    sep->se_family == cp->se_family &&
   2295  1.127  christos 	    ISMUX(sep) == ISMUX(cp);
   2296  1.127  christos }
   2297  1.127  christos 
   2298  1.130    rillig int
   2299  1.127  christos parse_protocol(struct servtab *sep)
   2300  1.130    rillig {
   2301  1.127  christos 	int val;
   2302  1.127  christos 
   2303  1.127  christos 	if (strcmp(sep->se_proto, "unix") == 0) {
   2304  1.127  christos 		sep->se_family = AF_LOCAL;
   2305  1.127  christos 	} else {
   2306  1.127  christos 		val = (int)strlen(sep->se_proto);
   2307  1.127  christos 		if (!val) {
   2308  1.127  christos 			ERR("%s: invalid protocol specified",
   2309  1.127  christos 			    sep->se_service);
   2310  1.127  christos 			return -1;
   2311  1.127  christos 		}
   2312  1.127  christos 		val = sep->se_proto[val - 1];
   2313  1.127  christos 		switch (val) {
   2314  1.127  christos 		case '4':	/*tcp4 or udp4*/
   2315  1.127  christos 			sep->se_family = AF_INET;
   2316  1.127  christos 			break;
   2317  1.127  christos #ifdef INET6
   2318  1.127  christos 		case '6':	/*tcp6 or udp6*/
   2319  1.127  christos 			sep->se_family = AF_INET6;
   2320  1.127  christos 			break;
   2321  1.127  christos #endif
   2322  1.127  christos 		default:
   2323  1.127  christos 			/* Use 'default' IP version which is IPv4, may eventually be
   2324  1.127  christos 			 * changed to AF_INET6 */
   2325  1.127  christos 			sep->se_family = AF_INET;
   2326  1.127  christos 			break;
   2327  1.127  christos 		}
   2328  1.127  christos 		if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
   2329  1.127  christos #ifdef RPC
   2330  1.127  christos 			char *cp1, *ccp;
   2331  1.127  christos 			cp1 = strchr(sep->se_service, '/');
   2332  1.127  christos 			if (cp1 == 0) {
   2333  1.127  christos 				ERR("%s: no rpc version",
   2334  1.127  christos 				    sep->se_service);
   2335  1.127  christos 				return -1;
   2336  1.127  christos 			}
   2337  1.127  christos 			*cp1++ = '\0';
   2338  1.127  christos 			sep->se_rpcversl = sep->se_rpcversh =
   2339  1.127  christos 			    (int)strtol(cp1, &ccp, 0);
   2340  1.127  christos 			if (ccp == cp1) {
   2341  1.127  christos 		badafterall:
   2342  1.127  christos 				ERR("%s/%s: bad rpc version",
   2343  1.127  christos 				    sep->se_service, cp1);
   2344  1.127  christos 				return -1;
   2345  1.127  christos 			}
   2346  1.127  christos 			if (*ccp == '-') {
   2347  1.127  christos 				cp1 = ccp + 1;
   2348  1.127  christos 				sep->se_rpcversh = (int)strtol(cp1, &ccp, 0);
   2349  1.127  christos 				if (ccp == cp1)
   2350  1.127  christos 					goto badafterall;
   2351  1.127  christos 			}
   2352  1.127  christos #else
   2353  1.127  christos 			ERR("%s: rpc services not supported",
   2354  1.127  christos 			    sep->se_service);
   2355  1.127  christos 			return -1;
   2356  1.127  christos #endif /* RPC */
   2357  1.127  christos 		}
   2358  1.127  christos 	}
   2359  1.127  christos 	return 0;
   2360  1.127  christos }
   2361  1.127  christos 
   2362  1.127  christos int
   2363  1.127  christos parse_wait(struct servtab *sep, int wait)
   2364  1.127  christos {
   2365  1.127  christos 	if (!ISMUX(sep)) {
   2366  1.127  christos 		sep->se_wait = wait;
   2367  1.127  christos 		return 0;
   2368  1.127  christos 	}
   2369  1.127  christos 	/*
   2370  1.127  christos 	 * Silently enforce "nowait" for TCPMUX services since
   2371  1.127  christos 	 * they don't have an assigned port to listen on.
   2372  1.127  christos 	 */
   2373  1.127  christos 	sep->se_wait = 0;
   2374  1.127  christos 
   2375  1.127  christos 	if (strncmp(sep->se_proto, "tcp", 3)) {
   2376  1.127  christos 		ERR("bad protocol for tcpmux service %s",
   2377  1.127  christos 			sep->se_service);
   2378  1.127  christos 		return -1;
   2379  1.127  christos 	}
   2380  1.127  christos 	if (sep->se_socktype != SOCK_STREAM) {
   2381  1.127  christos 		ERR("bad socket type for tcpmux service %s",
   2382  1.127  christos 		    sep->se_service);
   2383  1.127  christos 		return -1;
   2384  1.127  christos 	}
   2385  1.127  christos 	return 0;
   2386  1.127  christos }
   2387  1.127  christos 
   2388  1.127  christos int
   2389  1.127  christos parse_server(struct servtab *sep, const char *arg){
   2390  1.127  christos 	sep->se_server = newstr(arg);
   2391  1.129   mlelstv 	if (strcmp(sep->se_server, "internal") != 0) {
   2392  1.127  christos 		sep->se_bi = NULL;
   2393  1.127  christos 		return 0;
   2394  1.127  christos 	}
   2395  1.127  christos 	struct biltin *bi;
   2396  1.127  christos 
   2397  1.127  christos 	for (bi = biltins; bi->bi_service; bi++)
   2398  1.127  christos 		if (bi->bi_socktype == sep->se_socktype &&
   2399  1.127  christos 		    strcmp(bi->bi_service, sep->se_service) == 0)
   2400  1.127  christos 			break;
   2401  1.129   mlelstv 	if (bi->bi_service == NULL) {
   2402  1.127  christos 		ERR("Internal service %s unknown",
   2403  1.127  christos 		    sep->se_service);
   2404  1.127  christos 		return -1;
   2405  1.127  christos 	}
   2406  1.127  christos 	sep->se_bi = bi;
   2407  1.127  christos 	sep->se_wait = bi->bi_wait;
   2408  1.127  christos 	return 0;
   2409  1.127  christos }
   2410  1.127  christos 
   2411  1.127  christos /* TODO test to make sure accept filter still works */
   2412  1.130    rillig void
   2413  1.127  christos parse_accept_filter(char *arg, struct servtab *sep) {
   2414  1.127  christos 	char *accf, *accf_arg;
   2415  1.127  christos 	/* one and only one accept filter */
   2416  1.130    rillig 	accf = strchr(arg, ':');
   2417  1.127  christos 	if (!accf)
   2418  1.127  christos 		return;
   2419  1.127  christos 	if (accf != strrchr(arg, ':') || *(accf + 1) == '\0') {
   2420  1.127  christos 		/* more than one ||  nothing beyond */
   2421  1.127  christos 		sep->se_socktype = -1;
   2422  1.127  christos 		return;
   2423  1.127  christos 	}
   2424  1.127  christos 
   2425  1.127  christos 	accf++;			/* skip delimiter */
   2426  1.127  christos 	strlcpy(sep->se_accf.af_name, accf, sizeof(sep->se_accf.af_name));
   2427  1.127  christos 	accf_arg = strchr(accf, ',');
   2428  1.127  christos 	if (!accf_arg)		/* zero or one arg, no more */
   2429  1.127  christos 		return;
   2430  1.127  christos 
   2431  1.127  christos 	if (strrchr(accf, ',') != accf_arg) {
   2432  1.127  christos 		sep->se_socktype = -1;
   2433  1.127  christos 	} else {
   2434  1.127  christos 		accf_arg++;
   2435  1.127  christos 		strlcpy(sep->se_accf.af_arg, accf_arg,
   2436  1.127  christos 		    sizeof(sep->se_accf.af_arg));
   2437  1.127  christos 	}
   2438  1.127  christos }
   2439  1.127  christos 
   2440  1.130    rillig void
   2441  1.127  christos parse_socktype(char* arg, struct servtab* sep) {
   2442  1.127  christos 	/* stream socket may have an accept filter, only check first chars */
   2443  1.127  christos 	if (strncmp(arg, "stream", sizeof("stream") - 1) == 0)
   2444  1.127  christos 		sep->se_socktype = SOCK_STREAM;
   2445  1.127  christos 	else if (strcmp(arg, "dgram") == 0)
   2446  1.127  christos 		sep->se_socktype = SOCK_DGRAM;
   2447  1.127  christos 	else if (strcmp(arg, "rdm") == 0)
   2448  1.127  christos 		sep->se_socktype = SOCK_RDM;
   2449  1.127  christos 	else if (strcmp(arg, "seqpacket") == 0)
   2450  1.127  christos 		sep->se_socktype = SOCK_SEQPACKET;
   2451  1.127  christos 	else if (strcmp(arg, "raw") == 0)
   2452  1.127  christos 		sep->se_socktype = SOCK_RAW;
   2453  1.127  christos 	else
   2454  1.127  christos 		sep->se_socktype = -1;
   2455  1.127  christos }
   2456  1.127  christos 
   2457  1.130    rillig static struct servtab
   2458  1.127  christos init_servtab() {
   2459  1.127  christos 	/* This does not set every field to default. See enter() as well */
   2460  1.127  christos 	return (struct servtab) {
   2461  1.130    rillig 		/*
   2462  1.127  christos 		 * Set se_max to non-zero so uninitialized value is not
   2463  1.130    rillig 	 	 * a valid value. Useful in v2 syntax parsing.
   2464  1.127  christos 		 */
   2465  1.127  christos 		.se_service_max = SERVTAB_UNSPEC_SIZE_T,
   2466  1.127  christos 		.se_ip_max = SERVTAB_UNSPEC_SIZE_T,
   2467  1.127  christos 		.se_wait = SERVTAB_UNSPEC_VAL,
   2468  1.127  christos 		.se_socktype = SERVTAB_UNSPEC_VAL
   2469  1.127  christos 		/* All other fields initialized to 0 or null */
   2470  1.127  christos 	};
   2471  1.127  christos }
   2472  1.127  christos 
   2473  1.127  christos /* Include directives bookkeeping structure */
   2474  1.127  christos struct file_list {
   2475  1.127  christos 	/* Absolute path used for checking for circular references */
   2476  1.127  christos 	char *abs;
   2477  1.127  christos 	/* Pointer to the absolute path of the parent config file,
   2478  1.127  christos 	 * on the stack */
   2479  1.127  christos 	struct file_list *next;
   2480  1.127  christos } *file_list_head;
   2481  1.127  christos 
   2482  1.127  christos static void
   2483  1.127  christos include_configs(char *pattern)
   2484  1.127  christos {
   2485  1.127  christos 	/* Allocate global per-config state on the thread stack */
   2486  1.127  christos 	const char* save_CONFIG;
   2487  1.127  christos 	FILE	*save_fconfig;
   2488  1.127  christos 	size_t	save_line_number;
   2489  1.127  christos 	char    *save_defhost;
   2490  1.127  christos 	struct	file_list new_file;
   2491  1.127  christos #ifdef IPSEC
   2492  1.127  christos 	char *save_policy;
   2493  1.127  christos #endif
   2494  1.127  christos 
   2495  1.127  christos 	/* Store current globals on the stack */
   2496  1.127  christos 	save_CONFIG = CONFIG;
   2497  1.127  christos 	save_fconfig = fconfig;
   2498  1.127  christos 	save_line_number = line_number;
   2499  1.127  christos 	save_defhost = defhost;
   2500  1.127  christos 	new_file.abs = realpath(CONFIG, NULL);
   2501  1.127  christos 	new_file.next = file_list_head;
   2502  1.127  christos #ifdef IPSEC
   2503  1.127  christos 	save_policy = policy;
   2504  1.127  christos #endif
   2505  1.127  christos 	/* Put new_file at the top of the config stack */
   2506  1.127  christos 	file_list_head = &new_file;
   2507  1.127  christos 	read_glob_configs(pattern);
   2508  1.127  christos 	free((void *)new_file.abs);
   2509  1.127  christos 	/* Pop new_file off the stack */
   2510  1.127  christos 	file_list_head = new_file.next;
   2511  1.127  christos 
   2512  1.127  christos 	/* Restore global per-config state */
   2513  1.127  christos 	CONFIG = save_CONFIG;
   2514  1.127  christos 	fconfig = save_fconfig;
   2515  1.127  christos 	line_number = save_line_number;
   2516  1.127  christos 	defhost = save_defhost;
   2517  1.127  christos #ifdef IPSEC
   2518  1.127  christos 	policy = save_policy;
   2519  1.127  christos #endif
   2520  1.127  christos }
   2521  1.127  christos 
   2522  1.130    rillig static void
   2523  1.127  christos prepare_next_config(const char *file_name)
   2524  1.127  christos {
   2525  1.127  christos 	/* Setup new state that is normally only done in main */
   2526  1.127  christos 	CONFIG = file_name;
   2527  1.127  christos 
   2528  1.127  christos 	/* Inherit default host and IPsec policy */
   2529  1.127  christos 	defhost = newstr(defhost);
   2530  1.127  christos 
   2531  1.127  christos #ifdef IPSEC
   2532  1.127  christos 	policy = (policy == NULL) ? NULL : newstr(policy);
   2533  1.127  christos #endif
   2534  1.127  christos }
   2535  1.127  christos 
   2536  1.127  christos static void
   2537  1.127  christos read_glob_configs(char *pattern) {
   2538  1.127  christos 	glob_t results;
   2539  1.127  christos 	char *full_pattern;
   2540  1.127  christos 	int glob_result;
   2541  1.127  christos 	full_pattern = gen_file_pattern(CONFIG, pattern);
   2542  1.127  christos 
   2543  1.127  christos 	DPRINTCONF("Found include directive '%s'", full_pattern);
   2544  1.127  christos 
   2545  1.127  christos 	glob_result = glob(full_pattern, GLOB_NOSORT, glob_error, &results);
   2546  1.127  christos 	switch(glob_result) {
   2547  1.127  christos 	case 0:
   2548  1.127  christos 		/* No glob errors */
   2549  1.127  christos 		break;
   2550  1.127  christos 	case GLOB_ABORTED:
   2551  1.127  christos 		ERR("Error while searching for include files");
   2552  1.127  christos 		break;
   2553  1.127  christos 	case GLOB_NOMATCH:
   2554  1.127  christos 		/* It's fine if no files were matched. */
   2555  1.127  christos 		DPRINTCONF("No files matched pattern '%s'", full_pattern);
   2556  1.127  christos 		break;
   2557  1.127  christos 	case GLOB_NOSPACE:
   2558  1.127  christos 		ERR("Error when searching for include files: %s",
   2559  1.127  christos 		    strerror(errno));
   2560  1.127  christos 		break;
   2561  1.127  christos 	default:
   2562  1.127  christos 		ERR("Unknown glob(3) error %d", errno);
   2563  1.127  christos 		break;
   2564  1.127  christos 	}
   2565  1.127  christos 	free(full_pattern);
   2566  1.127  christos 
   2567  1.127  christos 	for (size_t i = 0; i < results.gl_pathc; i++) {
   2568  1.127  christos 		include_matched_path(results.gl_pathv[i]);
   2569  1.127  christos 	}
   2570  1.127  christos 
   2571  1.127  christos 	globfree(&results);
   2572  1.127  christos }
   2573  1.127  christos 
   2574  1.127  christos static void
   2575  1.127  christos include_matched_path(char *glob_path)
   2576  1.127  christos {
   2577  1.127  christos 	struct stat sb;
   2578  1.127  christos 	char *tmp;
   2579  1.127  christos 
   2580  1.127  christos 	if (lstat(glob_path, &sb)) {
   2581  1.127  christos 		ERR("Error calling stat on path '%s': %s", glob_path,
   2582  1.127  christos 		    strerror(errno));
   2583  1.127  christos 		return;
   2584  1.127  christos 	}
   2585  1.127  christos 
   2586  1.127  christos 	if (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode)) {
   2587  1.127  christos 		DPRINTCONF("'%s' is not a file.", glob_path);
   2588  1.127  christos 		ERR("The matched path '%s' is not a regular file", glob_path);
   2589  1.127  christos 		return;
   2590  1.127  christos 	}
   2591  1.127  christos 
   2592  1.127  christos 	DPRINTCONF("Include '%s'", glob_path);
   2593  1.127  christos 
   2594  1.127  christos 	if (S_ISLNK(sb.st_mode)) {
   2595  1.127  christos 		tmp = glob_path;
   2596  1.127  christos 		glob_path = realpath(tmp, NULL);
   2597  1.127  christos 	}
   2598  1.127  christos 
   2599  1.127  christos 	/* Ensure the file is not being reincluded .*/
   2600  1.127  christos 	if (check_no_reinclude(glob_path)) {
   2601  1.127  christos 		prepare_next_config(glob_path);
   2602  1.127  christos 		config();
   2603  1.127  christos 	} else {
   2604  1.127  christos 		DPRINTCONF("File '%s' already included in current include "
   2605  1.127  christos 		    "chain", glob_path);
   2606  1.127  christos 		WRN("Including file '%s' would cause a circular "
   2607  1.127  christos 		    "dependency", glob_path);
   2608  1.127  christos 	}
   2609  1.127  christos 
   2610  1.127  christos 	if (S_ISLNK(sb.st_mode)) {
   2611  1.127  christos 		free(glob_path);
   2612  1.127  christos 		glob_path = tmp;
   2613  1.127  christos 	}
   2614  1.127  christos }
   2615  1.127  christos 
   2616  1.127  christos static bool
   2617  1.127  christos check_no_reinclude(const char *glob_path)
   2618  1.127  christos {
   2619  1.127  christos 	struct file_list *cur = file_list_head;
   2620  1.127  christos 	char *abs_path = realpath(glob_path, NULL);
   2621  1.127  christos 
   2622  1.127  christos 	if (abs_path == NULL) {
   2623  1.127  christos 		ERR("Error checking real path for '%s': %s",
   2624  1.127  christos 			glob_path, strerror(errno));
   2625  1.127  christos 		return false;
   2626  1.127  christos 	}
   2627  1.127  christos 
   2628  1.127  christos 	DPRINTCONF("Absolute path '%s'", abs_path);
   2629  1.127  christos 
   2630  1.127  christos 	for (cur = file_list_head; cur != NULL; cur = cur->next) {
   2631  1.127  christos 		if (strcmp(cur->abs, abs_path) == 0) {
   2632  1.127  christos 			/* file included more than once */
   2633  1.127  christos 			/* TODO relative or abs path for logging error? */
   2634  1.127  christos 			free(abs_path);
   2635  1.127  christos 			return false;
   2636  1.127  christos 		}
   2637  1.127  christos 	}
   2638  1.127  christos 	free(abs_path);
   2639  1.127  christos 	return true;
   2640  1.127  christos }
   2641  1.127  christos 
   2642  1.127  christos /* Resolve the pattern relative to the config file the pattern is from  */
   2643  1.130    rillig static char *
   2644  1.127  christos gen_file_pattern(const char *cur_config, const char *pattern)
   2645  1.127  christos {
   2646  1.127  christos 	if(pattern[0] == '/') {
   2647  1.127  christos 		/* Absolute paths don't need any normalization */
   2648  1.127  christos 		return newstr(pattern);
   2649  1.127  christos 	}
   2650  1.127  christos 
   2651  1.127  christos 	/* pattern is relative */
   2652  1.127  christos 	/* Find the end of the file's directory */
   2653  1.127  christos 	int i, last = 0;
   2654  1.127  christos 	for (i = 0; cur_config[i] != '\0'; i++) {
   2655  1.127  christos 		if (cur_config[i] == '/') {
   2656  1.127  christos 			last = i;
   2657  1.127  christos 		}
   2658  1.127  christos 	}
   2659  1.127  christos 
   2660  1.127  christos 	if (last == 0) {
   2661  1.127  christos 		/* cur_config is just a filename, pattern already correct */
   2662  1.127  christos 		return newstr(pattern);
   2663  1.130    rillig 	}
   2664  1.127  christos 
   2665  1.127  christos 	/* Relativize pattern to cur_config file's directory */
   2666  1.127  christos 	char *full_pattern = malloc(last + 1 + strlen(pattern) + 1);
   2667  1.127  christos 	if (full_pattern == NULL) {
   2668  1.127  christos 		syslog(LOG_ERR, "Out of memory.");
   2669  1.127  christos 		exit(EXIT_FAILURE);
   2670  1.127  christos 	}
   2671  1.127  christos 	memcpy(full_pattern, cur_config, last);
   2672  1.127  christos 	full_pattern[last] = '/';
   2673  1.127  christos 	strcpy(&full_pattern[last + 1], pattern);
   2674  1.127  christos 	return full_pattern;
   2675  1.127  christos }
   2676  1.127  christos 
   2677  1.127  christos static int
   2678  1.130    rillig glob_error(const char *path, int error)
   2679  1.127  christos {
   2680  1.127  christos 	WRN("Error while resolving path '%s': %s", path, strerror(error));
   2681  1.127  christos 	return 0;
   2682  1.127  christos }
   2683  1.127  christos 
   2684  1.127  christos /* Return 0 on allow, -1 if connection should be blocked */
   2685  1.127  christos static int
   2686  1.127  christos rl_process(struct servtab *sep, int ctrl)
   2687  1.127  christos {
   2688  1.127  christos 	struct se_ip_list_node *node;
   2689  1.127  christos 	time_t now = 0; /* 0 prevents GCC from complaining */
   2690  1.127  christos 	bool istimevalid = false;
   2691  1.127  christos 	char hbuf[NI_MAXHOST];
   2692  1.127  christos 
   2693  1.127  christos 	DPRINTF(SERV_FMT ": processing rate-limiting",
   2694  1.127  christos 	    SERV_PARAMS(sep));
   2695  1.127  christos 	DPRINTF(SERV_FMT ": se_service_max "
   2696  1.127  christos 	    "%zu and se_count %zu", SERV_PARAMS(sep),
   2697  1.127  christos 	    sep->se_service_max, sep->se_count);
   2698  1.127  christos 
   2699  1.127  christos 	/* se_count is incremented if rl_process will return 0 */
   2700  1.127  christos 	if (sep->se_count == 0) {
   2701  1.127  christos 		now = rl_time();
   2702  1.127  christos 		sep->se_time = now;
   2703  1.127  christos 		istimevalid = true;
   2704  1.127  christos 	}
   2705  1.130    rillig 
   2706  1.127  christos 	if (sep->se_count >= sep->se_service_max) {
   2707  1.127  christos 		if(!istimevalid) {
   2708  1.127  christos 			now = rl_time();
   2709  1.127  christos 			istimevalid = true;
   2710  1.127  christos 		}
   2711  1.130    rillig 
   2712  1.127  christos 		if (now - sep->se_time > CNT_INTVL) {
   2713  1.127  christos 			rl_reset(sep, now);
   2714  1.127  christos 		} else {
   2715  1.127  christos 			syslog(LOG_ERR,
   2716  1.128  christos                             SERV_FMT ": max spawn rate (%zu in %ji seconds) "
   2717  1.127  christos                             "already met, closing until end of timeout in "
   2718  1.128  christos 			    "%ju seconds",
   2719  1.127  christos                             SERV_PARAMS(sep),
   2720  1.127  christos                             sep->se_service_max,
   2721  1.127  christos 			    (intmax_t)CNT_INTVL,
   2722  1.127  christos 			    (uintmax_t)RETRYTIME);
   2723  1.127  christos 
   2724  1.127  christos 			DPRINTF(SERV_FMT ": service not started",
   2725  1.127  christos 			    SERV_PARAMS(sep));
   2726  1.127  christos 
   2727  1.127  christos 			rl_drop_connection(sep, ctrl);
   2728  1.127  christos 
   2729  1.127  christos 			/* Close the server for 10 minutes */
   2730  1.127  christos 			close_sep(sep);
   2731  1.127  christos 			if (!timingout) {
   2732  1.127  christos 				timingout = 1;
   2733  1.127  christos 				alarm(RETRYTIME);
   2734  1.127  christos 			}
   2735  1.127  christos 
   2736  1.127  christos 			return -1;
   2737  1.127  christos 		}
   2738  1.127  christos 	}
   2739  1.127  christos 
   2740  1.127  christos 	if (sep->se_ip_max != SERVTAB_UNSPEC_SIZE_T) {
   2741  1.127  christos 		rl_get_name(sep, ctrl, hbuf);
   2742  1.127  christos 		node = rl_try_get_ip(sep, hbuf);
   2743  1.127  christos 		if(node == NULL) {
   2744  1.127  christos 			node = rl_add(sep, hbuf);
   2745  1.127  christos 		}
   2746  1.127  christos 
   2747  1.127  christos 		DPRINTF(
   2748  1.127  christos 		    SERV_FMT ": se_ip_max %zu and ip_count %zu",
   2749  1.127  christos 		    SERV_PARAMS(sep), sep->se_ip_max, node->count);
   2750  1.130    rillig 
   2751  1.127  christos 		if (node->count >= sep->se_ip_max) {
   2752  1.127  christos 			if (!istimevalid) {
   2753  1.130    rillig 				/*
   2754  1.127  christos 				 * Only get the clock time if we didn't
   2755  1.130    rillig 				 * already
   2756  1.127  christos 				 */
   2757  1.127  christos 				now = rl_time();
   2758  1.127  christos 				istimevalid = true;
   2759  1.127  christos 			}
   2760  1.130    rillig 
   2761  1.127  christos 			if (now - sep->se_time > CNT_INTVL) {
   2762  1.127  christos 				rl_reset(sep, now);
   2763  1.127  christos 				node = rl_add(sep, hbuf);
   2764  1.127  christos 			} else {
   2765  1.127  christos 				if (debug && node->count == sep->se_ip_max) {
   2766  1.127  christos 					/*
   2767  1.127  christos 					 * Only log first failed request to
   2768  1.127  christos 					 * prevent DoS attack writing to system
   2769  1.127  christos 					 * log
   2770  1.127  christos 					 */
   2771  1.127  christos 					syslog(LOG_ERR, SERV_FMT
   2772  1.130    rillig 					    ": max ip spawn rate (%zu in "
   2773  1.128  christos 					    "%ji seconds) for "
   2774  1.127  christos 					    "%." TOSTRING(NI_MAXHOST) "s "
   2775  1.127  christos 					    "already met; service not started",
   2776  1.127  christos 					    SERV_PARAMS(sep),
   2777  1.127  christos 					    sep->se_ip_max,
   2778  1.127  christos 					    (intmax_t)CNT_INTVL,
   2779  1.127  christos 					    node->address);
   2780  1.127  christos 				}
   2781  1.127  christos 
   2782  1.130    rillig 				DPRINTF(SERV_FMT ": service not started",
   2783  1.127  christos    				    SERV_PARAMS(sep));
   2784  1.127  christos 
   2785  1.127  christos 				rl_drop_connection(sep, ctrl);
   2786  1.127  christos 				/*
   2787  1.127  christos 				 * Increment so debug-syslog message will
   2788  1.130    rillig 				 * trigger only once
   2789  1.127  christos 				 */
   2790  1.127  christos 				node->count++;
   2791  1.127  christos 				return -1;
   2792  1.127  christos 			}
   2793  1.127  christos 		}
   2794  1.127  christos 		node->count++;
   2795  1.127  christos 	}
   2796  1.127  christos 
   2797  1.127  christos 	DPRINTF(SERV_FMT ": running service ", SERV_PARAMS(sep));
   2798  1.127  christos 
   2799  1.127  christos 	sep->se_count++;
   2800  1.127  christos 	return 0;
   2801  1.127  christos }
   2802  1.127  christos 
   2803  1.127  christos /* Get the remote's IP address in textual form into hbuf of size NI_MAXHOST */
   2804  1.127  christos static void
   2805  1.127  christos rl_get_name(struct servtab *sep, int ctrl, char *hbuf)
   2806  1.127  christos {
   2807  1.127  christos 	struct sockaddr_storage addr;
   2808  1.127  christos 	socklen_t len = sizeof(struct sockaddr_storage);
   2809  1.127  christos 	switch (sep->se_socktype) {
   2810  1.127  christos 	case SOCK_STREAM:
   2811  1.130    rillig 		if (getpeername(ctrl, (struct sockaddr *)&addr, &len)) {
   2812  1.127  christos 			/* error, log it and skip ip rate limiting */
   2813  1.127  christos 			syslog(LOG_ERR,
   2814  1.127  christos 				SERV_FMT " failed to get peer name of the "
   2815  1.127  christos 				"connection", SERV_PARAMS(sep));
   2816  1.127  christos 			exit(EXIT_FAILURE);
   2817  1.127  christos 		}
   2818  1.127  christos 		break;
   2819  1.127  christos 	case SOCK_DGRAM: {
   2820  1.127  christos 		struct msghdr header = {
   2821  1.127  christos 			.msg_name = &addr,
   2822  1.127  christos 			.msg_namelen = sizeof(struct sockaddr_storage),
   2823  1.127  christos 			/* scatter/gather and control info is null */
   2824  1.127  christos 		};
   2825  1.127  christos 		int count;
   2826  1.130    rillig 
   2827  1.127  christos 		/* Peek so service can still get the packet */
   2828  1.127  christos 		count = recvmsg(ctrl, &header, MSG_PEEK);
   2829  1.127  christos 		if (count == -1) {
   2830  1.127  christos 			syslog(LOG_ERR,
   2831  1.127  christos 			    "failed to get dgram source address: %s; exiting",
   2832  1.127  christos 			    strerror(errno));
   2833  1.127  christos 			exit(EXIT_FAILURE);
   2834  1.127  christos 		}
   2835  1.127  christos 		break;
   2836  1.127  christos 	}
   2837  1.127  christos 	default:
   2838  1.127  christos 		DPRINTF(SERV_FMT ": ip_max rate limiting not supported for "
   2839  1.127  christos 		    "socktype", SERV_PARAMS(sep));
   2840  1.127  christos 		syslog(LOG_ERR, SERV_FMT
   2841  1.127  christos 		    ": ip_max rate limiting not supported for socktype",
   2842  1.127  christos 		    SERV_PARAMS(sep));
   2843  1.127  christos 		exit(EXIT_FAILURE);
   2844  1.127  christos 	}
   2845  1.127  christos 
   2846  1.130    rillig 	if (getnameinfo((struct sockaddr *)&addr,
   2847  1.127  christos 		addr.ss_len, hbuf,
   2848  1.127  christos 		NI_MAXHOST, NULL, 0, NI_NUMERICHOST)) {
   2849  1.127  christos 		/* error, log it and skip ip rate limiting */
   2850  1.127  christos 		syslog(LOG_ERR,
   2851  1.127  christos 		    SERV_FMT ": failed to get name info of the incoming "
   2852  1.127  christos 		    "connection; exiting",
   2853  1.127  christos 		    SERV_PARAMS(sep));
   2854  1.127  christos 		exit(EXIT_FAILURE);
   2855  1.127  christos 	}
   2856  1.127  christos }
   2857  1.127  christos 
   2858  1.127  christos static void
   2859  1.127  christos rl_drop_connection(struct servtab *sep, int ctrl)
   2860  1.127  christos {
   2861  1.127  christos 
   2862  1.127  christos 	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
   2863  1.130    rillig 		/*
   2864  1.130    rillig 		 * If the fd isn't a listen socket,
   2865  1.130    rillig 		 * close the individual connection too.
   2866  1.127  christos 		 */
   2867  1.127  christos 		close(ctrl);
   2868  1.127  christos 		return;
   2869  1.127  christos 	}
   2870  1.127  christos 	if (sep->se_socktype != SOCK_DGRAM) {
   2871  1.127  christos 		return;
   2872  1.127  christos 	}
   2873  1.130    rillig 	/*
   2874  1.127  christos 	 * Drop the single datagram the service would have
   2875  1.127  christos 	 * consumed if nowait. If this is a wait service, this
   2876  1.127  christos 	 * will consume 1 datagram, and further received packets
   2877  1.127  christos 	 * will be removed in the same way.
   2878  1.127  christos 	 */
   2879  1.127  christos 	struct msghdr header = {
   2880  1.127  christos 		/* All fields null, just consume one message */
   2881  1.127  christos 	};
   2882  1.127  christos 	int count;
   2883  1.130    rillig 
   2884  1.127  christos 	count = recvmsg(ctrl, &header, 0);
   2885  1.127  christos 	if (count == -1) {
   2886  1.127  christos 		syslog(LOG_ERR,
   2887  1.127  christos 		    SERV_FMT ": failed to consume nowait dgram: %s",
   2888  1.127  christos 		    SERV_PARAMS(sep), strerror(errno));
   2889  1.127  christos 		exit(EXIT_FAILURE);
   2890  1.127  christos 	}
   2891  1.130    rillig 	DPRINTF(SERV_FMT ": dropped dgram message",
   2892  1.127  christos 	    SERV_PARAMS(sep));
   2893  1.127  christos }
   2894  1.127  christos 
   2895  1.130    rillig static time_t
   2896  1.127  christos rl_time()
   2897  1.127  christos {
   2898  1.127  christos 	struct timespec time;
   2899  1.127  christos 	if(clock_gettime(CLOCK_MONOTONIC, &time) == -1) {
   2900  1.127  christos 		syslog(LOG_ERR, "clock_gettime for rate limiting failed: %s; "
   2901  1.127  christos 		    "exiting", strerror(errno));
   2902  1.127  christos 		/* Exit inetd if rate limiting fails */
   2903  1.127  christos 		exit(EXIT_FAILURE);
   2904  1.127  christos 	}
   2905  1.127  christos 	return time.tv_sec;
   2906  1.127  christos }
   2907  1.127  christos 
   2908  1.127  christos static struct se_ip_list_node*
   2909  1.127  christos rl_add(struct servtab *sep, char* ip)
   2910  1.127  christos {
   2911  1.127  christos 	DPRINTF(
   2912  1.127  christos 	    SERV_FMT ": add ip %s to rate limiting tracking",
   2913  1.127  christos 	    SERV_PARAMS(sep), ip);
   2914  1.127  christos 
   2915  1.130    rillig 	/*
   2916  1.127  christos 	 * TODO memory could be saved by using a variable length malloc
   2917  1.127  christos 	 * with only the length of ip instead of the existing address field
   2918  1.127  christos 	 * NI_MAXHOST in length.
   2919  1.127  christos 	 */
   2920  1.127  christos 	struct se_ip_list_node* temp = malloc(sizeof(*temp));
   2921  1.127  christos 	if (temp == NULL) {
   2922  1.127  christos 		syslog(LOG_ERR, "Out of memory.");
   2923  1.127  christos 		exit(EXIT_FAILURE);
   2924  1.127  christos 	}
   2925  1.127  christos 	temp->count = 0;
   2926  1.127  christos 	temp->next = NULL;
   2927  1.127  christos 	strlcpy(temp->address, ip, sizeof(temp->address));
   2928  1.127  christos 
   2929  1.127  christos 	if (sep->se_ip_list_head == NULL) {
   2930  1.127  christos 		/* List empty, insert as head */
   2931  1.127  christos 		sep->se_ip_list_head = temp;
   2932  1.127  christos 	} else {
   2933  1.127  christos 		/* List not empty, insert as head, point next to prev head */
   2934  1.127  christos 		temp->next = sep->se_ip_list_head;
   2935  1.127  christos 		sep->se_ip_list_head = temp;
   2936  1.127  christos 	}
   2937  1.127  christos 
   2938  1.127  christos 	return temp;
   2939  1.127  christos }
   2940  1.127  christos 
   2941  1.127  christos static void
   2942  1.127  christos rl_reset(struct servtab *sep, time_t now)
   2943  1.127  christos {
   2944  1.130    rillig 	DPRINTF(SERV_FMT ": %ji seconds passed; resetting rate limiting ",
   2945  1.127  christos 	    SERV_PARAMS(sep), (intmax_t)(now - sep->se_time));
   2946  1.127  christos 
   2947  1.127  christos 	sep->se_count = 0;
   2948  1.127  christos 	sep->se_time = now;
   2949  1.127  christos 	if (sep->se_ip_max != SERVTAB_UNSPEC_SIZE_T) {
   2950  1.127  christos 		clear_ip_list(sep);
   2951  1.127  christos 	}
   2952  1.127  christos }
   2953  1.127  christos 
   2954  1.127  christos static void
   2955  1.127  christos clear_ip_list(struct servtab *sep) {
   2956  1.127  christos 	struct se_ip_list_node *curr, *next;
   2957  1.127  christos 	curr = sep->se_ip_list_head;
   2958  1.127  christos 
   2959  1.127  christos 	while (curr != NULL) {
   2960  1.127  christos 		next = curr->next;
   2961  1.127  christos 		free(curr);
   2962  1.127  christos 		curr = next;
   2963  1.127  christos 	}
   2964  1.127  christos 	sep->se_ip_list_head = NULL;
   2965  1.127  christos }
   2966  1.127  christos 
   2967  1.127  christos static struct se_ip_list_node *
   2968  1.127  christos rl_try_get_ip(struct servtab *sep, char *ip)
   2969  1.127  christos {
   2970  1.130    rillig 	struct se_ip_list_node *curr;
   2971  1.127  christos 
   2972  1.127  christos 	DPRINTF(
   2973  1.127  christos 	    SERV_FMT ": look up ip %s for ip_max rate limiting",
   2974  1.127  christos 	    SERV_PARAMS(sep), ip);
   2975  1.127  christos 
   2976  1.127  christos 	for (curr = sep->se_ip_list_head; curr != NULL; curr = curr->next) {
   2977  1.127  christos 		if (!strncmp(curr->address, ip, NI_MAXHOST)) {
   2978  1.127  christos 			/* IP addr match */
   2979  1.127  christos 			return curr;
   2980  1.127  christos 		}
   2981  1.127  christos 	}
   2982  1.127  christos 	return NULL;
   2983  1.127  christos }
   2984