inetd.c revision 1.33
1/*	$NetBSD: inetd.c,v 1.33 1997/03/19 00:05:05 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.33 1997/03/19 00:05:05 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 <fcntl.h>
179#include <grp.h>
180#include <netdb.h>
181#include <pwd.h>
182#include <signal.h>
183#include <stdio.h>
184#include <stdlib.h>
185#include <string.h>
186#include <syslog.h>
187#include <unistd.h>
188
189#include "pathnames.h"
190
191#ifdef LIBWRAP
192# include <tcpd.h>
193#ifndef LIBWRAP_ALLOW_FACILITY
194# define LIBWRAP_ALLOW_FACILITY LOG_AUTH
195#endif
196#ifndef LIBWRAP_ALLOW_SEVERITY
197# define LIBWRAP_ALLOW_SEVERITY LOG_INFO
198#endif
199#ifndef LIBWRAP_DENY_FACILITY
200# define LIBWRAP_DENY_FACILITY LOG_AUTH
201#endif
202#ifndef LIBWRAP_DENY_SEVERITY
203# define LIBWRAP_DENY_SEVERITY LOG_WARNING
204#endif
205int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
206int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
207#endif
208
209#define	TOOMANY		40		/* don't start more than TOOMANY */
210#define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
211#define	RETRYTIME	(60*10)		/* retry after bind or server fail */
212
213#define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
214
215int	debug;
216#ifdef LIBWRAP
217int	lflag;
218#endif
219int	nsock, maxsock;
220fd_set	allsock;
221int	options;
222int	timingout;
223struct	servent *sp;
224char	*curdom;
225
226#ifndef OPEN_MAX
227#define OPEN_MAX	64
228#endif
229
230/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
231#define FD_MARGIN	(8)
232typeof(((struct rlimit *)0)->rlim_cur)	rlim_ofile_cur = OPEN_MAX;
233
234#ifdef RLIMIT_NOFILE
235struct rlimit	rlim_ofile;
236#endif
237
238struct	servtab {
239	char	*se_hostaddr;		/* host address to listen on */
240	char	*se_service;		/* name of service */
241	int	se_socktype;		/* type of socket to use */
242	int	se_family;		/* address family */
243	char	*se_proto;		/* protocol used */
244	int	se_rpcprog;		/* rpc program number */
245	int	se_rpcversl;		/* rpc program lowest version */
246	int	se_rpcversh;		/* rpc program highest version */
247#define isrpcservice(sep)	((sep)->se_rpcversl != 0)
248	short	se_wait;		/* single threaded server */
249	short	se_checked;		/* looked at during merge */
250	char	*se_user;		/* user name to run as */
251	char	*se_group;		/* group name to run as */
252	struct	biltin *se_bi;		/* if built-in, description */
253	char	*se_server;		/* server program */
254#define	MAXARGV 20
255	char	*se_argv[MAXARGV+1];	/* program arguments */
256	int	se_fd;			/* open descriptor */
257	int	se_type;		/* type */
258	union {
259		struct	sockaddr se_un_ctrladdr;
260		struct	sockaddr_in se_un_ctrladdr_in;
261		struct	sockaddr_un se_un_ctrladdr_un;
262	} se_un;			/* bound address */
263#define se_ctrladdr	se_un.se_un_ctrladdr
264#define se_ctrladdr_in	se_un.se_un_ctrladdr_in
265#define se_ctrladdr_un	se_un.se_un_ctrladdr_un
266	int	se_ctrladdr_size;
267	int	se_max;			/* max # of instances of this service */
268	int	se_count;		/* number started since se_time */
269	struct	timeval se_time;	/* start of se_count */
270#ifdef MULOG
271	int	se_log;
272#define MULOG_RFC931	0x40000000
273#endif
274	struct	servtab *se_next;
275} *servtab;
276
277#define NORM_TYPE	0
278#define MUX_TYPE	1
279#define MUXPLUS_TYPE	2
280#define ISMUX(sep)	(((sep)->se_type == MUX_TYPE) || \
281			 ((sep)->se_type == MUXPLUS_TYPE))
282#define ISMUXPLUS(sep)	((sep)->se_type == MUXPLUS_TYPE)
283
284
285void		chargen_dg __P((int, struct servtab *));
286void		chargen_stream __P((int, struct servtab *));
287void		close_sep __P((struct servtab *));
288void		config __P((int));
289void		daytime_dg __P((int, struct servtab *));
290void		daytime_stream __P((int, struct servtab *));
291void		discard_dg __P((int, struct servtab *));
292void		discard_stream __P((int, struct servtab *));
293void		echo_dg __P((int, struct servtab *));
294void		echo_stream __P((int, struct servtab *));
295void		endconfig __P((void));
296struct servtab *enter __P((struct servtab *));
297void		freeconfig __P((struct servtab *));
298struct servtab *getconfigent __P((void));
299void		goaway __P((int));
300void		machtime_dg __P((int, struct servtab *));
301void		machtime_stream __P((int, struct servtab *));
302char	       *newstr __P((char *));
303char	       *nextline __P((FILE *));
304void		print_service __P((char *, struct servtab *));
305void		reapchild __P((int));
306void		retry __P((int));
307void		run_service __P((int, struct servtab *));
308int		setconfig __P((void));
309void		setup __P((struct servtab *));
310char	       *sskip __P((char **));
311char	       *skip __P((char **));
312void		tcpmux __P((int, struct servtab *));
313void		usage __P((void));
314
315struct biltin {
316	char	*bi_service;		/* internally provided service name */
317	int	bi_socktype;		/* type of socket supported */
318	short	bi_fork;		/* 1 if should fork before call */
319	short	bi_wait;		/* 1 if should wait for child */
320	void	(*bi_fn)();		/* function which performs it */
321} biltins[] = {
322	/* Echo received data */
323	{ "echo",	SOCK_STREAM,	1, 0,	echo_stream },
324	{ "echo",	SOCK_DGRAM,	0, 0,	echo_dg },
325
326	/* Internet /dev/null */
327	{ "discard",	SOCK_STREAM,	1, 0,	discard_stream },
328	{ "discard",	SOCK_DGRAM,	0, 0,	discard_dg },
329
330	/* Return 32 bit time since 1900 */
331	{ "time",	SOCK_STREAM,	0, 0,	machtime_stream },
332	{ "time",	SOCK_DGRAM,	0, 0,	machtime_dg },
333
334	/* Return human-readable time */
335	{ "daytime",	SOCK_STREAM,	0, 0,	daytime_stream },
336	{ "daytime",	SOCK_DGRAM,	0, 0,	daytime_dg },
337
338	/* Familiar character generator */
339	{ "chargen",	SOCK_STREAM,	1, 0,	chargen_stream },
340	{ "chargen",	SOCK_DGRAM,	0, 0,	chargen_dg },
341
342	{ "tcpmux",	SOCK_STREAM,	1, 0,	tcpmux },
343
344	{ NULL }
345};
346
347#define NUMINT	(sizeof(intab) / sizeof(struct inent))
348char	*CONFIG = _PATH_INETDCONF;
349char	**Argv;
350char 	*LastArg;
351extern char	*__progname;
352
353#ifdef sun
354/*
355 * Sun's RPC library caches the result of `dtablesize()'
356 * This is incompatible with our "bumping" of file descriptors "on demand"
357 */
358int
359_rpc_dtablesize()
360{
361	return rlim_ofile_cur;
362}
363#endif
364
365main(argc, argv, envp)
366	int argc;
367	char *argv[], *envp[];
368{
369	struct servtab *sep, *nsep;
370	struct sigvec sv;
371	int tmpint, ch, dofork;
372	pid_t pid;
373	char buf[50];
374
375	Argv = argv;
376	if (envp == 0 || *envp == 0)
377		envp = argv;
378	while (*envp)
379		envp++;
380	LastArg = envp[-1] + strlen(envp[-1]);
381
382	while ((ch = getopt(argc, argv,
383#ifdef LIBWRAP
384					"dl"
385#else
386					"d"
387#endif
388					   )) != EOF)
389		switch(ch) {
390		case 'd':
391			debug = 1;
392			options |= SO_DEBUG;
393			break;
394#ifdef LIBWRAP
395		case 'l':
396			lflag = 1;
397			break;
398#endif
399		case '?':
400		default:
401			usage();
402		}
403	argc -= optind;
404	argv += optind;
405
406	if (argc > 0)
407		CONFIG = argv[0];
408
409	if (debug == 0)
410		daemon(0, 0);
411	openlog(__progname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
412	logpid();
413
414#ifdef RLIMIT_NOFILE
415	if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
416		syslog(LOG_ERR, "getrlimit: %m");
417	} else {
418		rlim_ofile_cur = rlim_ofile.rlim_cur;
419		if (rlim_ofile_cur == RLIM_INFINITY)	/* ! */
420			rlim_ofile_cur = OPEN_MAX;
421	}
422#endif
423
424	memset(&sv, 0, sizeof(sv));
425	sv.sv_mask = SIGBLOCK;
426	sv.sv_handler = retry;
427	sigvec(SIGALRM, &sv, (struct sigvec *)0);
428	config(SIGHUP);
429	sv.sv_handler = config;
430	sigvec(SIGHUP, &sv, (struct sigvec *)0);
431	sv.sv_handler = reapchild;
432	sigvec(SIGCHLD, &sv, (struct sigvec *)0);
433	sv.sv_handler = goaway;
434	sigvec(SIGTERM, &sv, (struct sigvec *)0);
435	sv.sv_handler = goaway;
436	sigvec(SIGINT, &sv, (struct sigvec *)0);
437
438	{
439		/* space for daemons to overwrite environment for ps */
440#define	DUMMYSIZE	100
441		char dummy[DUMMYSIZE];
442
443		(void)memset(dummy, 'x', DUMMYSIZE - 1);
444		dummy[DUMMYSIZE - 1] = '\0';
445
446		(void)setenv("inetd_dummy", dummy, 1);
447	}
448
449	for (;;) {
450	    int n, ctrl;
451	    fd_set readable;
452
453	    if (nsock == 0) {
454		(void) sigblock(SIGBLOCK);
455		while (nsock == 0)
456		    sigpause(0L);
457		(void) sigsetmask(0L);
458	    }
459	    readable = allsock;
460	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
461		(fd_set *)0, (struct timeval *)0)) <= 0) {
462		    if (n < 0 && errno != EINTR)
463			syslog(LOG_WARNING, "select: %m");
464		    sleep(1);
465		    continue;
466	    }
467	    for (sep = servtab; n && sep; sep = nsep) {
468	    nsep = sep->se_next;
469	    if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
470		n--;
471		if (debug)
472			fprintf(stderr, "someone wants %s\n", sep->se_service);
473		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
474			/* XXX here do the libwrap check-before-accept */
475			ctrl = accept(sep->se_fd, (struct sockaddr *)0,
476			    (int *)0);
477			if (debug)
478				fprintf(stderr, "accept, ctrl %d\n", ctrl);
479			if (ctrl < 0) {
480				if (errno != EINTR)
481					syslog(LOG_WARNING,
482					    "accept (for %s): %m",
483					    sep->se_service);
484				continue;
485			}
486		} else
487			ctrl = sep->se_fd;
488		(void) sigblock(SIGBLOCK);
489		pid = 0;
490#ifdef LIBWRAP_INTERNAL
491		dofork = 1;
492#else
493		dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
494#endif
495		if (dofork) {
496			if (sep->se_count++ == 0)
497			    (void)gettimeofday(&sep->se_time,
498			        (struct timezone *)0);
499			else if (sep->se_count >= sep->se_max) {
500				struct timeval now;
501
502				(void)gettimeofday(&now, (struct timezone *)0);
503				if (now.tv_sec - sep->se_time.tv_sec >
504				    CNT_INTVL) {
505					sep->se_time = now;
506					sep->se_count = 1;
507				} else {
508					syslog(LOG_ERR,
509			"%s/%s server failing (looping), service terminated\n",
510					    sep->se_service, sep->se_proto);
511					close_sep(sep);
512					sigsetmask(0L);
513					if (!timingout) {
514						timingout = 1;
515						alarm(RETRYTIME);
516					}
517					continue;
518				}
519			}
520			pid = fork();
521			if (pid < 0) {
522				syslog(LOG_ERR, "fork: %m");
523				if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
524					close(ctrl);
525				sigsetmask(0L);
526				sleep(1);
527				continue;
528			}
529			if (pid != 0 && sep->se_wait) {
530				sep->se_wait = pid;
531				FD_CLR(sep->se_fd, &allsock);
532				nsock--;
533			}
534			if (pid == 0 && debug)
535				setsid();
536		}
537		sigsetmask(0L);
538		if (pid == 0) {
539			run_service(ctrl, sep);
540			if (dofork)
541				exit(0);
542		}
543		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
544			close(ctrl);
545	    }
546	    }
547	}
548}
549
550void
551run_service(ctrl, sep)
552	int ctrl;
553	struct servtab *sep;
554{
555	struct passwd *pwd;
556	struct group *grp;
557#ifdef LIBWRAP
558	struct request_info req;
559	int denied;
560	char buf[7], *service;
561#endif
562
563#ifdef LIBWRAP
564#ifndef LIBWRAP_INTERNAL
565	if (sep->se_bi == 0)
566#endif
567	if (!sep->se_wait || sep->se_socktype != SOCK_STREAM) {
568		request_init(&req, RQ_DAEMON, sep->se_argv[0] ?
569		    sep->se_argv[0] : sep->se_service, RQ_FILE, ctrl, NULL);
570		fromhost(&req);
571		denied = !hosts_access(&req);
572		if (denied || lflag) {
573			sp = getservbyport(sep->se_ctrladdr_in.sin_port,
574			    sep->se_proto);
575			if (sp == NULL) {
576				(void)snprintf(buf, sizeof buf, "%d",
577				    ntohs(sep->se_ctrladdr_in.sin_port));
578				service = buf;
579			} else
580				service = sp->s_name;
581		}
582		if (denied) {
583			syslog(deny_severity,
584			    "refused connection from %.500s, service %s (%s)",
585			    eval_client(&req), service, sep->se_proto);
586			goto reject;
587		}
588		if (lflag) {
589			syslog(allow_severity,
590			    "connection from %.500s, service %s (%s)",
591			    eval_client(&req), service, sep->se_proto);
592		}
593	}
594#endif /* LIBWRAP */
595
596	if (sep->se_bi) {
597		(*sep->se_bi->bi_fn)(ctrl, sep);
598	} else {
599		if ((pwd = getpwnam(sep->se_user)) == NULL) {
600			syslog(LOG_ERR, "%s/%s: %s: No such user",
601			    sep->se_service, sep->se_proto, sep->se_user);
602			goto reject;
603		}
604		if (sep->se_group &&
605		    (grp = getgrnam(sep->se_group)) == NULL) {
606			syslog(LOG_ERR, "%s/%s: %s: No such group",
607			    sep->se_service, sep->se_proto, sep->se_group);
608			goto reject;
609		}
610		if (pwd->pw_uid) {
611			if (sep->se_group)
612				pwd->pw_gid = grp->gr_gid;
613			if (setgid(pwd->pw_gid) < 0) {
614				syslog(LOG_ERR,
615				 "%s/%s: can't set gid %d: %m", sep->se_service,
616				    sep->se_proto, pwd->pw_gid);
617				goto reject;
618			}
619			(void) initgroups(pwd->pw_name,
620			    pwd->pw_gid);
621			if (setuid(pwd->pw_uid) < 0) {
622				syslog(LOG_ERR,
623				 "%s/%s: can't set uid %d: %m", sep->se_service,
624				    sep->se_proto, pwd->pw_uid);
625				goto reject;
626			}
627		} else if (sep->se_group) {
628			(void) setgid((gid_t)grp->gr_gid);
629		}
630		if (debug)
631			fprintf(stderr, "%d execl %s\n",
632			    getpid(), sep->se_server);
633#ifdef MULOG
634		if (sep->se_log)
635			dolog(sep, ctrl);
636#endif
637		/* Set our control descriptor to not close-on-exec... */
638		if (fcntl(ctrl, F_SETFD, 0) < 0)
639			syslog(LOG_ERR, "fcntl (F_SETFD, 0): %m");
640		/* ...and dup it to stdin, stdout, and stderr. */
641		if (ctrl != 0) {
642			dup2(ctrl, 0);
643			close(ctrl);
644			ctrl = 0;
645		}
646		dup2(0, 1);
647		dup2(0, 2);
648#ifdef RLIMIT_NOFILE
649		if (rlim_ofile.rlim_cur != rlim_ofile_cur &&
650		    setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
651			syslog(LOG_ERR, "setrlimit: %m");
652#endif
653		execv(sep->se_server, sep->se_argv);
654		syslog(LOG_ERR, "cannot execute %s: %m", sep->se_server);
655	reject:
656		if (sep->se_socktype != SOCK_STREAM)
657			recv(ctrl, buf, sizeof (buf), 0);
658		_exit(1);
659	}
660}
661
662void
663reapchild(signo)
664	int signo;
665{
666	int status;
667	pid_t pid;
668	struct servtab *sep;
669
670	for (;;) {
671		pid = wait3(&status, WNOHANG, (struct rusage *)0);
672		if (pid <= 0)
673			break;
674		if (debug)
675			fprintf(stderr, "%d reaped, status %#x\n",
676			    pid, status);
677		for (sep = servtab; sep; sep = sep->se_next)
678			if (sep->se_wait == pid) {
679				if (WIFEXITED(status) && WEXITSTATUS(status))
680					syslog(LOG_WARNING,
681					    "%s: exit status 0x%x",
682					    sep->se_server, WEXITSTATUS(status));
683				else if (WIFSIGNALED(status))
684					syslog(LOG_WARNING,
685					    "%s: exit signal 0x%x",
686					    sep->se_server, WTERMSIG(status));
687				sep->se_wait = 1;
688				FD_SET(sep->se_fd, &allsock);
689				nsock++;
690				if (debug)
691					fprintf(stderr, "restored %s, fd %d\n",
692					    sep->se_service, sep->se_fd);
693			}
694	}
695}
696
697void
698config(signo)
699	int signo;
700{
701	struct servtab *sep, *cp, **sepp;
702	struct passwd *pwd;
703	long omask;
704	int n;
705
706	if (!setconfig()) {
707		syslog(LOG_ERR, "%s: %m", CONFIG);
708		return;
709	}
710	for (sep = servtab; sep; sep = sep->se_next)
711		sep->se_checked = 0;
712	while (cp = getconfigent()) {
713		for (sep = servtab; sep; sep = sep->se_next)
714			if (strcmp(sep->se_service, cp->se_service) == 0 &&
715			    strcmp(sep->se_hostaddr, cp->se_hostaddr) == 0 &&
716			    strcmp(sep->se_proto, cp->se_proto) == 0 &&
717			    ISMUX(sep) == ISMUX(cp))
718				break;
719		if (sep != 0) {
720			int i;
721
722#define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
723
724			omask = sigblock(SIGBLOCK);
725			/*
726			 * sep->se_wait may be holding the pid of a daemon
727			 * that we're waiting for.  If so, don't overwrite
728			 * it unless the config file explicitly says don't
729			 * wait.
730			 */
731			if (cp->se_bi == 0 &&
732			    (sep->se_wait == 1 || cp->se_wait == 0))
733				sep->se_wait = cp->se_wait;
734			SWAP(char *, sep->se_user, cp->se_user);
735			SWAP(char *, sep->se_group, cp->se_group);
736			SWAP(char *, sep->se_server, cp->se_server);
737			for (i = 0; i < MAXARGV; i++)
738				SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
739			SWAP(int, cp->se_type, sep->se_type);
740			SWAP(int, cp->se_max, sep->se_max);
741#undef SWAP
742			if (isrpcservice(sep))
743				unregister_rpc(sep);
744			sep->se_rpcversl = cp->se_rpcversl;
745			sep->se_rpcversh = cp->se_rpcversh;
746			sigsetmask(omask);
747			freeconfig(cp);
748			if (debug)
749				print_service("REDO", sep);
750		} else {
751			sep = enter(cp);
752			if (debug)
753				print_service("ADD ", sep);
754		}
755		sep->se_checked = 1;
756
757		switch (sep->se_family) {
758		case AF_UNIX:
759			if (sep->se_fd != -1)
760				break;
761			(void)unlink(sep->se_service);
762			n = strlen(sep->se_service);
763			if (n > sizeof(sep->se_ctrladdr_un.sun_path) - 1)
764				n = sizeof(sep->se_ctrladdr_un.sun_path) - 1;
765			strncpy(sep->se_ctrladdr_un.sun_path,
766			    sep->se_service, n);
767			sep->se_ctrladdr_un.sun_family = AF_UNIX;
768			sep->se_ctrladdr_size = n +
769			    sizeof(sep->se_ctrladdr_un) -
770			    sizeof(sep->se_ctrladdr_un.sun_path);
771			if (!ISMUX(sep))
772				setup(sep);
773			break;
774		case AF_INET:
775			sep->se_ctrladdr_in.sin_family = AF_INET;
776			if (!strcmp(sep->se_hostaddr,"*"))
777				sep->se_ctrladdr_in.sin_addr.s_addr =
778				    INADDR_ANY;
779			else if (!inet_aton(sep->se_hostaddr,
780			    &sep->se_ctrladdr_in.sin_addr)) {
781				/* Do we really want to support hostname lookups here? */
782				struct hostent *hp;
783				hp = gethostbyname(sep->se_hostaddr);
784				if (hp == 0) {
785					syslog(LOG_ERR, "%s: unknown host",
786					    sep->se_hostaddr);
787					sep->se_checked = 0;
788					continue;
789				} else if (hp->h_addrtype != AF_INET) {
790					syslog(LOG_ERR,
791				       "%s: address isn't an Internet address",
792					    sep->se_hostaddr);
793					sep->se_checked = 0;
794					continue;
795				} else if (hp->h_length != sizeof(struct in_addr)) {
796					syslog(LOG_ERR,
797		       "%s: address size wrong (under DNS corruption attack?)",
798					    sep->se_hostaddr);
799					sep->se_checked = 0;
800					continue;
801				} else {
802					memcpy(&sep->se_ctrladdr_in.sin_addr,
803					    hp->h_addr_list[0],
804					    sizeof(struct in_addr));
805				}
806			}
807			if (ISMUX(sep)) {
808				sep->se_fd = -1;
809				continue;
810			}
811			sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr_in);
812			if (isrpcservice(sep)) {
813				struct rpcent *rp;
814
815				sep->se_rpcprog = atoi(sep->se_service);
816				if (sep->se_rpcprog == 0) {
817					rp = getrpcbyname(sep->se_service);
818					if (rp == 0) {
819						syslog(LOG_ERR,
820						    "%s/%s: unknown service",
821						    sep->se_service,
822						    sep->se_proto);
823						sep->se_checked = 0;
824						continue;
825					}
826					sep->se_rpcprog = rp->r_number;
827				}
828				if (sep->se_fd == -1 && !ISMUX(sep))
829					setup(sep);
830				if (sep->se_fd != -1)
831					register_rpc(sep);
832			} else {
833				u_short port = htons(atoi(sep->se_service));
834
835				if (!port) {
836					sp = getservbyname(sep->se_service,
837					    sep->se_proto);
838					if (sp == 0) {
839						syslog(LOG_ERR,
840						    "%s/%s: unknown service",
841						    sep->se_service,
842						    sep->se_proto);
843						sep->se_checked = 0;
844						continue;
845					}
846					port = sp->s_port;
847				}
848				if (port != sep->se_ctrladdr_in.sin_port) {
849					sep->se_ctrladdr_in.sin_port = port;
850					if (sep->se_fd >= 0)
851						close_sep(sep);
852				}
853				if (sep->se_fd == -1 && !ISMUX(sep))
854					setup(sep);
855			}
856		}
857	}
858	endconfig();
859	/*
860	 * Purge anything not looked at above.
861	 */
862	omask = sigblock(SIGBLOCK);
863	sepp = &servtab;
864	while (sep = *sepp) {
865		if (sep->se_checked) {
866			sepp = &sep->se_next;
867			continue;
868		}
869		*sepp = sep->se_next;
870		if (sep->se_fd >= 0)
871			close_sep(sep);
872		if (isrpcservice(sep))
873			unregister_rpc(sep);
874		if (sep->se_family == AF_UNIX)
875			(void)unlink(sep->se_service);
876		if (debug)
877			print_service("FREE", sep);
878		freeconfig(sep);
879		free((char *)sep);
880	}
881	(void) sigsetmask(omask);
882}
883
884void
885retry(signo)
886	int signo;
887{
888	struct servtab *sep;
889
890	timingout = 0;
891	for (sep = servtab; sep; sep = sep->se_next) {
892		if (sep->se_fd == -1 && !ISMUX(sep)) {
893			switch (sep->se_family) {
894			case AF_UNIX:
895			case AF_INET:
896				setup(sep);
897				if (sep->se_fd != -1 && isrpcservice(sep))
898					register_rpc(sep);
899				break;
900			}
901		}
902	}
903}
904
905void
906goaway(signo)
907	int signo;
908{
909	register struct servtab *sep;
910
911	for (sep = servtab; sep; sep = sep->se_next) {
912		if (sep->se_fd == -1)
913			continue;
914
915		switch (sep->se_family) {
916		case AF_UNIX:
917			(void)unlink(sep->se_service);
918			break;
919		case AF_INET:
920			if (sep->se_wait == 1 && isrpcservice(sep))
921				unregister_rpc(sep);
922			break;
923		}
924		(void)close(sep->se_fd);
925	}
926	(void)unlink(_PATH_INETDPID);
927	exit(0);
928}
929
930void
931setup(sep)
932	struct servtab *sep;
933{
934	int on = 1;
935
936	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
937		if (debug)
938			fprintf(stderr, "socket failed on %s/%s: %s\n",
939			    sep->se_service, sep->se_proto, strerror(errno));
940		syslog(LOG_ERR, "%s/%s: socket: %m",
941		    sep->se_service, sep->se_proto);
942		return;
943	}
944	/* Set all listening sockets to close-on-exec. */
945	if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0)
946		syslog(LOG_ERR, "fcntl (F_SETFD, FD_CLOEXEC): %m");
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
1806void
1807tcpmux(ctrl, sep)
1808	int ctrl;
1809	struct servtab *sep;
1810{
1811	char service[MAX_SERV_LEN+1];
1812	int len;
1813
1814	/* Get requested service name */
1815	if ((len = getline(ctrl, service, MAX_SERV_LEN)) < 0) {
1816		strwrite(ctrl, "-Error reading service name\r\n");
1817		goto reject;
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		strwrite(ctrl, "+Available services:\r\n");
1830		strwrite(ctrl, "help\r\n");
1831		for (sep = servtab; sep; sep = sep->se_next) {
1832			if (!ISMUX(sep))
1833				continue;
1834			(void)write(ctrl, sep->se_service,
1835			    strlen(sep->se_service));
1836			strwrite(ctrl, "\r\n");
1837		}
1838		goto reject;
1839	}
1840
1841	/* Try matching a service in inetd.conf with the request */
1842	for (sep = servtab; sep; sep = sep->se_next) {
1843		if (!ISMUX(sep))
1844			continue;
1845		if (!strcasecmp(service, sep->se_service)) {
1846			if (ISMUXPLUS(sep))
1847				strwrite(ctrl, "+Go\r\n");
1848			run_service(ctrl, sep);
1849			return;
1850		}
1851	}
1852	strwrite(ctrl, "-Service not available\r\n");
1853reject:
1854	_exit(1);
1855}
1856
1857
1858#ifdef MULOG
1859dolog(sep, ctrl)
1860	struct servtab *sep;
1861	int		ctrl;
1862{
1863	struct sockaddr		sa;
1864	struct sockaddr_in	*sin = (struct sockaddr_in *)&sa;
1865	int			len = sizeof(sa);
1866	struct hostent		*hp;
1867	char			*host, *dp, buf[BUFSIZ], *rfc931_name();
1868	int			connected = 1;
1869
1870	if (sep->se_family != AF_INET)
1871		return;
1872
1873	if (getpeername(ctrl, &sa, &len) < 0) {
1874		if (errno != ENOTCONN) {
1875			syslog(LOG_ERR, "getpeername: %m");
1876			return;
1877		}
1878		if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) {
1879			syslog(LOG_ERR, "recvfrom: %m");
1880			return;
1881		}
1882		connected = 0;
1883	}
1884	if (sa.sa_family != AF_INET) {
1885		syslog(LOG_ERR, "unexpected address family %u", sa.sa_family);
1886		return;
1887	}
1888
1889	hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
1890				sizeof (sin->sin_addr.s_addr), AF_INET);
1891
1892	host = hp?hp->h_name:inet_ntoa(sin->sin_addr);
1893
1894	switch (sep->se_log & ~MULOG_RFC931) {
1895	case 0:
1896		return;
1897	case 1:
1898		if (curdom == NULL || *curdom == '\0')
1899			break;
1900		dp = host + strlen(host) - strlen(curdom);
1901		if (dp < host)
1902			break;
1903		if (debug)
1904			fprintf(stderr, "check \"%s\" against curdom \"%s\"\n",
1905			    host, curdom);
1906		if (strcasecmp(dp, curdom) == 0)
1907			return;
1908		break;
1909	case 2:
1910	default:
1911		break;
1912	}
1913
1914	openlog("", LOG_NOWAIT, MULOG);
1915
1916	if (connected && (sep->se_log & MULOG_RFC931))
1917		syslog(LOG_INFO, "%s@%s wants %s",
1918		    rfc931_name(sin, ctrl), host, sep->se_service);
1919	else
1920		syslog(LOG_INFO, "%s wants %s",
1921		    host, sep->se_service);
1922}
1923
1924/*
1925 * From tcp_log by
1926 *  Wietse Venema, Eindhoven University of Technology, The Netherlands.
1927 */
1928#if 0
1929static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";
1930#endif
1931
1932#include <setjmp.h>
1933
1934#define	RFC931_PORT	113		/* Semi-well-known port */
1935#define	TIMEOUT		4
1936#define	TIMEOUT2	10
1937
1938static jmp_buf timebuf;
1939
1940/* timeout - handle timeouts */
1941
1942static void timeout(sig)
1943int     sig;
1944{
1945	longjmp(timebuf, sig);
1946}
1947
1948/* rfc931_name - return remote user name */
1949
1950char *
1951rfc931_name(there, ctrl)
1952struct sockaddr_in *there;		/* remote link information */
1953int	ctrl;
1954{
1955	struct sockaddr_in here;	/* local link information */
1956	struct sockaddr_in sin;		/* for talking to RFC931 daemon */
1957	int		length;
1958	int		s;
1959	unsigned	remote;
1960	unsigned	local;
1961	static char	user[256];		/* XXX */
1962	char		buf[256];
1963	char		*cp;
1964	char		*result = "USER_UNKNOWN";
1965	int		len;
1966
1967	/* Find out local port number of our stdin. */
1968
1969	length = sizeof(here);
1970	if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) {
1971		syslog(LOG_ERR, "getsockname: %m");
1972		return (result);
1973	}
1974	/* Set up timer so we won't get stuck. */
1975
1976	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
1977		syslog(LOG_ERR, "socket: %m");
1978		return (result);
1979	}
1980
1981	sin = here;
1982	sin.sin_port = htons(0);
1983	if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
1984		syslog(LOG_ERR, "bind: %m");
1985		return (result);
1986	}
1987
1988	signal(SIGALRM, timeout);
1989	if (setjmp(timebuf)) {
1990		close(s);			/* not: fclose(fp) */
1991		return (result);
1992	}
1993	alarm(TIMEOUT);
1994
1995	/* Connect to the RFC931 daemon. */
1996
1997	sin = *there;
1998	sin.sin_port = htons(RFC931_PORT);
1999	if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
2000		close(s);
2001		alarm(0);
2002		return (result);
2003	}
2004
2005	/* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
2006	(void)snprintf(buf, sizeof buf, "%u,%u\r\n", ntohs(there->sin_port),
2007	    ntohs(here.sin_port));
2008
2009
2010	for (len = 0, cp = buf; len < strlen(buf); ) {
2011		int	n;
2012
2013		if ((n = write(s, cp, strlen(buf) - len)) == -1) {
2014			close(s);
2015			alarm(0);
2016			return (result);
2017		}
2018		cp += n;
2019		len += n;
2020	}
2021
2022	/* Read response */
2023	for (cp = buf; cp < buf + sizeof(buf) - 1; ) {
2024		char	c;
2025		if (read(s, &c, 1) != 1) {
2026			close(s);
2027			alarm(0);
2028			return (result);
2029		}
2030		if (c == '\n')
2031			break;
2032		*cp++ = c;
2033	}
2034	*cp = '\0';
2035
2036	if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3
2037		&& ntohs(there->sin_port) == remote
2038		&& ntohs(here.sin_port) == local) {
2039
2040		/* Strip trailing carriage return. */
2041		if (cp = strchr(user, '\r'))
2042			*cp = 0;
2043		result = user;
2044	}
2045
2046	alarm(0);
2047	close(s);
2048	return (result);
2049}
2050#endif
2051