inetd.c revision 1.14
1/*	$NetBSD: inetd.c,v 1.14 1996/12/06 00:45:48 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.14 1996/12/06 00:45:48 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], RQ_FILE, ctrl, NULL);
421	fromhost(&req);
422	if (!hosts_access(&req)) {
423		sp = getservbyport(sep->se_ctrladdr_in.sin_port, sep->se_proto);
424		if (sp == NULL) {
425			(void)snprintf(buf, sizeof buf, "%d",
426			    ntohs(sep->se_ctrladdr_in.sin_port));
427			service = buf;
428		} else
429			service = sp->s_name;
430		syslog(deny_severity,
431		    "refused connection from %.500s, service %s (%s)",
432		    eval_client(&req), service, sep->se_proto);
433		shutdown(ctrl, 2);
434		close(ctrl);
435		continue;
436	}
437	if (lflag) {
438		sp = getservbyport(sep->se_ctrladdr_in.sin_port, sep->se_proto);
439		if (sp == NULL) {
440			(void)snprintf(buf, sizeof buf, "%d",
441			    ntohs(sep->se_ctrladdr_in.sin_port));
442			service = buf;
443		} else
444			service = sp->s_name;
445		syslog(allow_severity,"connection from %.500s, service %s (%s)",
446		    eval_client(&req), service, sep->se_proto);
447	}
448#endif /* LIBWRAP */
449		} else
450			ctrl = sep->se_fd;
451		(void) sigblock(SIGBLOCK);
452		pid = 0;
453		dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
454		if (dofork) {
455			if (sep->se_count++ == 0)
456			    (void)gettimeofday(&sep->se_time,
457			        (struct timezone *)0);
458			else if (sep->se_count >= sep->se_max) {
459				struct timeval now;
460
461				(void)gettimeofday(&now, (struct timezone *)0);
462				if (now.tv_sec - sep->se_time.tv_sec >
463				    CNT_INTVL) {
464					sep->se_time = now;
465					sep->se_count = 1;
466				} else {
467					syslog(LOG_ERR,
468			"%s/%s server failing (looping), service terminated\n",
469					    sep->se_service, sep->se_proto);
470					FD_CLR(sep->se_fd, &allsock);
471					(void) close(sep->se_fd);
472					sep->se_fd = -1;
473					sep->se_count = 0;
474					nsock--;
475					sigsetmask(0L);
476					if (!timingout) {
477						timingout = 1;
478						alarm(RETRYTIME);
479					}
480					continue;
481				}
482			}
483			pid = fork();
484		}
485		if (pid < 0) {
486			syslog(LOG_ERR, "fork: %m");
487			if (sep->se_socktype == SOCK_STREAM)
488				close(ctrl);
489			sigsetmask(0L);
490			sleep(1);
491			continue;
492		}
493		if (pid && sep->se_wait) {
494			sep->se_wait = pid;
495			FD_CLR(sep->se_fd, &allsock);
496			nsock--;
497		}
498		sigsetmask(0L);
499		if (pid == 0) {
500			if (debug && dofork)
501				setsid();
502			if (sep->se_bi)
503				(*sep->se_bi->bi_fn)(ctrl, sep);
504			else {
505				if ((pwd = getpwnam(sep->se_user)) == NULL) {
506					syslog(LOG_ERR,
507						"getpwnam: %s: No such user",
508						sep->se_user);
509					if (sep->se_socktype != SOCK_STREAM)
510						recv(0, buf, sizeof (buf), 0);
511					_exit(1);
512				}
513				if (sep->se_group &&
514				    (grp = getgrnam(sep->se_group)) == NULL) {
515					syslog(LOG_ERR,
516						"getgrnam: %s: No such group",
517						sep->se_group);
518					if (sep->se_socktype != SOCK_STREAM)
519						recv(0, buf, sizeof (buf), 0);
520					_exit(1);
521				}
522				if (pwd->pw_uid) {
523					if (sep->se_group)
524						pwd->pw_gid = grp->gr_gid;
525					(void) setgid((gid_t)pwd->pw_gid);
526					initgroups(pwd->pw_name, pwd->pw_gid);
527					(void) setuid((uid_t)pwd->pw_uid);
528				} else if (sep->se_group) {
529					(void) setgid((gid_t)grp->gr_gid);
530				}
531				if (debug)
532					fprintf(stderr, "%d execl %s\n",
533					    getpid(), sep->se_server);
534#ifdef MULOG
535				if (sep->se_log)
536					dolog(sep, ctrl);
537#endif
538				dup2(ctrl, 0);
539				close(ctrl);
540				dup2(0, 1);
541				dup2(0, 2);
542#ifdef RLIMIT_NOFILE
543				if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
544					if (setrlimit(RLIMIT_NOFILE,
545							&rlim_ofile) < 0)
546						syslog(LOG_ERR,"setrlimit: %m");
547				}
548#endif
549				for (tmpint = rlim_ofile_cur-1; --tmpint > 2; )
550					(void)close(tmpint);
551				execv(sep->se_server, sep->se_argv);
552				if (sep->se_socktype != SOCK_STREAM)
553					recv(0, buf, sizeof (buf), 0);
554				syslog(LOG_ERR, "execv %s: %m", sep->se_server);
555				_exit(1);
556			}
557		}
558		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
559			close(ctrl);
560	    }
561	}
562}
563
564void
565reapchild()
566{
567	int status;
568	int pid;
569	register struct servtab *sep;
570
571	for (;;) {
572		pid = wait3(&status, WNOHANG, (struct rusage *)0);
573		if (pid <= 0)
574			break;
575		if (debug)
576			fprintf(stderr, "%d reaped\n", pid);
577		for (sep = servtab; sep; sep = sep->se_next)
578			if (sep->se_wait == pid) {
579				if (WIFEXITED(status) && WEXITSTATUS(status))
580					syslog(LOG_WARNING,
581					    "%s: exit status 0x%x",
582					    sep->se_server, WEXITSTATUS(status));
583				else if (WIFSIGNALED(status))
584					syslog(LOG_WARNING,
585					    "%s: exit signal 0x%x",
586					    sep->se_server, WTERMSIG(status));
587				sep->se_wait = 1;
588				FD_SET(sep->se_fd, &allsock);
589				nsock++;
590				if (debug)
591					fprintf(stderr, "restored %s, fd %d\n",
592					    sep->se_service, sep->se_fd);
593			}
594	}
595}
596
597void
598config()
599{
600	register struct servtab *sep, *cp, **sepp;
601	struct servtab *getconfigent(), *enter();
602	long omask;
603	int n;
604
605	if (!setconfig()) {
606		syslog(LOG_ERR, "%s: %m", CONFIG);
607		return;
608	}
609	for (sep = servtab; sep; sep = sep->se_next)
610		sep->se_checked = 0;
611	while (cp = getconfigent()) {
612		for (sep = servtab; sep; sep = sep->se_next)
613			if (strcmp(sep->se_service, cp->se_service) == 0 &&
614			    strcmp(sep->se_proto, cp->se_proto) == 0)
615				break;
616		if (sep != 0) {
617			int i;
618
619#define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
620
621			omask = sigblock(SIGBLOCK);
622			/*
623			 * sep->se_wait may be holding the pid of a daemon
624			 * that we're waiting for.  If so, don't overwrite
625			 * it unless the config file explicitly says don't
626			 * wait.
627			 */
628			if (cp->se_bi == 0 &&
629			    (sep->se_wait == 1 || cp->se_wait == 0))
630				sep->se_wait = cp->se_wait;
631			SWAP(int, cp->se_max, sep->se_max);
632			SWAP(char *, sep->se_user, cp->se_user);
633			SWAP(char *, sep->se_group, cp->se_group);
634			SWAP(char *, sep->se_server, cp->se_server);
635			for (i = 0; i < MAXARGV; i++)
636				SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
637#undef SWAP
638			if (isrpcservice(sep))
639				unregister_rpc(sep);
640			sep->se_rpcversl = cp->se_rpcversl;
641			sep->se_rpcversh = cp->se_rpcversh;
642			sigsetmask(omask);
643			freeconfig(cp);
644			if (debug)
645				print_service("REDO", sep);
646		} else {
647			sep = enter(cp);
648			if (debug)
649				print_service("ADD ", sep);
650		}
651		sep->se_checked = 1;
652
653		switch (sep->se_family) {
654		case AF_UNIX:
655			if (sep->se_fd != -1)
656				break;
657			(void)unlink(sep->se_service);
658			n = strlen(sep->se_service);
659			if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
660				n = sizeof sep->se_ctrladdr_un.sun_path - 1;
661			strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n);
662			sep->se_ctrladdr_un.sun_family = AF_UNIX;
663			sep->se_ctrladdr_size = n +
664					sizeof sep->se_ctrladdr_un.sun_family;
665			setup(sep);
666			break;
667		case AF_INET:
668			sep->se_ctrladdr_in.sin_family = AF_INET;
669			sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
670			if (isrpcservice(sep)) {
671				struct rpcent *rp;
672
673				sep->se_rpcprog = atoi(sep->se_service);
674				if (sep->se_rpcprog == 0) {
675					rp = getrpcbyname(sep->se_service);
676					if (rp == 0) {
677						syslog(LOG_ERR,
678							"%s: unknown service",
679							sep->se_service);
680						continue;
681					}
682					sep->se_rpcprog = rp->r_number;
683				}
684				if (sep->se_fd == -1)
685					setup(sep);
686				if (sep->se_fd != -1)
687					register_rpc(sep);
688			} else {
689				u_short port = htons(atoi(sep->se_service));
690
691				if (!port) {
692					sp = getservbyname(sep->se_service,
693								sep->se_proto);
694					if (sp == 0) {
695						syslog(LOG_ERR,
696						    "%s/%s: unknown service",
697						    sep->se_service, sep->se_proto);
698						continue;
699					}
700					port = sp->s_port;
701				}
702				if (port != sep->se_ctrladdr_in.sin_port) {
703					sep->se_ctrladdr_in.sin_port = port;
704					if (sep->se_fd != -1) {
705						FD_CLR(sep->se_fd, &allsock);
706						nsock--;
707						(void) close(sep->se_fd);
708					}
709					sep->se_fd = -1;
710				}
711				if (sep->se_fd == -1)
712					setup(sep);
713			}
714		}
715	}
716	endconfig();
717	/*
718	 * Purge anything not looked at above.
719	 */
720	omask = sigblock(SIGBLOCK);
721	sepp = &servtab;
722	while (sep = *sepp) {
723		if (sep->se_checked) {
724			sepp = &sep->se_next;
725			continue;
726		}
727		*sepp = sep->se_next;
728		if (sep->se_fd != -1) {
729			FD_CLR(sep->se_fd, &allsock);
730			nsock--;
731			(void) close(sep->se_fd);
732		}
733		if (isrpcservice(sep))
734			unregister_rpc(sep);
735		if (sep->se_family == AF_UNIX)
736			(void)unlink(sep->se_service);
737		if (debug)
738			print_service("FREE", sep);
739		freeconfig(sep);
740		free((char *)sep);
741	}
742	(void) sigsetmask(omask);
743}
744
745void
746retry()
747{
748	register struct servtab *sep;
749
750	timingout = 0;
751	for (sep = servtab; sep; sep = sep->se_next) {
752		if (sep->se_fd == -1) {
753			switch (sep->se_family) {
754			case AF_UNIX:
755			case AF_INET:
756				setup(sep);
757				if (sep->se_fd != -1 && isrpcservice(sep))
758					register_rpc(sep);
759				break;
760			}
761		}
762	}
763}
764
765void
766goaway()
767{
768	register struct servtab *sep;
769
770	for (sep = servtab; sep; sep = sep->se_next) {
771		if (sep->se_fd == -1)
772			continue;
773
774		switch (sep->se_family) {
775		case AF_UNIX:
776			(void)unlink(sep->se_service);
777			break;
778		case AF_INET:
779			if (sep->se_wait == 1 && isrpcservice(sep))
780				unregister_rpc(sep);
781			break;
782		}
783		(void)close(sep->se_fd);
784	}
785	(void)unlink(_PATH_INETDPID);
786	exit(0);
787}
788
789
790setup(sep)
791	register struct servtab *sep;
792{
793	int on = 1;
794
795	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
796		syslog(LOG_ERR, "%s/%s: socket: %m",
797		    sep->se_service, sep->se_proto);
798		return;
799	}
800#define	turnon(fd, opt) \
801setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
802	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
803	    turnon(sep->se_fd, SO_DEBUG) < 0)
804		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
805	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
806		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
807#undef turnon
808	if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
809		syslog(LOG_ERR, "%s/%s: bind: %m",
810		    sep->se_service, sep->se_proto);
811		(void) close(sep->se_fd);
812		sep->se_fd = -1;
813		if (!timingout) {
814			timingout = 1;
815			alarm(RETRYTIME);
816		}
817		return;
818	}
819	if (sep->se_socktype == SOCK_STREAM)
820		listen(sep->se_fd, 10);
821
822	FD_SET(sep->se_fd, &allsock);
823	nsock++;
824	if (sep->se_fd > maxsock) {
825		maxsock = sep->se_fd;
826		if (maxsock > rlim_ofile_cur - FD_MARGIN)
827			bump_nofile();
828	}
829}
830
831register_rpc(sep)
832	register struct servtab *sep;
833{
834#ifdef RPC
835	int n;
836	struct sockaddr_in sin;
837	struct protoent *pp;
838
839	if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
840		syslog(LOG_ERR, "%s: getproto: %m",
841		    sep->se_proto);
842		return;
843	}
844	n = sizeof sin;
845	if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
846		syslog(LOG_ERR, "%s/%s: getsockname: %m",
847		    sep->se_service, sep->se_proto);
848		return;
849	}
850
851	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
852		if (debug)
853			fprintf(stderr, "pmap_set: %u %u %u %u\n",
854			sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
855		(void)pmap_unset(sep->se_rpcprog, n);
856		if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
857			syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m",
858			sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
859	}
860#endif /* RPC */
861}
862
863unregister_rpc(sep)
864	register struct servtab *sep;
865{
866#ifdef RPC
867	int n;
868
869	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
870		if (debug)
871			fprintf(stderr, "pmap_unset(%u, %u)\n",
872				sep->se_rpcprog, n);
873		if (!pmap_unset(sep->se_rpcprog, n))
874			syslog(LOG_ERR, "pmap_unset(%u, %u)\n",
875				sep->se_rpcprog, n);
876	}
877#endif /* RPC */
878}
879
880
881struct servtab *
882enter(cp)
883	struct servtab *cp;
884{
885	register struct servtab *sep;
886	long omask;
887
888	sep = (struct servtab *)malloc(sizeof (*sep));
889	if (sep == (struct servtab *)0) {
890		syslog(LOG_ERR, "Out of memory.");
891		exit(-1);
892	}
893	*sep = *cp;
894	sep->se_fd = -1;
895	sep->se_rpcprog = -1;
896	omask = sigblock(SIGBLOCK);
897	sep->se_next = servtab;
898	servtab = sep;
899	sigsetmask(omask);
900	return (sep);
901}
902
903FILE	*fconfig = NULL;
904struct	servtab serv;
905char	line[256];
906char	*skip(), *nextline();
907
908setconfig()
909{
910
911	if (fconfig != NULL) {
912		fseek(fconfig, 0L, L_SET);
913		return (1);
914	}
915	fconfig = fopen(CONFIG, "r");
916	return (fconfig != NULL);
917}
918
919endconfig()
920{
921	if (fconfig) {
922		(void) fclose(fconfig);
923		fconfig = NULL;
924	}
925}
926
927struct servtab *
928getconfigent()
929{
930	register struct servtab *sep = &serv;
931	int argc;
932	char *cp, *arg, *newstr();
933
934more:
935#ifdef MULOG
936	while ((cp = nextline(fconfig)) && *cp == '#') {
937		/* Avoid use of `skip' if there is a danger of it looking
938		 * at continuation lines.
939		 */
940		do {
941			cp++;
942		} while (*cp == ' ' || *cp == '\t');
943		if (*cp == '\0')
944			continue;
945		if ((arg = skip(&cp)) == NULL)
946			continue;
947		if (strcmp(arg, "DOMAIN"))
948			continue;
949		if (curdom)
950			free(curdom);
951		curdom = NULL;
952		while (*cp == ' ' || *cp == '\t')
953			cp++;
954		if (*cp == '\0')
955			continue;
956		arg = cp;
957		while (*cp && *cp != ' ' && *cp != '\t')
958			cp++;
959		if (*cp != '\0')
960			*cp++ = '\0';
961		curdom = newstr(arg);
962	}
963#else
964	while ((cp = nextline(fconfig)) && *cp == '#')
965		;
966#endif
967	if (cp == NULL)
968		return ((struct servtab *)0);
969	bzero((char *)sep, sizeof *sep);
970	sep->se_service = newstr(skip(&cp));
971	arg = skip(&cp);
972	if (arg == NULL)
973		goto more;
974
975	if (strcmp(arg, "stream") == 0)
976		sep->se_socktype = SOCK_STREAM;
977	else if (strcmp(arg, "dgram") == 0)
978		sep->se_socktype = SOCK_DGRAM;
979	else if (strcmp(arg, "rdm") == 0)
980		sep->se_socktype = SOCK_RDM;
981	else if (strcmp(arg, "seqpacket") == 0)
982		sep->se_socktype = SOCK_SEQPACKET;
983	else if (strcmp(arg, "raw") == 0)
984		sep->se_socktype = SOCK_RAW;
985	else
986		sep->se_socktype = -1;
987
988	sep->se_proto = newstr(skip(&cp));
989	if (strcmp(sep->se_proto, "unix") == 0) {
990		sep->se_family = AF_UNIX;
991	} else {
992		sep->se_family = AF_INET;
993		if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
994#ifdef RPC
995			char *cp, *ccp;
996			cp = index(sep->se_service, '/');
997			if (cp == 0) {
998				syslog(LOG_ERR, "%s: no rpc version",
999				    sep->se_service);
1000				goto more;
1001			}
1002			*cp++ = '\0';
1003			sep->se_rpcversl =
1004				sep->se_rpcversh = strtol(cp, &ccp, 0);
1005			if (ccp == cp) {
1006		badafterall:
1007				syslog(LOG_ERR, "%s/%s: bad rpc version",
1008				    sep->se_service, cp);
1009				goto more;
1010			}
1011			if (*ccp == '-') {
1012				cp = ccp + 1;
1013				sep->se_rpcversh = strtol(cp, &ccp, 0);
1014				if (ccp == cp)
1015					goto badafterall;
1016			}
1017#else
1018			syslog(LOG_ERR, "%s: rpc services not suported",
1019			    sep->se_service);
1020			goto more;
1021#endif /* RPC */
1022		}
1023	}
1024	arg = skip(&cp);
1025	if (arg == NULL)
1026		goto more;
1027	{
1028		char	*s = index(arg, '.');
1029		if (s) {
1030			*s++ = '\0';
1031			sep->se_max = atoi(s);
1032		} else
1033			sep->se_max = TOOMANY;
1034	}
1035	sep->se_wait = strcmp(arg, "wait") == 0;
1036	sep->se_user = newstr(skip(&cp));
1037	if (sep->se_group = index(sep->se_user, '.')) {
1038		*sep->se_group++ = '\0';
1039	}
1040	sep->se_server = newstr(skip(&cp));
1041	if (strcmp(sep->se_server, "internal") == 0) {
1042		register struct biltin *bi;
1043
1044		for (bi = biltins; bi->bi_service; bi++)
1045			if (bi->bi_socktype == sep->se_socktype &&
1046			    strcmp(bi->bi_service, sep->se_service) == 0)
1047				break;
1048		if (bi->bi_service == 0) {
1049			syslog(LOG_ERR, "internal service %s unknown\n",
1050				sep->se_service);
1051			goto more;
1052		}
1053		sep->se_bi = bi;
1054		sep->se_wait = bi->bi_wait;
1055	} else
1056		sep->se_bi = NULL;
1057	argc = 0;
1058	for (arg = skip(&cp); cp; arg = skip(&cp)) {
1059#if MULOG
1060		char *colon, *rindex();
1061
1062		if (argc == 0 && (colon = rindex(arg, ':'))) {
1063			while (arg < colon) {
1064				int	x;
1065				char	*ccp;
1066
1067				switch (*arg++) {
1068				case 'l':
1069					x = 1;
1070					if (isdigit(*arg)) {
1071						x = strtol(arg, &ccp, 0);
1072						if (ccp == arg)
1073							break;
1074						arg = ccp;
1075					}
1076					sep->se_log &= ~MULOG_RFC931;
1077					sep->se_log |= x;
1078					break;
1079				case 'a':
1080					sep->se_log |= MULOG_RFC931;
1081					break;
1082				default:
1083					break;
1084				}
1085			}
1086			arg = colon + 1;
1087		}
1088#endif
1089		if (argc < MAXARGV)
1090			sep->se_argv[argc++] = newstr(arg);
1091	}
1092	while (argc <= MAXARGV)
1093		sep->se_argv[argc++] = NULL;
1094	return (sep);
1095}
1096
1097freeconfig(cp)
1098	register struct servtab *cp;
1099{
1100	int i;
1101
1102	if (cp->se_service)
1103		free(cp->se_service);
1104	if (cp->se_proto)
1105		free(cp->se_proto);
1106	if (cp->se_user)
1107		free(cp->se_user);
1108	/* Note: se_group is part of the newstr'ed se_user */
1109	if (cp->se_server)
1110		free(cp->se_server);
1111	for (i = 0; i < MAXARGV; i++)
1112		if (cp->se_argv[i])
1113			free(cp->se_argv[i]);
1114}
1115
1116char *
1117skip(cpp)
1118	char **cpp;
1119{
1120	register char *cp = *cpp;
1121	char *start;
1122
1123	if (*cpp == NULL)
1124		return ((char *)0);
1125
1126again:
1127	while (*cp == ' ' || *cp == '\t')
1128		cp++;
1129	if (*cp == '\0') {
1130		int c;
1131
1132		c = getc(fconfig);
1133		(void) ungetc(c, fconfig);
1134		if (c == ' ' || c == '\t')
1135			if (cp = nextline(fconfig))
1136				goto again;
1137		*cpp = (char *)0;
1138		return ((char *)0);
1139	}
1140	start = cp;
1141	while (*cp && *cp != ' ' && *cp != '\t')
1142		cp++;
1143	if (*cp != '\0')
1144		*cp++ = '\0';
1145	*cpp = cp;
1146	return (start);
1147}
1148
1149char *
1150nextline(fd)
1151	FILE *fd;
1152{
1153	char *cp;
1154
1155	if (fgets(line, sizeof (line), fd) == NULL)
1156		return ((char *)0);
1157	cp = index(line, '\n');
1158	if (cp)
1159		*cp = '\0';
1160	return (line);
1161}
1162
1163char *
1164newstr(cp)
1165	char *cp;
1166{
1167	if (cp = strdup(cp ? cp : ""))
1168		return(cp);
1169	syslog(LOG_ERR, "strdup: %m");
1170	exit(-1);
1171}
1172
1173inetd_setproctitle(a, s)
1174	char *a;
1175	int s;
1176{
1177	int size;
1178	register char *cp;
1179	struct sockaddr_in sin;
1180	char buf[80];
1181
1182	cp = Argv[0];
1183	size = sizeof(sin);
1184	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1185		(void)snprintf(buf, sizeof buf, "-%s [%s]", a,
1186		    inet_ntoa(sin.sin_addr));
1187	else
1188		(void)snprintf(buf, sizeof buf, "-%s", a);
1189	strncpy(cp, buf, LastArg - cp);
1190	cp += strlen(cp);
1191	while (cp < LastArg)
1192		*cp++ = ' ';
1193}
1194
1195logpid()
1196{
1197	FILE *fp;
1198
1199	if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
1200		fprintf(fp, "%u\n", getpid());
1201		(void)fclose(fp);
1202	}
1203}
1204
1205bump_nofile()
1206{
1207#ifdef RLIMIT_NOFILE
1208
1209#define FD_CHUNK	32
1210
1211	struct rlimit rl;
1212
1213	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1214		syslog(LOG_ERR, "getrlimit: %m");
1215		return -1;
1216	}
1217	rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1218	if (rl.rlim_cur <= rlim_ofile_cur) {
1219		syslog(LOG_ERR,
1220			"bump_nofile: cannot extend file limit, max = %d",
1221			rl.rlim_cur);
1222		return -1;
1223	}
1224
1225	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1226		syslog(LOG_ERR, "setrlimit: %m");
1227		return -1;
1228	}
1229
1230	rlim_ofile_cur = rl.rlim_cur;
1231	return 0;
1232
1233#else
1234	syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
1235	return -1;
1236#endif
1237}
1238
1239/*
1240 * Internet services provided internally by inetd:
1241 */
1242#define	BUFSIZE	4096
1243
1244/* ARGSUSED */
1245echo_stream(s, sep)		/* Echo service -- echo data back */
1246	int s;
1247	struct servtab *sep;
1248{
1249	char buffer[BUFSIZE];
1250	int i;
1251
1252	inetd_setproctitle(sep->se_service, s);
1253	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1254	    write(s, buffer, i) > 0)
1255		;
1256	exit(0);
1257}
1258
1259/* ARGSUSED */
1260echo_dg(s, sep)			/* Echo service -- echo data back */
1261	int s;
1262	struct servtab *sep;
1263{
1264	char buffer[BUFSIZE];
1265	int i, size;
1266	struct sockaddr sa;
1267
1268	size = sizeof(sa);
1269	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
1270		return;
1271	(void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
1272}
1273
1274/* ARGSUSED */
1275discard_stream(s, sep)		/* Discard service -- ignore data */
1276	int s;
1277	struct servtab *sep;
1278{
1279	char buffer[BUFSIZE];
1280
1281	inetd_setproctitle(sep->se_service, s);
1282	while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1283			errno == EINTR)
1284		;
1285	exit(0);
1286}
1287
1288/* ARGSUSED */
1289discard_dg(s, sep)		/* Discard service -- ignore data */
1290	int s;
1291	struct servtab *sep;
1292{
1293	char buffer[BUFSIZE];
1294
1295	(void) read(s, buffer, sizeof(buffer));
1296}
1297
1298#include <ctype.h>
1299#define LINESIZ 72
1300char ring[128];
1301char *endring;
1302
1303initring()
1304{
1305	register int i;
1306
1307	endring = ring;
1308
1309	for (i = 0; i <= 128; ++i)
1310		if (isprint(i))
1311			*endring++ = i;
1312}
1313
1314/* ARGSUSED */
1315chargen_stream(s, sep)		/* Character generator */
1316	int s;
1317	struct servtab *sep;
1318{
1319	register char *rs;
1320	int len;
1321	char text[LINESIZ+2];
1322
1323	inetd_setproctitle(sep->se_service, s);
1324
1325	if (!endring) {
1326		initring();
1327		rs = ring;
1328	}
1329
1330	text[LINESIZ] = '\r';
1331	text[LINESIZ + 1] = '\n';
1332	for (rs = ring;;) {
1333		if ((len = endring - rs) >= LINESIZ)
1334			bcopy(rs, text, LINESIZ);
1335		else {
1336			bcopy(rs, text, len);
1337			bcopy(ring, text + len, LINESIZ - len);
1338		}
1339		if (++rs == endring)
1340			rs = ring;
1341		if (write(s, text, sizeof(text)) != sizeof(text))
1342			break;
1343	}
1344	exit(0);
1345}
1346
1347/* ARGSUSED */
1348chargen_dg(s, sep)		/* Character generator */
1349	int s;
1350	struct servtab *sep;
1351{
1352	struct sockaddr sa;
1353	static char *rs;
1354	int len, size;
1355	char text[LINESIZ+2];
1356
1357	if (endring == 0) {
1358		initring();
1359		rs = ring;
1360	}
1361
1362	size = sizeof(sa);
1363	if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1364		return;
1365
1366	if ((len = endring - rs) >= LINESIZ)
1367		bcopy(rs, text, LINESIZ);
1368	else {
1369		bcopy(rs, text, len);
1370		bcopy(ring, text + len, LINESIZ - len);
1371	}
1372	if (++rs == endring)
1373		rs = ring;
1374	text[LINESIZ] = '\r';
1375	text[LINESIZ + 1] = '\n';
1376	(void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1377}
1378
1379/*
1380 * Return a machine readable date and time, in the form of the
1381 * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1382 * returns the number of seconds since midnight, Jan 1, 1970,
1383 * we must add 2208988800 seconds to this figure to make up for
1384 * some seventy years Bell Labs was asleep.
1385 */
1386
1387long
1388machtime()
1389{
1390	struct timeval tv;
1391
1392	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1393		fprintf(stderr, "Unable to get time of day\n");
1394		return (0L);
1395	}
1396	return (htonl((long)tv.tv_sec + 2208988800UL));
1397}
1398
1399/* ARGSUSED */
1400machtime_stream(s, sep)
1401	int s;
1402	struct servtab *sep;
1403{
1404	long result;
1405
1406	result = machtime();
1407	(void) write(s, (char *) &result, sizeof(result));
1408}
1409
1410/* ARGSUSED */
1411machtime_dg(s, sep)
1412	int s;
1413	struct servtab *sep;
1414{
1415	long result;
1416	struct sockaddr sa;
1417	int size;
1418
1419	size = sizeof(sa);
1420	if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1421		return;
1422	result = machtime();
1423	(void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1424}
1425
1426/* ARGSUSED */
1427daytime_stream(s, sep)		/* Return human-readable time of day */
1428	int s;
1429	struct servtab *sep;
1430{
1431	char buffer[256];
1432	time_t time(), clock;
1433	int len;
1434
1435	clock = time((time_t *) 0);
1436
1437	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1438	(void) write(s, buffer, len);
1439}
1440
1441/* ARGSUSED */
1442daytime_dg(s, sep)		/* Return human-readable time of day */
1443	int s;
1444	struct servtab *sep;
1445{
1446	char buffer[256];
1447	time_t time(), clock;
1448	struct sockaddr sa;
1449	int size;
1450
1451	clock = time((time_t *) 0);
1452
1453	size = sizeof(sa);
1454	if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1455		return;
1456	size = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1457	(void) sendto(s, buffer, size, 0, &sa, sizeof(sa));
1458}
1459
1460/*
1461 * print_service:
1462 *	Dump relevant information to stderr
1463 */
1464print_service(action, sep)
1465	char *action;
1466	struct servtab *sep;
1467{
1468	if (isrpcservice(sep))
1469		fprintf(stderr,
1470		    "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
1471		    action, sep->se_service,
1472		    sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
1473		    sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
1474		    (long)sep->se_bi, sep->se_server);
1475	else
1476		fprintf(stderr,
1477		    "%s: %s proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%lx server=%s\n",
1478		    action, sep->se_service, sep->se_proto,
1479		    sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
1480		    (long)sep->se_bi, sep->se_server);
1481}
1482
1483#ifdef MULOG
1484dolog(sep, ctrl)
1485	struct servtab *sep;
1486	int		ctrl;
1487{
1488	struct sockaddr		sa;
1489	struct sockaddr_in	*sin = (struct sockaddr_in *)&sa;
1490	int			len = sizeof(sa);
1491	struct hostent		*hp;
1492	char			*host, *dp, buf[BUFSIZ], *rfc931_name();
1493	int			connected = 1;
1494
1495	if (sep->se_family != AF_INET)
1496		return;
1497
1498	if (getpeername(ctrl, &sa, &len) < 0) {
1499		if (errno != ENOTCONN) {
1500			syslog(LOG_ERR, "getpeername: %m");
1501			return;
1502		}
1503		if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) {
1504			syslog(LOG_ERR, "recvfrom: %m");
1505			return;
1506		}
1507		connected = 0;
1508	}
1509	if (sa.sa_family != AF_INET) {
1510		syslog(LOG_ERR, "unexpected address family %u", sa.sa_family);
1511		return;
1512	}
1513
1514	hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
1515				sizeof (sin->sin_addr.s_addr), AF_INET);
1516
1517	host = hp?hp->h_name:inet_ntoa(sin->sin_addr);
1518
1519	switch (sep->se_log & ~MULOG_RFC931) {
1520	case 0:
1521		return;
1522	case 1:
1523		if (curdom == NULL || *curdom == '\0')
1524			break;
1525		dp = host + strlen(host) - strlen(curdom);
1526		if (dp < host)
1527			break;
1528		if (debug)
1529			fprintf(stderr, "check \"%s\" against curdom \"%s\"\n",
1530					host, curdom);
1531		if (strcasecmp(dp, curdom) == 0)
1532			return;
1533		break;
1534	case 2:
1535	default:
1536		break;
1537	}
1538
1539	openlog("", LOG_NOWAIT, MULOG);
1540
1541	if (connected && (sep->se_log & MULOG_RFC931))
1542		syslog(LOG_INFO, "%s@%s wants %s",
1543				rfc931_name(sin, ctrl), host, sep->se_service);
1544	else
1545		syslog(LOG_INFO, "%s wants %s",
1546				host, sep->se_service);
1547}
1548/*
1549 * From tcp_log by
1550 *  Wietse Venema, Eindhoven University of Technology, The Netherlands.
1551 */
1552#if 0
1553static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";
1554#endif
1555
1556#include <setjmp.h>
1557
1558#define	RFC931_PORT	113		/* Semi-well-known port */
1559#define	TIMEOUT		4
1560#define	TIMEOUT2	10
1561
1562static jmp_buf timebuf;
1563
1564/* timeout - handle timeouts */
1565
1566static void timeout(sig)
1567int     sig;
1568{
1569	longjmp(timebuf, sig);
1570}
1571
1572/* rfc931_name - return remote user name */
1573
1574char *
1575rfc931_name(there, ctrl)
1576struct sockaddr_in *there;		/* remote link information */
1577int	ctrl;
1578{
1579	struct sockaddr_in here;	/* local link information */
1580	struct sockaddr_in sin;		/* for talking to RFC931 daemon */
1581	int		length;
1582	int		s;
1583	unsigned	remote;
1584	unsigned	local;
1585	static char	user[256];		/* XXX */
1586	char		buf[256];
1587	char		*cp;
1588	char		*result = "USER_UNKNOWN";
1589	int		len;
1590
1591	/* Find out local port number of our stdin. */
1592
1593	length = sizeof(here);
1594	if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) {
1595		syslog(LOG_ERR, "getsockname: %m");
1596		return (result);
1597	}
1598	/* Set up timer so we won't get stuck. */
1599
1600	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
1601		syslog(LOG_ERR, "socket: %m");
1602		return (result);
1603	}
1604
1605	sin = here;
1606	sin.sin_port = htons(0);
1607	if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
1608		syslog(LOG_ERR, "bind: %m");
1609		return (result);
1610	}
1611
1612	signal(SIGALRM, timeout);
1613	if (setjmp(timebuf)) {
1614		close(s);			/* not: fclose(fp) */
1615		return (result);
1616	}
1617	alarm(TIMEOUT);
1618
1619	/* Connect to the RFC931 daemon. */
1620
1621	sin = *there;
1622	sin.sin_port = htons(RFC931_PORT);
1623	if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
1624		close(s);
1625		alarm(0);
1626		return (result);
1627	}
1628
1629	/* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
1630	(void)snprintf(buf, sizeof buf, "%u,%u\r\n", ntohs(there->sin_port),
1631	    ntohs(here.sin_port));
1632
1633
1634	for (len = 0, cp = buf; len < strlen(buf); ) {
1635		int	n;
1636
1637		if ((n = write(s, cp, strlen(buf) - len)) == -1) {
1638			close(s);
1639			alarm(0);
1640			return (result);
1641		}
1642		cp += n;
1643		len += n;
1644	}
1645
1646	/* Read response */
1647	for (cp = buf; cp < buf + sizeof(buf) - 1; ) {
1648		char	c;
1649		if (read(s, &c, 1) != 1) {
1650			close(s);
1651			alarm(0);
1652			return (result);
1653		}
1654		if (c == '\n')
1655			break;
1656		*cp++ = c;
1657	}
1658	*cp = '\0';
1659
1660	if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3
1661		&& ntohs(there->sin_port) == remote
1662		&& ntohs(here.sin_port) == local) {
1663
1664		/* Strip trailing carriage return. */
1665		if (cp = strchr(user, '\r'))
1666			*cp = 0;
1667		result = user;
1668	}
1669
1670	alarm(0);
1671	close(s);
1672	return (result);
1673}
1674#endif
1675