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