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