xref: /netbsd-src/usr.sbin/inetd/inetd.c (revision cda4f8f6ee55684e8d311b86c99ea59191e6b74f)
1 /*
2  * Copyright (c) 1983,1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
37  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 static char sccsid[] = "@(#)inetd.c	5.30 (Berkeley) 6/3/91";
42 #endif /* not lint */
43 
44 /*
45  * Inetd - Internet super-server
46  *
47  * This program invokes all internet services as needed.
48  * connection-oriented services are invoked each time a
49  * connection is made, by creating a process.  This process
50  * is passed the connection as file descriptor 0 and is
51  * expected to do a getpeername to find out the source host
52  * and port.
53  *
54  * Datagram oriented services are invoked when a datagram
55  * arrives; a process is created and passed a pending message
56  * on file descriptor 0.  Datagram servers may either connect
57  * to their peer, freeing up the original socket for inetd
58  * to receive further messages on, or ``take over the socket'',
59  * processing all arriving datagrams and, eventually, timing
60  * out.	 The first type of server is said to be ``multi-threaded'';
61  * the second type of server ``single-threaded''.
62  *
63  * Inetd uses a configuration file which is read at startup
64  * and, possibly, at some later time in response to a hangup signal.
65  * The configuration file is ``free format'' with fields given in the
66  * order shown below.  Continuation lines for an entry must being with
67  * a space or tab.  All fields must be present in each entry.
68  *
69  *	service name			must be in /etc/services
70  *	socket type			stream/dgram/raw/rdm/seqpacket
71  *	protocol			must be in /etc/protocols
72  *	wait/nowait			single-threaded/multi-threaded
73  *	user				user to run daemon as
74  *	server program			full path name
75  *	server program arguments	maximum of MAXARGS (20)
76  *
77  * For RPC services
78  *      service name/version            must be in /etc/rpc
79  *	socket type			stream/dgram/raw/rdm/seqpacket
80  *	protocol			must be in /etc/protocols
81  *	wait/nowait			single-threaded/multi-threaded
82  *	user				user to run daemon as
83  *	server program			full path name
84  *	server program arguments	maximum of MAXARGS (20)
85  *
86  * Comment lines are indicated by a `#' in column 1.
87  */
88 #include <sys/param.h>
89 #include <sys/stat.h>
90 #include <sys/ioctl.h>
91 #include <sys/socket.h>
92 #include <sys/file.h>
93 #include <sys/wait.h>
94 #include <sys/time.h>
95 #include <sys/resource.h>
96 
97 #include <netinet/in.h>
98 #include <arpa/inet.h>
99 
100 #include <errno.h>
101 #include <signal.h>
102 #include <netdb.h>
103 #include <syslog.h>
104 #include <pwd.h>
105 #include <stdio.h>
106 #include <string.h>
107 #include <rpc/rpc.h>
108 #include "pathnames.h"
109 
110 #define	TOOMANY		40		/* don't start more than TOOMANY */
111 #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
112 #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
113 
114 #define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
115 
116 void	config(), reapchild(), retry(), unregisterrpc();
117 
118 int	debug = 0;
119 int	nsock, maxsock;
120 fd_set	allsock;
121 int	options;
122 int	timingout;
123 struct	servent *sp;
124 struct	rpcent *rpc;
125 
126 struct	servtab {
127 	char	*se_service;		/* name of service */
128 	int	se_socktype;		/* type of socket to use */
129 	char	*se_proto;		/* protocol used */
130 	short	se_wait;		/* single threaded server */
131 	short	se_checked;		/* looked at during merge */
132 	char	*se_user;		/* user name to run as */
133 	struct	biltin *se_bi;		/* if built-in, description */
134 	char	*se_server;		/* server program */
135 #define	MAXARGV 20
136 	char	*se_argv[MAXARGV+1];	/* program arguments */
137 	int	se_fd;			/* open descriptor */
138 	struct	sockaddr_in se_ctrladdr;/* bound address */
139 	int	se_rpc;			/* ==1 if this is an RPC service */
140         int	se_rpc_prog;		/* RPC program number */
141         u_int	se_rpc_lowvers;		/* RPC low version */
142         u_int	se_rpc_highvers;	/* RPC high version */
143 	int	se_count;		/* number started since se_time */
144 	struct	timeval se_time;	/* start of se_count */
145 	struct	servtab *se_next;
146 } *servtab;
147 
148 int echo_stream(), discard_stream(), machtime_stream();
149 int daytime_stream(), chargen_stream();
150 int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
151 
152 struct biltin {
153 	char	*bi_service;		/* internally provided service name */
154 	int	bi_socktype;		/* type of socket supported */
155 	short	bi_fork;		/* 1 if should fork before call */
156 	short	bi_wait;		/* 1 if should wait for child */
157 	int	(*bi_fn)();		/* function which performs it */
158 } biltins[] = {
159 	/* Echo received data */
160 	"echo",		SOCK_STREAM,	1, 0,	echo_stream,
161 	"echo",		SOCK_DGRAM,	0, 0,	echo_dg,
162 
163 	/* Internet /dev/null */
164 	"discard",	SOCK_STREAM,	1, 0,	discard_stream,
165 	"discard",	SOCK_DGRAM,	0, 0,	discard_dg,
166 
167 	/* Return 32 bit time since 1970 */
168 	"time",		SOCK_STREAM,	0, 0,	machtime_stream,
169 	"time",		SOCK_DGRAM,	0, 0,	machtime_dg,
170 
171 	/* Return human-readable time */
172 	"daytime",	SOCK_STREAM,	0, 0,	daytime_stream,
173 	"daytime",	SOCK_DGRAM,	0, 0,	daytime_dg,
174 
175 	/* Familiar character generator */
176 	"chargen",	SOCK_STREAM,	1, 0,	chargen_stream,
177 	"chargen",	SOCK_DGRAM,	0, 0,	chargen_dg,
178 	0
179 };
180 
181 #define NUMINT	(sizeof(intab) / sizeof(struct inent))
182 char	*CONFIG = _PATH_INETDCONF;
183 char	**Argv;
184 char 	*LastArg;
185 
186 main(argc, argv, envp)
187 	int argc;
188 	char *argv[], *envp[];
189 {
190 	extern char *optarg;
191 	extern int optind;
192 	register struct servtab *sep;
193 	register struct passwd *pwd;
194 	register int tmpint;
195 	struct sigvec sv;
196 	int ch, pid, dofork;
197 	char buf[50];
198 
199 	Argv = argv;
200 	if (envp == 0 || *envp == 0)
201 		envp = argv;
202 	while (*envp)
203 		envp++;
204 	LastArg = envp[-1] + strlen(envp[-1]);
205 
206 	while ((ch = getopt(argc, argv, "d")) != EOF)
207 		switch(ch) {
208 		case 'd':
209 			debug = 1;
210 			options |= SO_DEBUG;
211 			break;
212 		case '?':
213 		default:
214 			fprintf(stderr, "usage: inetd [-d]");
215 			exit(1);
216 		}
217 	argc -= optind;
218 	argv += optind;
219 
220 	if (argc > 0)
221 		CONFIG = argv[0];
222 	if (debug == 0)
223 		daemon(0, 0);
224 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
225 	bzero((char *)&sv, sizeof(sv));
226 	sv.sv_mask = SIGBLOCK;
227 	sv.sv_handler = retry;
228 	sigvec(SIGALRM, &sv, (struct sigvec *)0);
229 	config();
230 	sv.sv_handler = config;
231 	sigvec(SIGHUP, &sv, (struct sigvec *)0);
232 	sv.sv_handler = reapchild;
233 	sigvec(SIGCHLD, &sv, (struct sigvec *)0);
234 
235 	{
236 		/* space for daemons to overwrite environment for ps */
237 #define	DUMMYSIZE	100
238 		char dummy[DUMMYSIZE];
239 
240 		(void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1);
241 		dummy[DUMMYSIZE - 1] = '\0';
242 		(void)setenv("inetd_dummy", dummy, 1);
243 	}
244 
245 	for (;;) {
246 	    int n, ctrl;
247 	    fd_set readable;
248 
249 	    if (nsock == 0) {
250 		(void) sigblock(SIGBLOCK);
251 		while (nsock == 0)
252 		    sigpause(0L);
253 		(void) sigsetmask(0L);
254 	    }
255 	    readable = allsock;
256 	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
257 		(fd_set *)0, (struct timeval *)0)) <= 0) {
258 		    if (n < 0 && errno != EINTR)
259 			syslog(LOG_WARNING, "select: %m\n");
260 		    sleep(1);
261 		    continue;
262 	    }
263 	    for (sep = servtab; n && sep; sep = sep->se_next)
264 	        if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
265 		    n--;
266 		    if (debug)
267 			    fprintf(stderr, "someone wants %s\n",
268 				sep->se_service);
269 		    if (sep->se_socktype == SOCK_STREAM) {
270 			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
271 				(int *)0);
272 			    if (debug)
273 				    fprintf(stderr, "accept, ctrl %d\n", ctrl);
274 			    if (ctrl < 0) {
275 				    if (errno == EINTR)
276 					    continue;
277 				    syslog(LOG_WARNING, "accept (for %s): %m",
278 					    sep->se_service);
279 				    continue;
280 			    }
281 		    } else
282 			    ctrl = sep->se_fd;
283 		    (void) sigblock(SIGBLOCK);
284 		    pid = 0;
285 		    dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
286 		    if (dofork) {
287 			    if (sep->se_count++ == 0)
288 				(void)gettimeofday(&sep->se_time,
289 				    (struct timezone *)0);
290 			    else if (sep->se_count >= TOOMANY) {
291 				struct timeval now;
292 
293 				(void)gettimeofday(&now, (struct timezone *)0);
294 				if (now.tv_sec - sep->se_time.tv_sec >
295 				    CNT_INTVL) {
296 					sep->se_time = now;
297 					sep->se_count = 1;
298 				} else {
299 					syslog(LOG_ERR,
300 			"%s/%s server failing (looping), service terminated\n",
301 					    sep->se_service, sep->se_proto);
302 					FD_CLR(sep->se_fd, &allsock);
303 					(void) close(sep->se_fd);
304 					sep->se_fd = -1;
305 					sep->se_count = 0;
306 					nsock--;
307 					if (!timingout) {
308 						timingout = 1;
309 						alarm(RETRYTIME);
310 					}
311 				}
312 			    }
313 			    pid = fork();
314 		    }
315 		    if (pid < 0) {
316 			    syslog(LOG_ERR, "fork: %m");
317 			    if (sep->se_socktype == SOCK_STREAM)
318 				    close(ctrl);
319 			    sigsetmask(0L);
320 			    sleep(1);
321 			    continue;
322 		    }
323 		    if (pid && sep->se_wait) {
324 			    sep->se_wait = pid;
325 			    if (sep->se_fd >= 0) {
326 				FD_CLR(sep->se_fd, &allsock);
327 			        nsock--;
328 			    }
329 		    }
330 		    sigsetmask(0L);
331 		    if (pid == 0) {
332 			    if (debug && dofork)
333 				setsid();
334 			    if (dofork)
335 				for (tmpint = maxsock; --tmpint > 2; )
336 					if (tmpint != ctrl)
337 						close(tmpint);
338 			    if (sep->se_bi)
339 				(*sep->se_bi->bi_fn)(ctrl, sep);
340 			    else {
341 				if (debug)
342 					fprintf(stderr, "%d execl %s\n",
343 					    getpid(), sep->se_server);
344 				dup2(ctrl, 0);
345 				close(ctrl);
346 				dup2(0, 1);
347 				dup2(0, 2);
348 				if ((pwd = getpwnam(sep->se_user)) == NULL) {
349 					syslog(LOG_ERR,
350 					    "getpwnam: %s: No such user",
351 					    sep->se_user);
352 					if (sep->se_socktype != SOCK_STREAM)
353 						recv(0, buf, sizeof (buf), 0);
354 					_exit(1);
355 				}
356 				if (pwd->pw_uid) {
357 					(void) setgid((gid_t)pwd->pw_gid);
358 					initgroups(pwd->pw_name, pwd->pw_gid);
359 					(void) setuid((uid_t)pwd->pw_uid);
360 				}
361 				execv(sep->se_server, sep->se_argv);
362 				if (sep->se_socktype != SOCK_STREAM)
363 					recv(0, buf, sizeof (buf), 0);
364 				syslog(LOG_ERR, "execv %s: %m", sep->se_server);
365 				_exit(1);
366 			    }
367 		    }
368 		    if (sep->se_socktype == SOCK_STREAM)
369 			    close(ctrl);
370 		}
371 	}
372 }
373 
374 void
375 reapchild()
376 {
377 	int status;
378 	int pid;
379 	register struct servtab *sep;
380 
381 	for (;;) {
382 		pid = wait3(&status, WNOHANG, (struct rusage *)0);
383 		if (pid <= 0)
384 			break;
385 		if (debug)
386 			fprintf(stderr, "%d reaped\n", pid);
387 		for (sep = servtab; sep; sep = sep->se_next)
388 			if (sep->se_wait == pid) {
389 				if (status)
390 					syslog(LOG_WARNING,
391 					    "%s: exit status 0x%x",
392 					    sep->se_server, status);
393 				if (debug)
394 					fprintf(stderr, "restored %s, fd %d\n",
395 					    sep->se_service, sep->se_fd);
396 				FD_SET(sep->se_fd, &allsock);
397 				nsock++;
398 				sep->se_wait = 1;
399 			}
400 	}
401 }
402 
403 void
404 config()
405 {
406 	register struct servtab *sep, *cp, **sepp;
407 	struct servtab *getconfigent(), *enter();
408 	long omask;
409 
410 	if (!setconfig()) {
411 		syslog(LOG_ERR, "%s: %m", CONFIG);
412 		return;
413 	}
414 	for (sep = servtab; sep; sep = sep->se_next)
415 		sep->se_checked = 0;
416 	while (cp = getconfigent()) {
417 		for (sep = servtab; sep; sep = sep->se_next)
418 			if (strcmp(sep->se_service, cp->se_service) == 0 &&
419 			    strcmp(sep->se_proto, cp->se_proto) == 0)
420 				break;
421 		if (sep != 0) {
422 			int i;
423 
424 			omask = sigblock(SIGBLOCK);
425 			/*
426 			 * sep->se_wait may be holding the pid of a daemon
427 			 * that we're waiting for.  If so, don't overwrite
428 			 * it unless the config file explicitly says don't
429 			 * wait.
430 			 */
431 			if (cp->se_bi == 0 &&
432 			    (sep->se_wait == 1 || cp->se_wait == 0))
433 				sep->se_wait = cp->se_wait;
434 #define SWAP(a, b) { char *c = a; a = b; b = c; }
435 			if (cp->se_user)
436 				SWAP(sep->se_user, cp->se_user);
437 			if (cp->se_server)
438 				SWAP(sep->se_server, cp->se_server);
439 			for (i = 0; i < MAXARGV; i++)
440 				SWAP(sep->se_argv[i], cp->se_argv[i]);
441 			sigsetmask(omask);
442 			freeconfig(cp);
443 			if (debug)
444 				print_service("REDO", sep);
445 		} else {
446 			sep = enter(cp);
447 			if (debug)
448 				print_service("ADD ", sep);
449 		}
450 		sep->se_checked = 1;
451                 if (!sep->se_rpc) {
452                         sp = getservbyname(sep->se_service, sep->se_proto);
453                         if (sp == 0) {
454                                 syslog(LOG_ERR, "%s/%s: unknown service",
455                                        sep->se_service, sep->se_proto);
456                                 if (sep->se_fd != -1)
457                                         (void) close(sep->se_fd);
458                                 sep->se_fd = -1;
459                                 continue;
460                         }
461                         if (sp->s_port != sep->se_ctrladdr.sin_port) {
462                                 sep->se_ctrladdr.sin_port = sp->s_port;
463                                 if (sep->se_fd != -1)
464                                         (void) close(sep->se_fd);
465                                 sep->se_fd = -1;
466                         }
467 		}
468                 else {
469                         rpc = getrpcbyname(sep->se_service);
470                         if (rpc == 0) {
471                                 syslog(LOG_ERR, "%s/%s unknown RPC service.",
472                                        sep->se_service, sep->se_proto);
473                                 if (sep->se_fd != -1)
474                                         (void) close(sep->se_fd);
475                                 sep->se_fd = -1;
476                                 continue;
477                         }
478                         if (rpc->r_number != sep->se_rpc_prog) {
479                                 if (sep->se_rpc_prog)
480                                         unregisterrpc(sep);
481                                 sep->se_rpc_prog = rpc->r_number;
482                                 if (sep->se_fd != -1)
483                                         (void) close(sep->se_fd);
484                                 sep->se_fd = -1;
485                         }
486                 }
487 
488 		if (sep->se_fd == -1)
489 			setup(sep);
490 	}
491 	endconfig();
492 	/*
493 	 * Purge anything not looked at above.
494 	 */
495 	omask = sigblock(SIGBLOCK);
496 	sepp = &servtab;
497 	while (sep = *sepp) {
498 		if (sep->se_checked) {
499 			sepp = &sep->se_next;
500 			continue;
501 		}
502 		*sepp = sep->se_next;
503 		if (sep->se_fd != -1) {
504 			FD_CLR(sep->se_fd, &allsock);
505 			nsock--;
506 			(void) close(sep->se_fd);
507 		}
508 		if (debug)
509 			print_service("FREE", sep);
510                 if (sep->se_rpc && sep->se_rpc_prog > 0)
511                         unregisterrpc(sep);
512 		freeconfig(sep);
513 		free((char *)sep);
514 	}
515 	(void) sigsetmask(omask);
516 }
517 
518 void
519 unregisterrpc(sep)
520 	register struct servtab *sep;
521 {
522         int i;
523         struct servtab *sepp;
524 	long omask;
525 
526 	omask = sigblock(SIGBLOCK);
527         for (sepp = servtab; sepp; sepp = sepp->se_next) {
528                 if (sepp == sep)
529                         continue;
530 		if (sep->se_checked == 0 ||
531                     !sepp->se_rpc ||
532                     sep->se_rpc_prog != sepp->se_rpc_prog)
533 			continue;
534                 return;
535         }
536         if (debug)
537                 print_service("UNREG", sep);
538         for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
539                 pmap_unset(sep->se_rpc_prog, i);
540         if (sep->se_fd != -1)
541                 (void) close(sep->se_fd);
542         sep->se_fd = -1;
543 	(void) sigsetmask(omask);
544 }
545 
546 void
547 retry()
548 {
549 	register struct servtab *sep;
550 
551 	timingout = 0;
552 	for (sep = servtab; sep; sep = sep->se_next)
553 		if (sep->se_fd == -1)
554 			setup(sep);
555 }
556 
557 setup(sep)
558 	register struct servtab *sep;
559 {
560 	int on = 1;
561 
562 	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
563 		syslog(LOG_ERR, "%s/%s: socket: %m",
564 		    sep->se_service, sep->se_proto);
565 		return;
566 	}
567 #define	turnon(fd, opt) \
568 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
569 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
570 	    turnon(sep->se_fd, SO_DEBUG) < 0)
571 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
572 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
573 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
574 #undef turnon
575 	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
576 	    sizeof (sep->se_ctrladdr)) < 0) {
577 		syslog(LOG_ERR, "%s/%s: bind: %m",
578 		    sep->se_service, sep->se_proto);
579 		(void) close(sep->se_fd);
580 		sep->se_fd = -1;
581 		if (!timingout) {
582 			timingout = 1;
583 			alarm(RETRYTIME);
584 		}
585 		return;
586 	}
587         if (sep->se_rpc) {
588                 int i, len;
589                 if (getsockname(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
590                                 &len) < 0) {
591                         syslog(LOG_ERR, "%s/%s: getsockname: %m",
592                                sep->se_service, sep->se_proto);
593                         (void) close(sep->se_fd);
594                         sep->se_fd = -1;
595                         return;
596                 }
597                 if (debug)
598                         print_service("REG ", sep);
599                 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
600                         pmap_unset(sep->se_rpc_prog, i);
601                         pmap_set(sep->se_rpc_prog, i,
602                                  (sep->se_socktype == SOCK_DGRAM)
603                                  ? IPPROTO_UDP : IPPROTO_TCP,
604                                  ntohs(sep->se_ctrladdr.sin_port));
605                 }
606 
607         }
608 	if (sep->se_socktype == SOCK_STREAM)
609 		listen(sep->se_fd, 10);
610 	FD_SET(sep->se_fd, &allsock);
611 	nsock++;
612 	if (sep->se_fd > maxsock)
613 		maxsock = sep->se_fd;
614 }
615 
616 struct servtab *
617 enter(cp)
618 	struct servtab *cp;
619 {
620 	register struct servtab *sep;
621 	long omask;
622 
623 	sep = (struct servtab *)malloc(sizeof (*sep));
624 	if (sep == (struct servtab *)0) {
625 		syslog(LOG_ERR, "Out of memory.");
626 		exit(-1);
627 	}
628 	*sep = *cp;
629 	sep->se_fd = -1;
630 	omask = sigblock(SIGBLOCK);
631 	sep->se_next = servtab;
632 	servtab = sep;
633 	sigsetmask(omask);
634 	return (sep);
635 }
636 
637 FILE	*fconfig = NULL;
638 struct	servtab serv;
639 char	line[256];
640 char	*skip(), *nextline();
641 
642 setconfig()
643 {
644 
645 	if (fconfig != NULL) {
646 		fseek(fconfig, 0L, L_SET);
647 		return (1);
648 	}
649 	fconfig = fopen(CONFIG, "r");
650 	return (fconfig != NULL);
651 }
652 
653 endconfig()
654 {
655 	if (fconfig) {
656 		(void) fclose(fconfig);
657 		fconfig = NULL;
658 	}
659 }
660 
661 struct servtab *
662 getconfigent()
663 {
664 	register struct servtab *sep = &serv;
665 	int argc;
666 	char *cp, *arg, *newstr();
667         char *versp;
668 
669 more:
670 	while ((cp = nextline(fconfig)) && *cp == '#')
671 		;
672 	if (cp == NULL)
673 		return ((struct servtab *)0);
674 	sep->se_service = newstr(skip(&cp));
675 	arg = skip(&cp);
676 	if (strcmp(arg, "stream") == 0)
677 		sep->se_socktype = SOCK_STREAM;
678 	else if (strcmp(arg, "dgram") == 0)
679 		sep->se_socktype = SOCK_DGRAM;
680 	else if (strcmp(arg, "rdm") == 0)
681 		sep->se_socktype = SOCK_RDM;
682 	else if (strcmp(arg, "seqpacket") == 0)
683 		sep->se_socktype = SOCK_SEQPACKET;
684 	else if (strcmp(arg, "raw") == 0)
685 		sep->se_socktype = SOCK_RAW;
686 	else
687 		sep->se_socktype = -1;
688 	sep->se_proto = newstr(skip(&cp));
689         sep->se_rpc = 0;
690         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
691                 sep->se_proto += 4;
692                 sep->se_rpc = 1;
693                 sep->se_rpc_prog = sep->se_rpc_lowvers = sep->se_rpc_lowvers = 0;
694                 sep->se_ctrladdr.sin_family = AF_INET;
695                 sep->se_ctrladdr.sin_port = 0;
696                 sep->se_ctrladdr.sin_addr.s_addr = htonl(INADDR_ANY);
697                 if (versp = rindex(sep->se_service, '/')) {
698                         *versp++ = '\0';
699                         switch (sscanf(versp, "%d-%d",
700                                        &sep->se_rpc_lowvers,
701                                        &sep->se_rpc_highvers)) {
702                         case 2:
703                                 break;
704                         case 1:
705                                 sep->se_rpc_highvers =
706                                         sep->se_rpc_lowvers;
707                                 break;
708                         default:
709                                 syslog(LOG_ERR, "bad RPC version specifier; %s\n", sep->se_service);
710                                 freeconfig(sep);
711                                 goto more;
712                         }
713                 }
714                 else {
715                         sep->se_rpc_lowvers =
716                                 sep->se_rpc_highvers = 1;
717                 }
718         }
719 	arg = skip(&cp);
720 	sep->se_wait = strcmp(arg, "wait") == 0;
721 	sep->se_user = newstr(skip(&cp));
722 	sep->se_server = newstr(skip(&cp));
723 	if (strcmp(sep->se_server, "internal") == 0) {
724 		register struct biltin *bi;
725 
726 		for (bi = biltins; bi->bi_service; bi++)
727 			if (bi->bi_socktype == sep->se_socktype &&
728 			    strcmp(bi->bi_service, sep->se_service) == 0)
729 				break;
730 		if (bi->bi_service == 0) {
731 			syslog(LOG_ERR, "internal service %s unknown\n",
732 				sep->se_service);
733 			goto more;
734 		}
735 		sep->se_bi = bi;
736 		sep->se_wait = bi->bi_wait;
737 	} else
738 		sep->se_bi = NULL;
739 	argc = 0;
740 	for (arg = skip(&cp); cp; arg = skip(&cp))
741 		if (argc < MAXARGV)
742 			sep->se_argv[argc++] = newstr(arg);
743 	while (argc <= MAXARGV)
744 		sep->se_argv[argc++] = NULL;
745 	return (sep);
746 }
747 
748 freeconfig(cp)
749 	register struct servtab *cp;
750 {
751 	int i;
752 
753 	if (cp->se_service)
754 		free(cp->se_service);
755 	if (cp->se_proto)
756 		free(cp->se_proto);
757 	if (cp->se_user)
758 		free(cp->se_user);
759 	if (cp->se_server)
760 		free(cp->se_server);
761 	for (i = 0; i < MAXARGV; i++)
762 		if (cp->se_argv[i])
763 			free(cp->se_argv[i]);
764 }
765 
766 char *
767 skip(cpp)
768 	char **cpp;
769 {
770 	register char *cp = *cpp;
771 	char *start;
772 
773 again:
774 	while (*cp == ' ' || *cp == '\t')
775 		cp++;
776 	if (*cp == '\0') {
777 		int c;
778 
779 		c = getc(fconfig);
780 		(void) ungetc(c, fconfig);
781 		if (c == ' ' || c == '\t')
782 			if (cp = nextline(fconfig))
783 				goto again;
784 		*cpp = (char *)0;
785 		return ((char *)0);
786 	}
787 	start = cp;
788 	while (*cp && *cp != ' ' && *cp != '\t')
789 		cp++;
790 	if (*cp != '\0')
791 		*cp++ = '\0';
792 	*cpp = cp;
793 	return (start);
794 }
795 
796 char *
797 nextline(fd)
798 	FILE *fd;
799 {
800 	char *cp;
801 
802 	if (fgets(line, sizeof (line), fd) == NULL)
803 		return ((char *)0);
804 	cp = index(line, '\n');
805 	if (cp)
806 		*cp = '\0';
807 	return (line);
808 }
809 
810 char *
811 newstr(cp)
812 	char *cp;
813 {
814 	if (cp = strdup(cp ? cp : ""))
815 		return(cp);
816 	syslog(LOG_ERR, "strdup: %m");
817 	exit(-1);
818 }
819 
820 setproctitle(a, s)
821 	char *a;
822 	int s;
823 {
824 	int size;
825 	register char *cp;
826 	struct sockaddr_in sin;
827 	char buf[80];
828 
829 	cp = Argv[0];
830 	size = sizeof(sin);
831 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
832 		(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
833 	else
834 		(void) sprintf(buf, "-%s", a);
835 	strncpy(cp, buf, LastArg - cp);
836 	cp += strlen(cp);
837 	while (cp < LastArg)
838 		*cp++ = ' ';
839 }
840 
841 /*
842  * Internet services provided internally by inetd:
843  */
844 #define	BUFSIZE	8192
845 
846 /* ARGSUSED */
847 echo_stream(s, sep)		/* Echo service -- echo data back */
848 	int s;
849 	struct servtab *sep;
850 {
851 	char buffer[BUFSIZE];
852 	int i;
853 
854 	setproctitle(sep->se_service, s);
855 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
856 	    write(s, buffer, i) > 0)
857 		;
858 	exit(0);
859 }
860 
861 /* ARGSUSED */
862 echo_dg(s, sep)			/* Echo service -- echo data back */
863 	int s;
864 	struct servtab *sep;
865 {
866 	char buffer[BUFSIZE];
867 	int i, size;
868 	struct sockaddr sa;
869 
870 	size = sizeof(sa);
871 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
872 		return;
873 	(void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
874 }
875 
876 /* ARGSUSED */
877 discard_stream(s, sep)		/* Discard service -- ignore data */
878 	int s;
879 	struct servtab *sep;
880 {
881 	int ret;
882 	char buffer[BUFSIZE];
883 
884 	setproctitle(sep->se_service, s);
885 	while (1) {
886 		while ((ret = read(s, buffer, sizeof(buffer))) > 0)
887 			;
888 		if (ret == 0 || errno != EINTR)
889 			break;
890 	}
891 	exit(0);
892 }
893 
894 /* ARGSUSED */
895 discard_dg(s, sep)		/* Discard service -- ignore data */
896 	int s;
897 	struct servtab *sep;
898 {
899 	char buffer[BUFSIZE];
900 
901 	(void) read(s, buffer, sizeof(buffer));
902 }
903 
904 #include <ctype.h>
905 #define LINESIZ 72
906 char ring[128];
907 char *endring;
908 
909 initring()
910 {
911 	register int i;
912 
913 	endring = ring;
914 
915 	for (i = 0; i <= 128; ++i)
916 		if (isprint(i))
917 			*endring++ = i;
918 }
919 
920 /* ARGSUSED */
921 chargen_stream(s, sep)		/* Character generator */
922 	int s;
923 	struct servtab *sep;
924 {
925 	register char *rs;
926 	int len;
927 	char text[LINESIZ+2];
928 
929 	setproctitle(sep->se_service, s);
930 
931 	if (!endring) {
932 		initring();
933 		rs = ring;
934 	}
935 
936 	text[LINESIZ] = '\r';
937 	text[LINESIZ + 1] = '\n';
938 	for (rs = ring;;) {
939 		if ((len = endring - rs) >= LINESIZ)
940 			bcopy(rs, text, LINESIZ);
941 		else {
942 			bcopy(rs, text, len);
943 			bcopy(ring, text + len, LINESIZ - len);
944 		}
945 		if (++rs == endring)
946 			rs = ring;
947 		if (write(s, text, sizeof(text)) != sizeof(text))
948 			break;
949 	}
950 	exit(0);
951 }
952 
953 /* ARGSUSED */
954 chargen_dg(s, sep)		/* Character generator */
955 	int s;
956 	struct servtab *sep;
957 {
958 	struct sockaddr sa;
959 	static char *rs;
960 	int len, size;
961 	char text[LINESIZ+2];
962 
963 	if (endring == 0) {
964 		initring();
965 		rs = ring;
966 	}
967 
968 	size = sizeof(sa);
969 	if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
970 		return;
971 
972 	if ((len = endring - rs) >= LINESIZ)
973 		bcopy(rs, text, LINESIZ);
974 	else {
975 		bcopy(rs, text, len);
976 		bcopy(ring, text + len, LINESIZ - len);
977 	}
978 	if (++rs == endring)
979 		rs = ring;
980 	text[LINESIZ] = '\r';
981 	text[LINESIZ + 1] = '\n';
982 	(void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
983 }
984 
985 /*
986  * Return a machine readable date and time, in the form of the
987  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
988  * returns the number of seconds since midnight, Jan 1, 1970,
989  * we must add 2208988800 seconds to this figure to make up for
990  * some seventy years Bell Labs was asleep.
991  */
992 
993 long
994 machtime()
995 {
996 	struct timeval tv;
997 
998 	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
999 		fprintf(stderr, "Unable to get time of day\n");
1000 		return (0L);
1001 	}
1002 	return (htonl((long)tv.tv_sec + 2208988800));
1003 }
1004 
1005 /* ARGSUSED */
1006 machtime_stream(s, sep)
1007 	int s;
1008 	struct servtab *sep;
1009 {
1010 	long result;
1011 
1012 	result = machtime();
1013 	(void) write(s, (char *) &result, sizeof(result));
1014 }
1015 
1016 /* ARGSUSED */
1017 machtime_dg(s, sep)
1018 	int s;
1019 	struct servtab *sep;
1020 {
1021 	long result;
1022 	struct sockaddr sa;
1023 	int size;
1024 
1025 	size = sizeof(sa);
1026 	if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1027 		return;
1028 	result = machtime();
1029 	(void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1030 }
1031 
1032 /* ARGSUSED */
1033 daytime_stream(s, sep)		/* Return human-readable time of day */
1034 	int s;
1035 	struct servtab *sep;
1036 {
1037 	char buffer[256];
1038 	time_t time(), clock;
1039 	char *ctime();
1040 
1041 	clock = time((time_t *) 0);
1042 
1043 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1044 	(void) write(s, buffer, strlen(buffer));
1045 }
1046 
1047 /* ARGSUSED */
1048 daytime_dg(s, sep)		/* Return human-readable time of day */
1049 	int s;
1050 	struct servtab *sep;
1051 {
1052 	char buffer[256];
1053 	time_t time(), clock;
1054 	struct sockaddr sa;
1055 	int size;
1056 	char *ctime();
1057 
1058 	clock = time((time_t *) 0);
1059 
1060 	size = sizeof(sa);
1061 	if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1062 		return;
1063 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1064 	(void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
1065 }
1066 
1067 /*
1068  * print_service:
1069  *	Dump relevant information to stderr
1070  */
1071 print_service(action, sep)
1072 	char *action;
1073 	struct servtab *sep;
1074 {
1075         if (sep->se_rpc)
1076                 fprintf(stderr,
1077                         "%s: %s rpcnum=%d, rpcvers=%d/%d, wait=%d, user=%s builtin=%x server=%s\n",
1078                         action, sep->se_service,
1079                         sep->se_rpc_prog, sep->se_rpc_lowvers, sep->se_rpc_highvers,
1080                         sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
1081         else
1082                 fprintf(stderr,
1083                         "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
1084                         action, sep->se_service, sep->se_proto,
1085                         sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
1086 }
1087