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