inetd.c revision 17482
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
35static 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"; */
42static 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
137int	debug = 0;
138int	log = 0;
139int	nsock, maxsock;
140fd_set	allsock;
141int	options;
142int	timingout;
143int	toomany = TOOMANY;
144struct	servent *sp;
145struct	rpcent *rpc;
146struct	in_addr bind_address;
147
148struct	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
179void		chargen_dg __P((int, struct servtab *));
180void		chargen_stream __P((int, struct servtab *));
181void		close_sep __P((struct servtab *));
182void		config __P((int));
183void		daytime_dg __P((int, struct servtab *));
184void		daytime_stream __P((int, struct servtab *));
185void		discard_dg __P((int, struct servtab *));
186void		discard_stream __P((int, struct servtab *));
187void		echo_dg __P((int, struct servtab *));
188void		echo_stream __P((int, struct servtab *));
189void		endconfig __P((void));
190struct servtab *enter __P((struct servtab *));
191void		freeconfig __P((struct servtab *));
192struct servtab *getconfigent __P((void));
193void		machtime_dg __P((int, struct servtab *));
194void		machtime_stream __P((int, struct servtab *));
195char	       *newstr __P((char *));
196char	       *nextline __P((FILE *));
197void		print_service __P((char *, struct servtab *));
198void		reapchild __P((int));
199void		retry __P((int));
200int		setconfig __P((void));
201void		setup __P((struct servtab *));
202char	       *sskip __P((char **));
203char	       *skip __P((char **));
204struct servtab *tcpmux __P((int));
205
206void		unregisterrpc __P((register struct servtab *sep));
207
208struct 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))
241char	*CONFIG = _PATH_INETDCONF;
242char	*pid_file = _PATH_INETDPID;
243
244#ifdef OLD_SETPROCTITLE
245char	**Argv;
246char 	*LastArg;
247#endif
248
249int
250main(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
544void
545reapchild(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
575void
576config(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
694void
695unregisterrpc(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
722void
723retry(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
734void
735setup(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) \
750setsockopt(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 */
812void
813close_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
831struct servtab *
832enter(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
852FILE	*fconfig = NULL;
853struct	servtab serv;
854char	line[LINE_MAX];
855
856int
857setconfig()
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
868void
869endconfig()
870{
871	if (fconfig) {
872		(void) fclose(fconfig);
873		fconfig = NULL;
874	}
875}
876
877struct servtab *
878getconfigent()
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
887more:
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
1009void
1010freeconfig(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 */
1033char *
1034sskip(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
1047char *
1048skip(cpp)
1049	char **cpp;
1050{
1051	char *cp = *cpp;
1052	char *start;
1053	char quote = '\0';
1054
1055again:
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
1084char *
1085nextline(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
1098char *
1099newstr(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
1109void
1110inetd_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
1131void
1132inetd_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 */
1156void
1157echo_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
1171int 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 */
1194void
1195echo_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 */
1216void
1217discard_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 */
1235void
1236discard_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
1247char ring[128];
1248char *endring;
1249
1250void
1251initring()
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 */
1263void
1264chargen_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 */
1296void
1297chargen_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
1341long
1342machtime()
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 */
1357void
1358machtime_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 */
1369void
1370machtime_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 */
1392void
1393daytime_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 */
1407void
1408daytime_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 */
1436void
1437print_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
1461static int		/* # of characters upto \r,\n or \0 */
1462getline(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
1489struct servtab *
1490tcpmux(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