inetd.c revision 1.28
1/*	$NetBSD: inetd.c,v 1.28 1997/03/13 18:36:37 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.28 1997/03/13 18:36:37 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_INTERNAL
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#ifndef LIBWRAP_INTERNAL
557		    if (sep->se_bi != 0)
558#endif
559		    {
560			request_init(&req, RQ_DAEMON, sep->se_argv[0] ?
561			    sep->se_argv[0] : sep->se_service, RQ_FILE, ctrl,
562			    NULL);
563			fromhost(&req);
564			denied = !hosts_access(&req);
565			if (denied || lflag) {
566				sp = getservbyport(sep->se_ctrladdr_in.sin_port,
567				    sep->se_proto);
568				if (sp == NULL) {
569					(void)snprintf(buf, sizeof buf, "%d",
570					    ntohs(sep->se_ctrladdr_in.sin_port));
571					service = buf;
572				} else
573					service = sp->s_name;
574			}
575			if (denied) {
576				syslog(deny_severity, "refused "
577				    "connection from %.500s, service %s (%s)",
578				    eval_client(&req), service, sep->se_proto);
579				goto reject;
580			}
581			if (lflag) {
582				syslog(allow_severity,
583				    "connection from %.500s, service %s (%s)",
584				    eval_client(&req), service, sep->se_proto);
585			}
586		    }
587#endif /* LIBWRAP */
588			if (sep->se_bi) {
589				(*sep->se_bi->bi_fn)(ctrl, sep);
590				if (dofork)
591					exit(0);
592			} else {
593				if ((pwd = getpwnam(sep->se_user)) == NULL) {
594					syslog(LOG_ERR,
595					    "%s/%s: %s: No such user",
596					    sep->se_service, sep->se_proto,
597					    sep->se_user);
598					goto reject;
599				}
600				if (sep->se_group &&
601				    (grp = getgrnam(sep->se_group)) == NULL) {
602					syslog(LOG_ERR,
603					    "%s/%s: %s: No such group",
604					    sep->se_service, sep->se_proto,
605					    sep->se_group);
606					goto reject;
607				}
608				if (pwd->pw_uid) {
609					if (sep->se_group)
610						pwd->pw_gid = grp->gr_gid;
611					if (setgid(pwd->pw_gid) < 0) {
612						syslog(LOG_ERR,
613						 "%s/%s: can't set gid %d: %m",
614						    sep->se_service,
615						    sep->se_proto, pwd->pw_gid);
616						goto reject;
617					}
618					(void) initgroups(pwd->pw_name,
619					    pwd->pw_gid);
620					if (setuid(pwd->pw_uid) < 0) {
621						syslog(LOG_ERR,
622						 "%s/%s: can't set uid %d: %m",
623						    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				if (ctrl != 0) {
638					dup2(ctrl, 0);
639					close(ctrl);
640					ctrl = 0;
641				}
642				dup2(0, 1);
643				dup2(0, 2);
644#ifdef RLIMIT_NOFILE
645				if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
646					if (setrlimit(RLIMIT_NOFILE,
647							&rlim_ofile) < 0)
648						syslog(LOG_ERR,
649						    "setrlimit: %m");
650				}
651#endif
652				for (tmpint = rlim_ofile_cur-1; --tmpint > 2; )
653					(void)close(tmpint);
654				execv(sep->se_server, sep->se_argv);
655				syslog(LOG_ERR,
656				    "cannot execute %s: %m", sep->se_server);
657			reject:
658				if (sep->se_socktype != SOCK_STREAM)
659					recv(ctrl, buf, sizeof (buf), 0);
660				_exit(1);
661			}
662		}
663		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
664			close(ctrl);
665	    }
666	    }
667	}
668}
669
670void
671reapchild(signo)
672	int signo;
673{
674	int status;
675	pid_t pid;
676	struct servtab *sep;
677
678	for (;;) {
679		pid = wait3(&status, WNOHANG, (struct rusage *)0);
680		if (pid <= 0)
681			break;
682		if (debug)
683			fprintf(stderr, "%d reaped, status %#x\n",
684			    pid, status);
685		for (sep = servtab; sep; sep = sep->se_next)
686			if (sep->se_wait == pid) {
687				if (WIFEXITED(status) && WEXITSTATUS(status))
688					syslog(LOG_WARNING,
689					    "%s: exit status 0x%x",
690					    sep->se_server, WEXITSTATUS(status));
691				else if (WIFSIGNALED(status))
692					syslog(LOG_WARNING,
693					    "%s: exit signal 0x%x",
694					    sep->se_server, WTERMSIG(status));
695				sep->se_wait = 1;
696				FD_SET(sep->se_fd, &allsock);
697				nsock++;
698				if (debug)
699					fprintf(stderr, "restored %s, fd %d\n",
700					    sep->se_service, sep->se_fd);
701			}
702	}
703}
704
705void
706config(signo)
707	int signo;
708{
709	struct servtab *sep, *cp, **sepp;
710	struct passwd *pwd;
711	long omask;
712	int n;
713
714	if (!setconfig()) {
715		syslog(LOG_ERR, "%s: %m", CONFIG);
716		return;
717	}
718	for (sep = servtab; sep; sep = sep->se_next)
719		sep->se_checked = 0;
720	while (cp = getconfigent()) {
721		for (sep = servtab; sep; sep = sep->se_next)
722			if (strcmp(sep->se_service, cp->se_service) == 0 &&
723			    strcmp(sep->se_hostaddr, cp->se_hostaddr) == 0 &&
724			    strcmp(sep->se_proto, cp->se_proto) == 0 &&
725			    ISMUX(sep) == ISMUX(cp))
726				break;
727		if (sep != 0) {
728			int i;
729
730#define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
731
732			omask = sigblock(SIGBLOCK);
733			/*
734			 * sep->se_wait may be holding the pid of a daemon
735			 * that we're waiting for.  If so, don't overwrite
736			 * it unless the config file explicitly says don't
737			 * wait.
738			 */
739			if (cp->se_bi == 0 &&
740			    (sep->se_wait == 1 || cp->se_wait == 0))
741				sep->se_wait = cp->se_wait;
742			SWAP(char *, sep->se_user, cp->se_user);
743			SWAP(char *, sep->se_group, cp->se_group);
744			SWAP(char *, sep->se_server, cp->se_server);
745			for (i = 0; i < MAXARGV; i++)
746				SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
747			SWAP(int, cp->se_type, sep->se_type);
748			SWAP(int, cp->se_max, sep->se_max);
749#undef SWAP
750			if (isrpcservice(sep))
751				unregister_rpc(sep);
752			sep->se_rpcversl = cp->se_rpcversl;
753			sep->se_rpcversh = cp->se_rpcversh;
754			sigsetmask(omask);
755			freeconfig(cp);
756			if (debug)
757				print_service("REDO", sep);
758		} else {
759			sep = enter(cp);
760			if (debug)
761				print_service("ADD ", sep);
762		}
763		sep->se_checked = 1;
764
765		switch (sep->se_family) {
766		case AF_UNIX:
767			if (sep->se_fd != -1)
768				break;
769			(void)unlink(sep->se_service);
770			n = strlen(sep->se_service);
771			if (n > sizeof(sep->se_ctrladdr_un.sun_path) - 1)
772				n = sizeof(sep->se_ctrladdr_un.sun_path) - 1;
773			strncpy(sep->se_ctrladdr_un.sun_path,
774			    sep->se_service, n);
775			sep->se_ctrladdr_un.sun_family = AF_UNIX;
776			sep->se_ctrladdr_size = n +
777			    sizeof(sep->se_ctrladdr_un) -
778			    sizeof(sep->se_ctrladdr_un.sun_path);
779			if (!ISMUX(sep))
780				setup(sep);
781			break;
782		case AF_INET:
783			sep->se_ctrladdr_in.sin_family = AF_INET;
784			if (!strcmp(sep->se_hostaddr,"*"))
785				sep->se_ctrladdr_in.sin_addr.s_addr =
786				    INADDR_ANY;
787			else if (!inet_aton(sep->se_hostaddr,
788			    &sep->se_ctrladdr_in.sin_addr)) {
789				/* Do we really want to support hostname lookups here? */
790				struct hostent *hp;
791				hp = gethostbyname(sep->se_hostaddr);
792				if (hp == 0) {
793					syslog(LOG_ERR, "%s: unknown host",
794					    sep->se_hostaddr);
795					sep->se_checked = 0;
796					continue;
797				} else if (hp->h_addrtype != AF_INET) {
798					syslog(LOG_ERR,
799				       "%s: address isn't an Internet address",
800					    sep->se_hostaddr);
801					sep->se_checked = 0;
802					continue;
803				} else if (hp->h_length != sizeof(struct in_addr)) {
804					syslog(LOG_ERR,
805		       "%s: address size wrong (under DNS corruption attack?)",
806					    sep->se_hostaddr);
807					sep->se_checked = 0;
808					continue;
809				} else {
810					memcpy(&sep->se_ctrladdr_in.sin_addr,
811					    hp->h_addr_list[0],
812					    sizeof(struct in_addr));
813				}
814			}
815			if (ISMUX(sep)) {
816				sep->se_fd = -1;
817				continue;
818			}
819			sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr_in);
820			if (isrpcservice(sep)) {
821				struct rpcent *rp;
822
823				sep->se_rpcprog = atoi(sep->se_service);
824				if (sep->se_rpcprog == 0) {
825					rp = getrpcbyname(sep->se_service);
826					if (rp == 0) {
827						syslog(LOG_ERR,
828						    "%s/%s: unknown service",
829						    sep->se_service,
830						    sep->se_proto);
831						sep->se_checked = 0;
832						continue;
833					}
834					sep->se_rpcprog = rp->r_number;
835				}
836				if (sep->se_fd == -1 && !ISMUX(sep))
837					setup(sep);
838				if (sep->se_fd != -1)
839					register_rpc(sep);
840			} else {
841				u_short port = htons(atoi(sep->se_service));
842
843				if (!port) {
844					sp = getservbyname(sep->se_service,
845					    sep->se_proto);
846					if (sp == 0) {
847						syslog(LOG_ERR,
848						    "%s/%s: unknown service",
849						    sep->se_service,
850						    sep->se_proto);
851						sep->se_checked = 0;
852						continue;
853					}
854					port = sp->s_port;
855				}
856				if (port != sep->se_ctrladdr_in.sin_port) {
857					sep->se_ctrladdr_in.sin_port = port;
858					if (sep->se_fd >= 0)
859						close_sep(sep);
860				}
861				if (sep->se_fd == -1 && !ISMUX(sep))
862					setup(sep);
863			}
864		}
865	}
866	endconfig();
867	/*
868	 * Purge anything not looked at above.
869	 */
870	omask = sigblock(SIGBLOCK);
871	sepp = &servtab;
872	while (sep = *sepp) {
873		if (sep->se_checked) {
874			sepp = &sep->se_next;
875			continue;
876		}
877		*sepp = sep->se_next;
878		if (sep->se_fd >= 0)
879			close_sep(sep);
880		if (isrpcservice(sep))
881			unregister_rpc(sep);
882		if (sep->se_family == AF_UNIX)
883			(void)unlink(sep->se_service);
884		if (debug)
885			print_service("FREE", sep);
886		freeconfig(sep);
887		free((char *)sep);
888	}
889	(void) sigsetmask(omask);
890}
891
892void
893retry(signo)
894	int signo;
895{
896	struct servtab *sep;
897
898	timingout = 0;
899	for (sep = servtab; sep; sep = sep->se_next) {
900		if (sep->se_fd == -1 && !ISMUX(sep)) {
901			switch (sep->se_family) {
902			case AF_UNIX:
903			case AF_INET:
904				setup(sep);
905				if (sep->se_fd != -1 && isrpcservice(sep))
906					register_rpc(sep);
907				break;
908			}
909		}
910	}
911}
912
913void
914goaway(signo)
915	int signo;
916{
917	register struct servtab *sep;
918
919	for (sep = servtab; sep; sep = sep->se_next) {
920		if (sep->se_fd == -1)
921			continue;
922
923		switch (sep->se_family) {
924		case AF_UNIX:
925			(void)unlink(sep->se_service);
926			break;
927		case AF_INET:
928			if (sep->se_wait == 1 && isrpcservice(sep))
929				unregister_rpc(sep);
930			break;
931		}
932		(void)close(sep->se_fd);
933	}
934	(void)unlink(_PATH_INETDPID);
935	exit(0);
936}
937
938void
939setup(sep)
940	struct servtab *sep;
941{
942	int on = 1;
943
944	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
945		if (debug)
946			fprintf(stderr, "socket failed on %s/%s: %s\n",
947			    sep->se_service, sep->se_proto, strerror(errno));
948		syslog(LOG_ERR, "%s/%s: socket: %m",
949		    sep->se_service, sep->se_proto);
950		return;
951	}
952#define	turnon(fd, opt) \
953setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
954	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
955	    turnon(sep->se_fd, SO_DEBUG) < 0)
956		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
957	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
958		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
959#undef turnon
960	if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
961		if (debug)
962			fprintf(stderr, "bind failed on %s/%s: %s\n",
963			    sep->se_service, sep->se_proto, strerror(errno));
964		syslog(LOG_ERR, "%s/%s: bind: %m",
965		    sep->se_service, sep->se_proto);
966		(void) close(sep->se_fd);
967		sep->se_fd = -1;
968		if (!timingout) {
969			timingout = 1;
970			alarm(RETRYTIME);
971		}
972		return;
973	}
974	if (sep->se_socktype == SOCK_STREAM)
975		listen(sep->se_fd, 10);
976
977	FD_SET(sep->se_fd, &allsock);
978	nsock++;
979	if (sep->se_fd > maxsock) {
980		maxsock = sep->se_fd;
981		if (maxsock > rlim_ofile_cur - FD_MARGIN)
982			bump_nofile();
983	}
984	if (debug)
985		fprintf(stderr, "registered %s on %d\n",
986		    sep->se_server, sep->se_fd);
987}
988
989/*
990 * Finish with a service and its socket.
991 */
992void
993close_sep(sep)
994	struct servtab *sep;
995{
996	if (sep->se_fd >= 0) {
997		nsock--;
998		FD_CLR(sep->se_fd, &allsock);
999		(void) close(sep->se_fd);
1000		sep->se_fd = -1;
1001	}
1002	sep->se_count = 0;
1003	/*
1004	 * Don't keep the pid of this running deamon: when reapchild()
1005	 * reaps this pid, it would erroneously increment nsock.
1006	 */
1007	if (sep->se_wait > 1)
1008		sep->se_wait = 1;
1009}
1010
1011register_rpc(sep)
1012	register struct servtab *sep;
1013{
1014#ifdef RPC
1015	int n;
1016	struct sockaddr_in sin;
1017	struct protoent *pp;
1018
1019	if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
1020		syslog(LOG_ERR, "%s: getproto: %m",
1021		    sep->se_proto);
1022		return;
1023	}
1024	n = sizeof sin;
1025	if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
1026		syslog(LOG_ERR, "%s/%s: getsockname: %m",
1027		    sep->se_service, sep->se_proto);
1028		return;
1029	}
1030
1031	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1032		if (debug)
1033			fprintf(stderr, "pmap_set: %u %u %u %u\n",
1034			    sep->se_rpcprog, n, pp->p_proto,
1035			    ntohs(sin.sin_port));
1036		(void)pmap_unset(sep->se_rpcprog, n);
1037		if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
1038			syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m",
1039			    sep->se_rpcprog, n, pp->p_proto,
1040			    ntohs(sin.sin_port));
1041	}
1042#endif /* RPC */
1043}
1044
1045unregister_rpc(sep)
1046	register struct servtab *sep;
1047{
1048#ifdef RPC
1049	int n;
1050
1051	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1052		if (debug)
1053			fprintf(stderr, "pmap_unset(%u, %u)\n",
1054			    sep->se_rpcprog, n);
1055		if (!pmap_unset(sep->se_rpcprog, n))
1056			syslog(LOG_ERR, "pmap_unset(%u, %u)\n",
1057			    sep->se_rpcprog, n);
1058	}
1059#endif /* RPC */
1060}
1061
1062
1063struct servtab *
1064enter(cp)
1065	struct servtab *cp;
1066{
1067	struct servtab *sep;
1068	long omask;
1069
1070	sep = (struct servtab *)malloc(sizeof (*sep));
1071	if (sep == (struct servtab *)0) {
1072		syslog(LOG_ERR, "Out of memory.");
1073		exit(-1);
1074	}
1075	*sep = *cp;
1076	sep->se_fd = -1;
1077	sep->se_rpcprog = -1;
1078	omask = sigblock(SIGBLOCK);
1079	sep->se_next = servtab;
1080	servtab = sep;
1081	sigsetmask(omask);
1082	return (sep);
1083}
1084
1085FILE	*fconfig = NULL;
1086struct	servtab serv;
1087char	line[LINE_MAX];
1088char    *defhost;
1089
1090int
1091setconfig()
1092{
1093	if (defhost) free(defhost);
1094	defhost = newstr("*");
1095	if (fconfig != NULL) {
1096		fseek(fconfig, 0L, SEEK_SET);
1097		return (1);
1098	}
1099	fconfig = fopen(CONFIG, "r");
1100	return (fconfig != NULL);
1101}
1102
1103void
1104endconfig()
1105{
1106	if (fconfig) {
1107		(void) fclose(fconfig);
1108		fconfig = NULL;
1109	}
1110	if (defhost) {
1111		free(defhost);
1112		defhost = 0;
1113	}
1114}
1115
1116struct servtab *
1117getconfigent()
1118{
1119	struct servtab *sep = &serv;
1120	int argc;
1121	char *cp, *arg;
1122	static char TCPMUX_TOKEN[] = "tcpmux/";
1123#define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
1124	char *hostdelim;
1125
1126more:
1127#ifdef MULOG
1128	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0')) {
1129		/* Avoid use of `skip' if there is a danger of it looking
1130		 * at continuation lines.
1131		 */
1132		do {
1133			cp++;
1134		} while (*cp == ' ' || *cp == '\t');
1135		if (*cp == '\0')
1136			continue;
1137		if ((arg = skip(&cp)) == NULL)
1138			continue;
1139		if (strcmp(arg, "DOMAIN"))
1140			continue;
1141		if (curdom)
1142			free(curdom);
1143		curdom = NULL;
1144		while (*cp == ' ' || *cp == '\t')
1145			cp++;
1146		if (*cp == '\0')
1147			continue;
1148		arg = cp;
1149		while (*cp && *cp != ' ' && *cp != '\t')
1150			cp++;
1151		if (*cp != '\0')
1152			*cp++ = '\0';
1153		curdom = newstr(arg);
1154	}
1155#else
1156	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
1157		;
1158#endif
1159	if (cp == NULL)
1160		return ((struct servtab *)0);
1161	/*
1162	 * clear the static buffer, since some fields (se_ctrladdr,
1163	 * for example) don't get initialized here.
1164	 */
1165	memset((caddr_t)sep, 0, sizeof *sep);
1166	arg = skip(&cp);
1167	if (cp == NULL) {
1168		/* got an empty line containing just blanks/tabs. */
1169		goto more;
1170	}
1171	/* Check for a host name. */
1172	hostdelim = strrchr(arg, ':');
1173	if (hostdelim) {
1174		*hostdelim = '\0';
1175		sep->se_hostaddr = newstr(arg);
1176		arg = hostdelim + 1;
1177		/*
1178		 * If the line is of the form `host:', then just change the
1179		 * default host for the following lines.
1180		 */
1181		if (*arg == '\0') {
1182			arg = skip(&cp);
1183			if (cp == NULL) {
1184				free(defhost);
1185				defhost = sep->se_hostaddr;
1186				goto more;
1187			}
1188		}
1189	} else
1190		sep->se_hostaddr = newstr(defhost);
1191	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
1192		char *c = arg + MUX_LEN;
1193		if (*c == '+') {
1194			sep->se_type = MUXPLUS_TYPE;
1195			c++;
1196		} else
1197			sep->se_type = MUX_TYPE;
1198		sep->se_service = newstr(c);
1199	} else {
1200		sep->se_service = newstr(arg);
1201		sep->se_type = NORM_TYPE;
1202	}
1203
1204	arg = sskip(&cp);
1205	if (strcmp(arg, "stream") == 0)
1206		sep->se_socktype = SOCK_STREAM;
1207	else if (strcmp(arg, "dgram") == 0)
1208		sep->se_socktype = SOCK_DGRAM;
1209	else if (strcmp(arg, "rdm") == 0)
1210		sep->se_socktype = SOCK_RDM;
1211	else if (strcmp(arg, "seqpacket") == 0)
1212		sep->se_socktype = SOCK_SEQPACKET;
1213	else if (strcmp(arg, "raw") == 0)
1214		sep->se_socktype = SOCK_RAW;
1215	else
1216		sep->se_socktype = -1;
1217
1218	sep->se_proto = newstr(sskip(&cp));
1219	if (strcmp(sep->se_proto, "unix") == 0) {
1220		sep->se_family = AF_UNIX;
1221	} else {
1222		sep->se_family = AF_INET;
1223		if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1224#ifdef RPC
1225			char *cp, *ccp;
1226			cp = strchr(sep->se_service, '/');
1227			if (cp == 0) {
1228				syslog(LOG_ERR, "%s: no rpc version",
1229				    sep->se_service);
1230				goto more;
1231			}
1232			*cp++ = '\0';
1233			sep->se_rpcversl = sep->se_rpcversh =
1234			    strtol(cp, &ccp, 0);
1235			if (ccp == cp) {
1236		badafterall:
1237				syslog(LOG_ERR, "%s/%s: bad rpc version",
1238				    sep->se_service, cp);
1239				goto more;
1240			}
1241			if (*ccp == '-') {
1242				cp = ccp + 1;
1243				sep->se_rpcversh = strtol(cp, &ccp, 0);
1244				if (ccp == cp)
1245					goto badafterall;
1246			}
1247#else
1248			syslog(LOG_ERR, "%s: rpc services not suported",
1249			    sep->se_service);
1250			goto more;
1251#endif /* RPC */
1252		}
1253	}
1254	arg = sskip(&cp);
1255	{
1256		char *cp;
1257		cp = strchr(arg, '.');
1258		if (cp) {
1259			*cp++ = '\0';
1260			sep->se_max = atoi(cp);
1261		} else
1262			sep->se_max = TOOMANY;
1263	}
1264	sep->se_wait = strcmp(arg, "wait") == 0;
1265	if (ISMUX(sep)) {
1266		/*
1267		 * Silently enforce "nowait" for TCPMUX services since
1268		 * they don't have an assigned port to listen on.
1269		 */
1270		sep->se_wait = 0;
1271
1272		if (strcmp(sep->se_proto, "tcp")) {
1273			syslog(LOG_ERR,
1274			    "%s: bad protocol for tcpmux service %s",
1275			    CONFIG, sep->se_service);
1276			goto more;
1277		}
1278		if (sep->se_socktype != SOCK_STREAM) {
1279			syslog(LOG_ERR,
1280			    "%s: bad socket type for tcpmux service %s",
1281			    CONFIG, sep->se_service);
1282			goto more;
1283		}
1284	}
1285	sep->se_user = newstr(sskip(&cp));
1286	if (sep->se_group = strchr(sep->se_user, '.'))
1287		*sep->se_group++ = '\0';
1288	sep->se_server = newstr(sskip(&cp));
1289	if (strcmp(sep->se_server, "internal") == 0) {
1290		struct biltin *bi;
1291
1292		for (bi = biltins; bi->bi_service; bi++)
1293			if (bi->bi_socktype == sep->se_socktype &&
1294			    strcmp(bi->bi_service, sep->se_service) == 0)
1295				break;
1296		if (bi->bi_service == 0) {
1297			syslog(LOG_ERR, "internal service %s unknown",
1298			    sep->se_service);
1299			goto more;
1300		}
1301		sep->se_bi = bi;
1302		sep->se_wait = bi->bi_wait;
1303	} else
1304		sep->se_bi = NULL;
1305	argc = 0;
1306	for (arg = skip(&cp); cp; arg = skip(&cp)) {
1307#if MULOG
1308		char *colon;
1309
1310		if (argc == 0 && (colon = strrchr(arg, ':'))) {
1311			while (arg < colon) {
1312				int	x;
1313				char	*ccp;
1314
1315				switch (*arg++) {
1316				case 'l':
1317					x = 1;
1318					if (isdigit(*arg)) {
1319						x = strtol(arg, &ccp, 0);
1320						if (ccp == arg)
1321							break;
1322						arg = ccp;
1323					}
1324					sep->se_log &= ~MULOG_RFC931;
1325					sep->se_log |= x;
1326					break;
1327				case 'a':
1328					sep->se_log |= MULOG_RFC931;
1329					break;
1330				default:
1331					break;
1332				}
1333			}
1334			arg = colon + 1;
1335		}
1336#endif
1337		if (argc < MAXARGV)
1338			sep->se_argv[argc++] = newstr(arg);
1339	}
1340	while (argc <= MAXARGV)
1341		sep->se_argv[argc++] = NULL;
1342	return (sep);
1343}
1344
1345void
1346freeconfig(cp)
1347	struct servtab *cp;
1348{
1349	int i;
1350
1351	if (cp->se_hostaddr)
1352		free(cp->se_hostaddr);
1353	if (cp->se_service)
1354		free(cp->se_service);
1355	if (cp->se_proto)
1356		free(cp->se_proto);
1357	if (cp->se_user)
1358		free(cp->se_user);
1359	/* Note: se_group is part of the newstr'ed se_user */
1360	if (cp->se_server)
1361		free(cp->se_server);
1362	for (i = 0; i < MAXARGV; i++)
1363		if (cp->se_argv[i])
1364			free(cp->se_argv[i]);
1365}
1366
1367
1368/*
1369 * Safe skip - if skip returns null, log a syntax error in the
1370 * configuration file and exit.
1371 */
1372char *
1373sskip(cpp)
1374	char **cpp;
1375{
1376	char *cp;
1377
1378	cp = skip(cpp);
1379	if (cp == NULL) {
1380		syslog(LOG_ERR, "%s: syntax error", CONFIG);
1381		exit(-1);
1382	}
1383	return (cp);
1384}
1385
1386char *
1387skip(cpp)
1388	char **cpp;
1389{
1390	char *cp = *cpp;
1391	char *start;
1392
1393	if (*cpp == NULL)
1394		return ((char *)0);
1395
1396again:
1397	while (*cp == ' ' || *cp == '\t')
1398		cp++;
1399	if (*cp == '\0') {
1400		int c;
1401
1402		c = getc(fconfig);
1403		(void) ungetc(c, fconfig);
1404		if (c == ' ' || c == '\t')
1405			if (cp = nextline(fconfig))
1406				goto again;
1407		*cpp = (char *)0;
1408		return ((char *)0);
1409	}
1410	start = cp;
1411	while (*cp && *cp != ' ' && *cp != '\t')
1412		cp++;
1413	if (*cp != '\0')
1414		*cp++ = '\0';
1415	*cpp = cp;
1416	return (start);
1417}
1418
1419char *
1420nextline(fd)
1421	FILE *fd;
1422{
1423	char *cp;
1424
1425	if (fgets(line, sizeof (line), fd) == NULL)
1426		return ((char *)0);
1427	cp = strchr(line, '\n');
1428	if (cp)
1429		*cp = '\0';
1430	return (line);
1431}
1432
1433char *
1434newstr(cp)
1435	char *cp;
1436{
1437	if (cp = strdup(cp ? cp : ""))
1438		return (cp);
1439	syslog(LOG_ERR, "strdup: %m");
1440	exit(-1);
1441}
1442
1443void
1444inetd_setproctitle(a, s)
1445	char *a;
1446	int s;
1447{
1448	int size;
1449	char *cp;
1450	struct sockaddr_in sin;
1451	char buf[80];
1452
1453	cp = Argv[0];
1454	size = sizeof(sin);
1455	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1456		(void)snprintf(buf, sizeof buf, "-%s [%s]", a,
1457		    inet_ntoa(sin.sin_addr));
1458	else
1459		(void)snprintf(buf, sizeof buf, "-%s", a);
1460	strncpy(cp, buf, LastArg - cp);
1461	cp += strlen(cp);
1462	while (cp < LastArg)
1463		*cp++ = ' ';
1464}
1465
1466logpid()
1467{
1468	FILE *fp;
1469
1470	if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
1471		fprintf(fp, "%u\n", getpid());
1472		(void)fclose(fp);
1473	}
1474}
1475
1476bump_nofile()
1477{
1478#ifdef RLIMIT_NOFILE
1479
1480#define FD_CHUNK	32
1481
1482	struct rlimit rl;
1483
1484	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1485		syslog(LOG_ERR, "getrlimit: %m");
1486		return -1;
1487	}
1488	rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1489	if (rl.rlim_cur <= rlim_ofile_cur) {
1490		syslog(LOG_ERR,
1491		    "bump_nofile: cannot extend file limit, max = %d",
1492		    rl.rlim_cur);
1493		return -1;
1494	}
1495
1496	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1497		syslog(LOG_ERR, "setrlimit: %m");
1498		return -1;
1499	}
1500
1501	rlim_ofile_cur = rl.rlim_cur;
1502	return 0;
1503
1504#else
1505	syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
1506	return -1;
1507#endif
1508}
1509
1510/*
1511 * Internet services provided internally by inetd:
1512 */
1513#define	BUFSIZE	4096
1514
1515/* ARGSUSED */
1516void
1517echo_stream(s, sep)		/* Echo service -- echo data back */
1518	int s;
1519	struct servtab *sep;
1520{
1521	char buffer[BUFSIZE];
1522	int i;
1523
1524	inetd_setproctitle(sep->se_service, s);
1525	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1526	    write(s, buffer, i) > 0)
1527		;
1528}
1529
1530/* ARGSUSED */
1531void
1532echo_dg(s, sep)			/* Echo service -- echo data back */
1533	int s;
1534	struct servtab *sep;
1535{
1536	char buffer[BUFSIZE];
1537	int i, size;
1538	struct sockaddr sa;
1539
1540	size = sizeof(sa);
1541	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
1542		return;
1543	(void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
1544}
1545
1546/* ARGSUSED */
1547void
1548discard_stream(s, sep)		/* Discard service -- ignore data */
1549	int s;
1550	struct servtab *sep;
1551{
1552	char buffer[BUFSIZE];
1553
1554	inetd_setproctitle(sep->se_service, s);
1555	while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1556			errno == EINTR)
1557		;
1558}
1559
1560/* ARGSUSED */
1561void
1562discard_dg(s, sep)		/* Discard service -- ignore data */
1563	int s;
1564	struct servtab *sep;
1565{
1566	char buffer[BUFSIZE];
1567
1568	(void) read(s, buffer, sizeof(buffer));
1569}
1570
1571#include <ctype.h>
1572#define LINESIZ 72
1573char ring[128];
1574char *endring;
1575
1576void
1577initring()
1578{
1579	int i;
1580
1581	endring = ring;
1582
1583	for (i = 0; i <= 128; ++i)
1584		if (isprint(i))
1585			*endring++ = i;
1586}
1587
1588/* ARGSUSED */
1589void
1590chargen_stream(s, sep)		/* Character generator */
1591	int s;
1592	struct servtab *sep;
1593{
1594	int len;
1595	char *rs, text[LINESIZ+2];
1596
1597	inetd_setproctitle(sep->se_service, s);
1598
1599	if (!endring) {
1600		initring();
1601		rs = ring;
1602	}
1603
1604	text[LINESIZ] = '\r';
1605	text[LINESIZ + 1] = '\n';
1606	for (rs = ring;;) {
1607		if ((len = endring - rs) >= LINESIZ)
1608			memmove(text, rs, LINESIZ);
1609		else {
1610			memmove(text, rs, len);
1611			memmove(text + len, ring, LINESIZ - len);
1612		}
1613		if (++rs == endring)
1614			rs = ring;
1615		if (write(s, text, sizeof(text)) != sizeof(text))
1616			break;
1617	}
1618}
1619
1620/* ARGSUSED */
1621void
1622chargen_dg(s, sep)		/* Character generator */
1623	int s;
1624	struct servtab *sep;
1625{
1626	struct sockaddr sa;
1627	static char *rs;
1628	int len, size;
1629	char text[LINESIZ+2];
1630
1631	if (endring == 0) {
1632		initring();
1633		rs = ring;
1634	}
1635
1636	size = sizeof(sa);
1637	if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1638		return;
1639
1640	if ((len = endring - rs) >= LINESIZ)
1641		memmove(text, rs, LINESIZ);
1642	else {
1643		memmove(text, rs, len);
1644		memmove(text + len, ring, LINESIZ - len);
1645	}
1646	if (++rs == endring)
1647		rs = ring;
1648	text[LINESIZ] = '\r';
1649	text[LINESIZ + 1] = '\n';
1650	(void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1651}
1652
1653/*
1654 * Return a machine readable date and time, in the form of the
1655 * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1656 * returns the number of seconds since midnight, Jan 1, 1970,
1657 * we must add 2208988800 seconds to this figure to make up for
1658 * some seventy years Bell Labs was asleep.
1659 */
1660
1661long
1662machtime()
1663{
1664	struct timeval tv;
1665
1666	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1667		if (debug)
1668			fprintf(stderr, "Unable to get time of day\n");
1669		return (0L);
1670	}
1671#define	OFFSET ((u_long)25567 * 24*60*60)
1672	return (htonl((long)(tv.tv_sec + OFFSET)));
1673#undef OFFSET
1674}
1675
1676/* ARGSUSED */
1677void
1678machtime_stream(s, sep)
1679	int s;
1680	struct servtab *sep;
1681{
1682	long result;
1683
1684	result = machtime();
1685	(void) write(s, (char *) &result, sizeof(result));
1686}
1687
1688/* ARGSUSED */
1689void
1690machtime_dg(s, sep)
1691	int s;
1692	struct servtab *sep;
1693{
1694	long result;
1695	struct sockaddr sa;
1696	int size;
1697
1698	size = sizeof(sa);
1699	if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1700		return;
1701	result = machtime();
1702	(void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1703}
1704
1705/* ARGSUSED */
1706void
1707daytime_stream(s, sep)		/* Return human-readable time of day */
1708	int s;
1709	struct servtab *sep;
1710{
1711	char buffer[256];
1712	time_t clock;
1713	int len;
1714
1715	clock = time((time_t *) 0);
1716
1717	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1718	(void) write(s, buffer, len);
1719}
1720
1721/* ARGSUSED */
1722void
1723daytime_dg(s, sep)		/* Return human-readable time of day */
1724	int s;
1725	struct servtab *sep;
1726{
1727	char buffer[256];
1728	time_t clock;
1729	struct sockaddr sa;
1730	int size, len;
1731
1732	clock = time((time_t *) 0);
1733
1734	size = sizeof(sa);
1735	if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1736		return;
1737	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1738	(void) sendto(s, buffer, len, 0, &sa, sizeof(sa));
1739}
1740
1741/*
1742 * print_service:
1743 *	Dump relevant information to stderr
1744 */
1745void
1746print_service(action, sep)
1747	char *action;
1748	struct servtab *sep;
1749{
1750	if (isrpcservice(sep))
1751		fprintf(stderr,
1752		    "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
1753		    action, sep->se_service,
1754		    sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
1755		    sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
1756		    (long)sep->se_bi, sep->se_server);
1757	else
1758		fprintf(stderr,
1759		    "%s: %s proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
1760		    action, sep->se_service, sep->se_proto,
1761		    sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
1762		    (long)sep->se_bi, sep->se_server);
1763}
1764
1765void
1766usage()
1767{
1768
1769#ifdef LIBWRAP
1770	(void)fprintf(stderr, "usage: %s [-dl] [conf]\n", __progname);
1771#else
1772	(void)fprintf(stderr, "usage: %s [-d] [conf]\n", __progname);
1773#endif
1774	exit(1);
1775}
1776
1777
1778/*
1779 *  Based on TCPMUX.C by Mark K. Lottor November 1988
1780 *  sri-nic::ps:<mkl>tcpmux.c
1781 */
1782
1783static int		/* # of characters upto \r,\n or \0 */
1784getline(fd, buf, len)
1785	int fd;
1786	char *buf;
1787	int len;
1788{
1789	int count = 0, n;
1790
1791	do {
1792		n = read(fd, buf, len-count);
1793		if (n == 0)
1794			return (count);
1795		if (n < 0)
1796			return (-1);
1797		while (--n >= 0) {
1798			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
1799				return (count);
1800			count++;
1801			buf++;
1802		}
1803	} while (count < len);
1804	return (count);
1805}
1806
1807#define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
1808
1809#define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
1810
1811struct servtab *
1812tcpmux(s)
1813	int s;
1814{
1815	struct servtab *sep;
1816	char service[MAX_SERV_LEN+1];
1817	int len;
1818
1819	/* Get requested service name */
1820	if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
1821		strwrite(s, "-Error reading service name\r\n");
1822		return (NULL);
1823	}
1824	service[len] = '\0';
1825
1826	if (debug)
1827		fprintf(stderr, "tcpmux: someone wants %s\n", service);
1828
1829	/*
1830	 * Help is a required command, and lists available services,
1831	 * one per line.
1832	 */
1833	if (!strcasecmp(service, "help")) {
1834		for (sep = servtab; sep; sep = sep->se_next) {
1835			if (!ISMUX(sep))
1836				continue;
1837			(void)write(s,sep->se_service,strlen(sep->se_service));
1838			strwrite(s, "\r\n");
1839		}
1840		return (NULL);
1841	}
1842
1843	/* Try matching a service in inetd.conf with the request */
1844	for (sep = servtab; sep; sep = sep->se_next) {
1845		if (!ISMUX(sep))
1846			continue;
1847		if (!strcasecmp(service, sep->se_service)) {
1848			if (ISMUXPLUS(sep)) {
1849				strwrite(s, "+Go\r\n");
1850			}
1851			return (sep);
1852		}
1853	}
1854	strwrite(s, "-Service not available\r\n");
1855	return (NULL);
1856}
1857
1858
1859#ifdef MULOG
1860dolog(sep, ctrl)
1861	struct servtab *sep;
1862	int		ctrl;
1863{
1864	struct sockaddr		sa;
1865	struct sockaddr_in	*sin = (struct sockaddr_in *)&sa;
1866	int			len = sizeof(sa);
1867	struct hostent		*hp;
1868	char			*host, *dp, buf[BUFSIZ], *rfc931_name();
1869	int			connected = 1;
1870
1871	if (sep->se_family != AF_INET)
1872		return;
1873
1874	if (getpeername(ctrl, &sa, &len) < 0) {
1875		if (errno != ENOTCONN) {
1876			syslog(LOG_ERR, "getpeername: %m");
1877			return;
1878		}
1879		if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) {
1880			syslog(LOG_ERR, "recvfrom: %m");
1881			return;
1882		}
1883		connected = 0;
1884	}
1885	if (sa.sa_family != AF_INET) {
1886		syslog(LOG_ERR, "unexpected address family %u", sa.sa_family);
1887		return;
1888	}
1889
1890	hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
1891				sizeof (sin->sin_addr.s_addr), AF_INET);
1892
1893	host = hp?hp->h_name:inet_ntoa(sin->sin_addr);
1894
1895	switch (sep->se_log & ~MULOG_RFC931) {
1896	case 0:
1897		return;
1898	case 1:
1899		if (curdom == NULL || *curdom == '\0')
1900			break;
1901		dp = host + strlen(host) - strlen(curdom);
1902		if (dp < host)
1903			break;
1904		if (debug)
1905			fprintf(stderr, "check \"%s\" against curdom \"%s\"\n",
1906			    host, curdom);
1907		if (strcasecmp(dp, curdom) == 0)
1908			return;
1909		break;
1910	case 2:
1911	default:
1912		break;
1913	}
1914
1915	openlog("", LOG_NOWAIT, MULOG);
1916
1917	if (connected && (sep->se_log & MULOG_RFC931))
1918		syslog(LOG_INFO, "%s@%s wants %s",
1919		    rfc931_name(sin, ctrl), host, sep->se_service);
1920	else
1921		syslog(LOG_INFO, "%s wants %s",
1922		    host, sep->se_service);
1923}
1924
1925/*
1926 * From tcp_log by
1927 *  Wietse Venema, Eindhoven University of Technology, The Netherlands.
1928 */
1929#if 0
1930static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";
1931#endif
1932
1933#include <setjmp.h>
1934
1935#define	RFC931_PORT	113		/* Semi-well-known port */
1936#define	TIMEOUT		4
1937#define	TIMEOUT2	10
1938
1939static jmp_buf timebuf;
1940
1941/* timeout - handle timeouts */
1942
1943static void timeout(sig)
1944int     sig;
1945{
1946	longjmp(timebuf, sig);
1947}
1948
1949/* rfc931_name - return remote user name */
1950
1951char *
1952rfc931_name(there, ctrl)
1953struct sockaddr_in *there;		/* remote link information */
1954int	ctrl;
1955{
1956	struct sockaddr_in here;	/* local link information */
1957	struct sockaddr_in sin;		/* for talking to RFC931 daemon */
1958	int		length;
1959	int		s;
1960	unsigned	remote;
1961	unsigned	local;
1962	static char	user[256];		/* XXX */
1963	char		buf[256];
1964	char		*cp;
1965	char		*result = "USER_UNKNOWN";
1966	int		len;
1967
1968	/* Find out local port number of our stdin. */
1969
1970	length = sizeof(here);
1971	if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) {
1972		syslog(LOG_ERR, "getsockname: %m");
1973		return (result);
1974	}
1975	/* Set up timer so we won't get stuck. */
1976
1977	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
1978		syslog(LOG_ERR, "socket: %m");
1979		return (result);
1980	}
1981
1982	sin = here;
1983	sin.sin_port = htons(0);
1984	if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
1985		syslog(LOG_ERR, "bind: %m");
1986		return (result);
1987	}
1988
1989	signal(SIGALRM, timeout);
1990	if (setjmp(timebuf)) {
1991		close(s);			/* not: fclose(fp) */
1992		return (result);
1993	}
1994	alarm(TIMEOUT);
1995
1996	/* Connect to the RFC931 daemon. */
1997
1998	sin = *there;
1999	sin.sin_port = htons(RFC931_PORT);
2000	if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
2001		close(s);
2002		alarm(0);
2003		return (result);
2004	}
2005
2006	/* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
2007	(void)snprintf(buf, sizeof buf, "%u,%u\r\n", ntohs(there->sin_port),
2008	    ntohs(here.sin_port));
2009
2010
2011	for (len = 0, cp = buf; len < strlen(buf); ) {
2012		int	n;
2013
2014		if ((n = write(s, cp, strlen(buf) - len)) == -1) {
2015			close(s);
2016			alarm(0);
2017			return (result);
2018		}
2019		cp += n;
2020		len += n;
2021	}
2022
2023	/* Read response */
2024	for (cp = buf; cp < buf + sizeof(buf) - 1; ) {
2025		char	c;
2026		if (read(s, &c, 1) != 1) {
2027			close(s);
2028			alarm(0);
2029			return (result);
2030		}
2031		if (c == '\n')
2032			break;
2033		*cp++ = c;
2034	}
2035	*cp = '\0';
2036
2037	if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3
2038		&& ntohs(there->sin_port) == remote
2039		&& ntohs(here.sin_port) == local) {
2040
2041		/* Strip trailing carriage return. */
2042		if (cp = strchr(user, '\r'))
2043			*cp = 0;
2044		result = user;
2045	}
2046
2047	alarm(0);
2048	close(s);
2049	return (result);
2050}
2051#endif
2052