inetd.c revision 1.27
1/*	$NetBSD: inetd.c,v 1.27 1997/03/13 18:19:35 mycroft Exp $	*/
2
3/*
4 * Copyright (c) 1983, 1991, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#ifndef lint
37static char copyright[] =
38"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
39	The Regents of the University of California.  All rights reserved.\n";
40#endif /* not lint */
41
42#ifndef lint
43#if 0
44static char sccsid[] = "@(#)inetd.c	8.4 (Berkeley) 4/13/94";
45#else
46static char rcsid[] = "$NetBSD: inetd.c,v 1.27 1997/03/13 18:19:35 mycroft Exp $";
47#endif
48#endif /* not lint */
49
50/*
51 * Inetd - Internet super-server
52 *
53 * This program invokes all internet services as needed.  Connection-oriented
54 * services are invoked each time a connection is made, by creating a process.
55 * This process is passed the connection as file descriptor 0 and is expected
56 * to do a getpeername to find out the source host and port.
57 *
58 * Datagram oriented services are invoked when a datagram
59 * arrives; a process is created and passed a pending message
60 * on file descriptor 0.  Datagram servers may either connect
61 * to their peer, freeing up the original socket for inetd
62 * to receive further messages on, or ``take over the socket'',
63 * processing all arriving datagrams and, eventually, timing
64 * out.	 The first type of server is said to be ``multi-threaded'';
65 * the second type of server ``single-threaded''.
66 *
67 * Inetd uses a configuration file which is read at startup
68 * and, possibly, at some later time in response to a hangup signal.
69 * The configuration file is ``free format'' with fields given in the
70 * order shown below.  Continuation lines for an entry must being with
71 * a space or tab.  All fields must be present in each entry.
72 *
73 *	service name			must be in /etc/services or must
74 *					name a tcpmux service
75 *	socket type			stream/dgram/raw/rdm/seqpacket
76 *	protocol			must be in /etc/protocols
77 *	wait/nowait[.max]		single-threaded/multi-threaded, max #
78 *	user[.group]			user/group to run daemon as
79 *	server program			full path name
80 *	server program arguments	maximum of MAXARGS (20)
81 *
82 * For RPC services
83 *      service name/version            must be in /etc/rpc
84 *	socket type			stream/dgram/raw/rdm/seqpacket
85 *	protocol			must be in /etc/protocols
86 *	wait/nowait[.max]		single-threaded/multi-threaded
87 *	user[.group]			user to run daemon as
88 *	server program			full path name
89 *	server program arguments	maximum of MAXARGS (20)
90 *
91 * For non-RPC services, the "service name" can be of the form
92 * hostaddress:servicename, in which case the hostaddress is used
93 * as the host portion of the address to listen on.  If hostaddress
94 * consists of a single `*' character, INADDR_ANY is used.
95 *
96 * A line can also consist of just
97 *	hostaddress:
98 * where hostaddress is as in the preceding paragraph.  Such a line must
99 * have no further fields; the specified hostaddress is remembered and
100 * used for all further lines that have no hostaddress specified,
101 * until the next such line (or EOF).  (This is why * is provided to
102 * allow explicit specification of INADDR_ANY.)  A line
103 *	*:
104 * is implicitly in effect at the beginning of the file.
105 *
106 * The hostaddress specifier may (and often will) contain dots;
107 * the service name must not.
108 *
109 * For RPC services, host-address specifiers are accepted and will
110 * work to some extent; however, because of limitations in the
111 * portmapper interface, it will not work to try to give more than
112 * one line for any given RPC service, even if the host-address
113 * specifiers are different.
114 *
115 * TCP services without official port numbers are handled with the
116 * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
117 * requests. When a connection is made from a foreign host, the service
118 * requested is passed to tcpmux, which looks it up in the servtab list
119 * and returns the proper entry for the service. Tcpmux returns a
120 * negative reply if the service doesn't exist, otherwise the invoked
121 * server is expected to return the positive reply if the service type in
122 * inetd.conf file has the prefix "tcpmux/". If the service type has the
123 * prefix "tcpmux/+", tcpmux will return the positive reply for the
124 * process; this is for compatibility with older server code, and also
125 * allows you to invoke programs that use stdin/stdout without putting any
126 * special server code in them. Services that use tcpmux are "nowait"
127 * because they do not have a well-known port and hence cannot listen
128 * for new requests.
129 *
130 * Comment lines are indicated by a `#' in column 1.
131 */
132
133/*
134 * Here's the scoop concerning the user.group feature:
135 *
136 * 1) set-group-option off.
137 *
138 * 	a) user = root:	NO setuid() or setgid() is done
139 *
140 * 	b) other:	setuid()
141 * 			setgid(primary group as found in passwd)
142 * 			initgroups(name, primary group)
143 *
144 * 2) set-group-option on.
145 *
146 * 	a) user = root:	NO setuid()
147 * 			setgid(specified group)
148 * 			NO initgroups()
149 *
150 * 	b) other:	setuid()
151 * 			setgid(specified group)
152 * 			initgroups(name, specified group)
153 *
154 */
155
156#include <sys/param.h>
157#include <sys/stat.h>
158#include <sys/ioctl.h>
159#include <sys/socket.h>
160#include <sys/un.h>
161#include <sys/wait.h>
162#include <sys/time.h>
163#include <sys/resource.h>
164
165#ifndef RLIMIT_NOFILE
166#define RLIMIT_NOFILE	RLIMIT_OFILE
167#endif
168
169#define RPC
170
171#include <netinet/in.h>
172#include <arpa/inet.h>
173#ifdef RPC
174#include <rpc/rpc.h>
175#endif
176
177#include <errno.h>
178#include <grp.h>
179#include <netdb.h>
180#include <pwd.h>
181#include <signal.h>
182#include <stdio.h>
183#include <stdlib.h>
184#include <string.h>
185#include <syslog.h>
186#include <unistd.h>
187
188#include "pathnames.h"
189
190#ifdef LIBWRAP
191# include <tcpd.h>
192#ifndef LIBWRAP_ALLOW_FACILITY
193# define LIBWRAP_ALLOW_FACILITY LOG_AUTH
194#endif
195#ifndef LIBWRAP_ALLOW_SEVERITY
196# define LIBWRAP_ALLOW_SEVERITY LOG_INFO
197#endif
198#ifndef LIBWRAP_DENY_FACILITY
199# define LIBWRAP_DENY_FACILITY LOG_AUTH
200#endif
201#ifndef LIBWRAP_DENY_SEVERITY
202# define LIBWRAP_DENY_SEVERITY LOG_WARNING
203#endif
204int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
205int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
206#endif
207
208#define	TOOMANY		40		/* don't start more than TOOMANY */
209#define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
210#define	RETRYTIME	(60*10)		/* retry after bind or server fail */
211
212#define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
213
214int	debug;
215#ifdef LIBWRAP
216int	lflag;
217#endif
218int	nsock, maxsock;
219fd_set	allsock;
220int	options;
221int	timingout;
222struct	servent *sp;
223char	*curdom;
224
225#ifndef OPEN_MAX
226#define OPEN_MAX	64
227#endif
228
229/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
230#define FD_MARGIN	(8)
231typeof(((struct rlimit *)0)->rlim_cur)	rlim_ofile_cur = OPEN_MAX;
232
233#ifdef RLIMIT_NOFILE
234struct rlimit	rlim_ofile;
235#endif
236
237struct	servtab {
238	char	*se_hostaddr;		/* host address to listen on */
239	char	*se_service;		/* name of service */
240	int	se_socktype;		/* type of socket to use */
241	int	se_family;		/* address family */
242	char	*se_proto;		/* protocol used */
243	int	se_rpcprog;		/* rpc program number */
244	int	se_rpcversl;		/* rpc program lowest version */
245	int	se_rpcversh;		/* rpc program highest version */
246#define isrpcservice(sep)	((sep)->se_rpcversl != 0)
247	short	se_wait;		/* single threaded server */
248	short	se_checked;		/* looked at during merge */
249	char	*se_user;		/* user name to run as */
250	char	*se_group;		/* group name to run as */
251	struct	biltin *se_bi;		/* if built-in, description */
252	char	*se_server;		/* server program */
253#define	MAXARGV 20
254	char	*se_argv[MAXARGV+1];	/* program arguments */
255	int	se_fd;			/* open descriptor */
256	int	se_type;		/* type */
257	union {
258		struct	sockaddr se_un_ctrladdr;
259		struct	sockaddr_in se_un_ctrladdr_in;
260		struct	sockaddr_un se_un_ctrladdr_un;
261	} se_un;			/* bound address */
262#define se_ctrladdr	se_un.se_un_ctrladdr
263#define se_ctrladdr_in	se_un.se_un_ctrladdr_in
264#define se_ctrladdr_un	se_un.se_un_ctrladdr_un
265	int	se_ctrladdr_size;
266	int	se_max;			/* max # of instances of this service */
267	int	se_count;		/* number started since se_time */
268	struct	timeval se_time;	/* start of se_count */
269#ifdef MULOG
270	int	se_log;
271#define MULOG_RFC931	0x40000000
272#endif
273	struct	servtab *se_next;
274} *servtab;
275
276#define NORM_TYPE	0
277#define MUX_TYPE	1
278#define MUXPLUS_TYPE	2
279#define ISMUX(sep)	(((sep)->se_type == MUX_TYPE) || \
280			 ((sep)->se_type == MUXPLUS_TYPE))
281#define ISMUXPLUS(sep)	((sep)->se_type == MUXPLUS_TYPE)
282
283
284void		chargen_dg __P((int, struct servtab *));
285void		chargen_stream __P((int, struct servtab *));
286void		close_sep __P((struct servtab *));
287void		config __P((int));
288void		daytime_dg __P((int, struct servtab *));
289void		daytime_stream __P((int, struct servtab *));
290void		discard_dg __P((int, struct servtab *));
291void		discard_stream __P((int, struct servtab *));
292void		echo_dg __P((int, struct servtab *));
293void		echo_stream __P((int, struct servtab *));
294void		endconfig __P((void));
295struct servtab *enter __P((struct servtab *));
296void		freeconfig __P((struct servtab *));
297struct servtab *getconfigent __P((void));
298void		goaway __P((int));
299void		machtime_dg __P((int, struct servtab *));
300void		machtime_stream __P((int, struct servtab *));
301char	       *newstr __P((char *));
302char	       *nextline __P((FILE *));
303void		print_service __P((char *, struct servtab *));
304void		reapchild __P((int));
305void		retry __P((int));
306int		setconfig __P((void));
307void		setup __P((struct servtab *));
308char	       *sskip __P((char **));
309char	       *skip __P((char **));
310struct servtab *tcpmux __P((int));
311void		usage __P((void));
312
313struct biltin {
314	char	*bi_service;		/* internally provided service name */
315	int	bi_socktype;		/* type of socket supported */
316	short	bi_fork;		/* 1 if should fork before call */
317	short	bi_wait;		/* 1 if should wait for child */
318	void	(*bi_fn)();		/* function which performs it */
319} biltins[] = {
320	/* Echo received data */
321	{ "echo",	SOCK_STREAM,	1, 0,	echo_stream },
322	{ "echo",	SOCK_DGRAM,	0, 0,	echo_dg },
323
324	/* Internet /dev/null */
325	{ "discard",	SOCK_STREAM,	1, 0,	discard_stream },
326	{ "discard",	SOCK_DGRAM,	0, 0,	discard_dg },
327
328	/* Return 32 bit time since 1900 */
329	{ "time",	SOCK_STREAM,	0, 0,	machtime_stream },
330	{ "time",	SOCK_DGRAM,	0, 0,	machtime_dg },
331
332	/* Return human-readable time */
333	{ "daytime",	SOCK_STREAM,	0, 0,	daytime_stream },
334	{ "daytime",	SOCK_DGRAM,	0, 0,	daytime_dg },
335
336	/* Familiar character generator */
337	{ "chargen",	SOCK_STREAM,	1, 0,	chargen_stream },
338	{ "chargen",	SOCK_DGRAM,	0, 0,	chargen_dg },
339
340	{ "tcpmux",	SOCK_STREAM,	1, 0,	(void (*)())tcpmux },
341
342	{ NULL }
343};
344
345#define NUMINT	(sizeof(intab) / sizeof(struct inent))
346char	*CONFIG = _PATH_INETDCONF;
347char	**Argv;
348char 	*LastArg;
349extern char	*__progname;
350
351#ifdef sun
352/*
353 * Sun's RPC library caches the result of `dtablesize()'
354 * This is incompatible with our "bumping" of file descriptors "on demand"
355 */
356int
357_rpc_dtablesize()
358{
359	return rlim_ofile_cur;
360}
361#endif
362
363main(argc, argv, envp)
364	int argc;
365	char *argv[], *envp[];
366{
367	struct servtab *sep, *nsep;
368	struct passwd *pwd;
369	struct group *grp;
370	struct sigvec sv;
371	int tmpint, ch, dofork;
372	pid_t pid;
373	char buf[50];
374#ifdef LIBWRAP
375	struct request_info req;
376	int denied;
377	char *service;
378#endif
379
380	Argv = argv;
381	if (envp == 0 || *envp == 0)
382		envp = argv;
383	while (*envp)
384		envp++;
385	LastArg = envp[-1] + strlen(envp[-1]);
386
387	while ((ch = getopt(argc, argv,
388#ifdef LIBWRAP
389					"dl"
390#else
391					"d"
392#endif
393					   )) != EOF)
394		switch(ch) {
395		case 'd':
396			debug = 1;
397			options |= SO_DEBUG;
398			break;
399#ifdef LIBWRAP
400		case 'l':
401			lflag = 1;
402			break;
403#endif
404		case '?':
405		default:
406			usage();
407		}
408	argc -= optind;
409	argv += optind;
410
411	if (argc > 0)
412		CONFIG = argv[0];
413
414	if (debug == 0)
415		daemon(0, 0);
416	openlog(__progname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
417	logpid();
418
419#ifdef RLIMIT_NOFILE
420	if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
421		syslog(LOG_ERR, "getrlimit: %m");
422	} else {
423		rlim_ofile_cur = rlim_ofile.rlim_cur;
424		if (rlim_ofile_cur == RLIM_INFINITY)	/* ! */
425			rlim_ofile_cur = OPEN_MAX;
426	}
427#endif
428
429	memset(&sv, 0, sizeof(sv));
430	sv.sv_mask = SIGBLOCK;
431	sv.sv_handler = retry;
432	sigvec(SIGALRM, &sv, (struct sigvec *)0);
433	config(SIGHUP);
434	sv.sv_handler = config;
435	sigvec(SIGHUP, &sv, (struct sigvec *)0);
436	sv.sv_handler = reapchild;
437	sigvec(SIGCHLD, &sv, (struct sigvec *)0);
438	sv.sv_handler = goaway;
439	sigvec(SIGTERM, &sv, (struct sigvec *)0);
440	sv.sv_handler = goaway;
441	sigvec(SIGINT, &sv, (struct sigvec *)0);
442
443	{
444		/* space for daemons to overwrite environment for ps */
445#define	DUMMYSIZE	100
446		char dummy[DUMMYSIZE];
447
448		(void)memset(dummy, 'x', DUMMYSIZE - 1);
449		dummy[DUMMYSIZE - 1] = '\0';
450
451		(void)setenv("inetd_dummy", dummy, 1);
452	}
453
454	for (;;) {
455	    int n, ctrl;
456	    fd_set readable;
457
458	    if (nsock == 0) {
459		(void) sigblock(SIGBLOCK);
460		while (nsock == 0)
461		    sigpause(0L);
462		(void) sigsetmask(0L);
463	    }
464	    readable = allsock;
465	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
466		(fd_set *)0, (struct timeval *)0)) <= 0) {
467		    if (n < 0 && errno != EINTR)
468			syslog(LOG_WARNING, "select: %m");
469		    sleep(1);
470		    continue;
471	    }
472	    for (sep = servtab; n && sep; sep = nsep) {
473	    nsep = sep->se_next;
474	    if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
475		n--;
476		if (debug)
477			fprintf(stderr, "someone wants %s\n", sep->se_service);
478		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
479			/* XXX here do the libwrap check-before-accept */
480			ctrl = accept(sep->se_fd, (struct sockaddr *)0,
481			    (int *)0);
482			if (debug)
483				fprintf(stderr, "accept, ctrl %d\n", ctrl);
484			if (ctrl < 0) {
485				if (errno != EINTR)
486					syslog(LOG_WARNING,
487					    "accept (for %s): %m",
488					    sep->se_service);
489				continue;
490			}
491			/*
492			 * Call tcpmux to find the real service to exec.
493			 */
494			if (sep->se_bi &&
495			    sep->se_bi->bi_fn == (void (*)()) tcpmux) {
496				sep = tcpmux(ctrl);
497				if (sep == NULL) {
498					close(ctrl);
499					continue;
500				}
501			}
502		} else
503			ctrl = sep->se_fd;
504		(void) sigblock(SIGBLOCK);
505		pid = 0;
506#ifdef LIBWRAP
507		dofork = 1;
508#else
509		dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
510#endif
511		if (dofork) {
512			if (sep->se_count++ == 0)
513			    (void)gettimeofday(&sep->se_time,
514			        (struct timezone *)0);
515			else if (sep->se_count >= sep->se_max) {
516				struct timeval now;
517
518				(void)gettimeofday(&now, (struct timezone *)0);
519				if (now.tv_sec - sep->se_time.tv_sec >
520				    CNT_INTVL) {
521					sep->se_time = now;
522					sep->se_count = 1;
523				} else {
524					syslog(LOG_ERR,
525			"%s/%s server failing (looping), service terminated\n",
526					    sep->se_service, sep->se_proto);
527					close_sep(sep);
528					sigsetmask(0L);
529					if (!timingout) {
530						timingout = 1;
531						alarm(RETRYTIME);
532					}
533					continue;
534				}
535			}
536			pid = fork();
537			if (pid < 0) {
538				syslog(LOG_ERR, "fork: %m");
539				if (sep->se_socktype == SOCK_STREAM)
540					close(ctrl);
541				sigsetmask(0L);
542				sleep(1);
543				continue;
544			}
545			if (pid != 0 && sep->se_wait) {
546				sep->se_wait = pid;
547				FD_CLR(sep->se_fd, &allsock);
548				nsock--;
549			}
550			if (pid == 0 && debug)
551				setsid();
552		}
553		sigsetmask(0L);
554		if (pid == 0) {
555#ifdef LIBWRAP
556			request_init(&req, RQ_DAEMON, sep->se_argv[0] ?
557			    sep->se_argv[0] : sep->se_service, RQ_FILE, ctrl,
558			    NULL);
559			fromhost(&req);
560			denied = !hosts_access(&req);
561			if (denied || lflag) {
562				sp = getservbyport(sep->se_ctrladdr_in.sin_port,
563				    sep->se_proto);
564				if (sp == NULL) {
565					(void)snprintf(buf, sizeof buf, "%d",
566					    ntohs(sep->se_ctrladdr_in.sin_port));
567					service = buf;
568				} else
569					service = sp->s_name;
570			}
571			if (denied) {
572				syslog(deny_severity, "refused "
573				    "connection from %.500s, service %s (%s)",
574				    eval_client(&req), service, sep->se_proto);
575				goto reject;
576			}
577			if (lflag) {
578				syslog(allow_severity,
579				    "connection from %.500s, service %s (%s)",
580				    eval_client(&req), service, sep->se_proto);
581			}
582#endif /* LIBWRAP */
583			if (sep->se_bi) {
584				(*sep->se_bi->bi_fn)(ctrl, sep);
585				if (dofork)
586					exit(0);
587			} else {
588				if ((pwd = getpwnam(sep->se_user)) == NULL) {
589					syslog(LOG_ERR,
590					    "%s/%s: %s: No such user",
591					    sep->se_service, sep->se_proto,
592					    sep->se_user);
593					goto reject;
594				}
595				if (sep->se_group &&
596				    (grp = getgrnam(sep->se_group)) == NULL) {
597					syslog(LOG_ERR,
598					    "%s/%s: %s: No such group",
599					    sep->se_service, sep->se_proto,
600					    sep->se_group);
601					goto reject;
602				}
603				if (pwd->pw_uid) {
604					if (sep->se_group)
605						pwd->pw_gid = grp->gr_gid;
606					if (setgid(pwd->pw_gid) < 0) {
607						syslog(LOG_ERR,
608						 "%s/%s: can't set gid %d: %m",
609						    sep->se_service,
610						    sep->se_proto, pwd->pw_gid);
611						goto reject;
612					}
613					(void) initgroups(pwd->pw_name,
614					    pwd->pw_gid);
615					if (setuid(pwd->pw_uid) < 0) {
616						syslog(LOG_ERR,
617						 "%s/%s: can't set uid %d: %m",
618						    sep->se_service,
619						    sep->se_proto, pwd->pw_uid);
620						goto reject;
621					}
622				} else if (sep->se_group) {
623					(void) setgid((gid_t)grp->gr_gid);
624				}
625				if (debug)
626					fprintf(stderr, "%d execl %s\n",
627					    getpid(), sep->se_server);
628#ifdef MULOG
629				if (sep->se_log)
630					dolog(sep, ctrl);
631#endif
632				if (ctrl != 0) {
633					dup2(ctrl, 0);
634					close(ctrl);
635					ctrl = 0;
636				}
637				dup2(0, 1);
638				dup2(0, 2);
639#ifdef RLIMIT_NOFILE
640				if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
641					if (setrlimit(RLIMIT_NOFILE,
642							&rlim_ofile) < 0)
643						syslog(LOG_ERR,
644						    "setrlimit: %m");
645				}
646#endif
647				for (tmpint = rlim_ofile_cur-1; --tmpint > 2; )
648					(void)close(tmpint);
649				execv(sep->se_server, sep->se_argv);
650				syslog(LOG_ERR,
651				    "cannot execute %s: %m", sep->se_server);
652			reject:
653				if (sep->se_socktype != SOCK_STREAM)
654					recv(ctrl, buf, sizeof (buf), 0);
655				_exit(1);
656			}
657		}
658		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
659			close(ctrl);
660	    }
661	    }
662	}
663}
664
665void
666reapchild(signo)
667	int signo;
668{
669	int status;
670	pid_t pid;
671	struct servtab *sep;
672
673	for (;;) {
674		pid = wait3(&status, WNOHANG, (struct rusage *)0);
675		if (pid <= 0)
676			break;
677		if (debug)
678			fprintf(stderr, "%d reaped, status %#x\n",
679			    pid, status);
680		for (sep = servtab; sep; sep = sep->se_next)
681			if (sep->se_wait == pid) {
682				if (WIFEXITED(status) && WEXITSTATUS(status))
683					syslog(LOG_WARNING,
684					    "%s: exit status 0x%x",
685					    sep->se_server, WEXITSTATUS(status));
686				else if (WIFSIGNALED(status))
687					syslog(LOG_WARNING,
688					    "%s: exit signal 0x%x",
689					    sep->se_server, WTERMSIG(status));
690				sep->se_wait = 1;
691				FD_SET(sep->se_fd, &allsock);
692				nsock++;
693				if (debug)
694					fprintf(stderr, "restored %s, fd %d\n",
695					    sep->se_service, sep->se_fd);
696			}
697	}
698}
699
700void
701config(signo)
702	int signo;
703{
704	struct servtab *sep, *cp, **sepp;
705	struct passwd *pwd;
706	long omask;
707	int n;
708
709	if (!setconfig()) {
710		syslog(LOG_ERR, "%s: %m", CONFIG);
711		return;
712	}
713	for (sep = servtab; sep; sep = sep->se_next)
714		sep->se_checked = 0;
715	while (cp = getconfigent()) {
716		for (sep = servtab; sep; sep = sep->se_next)
717			if (strcmp(sep->se_service, cp->se_service) == 0 &&
718			    strcmp(sep->se_hostaddr, cp->se_hostaddr) == 0 &&
719			    strcmp(sep->se_proto, cp->se_proto) == 0 &&
720			    ISMUX(sep) == ISMUX(cp))
721				break;
722		if (sep != 0) {
723			int i;
724
725#define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
726
727			omask = sigblock(SIGBLOCK);
728			/*
729			 * sep->se_wait may be holding the pid of a daemon
730			 * that we're waiting for.  If so, don't overwrite
731			 * it unless the config file explicitly says don't
732			 * wait.
733			 */
734			if (cp->se_bi == 0 &&
735			    (sep->se_wait == 1 || cp->se_wait == 0))
736				sep->se_wait = cp->se_wait;
737			SWAP(char *, sep->se_user, cp->se_user);
738			SWAP(char *, sep->se_group, cp->se_group);
739			SWAP(char *, sep->se_server, cp->se_server);
740			for (i = 0; i < MAXARGV; i++)
741				SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
742			SWAP(int, cp->se_type, sep->se_type);
743			SWAP(int, cp->se_max, sep->se_max);
744#undef SWAP
745			if (isrpcservice(sep))
746				unregister_rpc(sep);
747			sep->se_rpcversl = cp->se_rpcversl;
748			sep->se_rpcversh = cp->se_rpcversh;
749			sigsetmask(omask);
750			freeconfig(cp);
751			if (debug)
752				print_service("REDO", sep);
753		} else {
754			sep = enter(cp);
755			if (debug)
756				print_service("ADD ", sep);
757		}
758		sep->se_checked = 1;
759
760		switch (sep->se_family) {
761		case AF_UNIX:
762			if (sep->se_fd != -1)
763				break;
764			(void)unlink(sep->se_service);
765			n = strlen(sep->se_service);
766			if (n > sizeof(sep->se_ctrladdr_un.sun_path) - 1)
767				n = sizeof(sep->se_ctrladdr_un.sun_path) - 1;
768			strncpy(sep->se_ctrladdr_un.sun_path,
769			    sep->se_service, n);
770			sep->se_ctrladdr_un.sun_family = AF_UNIX;
771			sep->se_ctrladdr_size = n +
772			    sizeof(sep->se_ctrladdr_un) -
773			    sizeof(sep->se_ctrladdr_un.sun_path);
774			if (!ISMUX(sep))
775				setup(sep);
776			break;
777		case AF_INET:
778			sep->se_ctrladdr_in.sin_family = AF_INET;
779			if (!strcmp(sep->se_hostaddr,"*"))
780				sep->se_ctrladdr_in.sin_addr.s_addr =
781				    INADDR_ANY;
782			else if (!inet_aton(sep->se_hostaddr,
783			    &sep->se_ctrladdr_in.sin_addr)) {
784				/* Do we really want to support hostname lookups here? */
785				struct hostent *hp;
786				hp = gethostbyname(sep->se_hostaddr);
787				if (hp == 0) {
788					syslog(LOG_ERR, "%s: unknown host",
789					    sep->se_hostaddr);
790					sep->se_checked = 0;
791					continue;
792				} else if (hp->h_addrtype != AF_INET) {
793					syslog(LOG_ERR,
794				       "%s: address isn't an Internet address",
795					    sep->se_hostaddr);
796					sep->se_checked = 0;
797					continue;
798				} else if (hp->h_length != sizeof(struct in_addr)) {
799					syslog(LOG_ERR,
800		       "%s: address size wrong (under DNS corruption attack?)",
801					    sep->se_hostaddr);
802					sep->se_checked = 0;
803					continue;
804				} else {
805					memcpy(&sep->se_ctrladdr_in.sin_addr,
806					    hp->h_addr_list[0],
807					    sizeof(struct in_addr));
808				}
809			}
810			if (ISMUX(sep)) {
811				sep->se_fd = -1;
812				continue;
813			}
814			sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr_in);
815			if (isrpcservice(sep)) {
816				struct rpcent *rp;
817
818				sep->se_rpcprog = atoi(sep->se_service);
819				if (sep->se_rpcprog == 0) {
820					rp = getrpcbyname(sep->se_service);
821					if (rp == 0) {
822						syslog(LOG_ERR,
823						    "%s/%s: unknown service",
824						    sep->se_service,
825						    sep->se_proto);
826						sep->se_checked = 0;
827						continue;
828					}
829					sep->se_rpcprog = rp->r_number;
830				}
831				if (sep->se_fd == -1 && !ISMUX(sep))
832					setup(sep);
833				if (sep->se_fd != -1)
834					register_rpc(sep);
835			} else {
836				u_short port = htons(atoi(sep->se_service));
837
838				if (!port) {
839					sp = getservbyname(sep->se_service,
840					    sep->se_proto);
841					if (sp == 0) {
842						syslog(LOG_ERR,
843						    "%s/%s: unknown service",
844						    sep->se_service,
845						    sep->se_proto);
846						sep->se_checked = 0;
847						continue;
848					}
849					port = sp->s_port;
850				}
851				if (port != sep->se_ctrladdr_in.sin_port) {
852					sep->se_ctrladdr_in.sin_port = port;
853					if (sep->se_fd >= 0)
854						close_sep(sep);
855				}
856				if (sep->se_fd == -1 && !ISMUX(sep))
857					setup(sep);
858			}
859		}
860	}
861	endconfig();
862	/*
863	 * Purge anything not looked at above.
864	 */
865	omask = sigblock(SIGBLOCK);
866	sepp = &servtab;
867	while (sep = *sepp) {
868		if (sep->se_checked) {
869			sepp = &sep->se_next;
870			continue;
871		}
872		*sepp = sep->se_next;
873		if (sep->se_fd >= 0)
874			close_sep(sep);
875		if (isrpcservice(sep))
876			unregister_rpc(sep);
877		if (sep->se_family == AF_UNIX)
878			(void)unlink(sep->se_service);
879		if (debug)
880			print_service("FREE", sep);
881		freeconfig(sep);
882		free((char *)sep);
883	}
884	(void) sigsetmask(omask);
885}
886
887void
888retry(signo)
889	int signo;
890{
891	struct servtab *sep;
892
893	timingout = 0;
894	for (sep = servtab; sep; sep = sep->se_next) {
895		if (sep->se_fd == -1 && !ISMUX(sep)) {
896			switch (sep->se_family) {
897			case AF_UNIX:
898			case AF_INET:
899				setup(sep);
900				if (sep->se_fd != -1 && isrpcservice(sep))
901					register_rpc(sep);
902				break;
903			}
904		}
905	}
906}
907
908void
909goaway(signo)
910	int signo;
911{
912	register struct servtab *sep;
913
914	for (sep = servtab; sep; sep = sep->se_next) {
915		if (sep->se_fd == -1)
916			continue;
917
918		switch (sep->se_family) {
919		case AF_UNIX:
920			(void)unlink(sep->se_service);
921			break;
922		case AF_INET:
923			if (sep->se_wait == 1 && isrpcservice(sep))
924				unregister_rpc(sep);
925			break;
926		}
927		(void)close(sep->se_fd);
928	}
929	(void)unlink(_PATH_INETDPID);
930	exit(0);
931}
932
933void
934setup(sep)
935	struct servtab *sep;
936{
937	int on = 1;
938
939	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
940		if (debug)
941			fprintf(stderr, "socket failed on %s/%s: %s\n",
942			    sep->se_service, sep->se_proto, strerror(errno));
943		syslog(LOG_ERR, "%s/%s: socket: %m",
944		    sep->se_service, sep->se_proto);
945		return;
946	}
947#define	turnon(fd, opt) \
948setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
949	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
950	    turnon(sep->se_fd, SO_DEBUG) < 0)
951		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
952	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
953		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
954#undef turnon
955	if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
956		if (debug)
957			fprintf(stderr, "bind failed on %s/%s: %s\n",
958			    sep->se_service, sep->se_proto, strerror(errno));
959		syslog(LOG_ERR, "%s/%s: bind: %m",
960		    sep->se_service, sep->se_proto);
961		(void) close(sep->se_fd);
962		sep->se_fd = -1;
963		if (!timingout) {
964			timingout = 1;
965			alarm(RETRYTIME);
966		}
967		return;
968	}
969	if (sep->se_socktype == SOCK_STREAM)
970		listen(sep->se_fd, 10);
971
972	FD_SET(sep->se_fd, &allsock);
973	nsock++;
974	if (sep->se_fd > maxsock) {
975		maxsock = sep->se_fd;
976		if (maxsock > rlim_ofile_cur - FD_MARGIN)
977			bump_nofile();
978	}
979	if (debug)
980		fprintf(stderr, "registered %s on %d\n",
981		    sep->se_server, sep->se_fd);
982}
983
984/*
985 * Finish with a service and its socket.
986 */
987void
988close_sep(sep)
989	struct servtab *sep;
990{
991	if (sep->se_fd >= 0) {
992		nsock--;
993		FD_CLR(sep->se_fd, &allsock);
994		(void) close(sep->se_fd);
995		sep->se_fd = -1;
996	}
997	sep->se_count = 0;
998	/*
999	 * Don't keep the pid of this running deamon: when reapchild()
1000	 * reaps this pid, it would erroneously increment nsock.
1001	 */
1002	if (sep->se_wait > 1)
1003		sep->se_wait = 1;
1004}
1005
1006register_rpc(sep)
1007	register struct servtab *sep;
1008{
1009#ifdef RPC
1010	int n;
1011	struct sockaddr_in sin;
1012	struct protoent *pp;
1013
1014	if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
1015		syslog(LOG_ERR, "%s: getproto: %m",
1016		    sep->se_proto);
1017		return;
1018	}
1019	n = sizeof sin;
1020	if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
1021		syslog(LOG_ERR, "%s/%s: getsockname: %m",
1022		    sep->se_service, sep->se_proto);
1023		return;
1024	}
1025
1026	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1027		if (debug)
1028			fprintf(stderr, "pmap_set: %u %u %u %u\n",
1029			    sep->se_rpcprog, n, pp->p_proto,
1030			    ntohs(sin.sin_port));
1031		(void)pmap_unset(sep->se_rpcprog, n);
1032		if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
1033			syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m",
1034			    sep->se_rpcprog, n, pp->p_proto,
1035			    ntohs(sin.sin_port));
1036	}
1037#endif /* RPC */
1038}
1039
1040unregister_rpc(sep)
1041	register struct servtab *sep;
1042{
1043#ifdef RPC
1044	int n;
1045
1046	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1047		if (debug)
1048			fprintf(stderr, "pmap_unset(%u, %u)\n",
1049			    sep->se_rpcprog, n);
1050		if (!pmap_unset(sep->se_rpcprog, n))
1051			syslog(LOG_ERR, "pmap_unset(%u, %u)\n",
1052			    sep->se_rpcprog, n);
1053	}
1054#endif /* RPC */
1055}
1056
1057
1058struct servtab *
1059enter(cp)
1060	struct servtab *cp;
1061{
1062	struct servtab *sep;
1063	long omask;
1064
1065	sep = (struct servtab *)malloc(sizeof (*sep));
1066	if (sep == (struct servtab *)0) {
1067		syslog(LOG_ERR, "Out of memory.");
1068		exit(-1);
1069	}
1070	*sep = *cp;
1071	sep->se_fd = -1;
1072	sep->se_rpcprog = -1;
1073	omask = sigblock(SIGBLOCK);
1074	sep->se_next = servtab;
1075	servtab = sep;
1076	sigsetmask(omask);
1077	return (sep);
1078}
1079
1080FILE	*fconfig = NULL;
1081struct	servtab serv;
1082char	line[LINE_MAX];
1083char    *defhost;
1084
1085int
1086setconfig()
1087{
1088	if (defhost) free(defhost);
1089	defhost = newstr("*");
1090	if (fconfig != NULL) {
1091		fseek(fconfig, 0L, SEEK_SET);
1092		return (1);
1093	}
1094	fconfig = fopen(CONFIG, "r");
1095	return (fconfig != NULL);
1096}
1097
1098void
1099endconfig()
1100{
1101	if (fconfig) {
1102		(void) fclose(fconfig);
1103		fconfig = NULL;
1104	}
1105	if (defhost) {
1106		free(defhost);
1107		defhost = 0;
1108	}
1109}
1110
1111struct servtab *
1112getconfigent()
1113{
1114	struct servtab *sep = &serv;
1115	int argc;
1116	char *cp, *arg;
1117	static char TCPMUX_TOKEN[] = "tcpmux/";
1118#define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
1119	char *hostdelim;
1120
1121more:
1122#ifdef MULOG
1123	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) {
1124		/* Avoid use of `skip' if there is a danger of it looking
1125		 * at continuation lines.
1126		 */
1127		do {
1128			cp++;
1129		} while (*cp == ' ' || *cp == '\t');
1130		if (*cp == '\0')
1131			continue;
1132		if ((arg = skip(&cp)) == NULL)
1133			continue;
1134		if (strcmp(arg, "DOMAIN"))
1135			continue;
1136		if (curdom)
1137			free(curdom);
1138		curdom = NULL;
1139		while (*cp == ' ' || *cp == '\t')
1140			cp++;
1141		if (*cp == '\0')
1142			continue;
1143		arg = cp;
1144		while (*cp && *cp != ' ' && *cp != '\t')
1145			cp++;
1146		if (*cp != '\0')
1147			*cp++ = '\0';
1148		curdom = newstr(arg);
1149	}
1150#else
1151	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
1152		;
1153#endif
1154	if (cp == NULL)
1155		return ((struct servtab *)0);
1156	/*
1157	 * clear the static buffer, since some fields (se_ctrladdr,
1158	 * for example) don't get initialized here.
1159	 */
1160	memset((caddr_t)sep, 0, sizeof *sep);
1161	arg = skip(&cp);
1162	if (cp == NULL) {
1163		/* got an empty line containing just blanks/tabs. */
1164		goto more;
1165	}
1166	/* Check for a host name. */
1167	hostdelim = strrchr(arg, ':');
1168	if (hostdelim) {
1169		*hostdelim = '\0';
1170		sep->se_hostaddr = newstr(arg);
1171		arg = hostdelim + 1;
1172		/*
1173		 * If the line is of the form `host:', then just change the
1174		 * default host for the following lines.
1175		 */
1176		if (*arg == '\0') {
1177			arg = skip(&cp);
1178			if (cp == NULL) {
1179				free(defhost);
1180				defhost = sep->se_hostaddr;
1181				goto more;
1182			}
1183		}
1184	} else
1185		sep->se_hostaddr = newstr(defhost);
1186	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
1187		char *c = arg + MUX_LEN;
1188		if (*c == '+') {
1189			sep->se_type = MUXPLUS_TYPE;
1190			c++;
1191		} else
1192			sep->se_type = MUX_TYPE;
1193		sep->se_service = newstr(c);
1194	} else {
1195		sep->se_service = newstr(arg);
1196		sep->se_type = NORM_TYPE;
1197	}
1198
1199	arg = sskip(&cp);
1200	if (strcmp(arg, "stream") == 0)
1201		sep->se_socktype = SOCK_STREAM;
1202	else if (strcmp(arg, "dgram") == 0)
1203		sep->se_socktype = SOCK_DGRAM;
1204	else if (strcmp(arg, "rdm") == 0)
1205		sep->se_socktype = SOCK_RDM;
1206	else if (strcmp(arg, "seqpacket") == 0)
1207		sep->se_socktype = SOCK_SEQPACKET;
1208	else if (strcmp(arg, "raw") == 0)
1209		sep->se_socktype = SOCK_RAW;
1210	else
1211		sep->se_socktype = -1;
1212
1213	sep->se_proto = newstr(sskip(&cp));
1214	if (strcmp(sep->se_proto, "unix") == 0) {
1215		sep->se_family = AF_UNIX;
1216	} else {
1217		sep->se_family = AF_INET;
1218		if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1219#ifdef RPC
1220			char *cp, *ccp;
1221			cp = strchr(sep->se_service, '/');
1222			if (cp == 0) {
1223				syslog(LOG_ERR, "%s: no rpc version",
1224				    sep->se_service);
1225				goto more;
1226			}
1227			*cp++ = '\0';
1228			sep->se_rpcversl = sep->se_rpcversh =
1229			    strtol(cp, &ccp, 0);
1230			if (ccp == cp) {
1231		badafterall:
1232				syslog(LOG_ERR, "%s/%s: bad rpc version",
1233				    sep->se_service, cp);
1234				goto more;
1235			}
1236			if (*ccp == '-') {
1237				cp = ccp + 1;
1238				sep->se_rpcversh = strtol(cp, &ccp, 0);
1239				if (ccp == cp)
1240					goto badafterall;
1241			}
1242#else
1243			syslog(LOG_ERR, "%s: rpc services not suported",
1244			    sep->se_service);
1245			goto more;
1246#endif /* RPC */
1247		}
1248	}
1249	arg = sskip(&cp);
1250	{
1251		char *cp;
1252		cp = strchr(arg, '.');
1253		if (cp) {
1254			*cp++ = '\0';
1255			sep->se_max = atoi(cp);
1256		} else
1257			sep->se_max = TOOMANY;
1258	}
1259	sep->se_wait = strcmp(arg, "wait") == 0;
1260	if (ISMUX(sep)) {
1261		/*
1262		 * Silently enforce "nowait" for TCPMUX services since
1263		 * they don't have an assigned port to listen on.
1264		 */
1265		sep->se_wait = 0;
1266
1267		if (strcmp(sep->se_proto, "tcp")) {
1268			syslog(LOG_ERR,
1269			    "%s: bad protocol for tcpmux service %s",
1270			    CONFIG, sep->se_service);
1271			goto more;
1272		}
1273		if (sep->se_socktype != SOCK_STREAM) {
1274			syslog(LOG_ERR,
1275			    "%s: bad socket type for tcpmux service %s",
1276			    CONFIG, sep->se_service);
1277			goto more;
1278		}
1279	}
1280	sep->se_user = newstr(sskip(&cp));
1281	if (sep->se_group = strchr(sep->se_user, '.'))
1282		*sep->se_group++ = '\0';
1283	sep->se_server = newstr(sskip(&cp));
1284	if (strcmp(sep->se_server, "internal") == 0) {
1285		struct biltin *bi;
1286
1287		for (bi = biltins; bi->bi_service; bi++)
1288			if (bi->bi_socktype == sep->se_socktype &&
1289			    strcmp(bi->bi_service, sep->se_service) == 0)
1290				break;
1291		if (bi->bi_service == 0) {
1292			syslog(LOG_ERR, "internal service %s unknown",
1293			    sep->se_service);
1294			goto more;
1295		}
1296		sep->se_bi = bi;
1297		sep->se_wait = bi->bi_wait;
1298	} else
1299		sep->se_bi = NULL;
1300	argc = 0;
1301	for (arg = skip(&cp); cp; arg = skip(&cp)) {
1302#if MULOG
1303		char *colon;
1304
1305		if (argc == 0 && (colon = strrchr(arg, ':'))) {
1306			while (arg < colon) {
1307				int	x;
1308				char	*ccp;
1309
1310				switch (*arg++) {
1311				case 'l':
1312					x = 1;
1313					if (isdigit(*arg)) {
1314						x = strtol(arg, &ccp, 0);
1315						if (ccp == arg)
1316							break;
1317						arg = ccp;
1318					}
1319					sep->se_log &= ~MULOG_RFC931;
1320					sep->se_log |= x;
1321					break;
1322				case 'a':
1323					sep->se_log |= MULOG_RFC931;
1324					break;
1325				default:
1326					break;
1327				}
1328			}
1329			arg = colon + 1;
1330		}
1331#endif
1332		if (argc < MAXARGV)
1333			sep->se_argv[argc++] = newstr(arg);
1334	}
1335	while (argc <= MAXARGV)
1336		sep->se_argv[argc++] = NULL;
1337	return (sep);
1338}
1339
1340void
1341freeconfig(cp)
1342	struct servtab *cp;
1343{
1344	int i;
1345
1346	if (cp->se_hostaddr)
1347		free(cp->se_hostaddr);
1348	if (cp->se_service)
1349		free(cp->se_service);
1350	if (cp->se_proto)
1351		free(cp->se_proto);
1352	if (cp->se_user)
1353		free(cp->se_user);
1354	/* Note: se_group is part of the newstr'ed se_user */
1355	if (cp->se_server)
1356		free(cp->se_server);
1357	for (i = 0; i < MAXARGV; i++)
1358		if (cp->se_argv[i])
1359			free(cp->se_argv[i]);
1360}
1361
1362
1363/*
1364 * Safe skip - if skip returns null, log a syntax error in the
1365 * configuration file and exit.
1366 */
1367char *
1368sskip(cpp)
1369	char **cpp;
1370{
1371	char *cp;
1372
1373	cp = skip(cpp);
1374	if (cp == NULL) {
1375		syslog(LOG_ERR, "%s: syntax error", CONFIG);
1376		exit(-1);
1377	}
1378	return (cp);
1379}
1380
1381char *
1382skip(cpp)
1383	char **cpp;
1384{
1385	char *cp = *cpp;
1386	char *start;
1387
1388	if (*cpp == NULL)
1389		return ((char *)0);
1390
1391again:
1392	while (*cp == ' ' || *cp == '\t')
1393		cp++;
1394	if (*cp == '\0') {
1395		int c;
1396
1397		c = getc(fconfig);
1398		(void) ungetc(c, fconfig);
1399		if (c == ' ' || c == '\t')
1400			if (cp = nextline(fconfig))
1401				goto again;
1402		*cpp = (char *)0;
1403		return ((char *)0);
1404	}
1405	start = cp;
1406	while (*cp && *cp != ' ' && *cp != '\t')
1407		cp++;
1408	if (*cp != '\0')
1409		*cp++ = '\0';
1410	*cpp = cp;
1411	return (start);
1412}
1413
1414char *
1415nextline(fd)
1416	FILE *fd;
1417{
1418	char *cp;
1419
1420	if (fgets(line, sizeof (line), fd) == NULL)
1421		return ((char *)0);
1422	cp = strchr(line, '\n');
1423	if (cp)
1424		*cp = '\0';
1425	return (line);
1426}
1427
1428char *
1429newstr(cp)
1430	char *cp;
1431{
1432	if (cp = strdup(cp ? cp : ""))
1433		return (cp);
1434	syslog(LOG_ERR, "strdup: %m");
1435	exit(-1);
1436}
1437
1438void
1439inetd_setproctitle(a, s)
1440	char *a;
1441	int s;
1442{
1443	int size;
1444	char *cp;
1445	struct sockaddr_in sin;
1446	char buf[80];
1447
1448	cp = Argv[0];
1449	size = sizeof(sin);
1450	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1451		(void)snprintf(buf, sizeof buf, "-%s [%s]", a,
1452		    inet_ntoa(sin.sin_addr));
1453	else
1454		(void)snprintf(buf, sizeof buf, "-%s", a);
1455	strncpy(cp, buf, LastArg - cp);
1456	cp += strlen(cp);
1457	while (cp < LastArg)
1458		*cp++ = ' ';
1459}
1460
1461logpid()
1462{
1463	FILE *fp;
1464
1465	if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
1466		fprintf(fp, "%u\n", getpid());
1467		(void)fclose(fp);
1468	}
1469}
1470
1471bump_nofile()
1472{
1473#ifdef RLIMIT_NOFILE
1474
1475#define FD_CHUNK	32
1476
1477	struct rlimit rl;
1478
1479	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1480		syslog(LOG_ERR, "getrlimit: %m");
1481		return -1;
1482	}
1483	rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1484	if (rl.rlim_cur <= rlim_ofile_cur) {
1485		syslog(LOG_ERR,
1486		    "bump_nofile: cannot extend file limit, max = %d",
1487		    rl.rlim_cur);
1488		return -1;
1489	}
1490
1491	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1492		syslog(LOG_ERR, "setrlimit: %m");
1493		return -1;
1494	}
1495
1496	rlim_ofile_cur = rl.rlim_cur;
1497	return 0;
1498
1499#else
1500	syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
1501	return -1;
1502#endif
1503}
1504
1505/*
1506 * Internet services provided internally by inetd:
1507 */
1508#define	BUFSIZE	4096
1509
1510/* ARGSUSED */
1511void
1512echo_stream(s, sep)		/* Echo service -- echo data back */
1513	int s;
1514	struct servtab *sep;
1515{
1516	char buffer[BUFSIZE];
1517	int i;
1518
1519	inetd_setproctitle(sep->se_service, s);
1520	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1521	    write(s, buffer, i) > 0)
1522		;
1523}
1524
1525/* ARGSUSED */
1526void
1527echo_dg(s, sep)			/* Echo service -- echo data back */
1528	int s;
1529	struct servtab *sep;
1530{
1531	char buffer[BUFSIZE];
1532	int i, size;
1533	struct sockaddr sa;
1534
1535	size = sizeof(sa);
1536	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
1537		return;
1538	(void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
1539}
1540
1541/* ARGSUSED */
1542void
1543discard_stream(s, sep)		/* Discard service -- ignore data */
1544	int s;
1545	struct servtab *sep;
1546{
1547	char buffer[BUFSIZE];
1548
1549	inetd_setproctitle(sep->se_service, s);
1550	while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1551			errno == EINTR)
1552		;
1553}
1554
1555/* ARGSUSED */
1556void
1557discard_dg(s, sep)		/* Discard service -- ignore data */
1558	int s;
1559	struct servtab *sep;
1560{
1561	char buffer[BUFSIZE];
1562
1563	(void) read(s, buffer, sizeof(buffer));
1564}
1565
1566#include <ctype.h>
1567#define LINESIZ 72
1568char ring[128];
1569char *endring;
1570
1571void
1572initring()
1573{
1574	int i;
1575
1576	endring = ring;
1577
1578	for (i = 0; i <= 128; ++i)
1579		if (isprint(i))
1580			*endring++ = i;
1581}
1582
1583/* ARGSUSED */
1584void
1585chargen_stream(s, sep)		/* Character generator */
1586	int s;
1587	struct servtab *sep;
1588{
1589	int len;
1590	char *rs, text[LINESIZ+2];
1591
1592	inetd_setproctitle(sep->se_service, s);
1593
1594	if (!endring) {
1595		initring();
1596		rs = ring;
1597	}
1598
1599	text[LINESIZ] = '\r';
1600	text[LINESIZ + 1] = '\n';
1601	for (rs = ring;;) {
1602		if ((len = endring - rs) >= LINESIZ)
1603			memmove(text, rs, LINESIZ);
1604		else {
1605			memmove(text, rs, len);
1606			memmove(text + len, ring, LINESIZ - len);
1607		}
1608		if (++rs == endring)
1609			rs = ring;
1610		if (write(s, text, sizeof(text)) != sizeof(text))
1611			break;
1612	}
1613}
1614
1615/* ARGSUSED */
1616void
1617chargen_dg(s, sep)		/* Character generator */
1618	int s;
1619	struct servtab *sep;
1620{
1621	struct sockaddr sa;
1622	static char *rs;
1623	int len, size;
1624	char text[LINESIZ+2];
1625
1626	if (endring == 0) {
1627		initring();
1628		rs = ring;
1629	}
1630
1631	size = sizeof(sa);
1632	if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1633		return;
1634
1635	if ((len = endring - rs) >= LINESIZ)
1636		memmove(text, rs, LINESIZ);
1637	else {
1638		memmove(text, rs, len);
1639		memmove(text + len, ring, LINESIZ - len);
1640	}
1641	if (++rs == endring)
1642		rs = ring;
1643	text[LINESIZ] = '\r';
1644	text[LINESIZ + 1] = '\n';
1645	(void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1646}
1647
1648/*
1649 * Return a machine readable date and time, in the form of the
1650 * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1651 * returns the number of seconds since midnight, Jan 1, 1970,
1652 * we must add 2208988800 seconds to this figure to make up for
1653 * some seventy years Bell Labs was asleep.
1654 */
1655
1656long
1657machtime()
1658{
1659	struct timeval tv;
1660
1661	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1662		if (debug)
1663			fprintf(stderr, "Unable to get time of day\n");
1664		return (0L);
1665	}
1666#define	OFFSET ((u_long)25567 * 24*60*60)
1667	return (htonl((long)(tv.tv_sec + OFFSET)));
1668#undef OFFSET
1669}
1670
1671/* ARGSUSED */
1672void
1673machtime_stream(s, sep)
1674	int s;
1675	struct servtab *sep;
1676{
1677	long result;
1678
1679	result = machtime();
1680	(void) write(s, (char *) &result, sizeof(result));
1681}
1682
1683/* ARGSUSED */
1684void
1685machtime_dg(s, sep)
1686	int s;
1687	struct servtab *sep;
1688{
1689	long result;
1690	struct sockaddr sa;
1691	int size;
1692
1693	size = sizeof(sa);
1694	if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1695		return;
1696	result = machtime();
1697	(void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1698}
1699
1700/* ARGSUSED */
1701void
1702daytime_stream(s, sep)		/* Return human-readable time of day */
1703	int s;
1704	struct servtab *sep;
1705{
1706	char buffer[256];
1707	time_t clock;
1708	int len;
1709
1710	clock = time((time_t *) 0);
1711
1712	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1713	(void) write(s, buffer, len);
1714}
1715
1716/* ARGSUSED */
1717void
1718daytime_dg(s, sep)		/* Return human-readable time of day */
1719	int s;
1720	struct servtab *sep;
1721{
1722	char buffer[256];
1723	time_t clock;
1724	struct sockaddr sa;
1725	int size, len;
1726
1727	clock = time((time_t *) 0);
1728
1729	size = sizeof(sa);
1730	if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1731		return;
1732	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1733	(void) sendto(s, buffer, len, 0, &sa, sizeof(sa));
1734}
1735
1736/*
1737 * print_service:
1738 *	Dump relevant information to stderr
1739 */
1740void
1741print_service(action, sep)
1742	char *action;
1743	struct servtab *sep;
1744{
1745	if (isrpcservice(sep))
1746		fprintf(stderr,
1747		    "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
1748		    action, sep->se_service,
1749		    sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
1750		    sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
1751		    (long)sep->se_bi, sep->se_server);
1752	else
1753		fprintf(stderr,
1754		    "%s: %s proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
1755		    action, sep->se_service, sep->se_proto,
1756		    sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
1757		    (long)sep->se_bi, sep->se_server);
1758}
1759
1760void
1761usage()
1762{
1763
1764#ifdef LIBWRAP
1765	(void)fprintf(stderr, "usage: %s [-dl] [conf]\n", __progname);
1766#else
1767	(void)fprintf(stderr, "usage: %s [-d] [conf]\n", __progname);
1768#endif
1769	exit(1);
1770}
1771
1772
1773/*
1774 *  Based on TCPMUX.C by Mark K. Lottor November 1988
1775 *  sri-nic::ps:<mkl>tcpmux.c
1776 */
1777
1778static int		/* # of characters upto \r,\n or \0 */
1779getline(fd, buf, len)
1780	int fd;
1781	char *buf;
1782	int len;
1783{
1784	int count = 0, n;
1785
1786	do {
1787		n = read(fd, buf, len-count);
1788		if (n == 0)
1789			return (count);
1790		if (n < 0)
1791			return (-1);
1792		while (--n >= 0) {
1793			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
1794				return (count);
1795			count++;
1796			buf++;
1797		}
1798	} while (count < len);
1799	return (count);
1800}
1801
1802#define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
1803
1804#define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
1805
1806struct servtab *
1807tcpmux(s)
1808	int s;
1809{
1810	struct servtab *sep;
1811	char service[MAX_SERV_LEN+1];
1812	int len;
1813
1814	/* Get requested service name */
1815	if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
1816		strwrite(s, "-Error reading service name\r\n");
1817		return (NULL);
1818	}
1819	service[len] = '\0';
1820
1821	if (debug)
1822		fprintf(stderr, "tcpmux: someone wants %s\n", service);
1823
1824	/*
1825	 * Help is a required command, and lists available services,
1826	 * one per line.
1827	 */
1828	if (!strcasecmp(service, "help")) {
1829		for (sep = servtab; sep; sep = sep->se_next) {
1830			if (!ISMUX(sep))
1831				continue;
1832			(void)write(s,sep->se_service,strlen(sep->se_service));
1833			strwrite(s, "\r\n");
1834		}
1835		return (NULL);
1836	}
1837
1838	/* Try matching a service in inetd.conf with the request */
1839	for (sep = servtab; sep; sep = sep->se_next) {
1840		if (!ISMUX(sep))
1841			continue;
1842		if (!strcasecmp(service, sep->se_service)) {
1843			if (ISMUXPLUS(sep)) {
1844				strwrite(s, "+Go\r\n");
1845			}
1846			return (sep);
1847		}
1848	}
1849	strwrite(s, "-Service not available\r\n");
1850	return (NULL);
1851}
1852
1853
1854#ifdef MULOG
1855dolog(sep, ctrl)
1856	struct servtab *sep;
1857	int		ctrl;
1858{
1859	struct sockaddr		sa;
1860	struct sockaddr_in	*sin = (struct sockaddr_in *)&sa;
1861	int			len = sizeof(sa);
1862	struct hostent		*hp;
1863	char			*host, *dp, buf[BUFSIZ], *rfc931_name();
1864	int			connected = 1;
1865
1866	if (sep->se_family != AF_INET)
1867		return;
1868
1869	if (getpeername(ctrl, &sa, &len) < 0) {
1870		if (errno != ENOTCONN) {
1871			syslog(LOG_ERR, "getpeername: %m");
1872			return;
1873		}
1874		if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) {
1875			syslog(LOG_ERR, "recvfrom: %m");
1876			return;
1877		}
1878		connected = 0;
1879	}
1880	if (sa.sa_family != AF_INET) {
1881		syslog(LOG_ERR, "unexpected address family %u", sa.sa_family);
1882		return;
1883	}
1884
1885	hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
1886				sizeof (sin->sin_addr.s_addr), AF_INET);
1887
1888	host = hp?hp->h_name:inet_ntoa(sin->sin_addr);
1889
1890	switch (sep->se_log & ~MULOG_RFC931) {
1891	case 0:
1892		return;
1893	case 1:
1894		if (curdom == NULL || *curdom == '\0')
1895			break;
1896		dp = host + strlen(host) - strlen(curdom);
1897		if (dp < host)
1898			break;
1899		if (debug)
1900			fprintf(stderr, "check \"%s\" against curdom \"%s\"\n",
1901			    host, curdom);
1902		if (strcasecmp(dp, curdom) == 0)
1903			return;
1904		break;
1905	case 2:
1906	default:
1907		break;
1908	}
1909
1910	openlog("", LOG_NOWAIT, MULOG);
1911
1912	if (connected && (sep->se_log & MULOG_RFC931))
1913		syslog(LOG_INFO, "%s@%s wants %s",
1914		    rfc931_name(sin, ctrl), host, sep->se_service);
1915	else
1916		syslog(LOG_INFO, "%s wants %s",
1917		    host, sep->se_service);
1918}
1919
1920/*
1921 * From tcp_log by
1922 *  Wietse Venema, Eindhoven University of Technology, The Netherlands.
1923 */
1924#if 0
1925static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";
1926#endif
1927
1928#include <setjmp.h>
1929
1930#define	RFC931_PORT	113		/* Semi-well-known port */
1931#define	TIMEOUT		4
1932#define	TIMEOUT2	10
1933
1934static jmp_buf timebuf;
1935
1936/* timeout - handle timeouts */
1937
1938static void timeout(sig)
1939int     sig;
1940{
1941	longjmp(timebuf, sig);
1942}
1943
1944/* rfc931_name - return remote user name */
1945
1946char *
1947rfc931_name(there, ctrl)
1948struct sockaddr_in *there;		/* remote link information */
1949int	ctrl;
1950{
1951	struct sockaddr_in here;	/* local link information */
1952	struct sockaddr_in sin;		/* for talking to RFC931 daemon */
1953	int		length;
1954	int		s;
1955	unsigned	remote;
1956	unsigned	local;
1957	static char	user[256];		/* XXX */
1958	char		buf[256];
1959	char		*cp;
1960	char		*result = "USER_UNKNOWN";
1961	int		len;
1962
1963	/* Find out local port number of our stdin. */
1964
1965	length = sizeof(here);
1966	if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) {
1967		syslog(LOG_ERR, "getsockname: %m");
1968		return (result);
1969	}
1970	/* Set up timer so we won't get stuck. */
1971
1972	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
1973		syslog(LOG_ERR, "socket: %m");
1974		return (result);
1975	}
1976
1977	sin = here;
1978	sin.sin_port = htons(0);
1979	if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
1980		syslog(LOG_ERR, "bind: %m");
1981		return (result);
1982	}
1983
1984	signal(SIGALRM, timeout);
1985	if (setjmp(timebuf)) {
1986		close(s);			/* not: fclose(fp) */
1987		return (result);
1988	}
1989	alarm(TIMEOUT);
1990
1991	/* Connect to the RFC931 daemon. */
1992
1993	sin = *there;
1994	sin.sin_port = htons(RFC931_PORT);
1995	if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
1996		close(s);
1997		alarm(0);
1998		return (result);
1999	}
2000
2001	/* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
2002	(void)snprintf(buf, sizeof buf, "%u,%u\r\n", ntohs(there->sin_port),
2003	    ntohs(here.sin_port));
2004
2005
2006	for (len = 0, cp = buf; len < strlen(buf); ) {
2007		int	n;
2008
2009		if ((n = write(s, cp, strlen(buf) - len)) == -1) {
2010			close(s);
2011			alarm(0);
2012			return (result);
2013		}
2014		cp += n;
2015		len += n;
2016	}
2017
2018	/* Read response */
2019	for (cp = buf; cp < buf + sizeof(buf) - 1; ) {
2020		char	c;
2021		if (read(s, &c, 1) != 1) {
2022			close(s);
2023			alarm(0);
2024			return (result);
2025		}
2026		if (c == '\n')
2027			break;
2028		*cp++ = c;
2029	}
2030	*cp = '\0';
2031
2032	if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3
2033		&& ntohs(there->sin_port) == remote
2034		&& ntohs(here.sin_port) == local) {
2035
2036		/* Strip trailing carriage return. */
2037		if (cp = strchr(user, '\r'))
2038			*cp = 0;
2039		result = user;
2040	}
2041
2042	alarm(0);
2043	close(s);
2044	return (result);
2045}
2046#endif
2047