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