xref: /freebsd/usr.sbin/inetd/inetd.c (revision 0de89efe5c443f213c7ea28773ef2dc6cf3af2ed)
1 /*
2  * Copyright (c) 1983, 1991, 1993, 1994
3  *	The Regents of the University of California.  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 static const char copyright[] =
36 "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
37 	The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)from: inetd.c	8.4 (Berkeley) 4/13/94";
43 #endif
44 static const char rcsid[] =
45 	"$Id$";
46 #endif /* not lint */
47 
48 /*
49  * Inetd - Internet super-server
50  *
51  * This program invokes all internet services as needed.  Connection-oriented
52  * services are invoked each time a connection is made, by creating a process.
53  * This process is passed the connection as file descriptor 0 and is expected
54  * to do a getpeername to find out the source host 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 or must
72  *					name a tcpmux service
73  *	socket type			stream/dgram/raw/rdm/seqpacket
74  *	protocol			must be in /etc/protocols
75  *	wait/nowait			single-threaded/multi-threaded
76  *	user				user to run daemon as
77  *	server program			full path name
78  *	server program arguments	maximum of MAXARGS (20)
79  *
80  * TCP services without official port numbers are handled with the
81  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
82  * requests. When a connection is made from a foreign host, the service
83  * requested is passed to tcpmux, which looks it up in the servtab list
84  * and returns the proper entry for the service. Tcpmux returns a
85  * negative reply if the service doesn't exist, otherwise the invoked
86  * server is expected to return the positive reply if the service type in
87  * inetd.conf file has the prefix "tcpmux/". If the service type has the
88  * prefix "tcpmux/+", tcpmux will return the positive reply for the
89  * process; this is for compatibility with older server code, and also
90  * allows you to invoke programs that use stdin/stdout without putting any
91  * special server code in them. Services that use tcpmux are "nowait"
92  * because they do not have a well-known port and hence cannot listen
93  * for new requests.
94  *
95  * For RPC services
96  *	service name/version		must be in /etc/rpc
97  *	socket type			stream/dgram/raw/rdm/seqpacket
98  *	protocol			must be in /etc/protocols
99  *	wait/nowait			single-threaded/multi-threaded
100  *	user				user to run daemon as
101  *	server program			full path name
102  *	server program arguments	maximum of MAXARGS
103  *
104  * Comment lines are indicated by a `#' in column 1.
105  */
106 #include <sys/param.h>
107 #include <sys/stat.h>
108 #include <sys/ioctl.h>
109 #include <sys/socket.h>
110 #include <sys/wait.h>
111 #include <sys/time.h>
112 #include <sys/resource.h>
113 
114 #include <netinet/in.h>
115 #include <arpa/inet.h>
116 #include <rpc/rpc.h>
117 #include <rpc/pmap_clnt.h>
118 
119 #include <errno.h>
120 #include <err.h>
121 #include <fcntl.h>
122 #include <netdb.h>
123 #include <pwd.h>
124 #include <signal.h>
125 #include <stdio.h>
126 #include <stdlib.h>
127 #include <string.h>
128 #include <syslog.h>
129 #include <unistd.h>
130 #include <libutil.h>
131 #include <sysexits.h>
132 
133 #ifdef LOGIN_CAP
134 #include <login_cap.h>
135 #endif
136 
137 #include "pathnames.h"
138 
139 #define	TOOMANY		256		/* don't start more than TOOMANY */
140 #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
141 #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
142 #define MAX_MAXCHLD	32767		/* max allowable max children */
143 
144 #define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
145 
146 int	debug = 0;
147 int	log = 0;
148 int	nsock, maxsock;
149 fd_set	allsock;
150 int	options;
151 int	timingout;
152 int	toomany = TOOMANY;
153 struct	servent *sp;
154 struct	rpcent *rpc;
155 struct	in_addr bind_address;
156 
157 struct	servtab {
158 	char	*se_service;		/* name of service */
159 	int	se_socktype;		/* type of socket to use */
160 	char	*se_proto;		/* protocol used */
161 	short	se_maxchild;		/* max number of children */
162 	short	se_numchild;		/* current number of children */
163 	pid_t	*se_pids;		/* array of child pids */
164 	char	*se_user;		/* user name to run as */
165 	struct	biltin *se_bi;		/* if built-in, description */
166 	char	*se_server;		/* server program */
167 #define	MAXARGV 20
168 	char	*se_argv[MAXARGV+1];	/* program arguments */
169 	int	se_fd;			/* open descriptor */
170 	struct	sockaddr_in se_ctrladdr;/* bound address */
171 	u_char	se_type;		/* type: normal, mux, or mux+ */
172 	u_char	se_checked;		/* looked at during merge */
173 	u_char	se_accept;		/* i.e., wait/nowait mode */
174 	u_char	se_rpc;			/* ==1 if RPC service */
175 	int	se_rpc_prog;		/* RPC program number */
176 	u_int	se_rpc_lowvers;		/* RPC low version */
177 	u_int	se_rpc_highvers;	/* RPC high version */
178 	int	se_count;		/* number started since se_time */
179 	struct	timeval se_time;	/* start of se_count */
180 	struct	servtab *se_next;
181 } *servtab;
182 
183 #define NORM_TYPE	0
184 #define MUX_TYPE	1
185 #define MUXPLUS_TYPE	2
186 #define ISMUX(sep)	(((sep)->se_type == MUX_TYPE) || \
187 			 ((sep)->se_type == MUXPLUS_TYPE))
188 #define ISMUXPLUS(sep)	((sep)->se_type == MUXPLUS_TYPE)
189 
190 
191 void		chargen_dg __P((int, struct servtab *));
192 void		chargen_stream __P((int, struct servtab *));
193 void		close_sep __P((struct servtab *));
194 void		config __P((int));
195 void		daytime_dg __P((int, struct servtab *));
196 void		daytime_stream __P((int, struct servtab *));
197 void		discard_dg __P((int, struct servtab *));
198 void		discard_stream __P((int, struct servtab *));
199 void		echo_dg __P((int, struct servtab *));
200 void		echo_stream __P((int, struct servtab *));
201 void		endconfig __P((void));
202 struct servtab *enter __P((struct servtab *));
203 void		freeconfig __P((struct servtab *));
204 struct servtab *getconfigent __P((void));
205 void		machtime_dg __P((int, struct servtab *));
206 void		machtime_stream __P((int, struct servtab *));
207 char	       *newstr __P((char *));
208 char	       *nextline __P((FILE *));
209 void		print_service __P((char *, struct servtab *));
210 void		addchild __P((struct servtab *, int));
211 void		reapchild __P((int));
212 void		enable __P((struct servtab *));
213 void		disable __P((struct servtab *));
214 void		retry __P((int));
215 int		setconfig __P((void));
216 void		setup __P((struct servtab *));
217 char	       *sskip __P((char **));
218 char	       *skip __P((char **));
219 struct servtab *tcpmux __P((int));
220 
221 void		unregisterrpc __P((register struct servtab *sep));
222 
223 struct biltin {
224 	char	*bi_service;		/* internally provided service name */
225 	int	bi_socktype;		/* type of socket supported */
226 	short	bi_fork;		/* 1 if should fork before call */
227 	short	bi_maxchild;		/* max number of children (default) */
228 	void	(*bi_fn)();		/* function which performs it */
229 } biltins[] = {
230 	/* Echo received data */
231 	{ "echo",	SOCK_STREAM,	1, 0,	echo_stream },
232 	{ "echo",	SOCK_DGRAM,	0, 0,	echo_dg },
233 
234 	/* Internet /dev/null */
235 	{ "discard",	SOCK_STREAM,	1, 0,	discard_stream },
236 	{ "discard",	SOCK_DGRAM,	0, 0,	discard_dg },
237 
238 	/* Return 32 bit time since 1970 */
239 	{ "time",	SOCK_STREAM,	0, 0,	machtime_stream },
240 	{ "time",	SOCK_DGRAM,	0, 0,	machtime_dg },
241 
242 	/* Return human-readable time */
243 	{ "daytime",	SOCK_STREAM,	0, 0,	daytime_stream },
244 	{ "daytime",	SOCK_DGRAM,	0, 0,	daytime_dg },
245 
246 	/* Familiar character generator */
247 	{ "chargen",	SOCK_STREAM,	1, 0,	chargen_stream },
248 	{ "chargen",	SOCK_DGRAM,	0, 0,	chargen_dg },
249 
250 	{ "tcpmux",	SOCK_STREAM,	1, 0,	(void (*)())tcpmux },
251 
252 	{ NULL }
253 };
254 
255 #define NUMINT	(sizeof(intab) / sizeof(struct inent))
256 char	*CONFIG = _PATH_INETDCONF;
257 char	*pid_file = _PATH_INETDPID;
258 
259 #ifdef OLD_SETPROCTITLE
260 char	**Argv;
261 char 	*LastArg;
262 #endif
263 
264 int
265 main(argc, argv, envp)
266 	int argc;
267 	char *argv[], *envp[];
268 {
269 	struct servtab *sep;
270 	struct passwd *pwd;
271 	struct sigvec sv;
272 	int tmpint, ch, dofork;
273 	pid_t pid;
274 	char buf[50];
275 	struct  sockaddr_in peer;
276 	int i;
277 #ifdef LOGIN_CAP
278 	login_cap_t *lc = NULL;
279 #endif
280 
281 
282 #ifdef OLD_SETPROCTITLE
283 	Argv = argv;
284 	if (envp == 0 || *envp == 0)
285 		envp = argv;
286 	while (*envp)
287 		envp++;
288 	LastArg = envp[-1] + strlen(envp[-1]);
289 #endif
290 
291 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
292 
293 	bind_address.s_addr = htonl(INADDR_ANY);
294 	while ((ch = getopt(argc, argv, "dlR:a:p:")) != -1)
295 		switch(ch) {
296 		case 'd':
297 			debug = 1;
298 			options |= SO_DEBUG;
299 			break;
300 		case 'l':
301 			log = 1;
302 			break;
303 		case 'R': {	/* invocation rate */
304 			char *p;
305 
306 			tmpint = strtol(optarg, &p, 0);
307 			if (tmpint < 1 || *p)
308 				syslog(LOG_ERR,
309 			         "-R %s: bad value for service invocation rate",
310 					optarg);
311 			else
312 				toomany = tmpint;
313 			break;
314 		}
315 		case 'a':
316 			if (!inet_aton(optarg, &bind_address)) {
317 				syslog(LOG_ERR,
318 			         "-a %s: invalid IP address", optarg);
319 				exit(EX_USAGE);
320 			}
321 			break;
322 		case 'p':
323 			pid_file = optarg;
324 			break;
325 		case '?':
326 		default:
327 			syslog(LOG_ERR,
328 				"usage: inetd [-dl] [-a address] [-R rate]"
329 				" [-p pidfile] [conf-file]");
330 			exit(EX_USAGE);
331 		}
332 	argc -= optind;
333 	argv += optind;
334 
335 	if (argc > 0)
336 		CONFIG = argv[0];
337 	if (debug == 0) {
338 		FILE *fp;
339 		if (daemon(0, 0) < 0) {
340 			syslog(LOG_WARNING, "daemon(0,0) failed: %m");
341 		}
342 		/*
343 		 * In case somebody has started inetd manually, we need to
344 		 * clear the logname, so that old servers run as root do not
345 		 * get the user's logname..
346 		 */
347 		if (setlogin("") < 0) {
348 			syslog(LOG_WARNING, "cannot clear logname: %m");
349 			/* no big deal if it fails.. */
350 		}
351 		pid = getpid();
352 		fp = fopen(pid_file, "w");
353 		if (fp) {
354 			fprintf(fp, "%ld\n", (long)pid);
355 			fclose(fp);
356 		} else {
357 			syslog(LOG_WARNING, "%s: %m", pid_file);
358 		}
359 	}
360 	memset(&sv, 0, sizeof(sv));
361 	sv.sv_mask = SIGBLOCK;
362 	sv.sv_handler = retry;
363 	sigvec(SIGALRM, &sv, (struct sigvec *)0);
364 	config(SIGHUP);
365 	sv.sv_handler = config;
366 	sigvec(SIGHUP, &sv, (struct sigvec *)0);
367 	sv.sv_handler = reapchild;
368 	sigvec(SIGCHLD, &sv, (struct sigvec *)0);
369 
370 	{
371 		/* space for daemons to overwrite environment for ps */
372 #define	DUMMYSIZE	100
373 		char dummy[DUMMYSIZE];
374 
375 		(void)memset(dummy, 'x', DUMMYSIZE - 1);
376 		dummy[DUMMYSIZE - 1] = '\0';
377 		(void)setenv("inetd_dummy", dummy, 1);
378 	}
379 
380 	for (;;) {
381 	    int n, ctrl;
382 	    fd_set readable;
383 
384 	    if (nsock == 0) {
385 		(void) sigblock(SIGBLOCK);
386 		while (nsock == 0)
387 		    sigpause(0L);
388 		(void) sigsetmask(0L);
389 	    }
390 	    readable = allsock;
391 	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
392 		(fd_set *)0, (struct timeval *)0)) <= 0) {
393 		    if (n < 0 && errno != EINTR) {
394 			syslog(LOG_WARNING, "select: %m");
395 			sleep(1);
396 		    }
397 		    continue;
398 	    }
399 	    for (sep = servtab; n && sep; sep = sep->se_next)
400 	        if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
401 		    n--;
402 		    if (debug)
403 			    warnx("someone wants %s", sep->se_service);
404 		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM) {
405 			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
406 				(int *)0);
407 			    if (debug)
408 				    warnx("accept, ctrl %d", ctrl);
409 			    if (ctrl < 0) {
410 				    if (errno != EINTR)
411 					    syslog(LOG_WARNING,
412 						"accept (for %s): %m",
413 						sep->se_service);
414 				    continue;
415 			    }
416 			    if (log) {
417 				i = sizeof peer;
418 				if(getpeername(ctrl, (struct sockaddr *)
419 						&peer, &i)) {
420 					syslog(LOG_WARNING,
421 						"getpeername(for %s): %m",
422 						sep->se_service);
423 					continue;
424 				}
425 				syslog(LOG_INFO,"%s from %s",
426 					sep->se_service,
427 					inet_ntoa(peer.sin_addr));
428 			    }
429 			    /*
430 			     * Call tcpmux to find the real service to exec.
431 			     */
432 			    if (sep->se_bi &&
433 				sep->se_bi->bi_fn == (void (*)()) tcpmux) {
434 				    struct servtab *tsep;
435 
436 				    tsep = tcpmux(ctrl);
437 				    if (tsep == NULL) {
438 					    close(ctrl);
439 					    continue;
440 				    }
441 				    sep = tsep;
442 			    }
443 		    } else
444 			    ctrl = sep->se_fd;
445 		    (void) sigblock(SIGBLOCK);
446 		    pid = 0;
447 		    dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
448 		    if (dofork) {
449 			    if (sep->se_count++ == 0)
450 				(void)gettimeofday(&sep->se_time,
451 				    (struct timezone *)0);
452 			    else if (sep->se_count >= toomany) {
453 				struct timeval now;
454 
455 				(void)gettimeofday(&now, (struct timezone *)0);
456 				if (now.tv_sec - sep->se_time.tv_sec >
457 				    CNT_INTVL) {
458 					sep->se_time = now;
459 					sep->se_count = 1;
460 				} else {
461 					syslog(LOG_ERR,
462 			"%s/%s server failing (looping), service terminated",
463 					    sep->se_service, sep->se_proto);
464 					close_sep(sep);
465 					sigsetmask(0L);
466 					if (!timingout) {
467 						timingout = 1;
468 						alarm(RETRYTIME);
469 					}
470 					continue;
471 				}
472 			    }
473 			    pid = fork();
474 		    }
475 		    if (pid < 0) {
476 			    syslog(LOG_ERR, "fork: %m");
477 			    if (sep->se_accept &&
478 				sep->se_socktype == SOCK_STREAM)
479 				    close(ctrl);
480 			    sigsetmask(0L);
481 			    sleep(1);
482 			    continue;
483 		    }
484 		    if (pid)
485 			addchild(sep, pid);
486 		    sigsetmask(0L);
487 		    if (pid == 0) {
488 			    if (dofork) {
489 				if (debug)
490 					warnx("+ closing from %d", maxsock);
491 				for (tmpint = maxsock; tmpint > 2; tmpint--)
492 					if (tmpint != ctrl)
493 						(void) close(tmpint);
494 			    }
495 			    if (sep->se_bi) {
496 				(*sep->se_bi->bi_fn)(ctrl, sep);
497 				/* NOTREACHED */
498 			    } else {
499 				if (debug)
500 					warnx("%d execl %s",
501 						getpid(), sep->se_server);
502 				dup2(ctrl, 0);
503 				close(ctrl);
504 				dup2(0, 1);
505 				dup2(0, 2);
506 				if ((pwd = getpwnam(sep->se_user)) == NULL) {
507 					syslog(LOG_ERR,
508 					    "%s/%s: %s: No such user",
509 						sep->se_service, sep->se_proto,
510 						sep->se_user);
511 					if (sep->se_socktype != SOCK_STREAM)
512 						recv(0, buf, sizeof (buf), 0);
513 					_exit(EX_NOUSER);
514 				}
515 #ifdef LOGIN_CAP
516 				/*
517 				 * Establish the class now, falls back to
518 				 * the "default" if unavailable.
519 				 */
520 				lc = login_getpwclass(pwd);
521 #endif
522 				if (setsid() < 0) {
523 					syslog(LOG_ERR,
524 						"%s: can't setsid(): %m",
525 						 sep->se_service);
526 					/* _exit(EX_OSERR); not fatal yet */
527 				}
528 #ifdef LOGIN_CAP
529 				if (setusercontext(lc, pwd, pwd->pw_uid,
530 				    LOGIN_SETALL) != 0) {
531 					syslog(LOG_ERR,
532 					 "%s: can't setusercontext(..%s..): %m",
533 					 sep->se_service, sep->se_user);
534 					_exit(EX_OSERR);
535 				}
536 #else
537 				if (pwd->pw_uid) {
538 					if (setlogin(sep->se_user) < 0) {
539 						syslog(LOG_ERR,
540 						 "%s: can't setlogin(%s): %m",
541 						 sep->se_service, sep->se_user);
542 						/* _exit(EX_OSERR); not yet */
543 					}
544 					if (setgid(pwd->pw_gid) < 0) {
545 						syslog(LOG_ERR,
546 						  "%s: can't set gid %d: %m",
547 						  sep->se_service, pwd->pw_gid);
548 						_exit(EX_OSERR);
549 					}
550 					(void) initgroups(pwd->pw_name,
551 							pwd->pw_gid);
552 					if (setuid(pwd->pw_uid) < 0) {
553 						syslog(LOG_ERR,
554 						  "%s: can't set uid %d: %m",
555 						  sep->se_service, pwd->pw_uid);
556 						_exit(EX_OSERR);
557 					}
558 				}
559 #endif
560 				execv(sep->se_server, sep->se_argv);
561 				if (sep->se_socktype != SOCK_STREAM)
562 					recv(0, buf, sizeof (buf), 0);
563 				syslog(LOG_ERR,
564 				    "cannot execute %s: %m", sep->se_server);
565 				_exit(EX_OSERR);
566 			    }
567 		    }
568 		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM)
569 			    close(ctrl);
570 		}
571 	}
572 }
573 
574 /*
575  * Record a new child pid for this service. If we've reached the
576  * limit on children, then stop accepting incoming requests.
577  */
578 
579 void
580 addchild(struct servtab *sep, pid_t pid)
581 {
582 #ifdef SANITY_CHECK
583 	if (sep->se_numchild >= sep->se_maxchild) {
584 		syslog(LOG_ERR, "%s: %d >= %d",
585 		    __FUNCTION__, sep->se_numchild, sep->se_maxchild);
586 		exit(EX_SOFTWARE);
587 	}
588 #endif
589 	if (sep->se_maxchild == 0)
590 		return;
591 	sep->se_pids[sep->se_numchild++] = pid;
592 	if (sep->se_numchild == sep->se_maxchild)
593 		disable(sep);
594 }
595 
596 /*
597  * Some child process has exited. See if it's on somebody's list.
598  */
599 
600 void
601 reapchild(signo)
602 	int signo;
603 {
604 	int k, status;
605 	pid_t pid;
606 	struct servtab *sep;
607 
608 	for (;;) {
609 		pid = wait3(&status, WNOHANG, (struct rusage *)0);
610 		if (pid <= 0)
611 			break;
612 		if (debug)
613 			warnx("%d reaped, status %#x", pid, status);
614 		for (sep = servtab; sep; sep = sep->se_next) {
615 			for (k = 0; k < sep->se_numchild; k++)
616 				if (sep->se_pids[k] == pid)
617 					break;
618 			if (k == sep->se_numchild)
619 				continue;
620 			if (sep->se_numchild == sep->se_maxchild)
621 				enable(sep);
622 			sep->se_pids[k] = sep->se_pids[--sep->se_numchild];
623 			if (status)
624 				syslog(LOG_WARNING,
625 				    "%s[%d]: exit status 0x%x",
626 				    sep->se_server, pid, status);
627 			break;
628 		}
629 	}
630 }
631 
632 void
633 config(signo)
634 	int signo;
635 {
636 	struct servtab *sep, *new, **sepp;
637 	struct passwd *pwd;
638 	long omask;
639 
640 	if (!setconfig()) {
641 		syslog(LOG_ERR, "%s: %m", CONFIG);
642 		return;
643 	}
644 	for (sep = servtab; sep; sep = sep->se_next)
645 		sep->se_checked = 0;
646 	while ((new = getconfigent())) {
647 		if ((pwd = getpwnam(new->se_user)) == NULL) {
648 			syslog(LOG_ERR,
649 				"%s/%s: No such user '%s', service ignored",
650 				new->se_service, new->se_proto, new->se_user);
651 			continue;
652 		}
653 		for (sep = servtab; sep; sep = sep->se_next)
654 			if (strcmp(sep->se_service, new->se_service) == 0 &&
655 			    strcmp(sep->se_proto, new->se_proto) == 0)
656 				break;
657 		if (sep != 0) {
658 			int i;
659 
660 #define SWAP(a, b) { typeof(a) c = a; a = b; b = c; }
661 			omask = sigblock(SIGBLOCK);
662 			/* copy over outstanding child pids */
663 			if (sep->se_maxchild && new->se_maxchild) {
664 				new->se_numchild = sep->se_numchild;
665 				if (new->se_numchild > new->se_maxchild)
666 					new->se_numchild = new->se_maxchild;
667 				memcpy(new->se_pids, sep->se_pids,
668 				    new->se_numchild * sizeof(*new->se_pids));
669 			}
670 			SWAP(sep->se_pids, new->se_pids);
671 			sep->se_maxchild = new->se_maxchild;
672 			sep->se_numchild = new->se_numchild;
673 			/* might need to turn on or off service now */
674 			if (sep->se_fd >= 0) {
675 			      if (sep->se_maxchild
676 				  && sep->se_numchild == sep->se_maxchild) {
677 				      if (FD_ISSET(sep->se_fd, &allsock))
678 					  disable(sep);
679 			      } else {
680 				      if (!FD_ISSET(sep->se_fd, &allsock))
681 					  enable(sep);
682 			      }
683 			}
684 			sep->se_accept = new->se_accept;
685 			if (new->se_user)
686 				SWAP(sep->se_user, new->se_user);
687 			if (new->se_server)
688 				SWAP(sep->se_server, new->se_server);
689 			for (i = 0; i < MAXARGV; i++)
690 				SWAP(sep->se_argv[i], new->se_argv[i]);
691 			sigsetmask(omask);
692 			freeconfig(new);
693 			if (debug)
694 				print_service("REDO", sep);
695 		} else {
696 			sep = enter(new);
697 			if (debug)
698 				print_service("ADD ", sep);
699 		}
700 		sep->se_checked = 1;
701 		if (ISMUX(sep)) {
702 			sep->se_fd = -1;
703 			continue;
704 		}
705 		if (!sep->se_rpc) {
706 			sp = getservbyname(sep->se_service, sep->se_proto);
707 			if (sp == 0) {
708 				syslog(LOG_ERR, "%s/%s: unknown service",
709 			    	sep->se_service, sep->se_proto);
710 				sep->se_checked = 0;
711 				continue;
712 			}
713 			if (sp->s_port != sep->se_ctrladdr.sin_port) {
714 				sep->se_ctrladdr.sin_family = AF_INET;
715 				sep->se_ctrladdr.sin_addr = bind_address;
716 				sep->se_ctrladdr.sin_port = sp->s_port;
717 				if (sep->se_fd >= 0)
718 					close_sep(sep);
719 			}
720 		} else {
721 			rpc = getrpcbyname(sep->se_service);
722 			if (rpc == 0) {
723 				syslog(LOG_ERR, "%s/%s unknown RPC service.",
724 					sep->se_service, sep->se_proto);
725 				if (sep->se_fd != -1)
726 					(void) close(sep->se_fd);
727 				sep->se_fd = -1;
728 					continue;
729 			}
730 			if (rpc->r_number != sep->se_rpc_prog) {
731 				if (sep->se_rpc_prog)
732 					unregisterrpc(sep);
733 				sep->se_rpc_prog = rpc->r_number;
734 				if (sep->se_fd != -1)
735 					(void) close(sep->se_fd);
736 				sep->se_fd = -1;
737 			}
738 		}
739 		if (sep->se_fd == -1)
740 			setup(sep);
741 	}
742 	endconfig();
743 	/*
744 	 * Purge anything not looked at above.
745 	 */
746 	omask = sigblock(SIGBLOCK);
747 	sepp = &servtab;
748 	while ((sep = *sepp)) {
749 		if (sep->se_checked) {
750 			sepp = &sep->se_next;
751 			continue;
752 		}
753 		*sepp = sep->se_next;
754 		if (sep->se_fd >= 0)
755 			close_sep(sep);
756 		if (debug)
757 			print_service("FREE", sep);
758 		if (sep->se_rpc && sep->se_rpc_prog > 0)
759 			unregisterrpc(sep);
760 		freeconfig(sep);
761 		free((char *)sep);
762 	}
763 	(void) sigsetmask(omask);
764 }
765 
766 void
767 unregisterrpc(sep)
768 	struct servtab *sep;
769 {
770         int i;
771         struct servtab *sepp;
772 	long omask;
773 
774 	omask = sigblock(SIGBLOCK);
775         for (sepp = servtab; sepp; sepp = sepp->se_next) {
776                 if (sepp == sep)
777                         continue;
778 		if (sep->se_checked == 0 ||
779                     !sepp->se_rpc ||
780                     sep->se_rpc_prog != sepp->se_rpc_prog)
781 			continue;
782                 return;
783         }
784         if (debug)
785                 print_service("UNREG", sep);
786         for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
787                 pmap_unset(sep->se_rpc_prog, i);
788         if (sep->se_fd != -1)
789                 (void) close(sep->se_fd);
790         sep->se_fd = -1;
791 	(void) sigsetmask(omask);
792 }
793 
794 void
795 retry(signo)
796 	int signo;
797 {
798 	struct servtab *sep;
799 
800 	timingout = 0;
801 	for (sep = servtab; sep; sep = sep->se_next)
802 		if (sep->se_fd == -1 && !ISMUX(sep))
803 			setup(sep);
804 }
805 
806 void
807 setup(sep)
808 	struct servtab *sep;
809 {
810 	int on = 1;
811 
812 	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
813 		if (debug)
814 			warn("socket failed on %s/%s",
815 				sep->se_service, sep->se_proto);
816 		syslog(LOG_ERR, "%s/%s: socket: %m",
817 		    sep->se_service, sep->se_proto);
818 		return;
819 	}
820 #define	turnon(fd, opt) \
821 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
822 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
823 	    turnon(sep->se_fd, SO_DEBUG) < 0)
824 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
825 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
826 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
827 #ifdef SO_PRIVSTATE
828 	if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
829 		syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
830 #endif
831 #undef turnon
832 	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
833 	    sizeof (sep->se_ctrladdr)) < 0) {
834 		if (debug)
835 			warn("bind failed on %s/%s",
836 				sep->se_service, sep->se_proto);
837 		syslog(LOG_ERR, "%s/%s: bind: %m",
838 		    sep->se_service, sep->se_proto);
839 		(void) close(sep->se_fd);
840 		sep->se_fd = -1;
841 		if (!timingout) {
842 			timingout = 1;
843 			alarm(RETRYTIME);
844 		}
845 		return;
846 	}
847         if (sep->se_rpc) {
848                 int i, len = sizeof(struct sockaddr);
849 
850                 if (getsockname(sep->se_fd,
851 				(struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
852                         syslog(LOG_ERR, "%s/%s: getsockname: %m",
853                                sep->se_service, sep->se_proto);
854                         (void) close(sep->se_fd);
855                         sep->se_fd = -1;
856                         return;
857                 }
858                 if (debug)
859                         print_service("REG ", sep);
860                 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
861                         pmap_unset(sep->se_rpc_prog, i);
862                         pmap_set(sep->se_rpc_prog, i,
863                                  (sep->se_socktype == SOCK_DGRAM)
864                                  ? IPPROTO_UDP : IPPROTO_TCP,
865                                  ntohs(sep->se_ctrladdr.sin_port));
866                 }
867 
868         }
869 	if (sep->se_socktype == SOCK_STREAM)
870 		listen(sep->se_fd, 64);
871 	enable(sep);
872 	if (debug) {
873 		warnx("registered %s on %d",
874 			sep->se_server, sep->se_fd);
875 	}
876 }
877 
878 /*
879  * Finish with a service and its socket.
880  */
881 void
882 close_sep(sep)
883 	struct servtab *sep;
884 {
885 	if (sep->se_fd >= 0) {
886 		if (FD_ISSET(sep->se_fd, &allsock))
887 			disable(sep);
888 		(void) close(sep->se_fd);
889 		sep->se_fd = -1;
890 	}
891 	sep->se_count = 0;
892 	sep->se_numchild = 0;	/* forget about any existing children */
893 }
894 
895 struct servtab *
896 enter(cp)
897 	struct servtab *cp;
898 {
899 	struct servtab *sep;
900 	long omask;
901 
902 	sep = (struct servtab *)malloc(sizeof (*sep));
903 	if (sep == (struct servtab *)0) {
904 		syslog(LOG_ERR, "Out of memory.");
905 		exit(EX_OSERR);
906 	}
907 	*sep = *cp;
908 	sep->se_fd = -1;
909 	omask = sigblock(SIGBLOCK);
910 	sep->se_next = servtab;
911 	servtab = sep;
912 	sigsetmask(omask);
913 	return (sep);
914 }
915 
916 void
917 enable(struct servtab *sep)
918 {
919 	if (debug)
920 		warnx(
921 		    "enabling %s, fd %d", sep->se_service, sep->se_fd);
922 #ifdef SANITY_CHECK
923 	if (sep->se_fd < 0) {
924 		syslog(LOG_ERR,
925 		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
926 		exit(EX_SOFTWARE);
927 	}
928 	if (ISMUX(sep)) {
929 		syslog(LOG_ERR,
930 		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
931 		exit(EX_SOFTWARE);
932 	}
933 	if (FD_ISSET(sep->se_fd, &allsock)) {
934 		syslog(LOG_ERR,
935 		    "%s: %s: not off", __FUNCTION__, sep->se_service);
936 		exit(EX_SOFTWARE);
937 	}
938 #endif
939 	FD_SET(sep->se_fd, &allsock);
940 	nsock++;
941 	if (sep->se_fd > maxsock)
942 		maxsock = sep->se_fd;
943 }
944 
945 void
946 disable(struct servtab *sep)
947 {
948 	if (debug)
949 		warnx(
950 		    "disabling %s, fd %d", sep->se_service, sep->se_fd);
951 #ifdef SANITY_CHECK
952 	if (sep->se_fd < 0) {
953 		syslog(LOG_ERR,
954 		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
955 		exit(EX_SOFTWARE);
956 	}
957 	if (ISMUX(sep)) {
958 		syslog(LOG_ERR,
959 		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
960 		exit(EX_SOFTWARE);
961 	}
962 	if (!FD_ISSET(sep->se_fd, &allsock)) {
963 		syslog(LOG_ERR,
964 		    "%s: %s: not on", __FUNCTION__, sep->se_service);
965 		exit(EX_SOFTWARE);
966 	}
967 	if (nsock == 0) {
968 		syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
969 		exit(EX_SOFTWARE);
970 	}
971 #endif
972 	FD_CLR(sep->se_fd, &allsock);
973 	nsock--;
974 	if (sep->se_fd == maxsock)
975 		maxsock--;
976 }
977 
978 FILE	*fconfig = NULL;
979 struct	servtab serv;
980 char	line[LINE_MAX];
981 
982 int
983 setconfig()
984 {
985 
986 	if (fconfig != NULL) {
987 		fseek(fconfig, 0L, SEEK_SET);
988 		return (1);
989 	}
990 	fconfig = fopen(CONFIG, "r");
991 	return (fconfig != NULL);
992 }
993 
994 void
995 endconfig()
996 {
997 	if (fconfig) {
998 		(void) fclose(fconfig);
999 		fconfig = NULL;
1000 	}
1001 }
1002 
1003 struct servtab *
1004 getconfigent()
1005 {
1006 	struct servtab *sep = &serv;
1007 	int argc;
1008 	char *cp, *arg, *s;
1009 	char *versp;
1010 	static char TCPMUX_TOKEN[] = "tcpmux/";
1011 #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
1012 
1013 more:
1014 	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
1015 		;
1016 	if (cp == NULL)
1017 		return ((struct servtab *)0);
1018 	/*
1019 	 * clear the static buffer, since some fields (se_ctrladdr,
1020 	 * for example) don't get initialized here.
1021 	 */
1022 	memset((caddr_t)sep, 0, sizeof *sep);
1023 	arg = skip(&cp);
1024 	if (cp == NULL) {
1025 		/* got an empty line containing just blanks/tabs. */
1026 		goto more;
1027 	}
1028 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
1029 		char *c = arg + MUX_LEN;
1030 		if (*c == '+') {
1031 			sep->se_type = MUXPLUS_TYPE;
1032 			c++;
1033 		} else
1034 			sep->se_type = MUX_TYPE;
1035 		sep->se_service = newstr(c);
1036 	} else {
1037 		sep->se_service = newstr(arg);
1038 		sep->se_type = NORM_TYPE;
1039 	}
1040 	arg = sskip(&cp);
1041 	if (strcmp(arg, "stream") == 0)
1042 		sep->se_socktype = SOCK_STREAM;
1043 	else if (strcmp(arg, "dgram") == 0)
1044 		sep->se_socktype = SOCK_DGRAM;
1045 	else if (strcmp(arg, "rdm") == 0)
1046 		sep->se_socktype = SOCK_RDM;
1047 	else if (strcmp(arg, "seqpacket") == 0)
1048 		sep->se_socktype = SOCK_SEQPACKET;
1049 	else if (strcmp(arg, "raw") == 0)
1050 		sep->se_socktype = SOCK_RAW;
1051 	else
1052 		sep->se_socktype = -1;
1053 	sep->se_proto = newstr(sskip(&cp));
1054         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1055                 memmove(sep->se_proto, sep->se_proto + 4,
1056                     strlen(sep->se_proto) + 1 - 4);
1057                 sep->se_rpc = 1;
1058                 sep->se_rpc_prog = sep->se_rpc_lowvers =
1059 			sep->se_rpc_lowvers = 0;
1060                 sep->se_ctrladdr.sin_family = AF_INET;
1061                 sep->se_ctrladdr.sin_port = 0;
1062                 sep->se_ctrladdr.sin_addr = bind_address;
1063                 if ((versp = rindex(sep->se_service, '/'))) {
1064                         *versp++ = '\0';
1065                         switch (sscanf(versp, "%d-%d",
1066                                        &sep->se_rpc_lowvers,
1067                                        &sep->se_rpc_highvers)) {
1068                         case 2:
1069                                 break;
1070                         case 1:
1071                                 sep->se_rpc_highvers =
1072                                         sep->se_rpc_lowvers;
1073                                 break;
1074                         default:
1075                                 syslog(LOG_ERR,
1076 					"bad RPC version specifier; %s\n",
1077 					sep->se_service);
1078                                 freeconfig(sep);
1079                                 goto more;
1080                         }
1081                 }
1082                 else {
1083                         sep->se_rpc_lowvers =
1084                                 sep->se_rpc_highvers = 1;
1085                 }
1086         }
1087 	arg = sskip(&cp);
1088 	if (!strncmp(arg, "wait", 4))
1089 		sep->se_accept = 0;
1090 	else if (!strncmp(arg, "nowait", 6))
1091 		sep->se_accept = 1;
1092 	else {
1093 		syslog(LOG_ERR,
1094 			"%s: bad wait/nowait for service %s",
1095 			CONFIG, sep->se_service);
1096 		goto more;
1097 	}
1098 	sep->se_maxchild = -1;
1099 	if ((s = strchr(arg, '/')) != NULL) {
1100 		char *eptr;
1101 		u_long val;
1102 
1103 		val = strtoul(s + 1, &eptr, 10);
1104 		if (eptr == s + 1 || *eptr || val > MAX_MAXCHLD) {
1105 			syslog(LOG_ERR,
1106 				"%s: bad max-child for service %s",
1107 				CONFIG, sep->se_service);
1108 			goto more;
1109 		}
1110 		sep->se_maxchild = val;
1111 	}
1112 	if (ISMUX(sep)) {
1113 		/*
1114 		 * Silently enforce "nowait" mode for TCPMUX services
1115 		 * since they don't have an assigned port to listen on.
1116 		 */
1117 		sep->se_accept = 1;
1118 		if (strcmp(sep->se_proto, "tcp")) {
1119 			syslog(LOG_ERR,
1120 				"%s: bad protocol for tcpmux service %s",
1121 				CONFIG, sep->se_service);
1122 			goto more;
1123 		}
1124 		if (sep->se_socktype != SOCK_STREAM) {
1125 			syslog(LOG_ERR,
1126 				"%s: bad socket type for tcpmux service %s",
1127 				CONFIG, sep->se_service);
1128 			goto more;
1129 		}
1130 	}
1131 	sep->se_user = newstr(sskip(&cp));
1132 	sep->se_server = newstr(sskip(&cp));
1133 	if (strcmp(sep->se_server, "internal") == 0) {
1134 		struct biltin *bi;
1135 
1136 		for (bi = biltins; bi->bi_service; bi++)
1137 			if (bi->bi_socktype == sep->se_socktype &&
1138 			    strcmp(bi->bi_service, sep->se_service) == 0)
1139 				break;
1140 		if (bi->bi_service == 0) {
1141 			syslog(LOG_ERR, "internal service %s unknown",
1142 				sep->se_service);
1143 			goto more;
1144 		}
1145 		sep->se_accept = 1;	/* force accept mode for built-ins */
1146 		sep->se_bi = bi;
1147 	} else
1148 		sep->se_bi = NULL;
1149 	if (sep->se_maxchild < 0)	/* apply default max-children */
1150 		if (sep->se_bi)
1151 			sep->se_maxchild = sep->se_bi->bi_maxchild;
1152 		else
1153 			sep->se_maxchild = sep->se_accept ? 0 : 1;
1154 	if (sep->se_maxchild) {
1155 		sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids));
1156 		if (sep->se_pids == NULL) {
1157 			syslog(LOG_ERR, "Out of memory.");
1158 			exit(EX_OSERR);
1159 		}
1160 	}
1161 	argc = 0;
1162 	for (arg = skip(&cp); cp; arg = skip(&cp))
1163 		if (argc < MAXARGV) {
1164 			sep->se_argv[argc++] = newstr(arg);
1165 		} else {
1166 			syslog(LOG_ERR,
1167 				"%s: too many arguments for service %s",
1168 				CONFIG, sep->se_service);
1169 			goto more;
1170 		}
1171 	while (argc <= MAXARGV)
1172 		sep->se_argv[argc++] = NULL;
1173 	return (sep);
1174 }
1175 
1176 void
1177 freeconfig(cp)
1178 	struct servtab *cp;
1179 {
1180 	int i;
1181 
1182 	if (cp->se_service)
1183 		free(cp->se_service);
1184 	if (cp->se_proto)
1185 		free(cp->se_proto);
1186 	if (cp->se_user)
1187 		free(cp->se_user);
1188 	if (cp->se_server)
1189 		free(cp->se_server);
1190 	if (cp->se_pids)
1191 		free(cp->se_pids);
1192 	for (i = 0; i < MAXARGV; i++)
1193 		if (cp->se_argv[i])
1194 			free(cp->se_argv[i]);
1195 }
1196 
1197 
1198 /*
1199  * Safe skip - if skip returns null, log a syntax error in the
1200  * configuration file and exit.
1201  */
1202 char *
1203 sskip(cpp)
1204 	char **cpp;
1205 {
1206 	char *cp;
1207 
1208 	cp = skip(cpp);
1209 	if (cp == NULL) {
1210 		syslog(LOG_ERR, "%s: syntax error", CONFIG);
1211 		exit(EX_DATAERR);
1212 	}
1213 	return (cp);
1214 }
1215 
1216 char *
1217 skip(cpp)
1218 	char **cpp;
1219 {
1220 	char *cp = *cpp;
1221 	char *start;
1222 	char quote = '\0';
1223 
1224 again:
1225 	while (*cp == ' ' || *cp == '\t')
1226 		cp++;
1227 	if (*cp == '\0') {
1228 		int c;
1229 
1230 		c = getc(fconfig);
1231 		(void) ungetc(c, fconfig);
1232 		if (c == ' ' || c == '\t')
1233 			if ((cp = nextline(fconfig)))
1234 				goto again;
1235 		*cpp = (char *)0;
1236 		return ((char *)0);
1237 	}
1238 	if (*cp == '"' || *cp == '\'')
1239 		quote = *cp++;
1240 	start = cp;
1241 	if (quote)
1242 		while (*cp && *cp != quote)
1243 			cp++;
1244 	else
1245 		while (*cp && *cp != ' ' && *cp != '\t')
1246 			cp++;
1247 	if (*cp != '\0')
1248 		*cp++ = '\0';
1249 	*cpp = cp;
1250 	return (start);
1251 }
1252 
1253 char *
1254 nextline(fd)
1255 	FILE *fd;
1256 {
1257 	char *cp;
1258 
1259 	if (fgets(line, sizeof (line), fd) == NULL)
1260 		return ((char *)0);
1261 	cp = strchr(line, '\n');
1262 	if (cp)
1263 		*cp = '\0';
1264 	return (line);
1265 }
1266 
1267 char *
1268 newstr(cp)
1269 	char *cp;
1270 {
1271 	if ((cp = strdup(cp ? cp : "")))
1272 		return (cp);
1273 	syslog(LOG_ERR, "strdup: %m");
1274 	exit(EX_OSERR);
1275 }
1276 
1277 #ifdef OLD_SETPROCTITLE
1278 void
1279 inetd_setproctitle(a, s)
1280 	char *a;
1281 	int s;
1282 {
1283 	int size;
1284 	char *cp;
1285 	struct sockaddr_in sin;
1286 	char buf[80];
1287 
1288 	cp = Argv[0];
1289 	size = sizeof(sin);
1290 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1291 		(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
1292 	else
1293 		(void) sprintf(buf, "-%s", a);
1294 	strncpy(cp, buf, LastArg - cp);
1295 	cp += strlen(cp);
1296 	while (cp < LastArg)
1297 		*cp++ = ' ';
1298 }
1299 #else
1300 void
1301 inetd_setproctitle(a, s)
1302 	char *a;
1303 	int s;
1304 {
1305 	int size;
1306 	struct sockaddr_in sin;
1307 	char buf[80];
1308 
1309 	size = sizeof(sin);
1310 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1311 		(void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr));
1312 	else
1313 		(void) sprintf(buf, "%s", a);
1314 	setproctitle("%s", buf);
1315 }
1316 #endif
1317 
1318 
1319 /*
1320  * Internet services provided internally by inetd:
1321  */
1322 #define	BUFSIZE	8192
1323 
1324 /* ARGSUSED */
1325 void
1326 echo_stream(s, sep)		/* Echo service -- echo data back */
1327 	int s;
1328 	struct servtab *sep;
1329 {
1330 	char buffer[BUFSIZE];
1331 	int i;
1332 
1333 	inetd_setproctitle(sep->se_service, s);
1334 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1335 	    write(s, buffer, i) > 0)
1336 		;
1337 	exit(0);
1338 }
1339 
1340 int check_loop(sin, sep)
1341 	struct sockaddr_in *sin;
1342 	struct servtab *sep;
1343 {
1344 	struct servtab *se2;
1345 
1346 	for (se2 = servtab; se2; se2 = se2->se_next) {
1347 		if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
1348 			continue;
1349 
1350 		if (sin->sin_port == se2->se_ctrladdr.sin_port) {
1351 			syslog(LOG_WARNING,
1352 			       "%s/%s:%s/%s loop request REFUSED from %s",
1353 			       sep->se_service, sep->se_proto,
1354 			       se2->se_service, se2->se_proto,
1355 			       inet_ntoa(sin->sin_addr));
1356 			return 1;
1357 		}
1358 	}
1359 	return 0;
1360 }
1361 
1362 /* ARGSUSED */
1363 void
1364 echo_dg(s, sep)			/* Echo service -- echo data back */
1365 	int s;
1366 	struct servtab *sep;
1367 {
1368 	char buffer[BUFSIZE];
1369 	int i, size;
1370 	struct sockaddr_in sin;
1371 
1372 	size = sizeof(sin);
1373 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
1374 			  (struct sockaddr *)&sin, &size)) < 0)
1375 		return;
1376 
1377 	if (check_loop(&sin, sep))
1378 		return;
1379 
1380 	(void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin,
1381 		      sizeof(sin));
1382 }
1383 
1384 /* ARGSUSED */
1385 void
1386 discard_stream(s, sep)		/* Discard service -- ignore data */
1387 	int s;
1388 	struct servtab *sep;
1389 {
1390 	int ret;
1391 	char buffer[BUFSIZE];
1392 
1393 	inetd_setproctitle(sep->se_service, s);
1394 	while (1) {
1395 		while ((ret = read(s, buffer, sizeof(buffer))) > 0)
1396 			;
1397 		if (ret == 0 || errno != EINTR)
1398 			break;
1399 	}
1400 	exit(0);
1401 }
1402 
1403 /* ARGSUSED */
1404 void
1405 discard_dg(s, sep)		/* Discard service -- ignore data */
1406 	int s;
1407 	struct servtab *sep;
1408 {
1409 	char buffer[BUFSIZE];
1410 
1411 	(void) read(s, buffer, sizeof(buffer));
1412 }
1413 
1414 #include <ctype.h>
1415 #define LINESIZ 72
1416 char ring[128];
1417 char *endring;
1418 
1419 void
1420 initring()
1421 {
1422 	int i;
1423 
1424 	endring = ring;
1425 
1426 	for (i = 0; i <= 128; ++i)
1427 		if (isprint(i))
1428 			*endring++ = i;
1429 }
1430 
1431 /* ARGSUSED */
1432 void
1433 chargen_stream(s, sep)		/* Character generator */
1434 	int s;
1435 	struct servtab *sep;
1436 {
1437 	int len;
1438 	char *rs, text[LINESIZ+2];
1439 
1440 	inetd_setproctitle(sep->se_service, s);
1441 
1442 	if (!endring) {
1443 		initring();
1444 		rs = ring;
1445 	}
1446 
1447 	text[LINESIZ] = '\r';
1448 	text[LINESIZ + 1] = '\n';
1449 	for (rs = ring;;) {
1450 		if ((len = endring - rs) >= LINESIZ)
1451 			memmove(text, rs, LINESIZ);
1452 		else {
1453 			memmove(text, rs, len);
1454 			memmove(text + len, ring, LINESIZ - len);
1455 		}
1456 		if (++rs == endring)
1457 			rs = ring;
1458 		if (write(s, text, sizeof(text)) != sizeof(text))
1459 			break;
1460 	}
1461 	exit(0);
1462 }
1463 
1464 /* ARGSUSED */
1465 void
1466 chargen_dg(s, sep)		/* Character generator */
1467 	int s;
1468 	struct servtab *sep;
1469 {
1470 	struct sockaddr_in sin;
1471 	static char *rs;
1472 	int len, size;
1473 	char text[LINESIZ+2];
1474 
1475 	if (endring == 0) {
1476 		initring();
1477 		rs = ring;
1478 	}
1479 
1480 	size = sizeof(sin);
1481 	if (recvfrom(s, text, sizeof(text), 0,
1482 		     (struct sockaddr *)&sin, &size) < 0)
1483 		return;
1484 
1485 	if (check_loop(&sin, sep))
1486 		return;
1487 
1488 	if ((len = endring - rs) >= LINESIZ)
1489 		memmove(text, rs, LINESIZ);
1490 	else {
1491 		memmove(text, rs, len);
1492 		memmove(text + len, ring, LINESIZ - len);
1493 	}
1494 	if (++rs == endring)
1495 		rs = ring;
1496 	text[LINESIZ] = '\r';
1497 	text[LINESIZ + 1] = '\n';
1498 	(void) sendto(s, text, sizeof(text), 0,
1499 		      (struct sockaddr *)&sin, sizeof(sin));
1500 }
1501 
1502 /*
1503  * Return a machine readable date and time, in the form of the
1504  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1505  * returns the number of seconds since midnight, Jan 1, 1970,
1506  * we must add 2208988800 seconds to this figure to make up for
1507  * some seventy years Bell Labs was asleep.
1508  */
1509 
1510 long
1511 machtime()
1512 {
1513 	struct timeval tv;
1514 
1515 	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1516 		if (debug)
1517 			warnx("unable to get time of day");
1518 		return (0L);
1519 	}
1520 #define	OFFSET ((u_long)25567 * 24*60*60)
1521 	return (htonl((long)(tv.tv_sec + OFFSET)));
1522 #undef OFFSET
1523 }
1524 
1525 /* ARGSUSED */
1526 void
1527 machtime_stream(s, sep)
1528 	int s;
1529 	struct servtab *sep;
1530 {
1531 	long result;
1532 
1533 	result = machtime();
1534 	(void) write(s, (char *) &result, sizeof(result));
1535 }
1536 
1537 /* ARGSUSED */
1538 void
1539 machtime_dg(s, sep)
1540 	int s;
1541 	struct servtab *sep;
1542 {
1543 	long result;
1544 	struct sockaddr_in sin;
1545 	int size;
1546 
1547 	size = sizeof(sin);
1548 	if (recvfrom(s, (char *)&result, sizeof(result), 0,
1549 		     (struct sockaddr *)&sin, &size) < 0)
1550 		return;
1551 
1552 	if (check_loop(&sin, sep))
1553 		return;
1554 
1555 	result = machtime();
1556 	(void) sendto(s, (char *) &result, sizeof(result), 0,
1557 		      (struct sockaddr *)&sin, sizeof(sin));
1558 }
1559 
1560 /* ARGSUSED */
1561 void
1562 daytime_stream(s, sep)		/* Return human-readable time of day */
1563 	int s;
1564 	struct servtab *sep;
1565 {
1566 	char buffer[256];
1567 	time_t clock;
1568 
1569 	clock = time((time_t *) 0);
1570 
1571 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1572 	(void) write(s, buffer, strlen(buffer));
1573 }
1574 
1575 /* ARGSUSED */
1576 void
1577 daytime_dg(s, sep)		/* Return human-readable time of day */
1578 	int s;
1579 	struct servtab *sep;
1580 {
1581 	char buffer[256];
1582 	time_t clock;
1583 	struct sockaddr_in sin;
1584 	int size;
1585 
1586 	clock = time((time_t *) 0);
1587 
1588 	size = sizeof(sin);
1589 	if (recvfrom(s, buffer, sizeof(buffer), 0,
1590 		     (struct sockaddr *)&sin, &size) < 0)
1591 		return;
1592 
1593 	if (check_loop(&sin, sep))
1594 		return;
1595 
1596 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1597 	(void) sendto(s, buffer, strlen(buffer), 0,
1598 		      (struct sockaddr *)&sin, sizeof(sin));
1599 }
1600 
1601 /*
1602  * print_service:
1603  *	Dump relevant information to stderr
1604  */
1605 void
1606 print_service(action, sep)
1607 	char *action;
1608 	struct servtab *sep;
1609 {
1610 	fprintf(stderr,
1611 	    "%s: %s proto=%s accept=%d max=%d user=%s builtin=%x server=%s\n",
1612 	    action, sep->se_service, sep->se_proto,
1613 	    sep->se_accept, sep->se_maxchild, sep->se_user,
1614 	    (int)sep->se_bi, sep->se_server);
1615 }
1616 
1617 /*
1618  *  Based on TCPMUX.C by Mark K. Lottor November 1988
1619  *  sri-nic::ps:<mkl>tcpmux.c
1620  */
1621 
1622 
1623 static int		/* # of characters upto \r,\n or \0 */
1624 getline(fd, buf, len)
1625 	int fd;
1626 	char *buf;
1627 	int len;
1628 {
1629 	int count = 0, n;
1630 
1631 	do {
1632 		n = read(fd, buf, len-count);
1633 		if (n == 0)
1634 			return (count);
1635 		if (n < 0)
1636 			return (-1);
1637 		while (--n >= 0) {
1638 			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
1639 				return (count);
1640 			count++;
1641 			buf++;
1642 		}
1643 	} while (count < len);
1644 	return (count);
1645 }
1646 
1647 #define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
1648 
1649 #define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
1650 
1651 struct servtab *
1652 tcpmux(s)
1653 	int s;
1654 {
1655 	struct servtab *sep;
1656 	char service[MAX_SERV_LEN+1];
1657 	int len;
1658 
1659 	/* Get requested service name */
1660 	if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
1661 		strwrite(s, "-Error reading service name\r\n");
1662 		return (NULL);
1663 	}
1664 	service[len] = '\0';
1665 
1666 	if (debug)
1667 		warnx("tcpmux: someone wants %s", service);
1668 
1669 	/*
1670 	 * Help is a required command, and lists available services,
1671 	 * one per line.
1672 	 */
1673 	if (!strcasecmp(service, "help")) {
1674 		for (sep = servtab; sep; sep = sep->se_next) {
1675 			if (!ISMUX(sep))
1676 				continue;
1677 			(void)write(s,sep->se_service,strlen(sep->se_service));
1678 			strwrite(s, "\r\n");
1679 		}
1680 		return (NULL);
1681 	}
1682 
1683 	/* Try matching a service in inetd.conf with the request */
1684 	for (sep = servtab; sep; sep = sep->se_next) {
1685 		if (!ISMUX(sep))
1686 			continue;
1687 		if (!strcasecmp(service, sep->se_service)) {
1688 			if (ISMUXPLUS(sep)) {
1689 				strwrite(s, "+Go\r\n");
1690 			}
1691 			return (sep);
1692 		}
1693 	}
1694 	strwrite(s, "-Service not available\r\n");
1695 	return (NULL);
1696 }
1697