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