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