xref: /freebsd/usr.sbin/inetd/inetd.c (revision d4788da623d086a254dbe085d78ec593cad8cb23)
1dea673e9SRodney W. Grimes /*
2dea673e9SRodney W. Grimes  * Copyright (c) 1983, 1991, 1993, 1994
3dea673e9SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4dea673e9SRodney W. Grimes  *
5dea673e9SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6dea673e9SRodney W. Grimes  * modification, are permitted provided that the following conditions
7dea673e9SRodney W. Grimes  * are met:
8dea673e9SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9dea673e9SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10dea673e9SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11dea673e9SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12dea673e9SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13dea673e9SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
14dea673e9SRodney W. Grimes  *    must display the following acknowledgement:
15dea673e9SRodney W. Grimes  *	This product includes software developed by the University of
16dea673e9SRodney W. Grimes  *	California, Berkeley and its contributors.
17dea673e9SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
18dea673e9SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19dea673e9SRodney W. Grimes  *    without specific prior written permission.
20dea673e9SRodney W. Grimes  *
21dea673e9SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22dea673e9SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23dea673e9SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24dea673e9SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25dea673e9SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26dea673e9SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27dea673e9SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28dea673e9SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29dea673e9SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30dea673e9SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31dea673e9SRodney W. Grimes  * SUCH DAMAGE.
32dea673e9SRodney W. Grimes  */
33dea673e9SRodney W. Grimes 
34dea673e9SRodney W. Grimes #ifndef lint
35dea673e9SRodney W. Grimes static char copyright[] =
36dea673e9SRodney W. Grimes "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
37dea673e9SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
38dea673e9SRodney W. Grimes #endif /* not lint */
39dea673e9SRodney W. Grimes 
40dea673e9SRodney W. Grimes #ifndef lint
4155b91f3aSGeoff Rehmet /* from: @(#)inetd.c	8.4 (Berkeley) 4/13/94"; */
4271704f34SGarrett Wollman static char inetd_c_rcsid[] =
43d4788da6SJoerg Wunsch 	"$Id: inetd.c,v 1.13 1996/08/09 22:20:24 julian Exp $";
44dea673e9SRodney W. Grimes #endif /* not lint */
45dea673e9SRodney W. Grimes 
46dea673e9SRodney W. Grimes /*
47dea673e9SRodney W. Grimes  * Inetd - Internet super-server
48dea673e9SRodney W. Grimes  *
49dea673e9SRodney W. Grimes  * This program invokes all internet services as needed.  Connection-oriented
50dea673e9SRodney W. Grimes  * services are invoked each time a connection is made, by creating a process.
51dea673e9SRodney W. Grimes  * This process is passed the connection as file descriptor 0 and is expected
52dea673e9SRodney W. Grimes  * to do a getpeername to find out the source host and port.
53dea673e9SRodney W. Grimes  *
54dea673e9SRodney W. Grimes  * Datagram oriented services are invoked when a datagram
55dea673e9SRodney W. Grimes  * arrives; a process is created and passed a pending message
56dea673e9SRodney W. Grimes  * on file descriptor 0.  Datagram servers may either connect
57dea673e9SRodney W. Grimes  * to their peer, freeing up the original socket for inetd
58dea673e9SRodney W. Grimes  * to receive further messages on, or ``take over the socket'',
59dea673e9SRodney W. Grimes  * processing all arriving datagrams and, eventually, timing
60dea673e9SRodney W. Grimes  * out.	 The first type of server is said to be ``multi-threaded'';
61dea673e9SRodney W. Grimes  * the second type of server ``single-threaded''.
62dea673e9SRodney W. Grimes  *
63dea673e9SRodney W. Grimes  * Inetd uses a configuration file which is read at startup
64dea673e9SRodney W. Grimes  * and, possibly, at some later time in response to a hangup signal.
65dea673e9SRodney W. Grimes  * The configuration file is ``free format'' with fields given in the
66dea673e9SRodney W. Grimes  * order shown below.  Continuation lines for an entry must being with
67dea673e9SRodney W. Grimes  * a space or tab.  All fields must be present in each entry.
68dea673e9SRodney W. Grimes  *
69dea673e9SRodney W. Grimes  *	service name			must be in /etc/services or must
70dea673e9SRodney W. Grimes  *					name a tcpmux service
71dea673e9SRodney W. Grimes  *	socket type			stream/dgram/raw/rdm/seqpacket
72dea673e9SRodney W. Grimes  *	protocol			must be in /etc/protocols
73dea673e9SRodney W. Grimes  *	wait/nowait			single-threaded/multi-threaded
74dea673e9SRodney W. Grimes  *	user				user to run daemon as
75dea673e9SRodney W. Grimes  *	server program			full path name
76dea673e9SRodney W. Grimes  *	server program arguments	maximum of MAXARGS (20)
77dea673e9SRodney W. Grimes  *
78dea673e9SRodney W. Grimes  * TCP services without official port numbers are handled with the
79dea673e9SRodney W. Grimes  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
80dea673e9SRodney W. Grimes  * requests. When a connection is made from a foreign host, the service
81dea673e9SRodney W. Grimes  * requested is passed to tcpmux, which looks it up in the servtab list
82dea673e9SRodney W. Grimes  * and returns the proper entry for the service. Tcpmux returns a
83dea673e9SRodney W. Grimes  * negative reply if the service doesn't exist, otherwise the invoked
84dea673e9SRodney W. Grimes  * server is expected to return the positive reply if the service type in
85dea673e9SRodney W. Grimes  * inetd.conf file has the prefix "tcpmux/". If the service type has the
86dea673e9SRodney W. Grimes  * prefix "tcpmux/+", tcpmux will return the positive reply for the
87dea673e9SRodney W. Grimes  * process; this is for compatibility with older server code, and also
88dea673e9SRodney W. Grimes  * allows you to invoke programs that use stdin/stdout without putting any
89dea673e9SRodney W. Grimes  * special server code in them. Services that use tcpmux are "nowait"
90dea673e9SRodney W. Grimes  * because they do not have a well-known port and hence cannot listen
91dea673e9SRodney W. Grimes  * for new requests.
92dea673e9SRodney W. Grimes  *
9355b91f3aSGeoff Rehmet  * For RPC services
9455b91f3aSGeoff Rehmet  *	service name/version		must be in /etc/rpc
9555b91f3aSGeoff Rehmet  *	socket type			stream/dgram/raw/rdm/seqpacket
9655b91f3aSGeoff Rehmet  *	protocol			must be in /etc/protocols
9755b91f3aSGeoff Rehmet  *	wait/nowait			single-threaded/multi-threaded
9855b91f3aSGeoff Rehmet  *	user				user to run daemon as
9955b91f3aSGeoff Rehmet  *	server program			full path name
10055b91f3aSGeoff Rehmet  *	server program arguments	maximum of MAXARGS
10155b91f3aSGeoff Rehmet  *
102dea673e9SRodney W. Grimes  * Comment lines are indicated by a `#' in column 1.
103dea673e9SRodney W. Grimes  */
104dea673e9SRodney W. Grimes #include <sys/param.h>
105dea673e9SRodney W. Grimes #include <sys/stat.h>
106dea673e9SRodney W. Grimes #include <sys/ioctl.h>
107dea673e9SRodney W. Grimes #include <sys/socket.h>
108dea673e9SRodney W. Grimes #include <sys/wait.h>
109dea673e9SRodney W. Grimes #include <sys/time.h>
110dea673e9SRodney W. Grimes #include <sys/resource.h>
111dea673e9SRodney W. Grimes 
112dea673e9SRodney W. Grimes #include <netinet/in.h>
113dea673e9SRodney W. Grimes #include <arpa/inet.h>
11455b91f3aSGeoff Rehmet #include <rpc/rpc.h>
115dea673e9SRodney W. Grimes 
116dea673e9SRodney W. Grimes #include <errno.h>
117dea673e9SRodney W. Grimes #include <fcntl.h>
118dea673e9SRodney W. Grimes #include <netdb.h>
119dea673e9SRodney W. Grimes #include <pwd.h>
120dea673e9SRodney W. Grimes #include <signal.h>
121dea673e9SRodney W. Grimes #include <stdio.h>
122dea673e9SRodney W. Grimes #include <stdlib.h>
123dea673e9SRodney W. Grimes #include <string.h>
124dea673e9SRodney W. Grimes #include <syslog.h>
125dea673e9SRodney W. Grimes #include <unistd.h>
126c1283020SPeter Wemm #include <libutil.h>
127dea673e9SRodney W. Grimes 
128dea673e9SRodney W. Grimes #include "pathnames.h"
129dea673e9SRodney W. Grimes 
130bee39b42SGeoff Rehmet #define	TOOMANY		256		/* don't start more than TOOMANY */
131dea673e9SRodney W. Grimes #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
132dea673e9SRodney W. Grimes #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
133dea673e9SRodney W. Grimes 
134dea673e9SRodney W. Grimes #define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
135dea673e9SRodney W. Grimes 
136dea673e9SRodney W. Grimes 
137dea673e9SRodney W. Grimes int	debug = 0;
138bee39b42SGeoff Rehmet int	log = 0;
139dea673e9SRodney W. Grimes int	nsock, maxsock;
140dea673e9SRodney W. Grimes fd_set	allsock;
141dea673e9SRodney W. Grimes int	options;
142dea673e9SRodney W. Grimes int	timingout;
143dea673e9SRodney W. Grimes int	toomany = TOOMANY;
144dea673e9SRodney W. Grimes struct	servent *sp;
14555b91f3aSGeoff Rehmet struct	rpcent *rpc;
1467356460fSJulian Elischer struct	in_addr bind_address;
147dea673e9SRodney W. Grimes 
148dea673e9SRodney W. Grimes struct	servtab {
149dea673e9SRodney W. Grimes 	char	*se_service;		/* name of service */
150dea673e9SRodney W. Grimes 	int	se_socktype;		/* type of socket to use */
151dea673e9SRodney W. Grimes 	char	*se_proto;		/* protocol used */
152dea673e9SRodney W. Grimes 	short	se_wait;		/* single threaded server */
153dea673e9SRodney W. Grimes 	short	se_checked;		/* looked at during merge */
154dea673e9SRodney W. Grimes 	char	*se_user;		/* user name to run as */
155dea673e9SRodney W. Grimes 	struct	biltin *se_bi;		/* if built-in, description */
156dea673e9SRodney W. Grimes 	char	*se_server;		/* server program */
157dea673e9SRodney W. Grimes #define	MAXARGV 20
158dea673e9SRodney W. Grimes 	char	*se_argv[MAXARGV+1];	/* program arguments */
159dea673e9SRodney W. Grimes 	int	se_fd;			/* open descriptor */
160dea673e9SRodney W. Grimes 	int	se_type;		/* type */
161dea673e9SRodney W. Grimes 	struct	sockaddr_in se_ctrladdr;/* bound address */
16255b91f3aSGeoff Rehmet 	int	se_rpc;			/* ==1 if RPC service */
16355b91f3aSGeoff Rehmet 	int	se_rpc_prog;		/* RPC program number */
16455b91f3aSGeoff Rehmet 	u_int	se_rpc_lowvers;		/* RPC low version */
16555b91f3aSGeoff Rehmet 	u_int	se_rpc_highvers;	/* RPC high version */
166dea673e9SRodney W. Grimes 	int	se_count;		/* number started since se_time */
167dea673e9SRodney W. Grimes 	struct	timeval se_time;	/* start of se_count */
168dea673e9SRodney W. Grimes 	struct	servtab *se_next;
169dea673e9SRodney W. Grimes } *servtab;
170dea673e9SRodney W. Grimes 
171dea673e9SRodney W. Grimes #define NORM_TYPE	0
172dea673e9SRodney W. Grimes #define MUX_TYPE	1
173dea673e9SRodney W. Grimes #define MUXPLUS_TYPE	2
174dea673e9SRodney W. Grimes #define ISMUX(sep)	(((sep)->se_type == MUX_TYPE) || \
175dea673e9SRodney W. Grimes 			 ((sep)->se_type == MUXPLUS_TYPE))
176dea673e9SRodney W. Grimes #define ISMUXPLUS(sep)	((sep)->se_type == MUXPLUS_TYPE)
177dea673e9SRodney W. Grimes 
178dea673e9SRodney W. Grimes 
179dea673e9SRodney W. Grimes void		chargen_dg __P((int, struct servtab *));
180dea673e9SRodney W. Grimes void		chargen_stream __P((int, struct servtab *));
181dea673e9SRodney W. Grimes void		close_sep __P((struct servtab *));
182dea673e9SRodney W. Grimes void		config __P((int));
183dea673e9SRodney W. Grimes void		daytime_dg __P((int, struct servtab *));
184dea673e9SRodney W. Grimes void		daytime_stream __P((int, struct servtab *));
185dea673e9SRodney W. Grimes void		discard_dg __P((int, struct servtab *));
186dea673e9SRodney W. Grimes void		discard_stream __P((int, struct servtab *));
187dea673e9SRodney W. Grimes void		echo_dg __P((int, struct servtab *));
188dea673e9SRodney W. Grimes void		echo_stream __P((int, struct servtab *));
189dea673e9SRodney W. Grimes void		endconfig __P((void));
190dea673e9SRodney W. Grimes struct servtab *enter __P((struct servtab *));
191dea673e9SRodney W. Grimes void		freeconfig __P((struct servtab *));
192dea673e9SRodney W. Grimes struct servtab *getconfigent __P((void));
193dea673e9SRodney W. Grimes void		machtime_dg __P((int, struct servtab *));
194dea673e9SRodney W. Grimes void		machtime_stream __P((int, struct servtab *));
195dea673e9SRodney W. Grimes char	       *newstr __P((char *));
196dea673e9SRodney W. Grimes char	       *nextline __P((FILE *));
197dea673e9SRodney W. Grimes void		print_service __P((char *, struct servtab *));
198dea673e9SRodney W. Grimes void		reapchild __P((int));
199dea673e9SRodney W. Grimes void		retry __P((int));
200dea673e9SRodney W. Grimes int		setconfig __P((void));
201dea673e9SRodney W. Grimes void		setup __P((struct servtab *));
202dea673e9SRodney W. Grimes char	       *sskip __P((char **));
203dea673e9SRodney W. Grimes char	       *skip __P((char **));
204dea673e9SRodney W. Grimes struct servtab *tcpmux __P((int));
205dea673e9SRodney W. Grimes 
20655b91f3aSGeoff Rehmet void		unregisterrpc __P((register struct servtab *sep));
20755b91f3aSGeoff Rehmet 
208dea673e9SRodney W. Grimes struct biltin {
209dea673e9SRodney W. Grimes 	char	*bi_service;		/* internally provided service name */
210dea673e9SRodney W. Grimes 	int	bi_socktype;		/* type of socket supported */
211dea673e9SRodney W. Grimes 	short	bi_fork;		/* 1 if should fork before call */
212dea673e9SRodney W. Grimes 	short	bi_wait;		/* 1 if should wait for child */
213dea673e9SRodney W. Grimes 	void	(*bi_fn)();		/* function which performs it */
214dea673e9SRodney W. Grimes } biltins[] = {
215dea673e9SRodney W. Grimes 	/* Echo received data */
216dea673e9SRodney W. Grimes 	{ "echo",	SOCK_STREAM,	1, 0,	echo_stream },
217dea673e9SRodney W. Grimes 	{ "echo",	SOCK_DGRAM,	0, 0,	echo_dg },
218dea673e9SRodney W. Grimes 
219dea673e9SRodney W. Grimes 	/* Internet /dev/null */
220dea673e9SRodney W. Grimes 	{ "discard",	SOCK_STREAM,	1, 0,	discard_stream },
221dea673e9SRodney W. Grimes 	{ "discard",	SOCK_DGRAM,	0, 0,	discard_dg },
222dea673e9SRodney W. Grimes 
223dea673e9SRodney W. Grimes 	/* Return 32 bit time since 1970 */
224dea673e9SRodney W. Grimes 	{ "time",	SOCK_STREAM,	0, 0,	machtime_stream },
225dea673e9SRodney W. Grimes 	{ "time",	SOCK_DGRAM,	0, 0,	machtime_dg },
226dea673e9SRodney W. Grimes 
227dea673e9SRodney W. Grimes 	/* Return human-readable time */
228dea673e9SRodney W. Grimes 	{ "daytime",	SOCK_STREAM,	0, 0,	daytime_stream },
229dea673e9SRodney W. Grimes 	{ "daytime",	SOCK_DGRAM,	0, 0,	daytime_dg },
230dea673e9SRodney W. Grimes 
231dea673e9SRodney W. Grimes 	/* Familiar character generator */
232dea673e9SRodney W. Grimes 	{ "chargen",	SOCK_STREAM,	1, 0,	chargen_stream },
233dea673e9SRodney W. Grimes 	{ "chargen",	SOCK_DGRAM,	0, 0,	chargen_dg },
234dea673e9SRodney W. Grimes 
235dea673e9SRodney W. Grimes 	{ "tcpmux",	SOCK_STREAM,	1, 0,	(void (*)())tcpmux },
236dea673e9SRodney W. Grimes 
237dea673e9SRodney W. Grimes 	{ NULL }
238dea673e9SRodney W. Grimes };
239dea673e9SRodney W. Grimes 
240dea673e9SRodney W. Grimes #define NUMINT	(sizeof(intab) / sizeof(struct inent))
241dea673e9SRodney W. Grimes char	*CONFIG = _PATH_INETDCONF;
2427356460fSJulian Elischer char	*pid_file = _PATH_INETDPID;
243c1283020SPeter Wemm 
244c1283020SPeter Wemm #ifdef OLD_SETPROCTITLE
245dea673e9SRodney W. Grimes char	**Argv;
246dea673e9SRodney W. Grimes char 	*LastArg;
247c1283020SPeter Wemm #endif
248dea673e9SRodney W. Grimes 
249dea673e9SRodney W. Grimes int
250dea673e9SRodney W. Grimes main(argc, argv, envp)
251dea673e9SRodney W. Grimes 	int argc;
252dea673e9SRodney W. Grimes 	char *argv[], *envp[];
253dea673e9SRodney W. Grimes {
254dea673e9SRodney W. Grimes 	struct servtab *sep;
255dea673e9SRodney W. Grimes 	struct passwd *pwd;
256dea673e9SRodney W. Grimes 	struct sigvec sv;
257dea673e9SRodney W. Grimes 	int tmpint, ch, dofork;
258dea673e9SRodney W. Grimes 	pid_t pid;
259dea673e9SRodney W. Grimes 	char buf[50];
260bee39b42SGeoff Rehmet 	struct  sockaddr_in peer;
261bee39b42SGeoff Rehmet 	int i;
262dea673e9SRodney W. Grimes 
263c1283020SPeter Wemm 
264c1283020SPeter Wemm #ifdef OLD_SETPROCTITLE
265dea673e9SRodney W. Grimes 	Argv = argv;
266dea673e9SRodney W. Grimes 	if (envp == 0 || *envp == 0)
267dea673e9SRodney W. Grimes 		envp = argv;
268dea673e9SRodney W. Grimes 	while (*envp)
269dea673e9SRodney W. Grimes 		envp++;
270dea673e9SRodney W. Grimes 	LastArg = envp[-1] + strlen(envp[-1]);
271c1283020SPeter Wemm #endif
272dea673e9SRodney W. Grimes 
273dea673e9SRodney W. Grimes 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
274dea673e9SRodney W. Grimes 
2757356460fSJulian Elischer 	bind_address.s_addr = htonl(INADDR_ANY);
2767356460fSJulian Elischer 	while ((ch = getopt(argc, argv, "dlR:a:p:")) != EOF)
277dea673e9SRodney W. Grimes 		switch(ch) {
278dea673e9SRodney W. Grimes 		case 'd':
279dea673e9SRodney W. Grimes 			debug = 1;
280dea673e9SRodney W. Grimes 			options |= SO_DEBUG;
281dea673e9SRodney W. Grimes 			break;
282bee39b42SGeoff Rehmet 		case 'l':
283bee39b42SGeoff Rehmet 			log = 1;
284bee39b42SGeoff Rehmet 			break;
285dea673e9SRodney W. Grimes 		case 'R': {	/* invocation rate */
286dea673e9SRodney W. Grimes 			char *p;
287dea673e9SRodney W. Grimes 
288dea673e9SRodney W. Grimes 			tmpint = strtol(optarg, &p, 0);
289dea673e9SRodney W. Grimes 			if (tmpint < 1 || *p)
290dea673e9SRodney W. Grimes 				syslog(LOG_ERR,
291dea673e9SRodney W. Grimes 			         "-R %s: bad value for service invocation rate",
292dea673e9SRodney W. Grimes 					optarg);
293dea673e9SRodney W. Grimes 			else
294dea673e9SRodney W. Grimes 				toomany = tmpint;
295dea673e9SRodney W. Grimes 			break;
296dea673e9SRodney W. Grimes 		}
2977356460fSJulian Elischer 		case 'a':
2987356460fSJulian Elischer 			if (!inet_aton(optarg, &bind_address)) {
2997356460fSJulian Elischer 				syslog(LOG_ERR,
3007356460fSJulian Elischer 			         "-a %s: invalid IP address", optarg);
3017356460fSJulian Elischer 				 exit(1);
3027356460fSJulian Elischer 			}
3037356460fSJulian Elischer 			break;
3047356460fSJulian Elischer 		case 'p':
3057356460fSJulian Elischer 			pid_file = optarg;
3067356460fSJulian Elischer 			break;
307dea673e9SRodney W. Grimes 		case '?':
308dea673e9SRodney W. Grimes 		default:
309dea673e9SRodney W. Grimes 			syslog(LOG_ERR,
3107356460fSJulian Elischer 				"usage: inetd [-dl] [-a address] [-R rate]"
3117356460fSJulian Elischer 				" [-p pidfile] [conf-file]");
312dea673e9SRodney W. Grimes 			exit(1);
313dea673e9SRodney W. Grimes 		}
314dea673e9SRodney W. Grimes 	argc -= optind;
315dea673e9SRodney W. Grimes 	argv += optind;
316dea673e9SRodney W. Grimes 
317dea673e9SRodney W. Grimes 	if (argc > 0)
318dea673e9SRodney W. Grimes 		CONFIG = argv[0];
319dea673e9SRodney W. Grimes 	if (debug == 0) {
3209fe96cbbSGarrett Wollman 		FILE *fp;
32184c60f0dSPeter Wemm 		if (daemon(0, 0) < 0) {
32284c60f0dSPeter Wemm 			syslog(LOG_WARNING, "daemon(0,0) failed: %m");
32384c60f0dSPeter Wemm 		}
32484c60f0dSPeter Wemm 		/*
32584c60f0dSPeter Wemm 		 * In case somebody has started inetd manually, we need to
32684c60f0dSPeter Wemm 		 * clear the logname, so that old servers run as root do not
32784c60f0dSPeter Wemm 		 * get the user's logname..
32884c60f0dSPeter Wemm 		 */
32984c60f0dSPeter Wemm 		if (setlogin("") < 0) {
33084c60f0dSPeter Wemm 			syslog(LOG_WARNING, "cannot clear logname: %m");
33184c60f0dSPeter Wemm 			/* no big deal if it fails.. */
33284c60f0dSPeter Wemm 		}
3339fe96cbbSGarrett Wollman 		pid = getpid();
3347356460fSJulian Elischer 		fp = fopen(pid_file, "w");
3359fe96cbbSGarrett Wollman 		if (fp) {
3369fe96cbbSGarrett Wollman 			fprintf(fp, "%ld\n", (long)pid);
3379fe96cbbSGarrett Wollman 			fclose(fp);
3389fe96cbbSGarrett Wollman 		} else {
3397356460fSJulian Elischer 			syslog(LOG_WARNING, "%s: %m", pid_file);
3409fe96cbbSGarrett Wollman 		}
341dea673e9SRodney W. Grimes 	}
342dea673e9SRodney W. Grimes 	memset(&sv, 0, sizeof(sv));
343dea673e9SRodney W. Grimes 	sv.sv_mask = SIGBLOCK;
344dea673e9SRodney W. Grimes 	sv.sv_handler = retry;
345dea673e9SRodney W. Grimes 	sigvec(SIGALRM, &sv, (struct sigvec *)0);
346dea673e9SRodney W. Grimes 	config(SIGHUP);
347dea673e9SRodney W. Grimes 	sv.sv_handler = config;
348dea673e9SRodney W. Grimes 	sigvec(SIGHUP, &sv, (struct sigvec *)0);
349dea673e9SRodney W. Grimes 	sv.sv_handler = reapchild;
350dea673e9SRodney W. Grimes 	sigvec(SIGCHLD, &sv, (struct sigvec *)0);
351dea673e9SRodney W. Grimes 
352dea673e9SRodney W. Grimes 	{
353dea673e9SRodney W. Grimes 		/* space for daemons to overwrite environment for ps */
354dea673e9SRodney W. Grimes #define	DUMMYSIZE	100
355dea673e9SRodney W. Grimes 		char dummy[DUMMYSIZE];
356dea673e9SRodney W. Grimes 
357dea673e9SRodney W. Grimes 		(void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1);
358dea673e9SRodney W. Grimes 		dummy[DUMMYSIZE - 1] = '\0';
359dea673e9SRodney W. Grimes 		(void)setenv("inetd_dummy", dummy, 1);
360dea673e9SRodney W. Grimes 	}
361dea673e9SRodney W. Grimes 
362dea673e9SRodney W. Grimes 	for (;;) {
363dea673e9SRodney W. Grimes 	    int n, ctrl;
364dea673e9SRodney W. Grimes 	    fd_set readable;
365dea673e9SRodney W. Grimes 
366dea673e9SRodney W. Grimes 	    if (nsock == 0) {
367dea673e9SRodney W. Grimes 		(void) sigblock(SIGBLOCK);
368dea673e9SRodney W. Grimes 		while (nsock == 0)
369dea673e9SRodney W. Grimes 		    sigpause(0L);
370dea673e9SRodney W. Grimes 		(void) sigsetmask(0L);
371dea673e9SRodney W. Grimes 	    }
372dea673e9SRodney W. Grimes 	    readable = allsock;
373dea673e9SRodney W. Grimes 	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
374dea673e9SRodney W. Grimes 		(fd_set *)0, (struct timeval *)0)) <= 0) {
375dea673e9SRodney W. Grimes 		    if (n < 0 && errno != EINTR)
376dea673e9SRodney W. Grimes 			syslog(LOG_WARNING, "select: %m");
377dea673e9SRodney W. Grimes 		    sleep(1);
378dea673e9SRodney W. Grimes 		    continue;
379dea673e9SRodney W. Grimes 	    }
380dea673e9SRodney W. Grimes 	    for (sep = servtab; n && sep; sep = sep->se_next)
381dea673e9SRodney W. Grimes 	        if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
382dea673e9SRodney W. Grimes 		    n--;
383dea673e9SRodney W. Grimes 		    if (debug)
384dea673e9SRodney W. Grimes 			    fprintf(stderr, "someone wants %s\n",
385dea673e9SRodney W. Grimes 				sep->se_service);
386dea673e9SRodney W. Grimes 		    if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
387dea673e9SRodney W. Grimes 			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
388dea673e9SRodney W. Grimes 				(int *)0);
389dea673e9SRodney W. Grimes 			    if (debug)
390dea673e9SRodney W. Grimes 				    fprintf(stderr, "accept, ctrl %d\n", ctrl);
391dea673e9SRodney W. Grimes 			    if (ctrl < 0) {
392dea673e9SRodney W. Grimes 				    if (errno != EINTR)
393dea673e9SRodney W. Grimes 					    syslog(LOG_WARNING,
394dea673e9SRodney W. Grimes 						"accept (for %s): %m",
395dea673e9SRodney W. Grimes 						sep->se_service);
396dea673e9SRodney W. Grimes 				    continue;
397dea673e9SRodney W. Grimes 			    }
398bee39b42SGeoff Rehmet 			    if(log) {
399bee39b42SGeoff Rehmet 				i = sizeof peer;
400bee39b42SGeoff Rehmet 				if(getpeername(ctrl, (struct sockaddr *)
401bee39b42SGeoff Rehmet 						&peer, &i)) {
402bee39b42SGeoff Rehmet 					syslog(LOG_WARNING,
403bee39b42SGeoff Rehmet 						"getpeername(for %s): %m",
404bee39b42SGeoff Rehmet 						sep->se_service);
405bee39b42SGeoff Rehmet 					continue;
406bee39b42SGeoff Rehmet 				}
407bee39b42SGeoff Rehmet 				syslog(LOG_INFO,"%s from %s",
408bee39b42SGeoff Rehmet 					sep->se_service,
409bee39b42SGeoff Rehmet 					inet_ntoa(peer.sin_addr));
410bee39b42SGeoff Rehmet 			    }
411dea673e9SRodney W. Grimes 			    /*
412dea673e9SRodney W. Grimes 			     * Call tcpmux to find the real service to exec.
413dea673e9SRodney W. Grimes 			     */
414dea673e9SRodney W. Grimes 			    if (sep->se_bi &&
415dea673e9SRodney W. Grimes 				sep->se_bi->bi_fn == (void (*)()) tcpmux) {
416d3628763SRodney W. Grimes 				    struct servtab *tsep;
417d3628763SRodney W. Grimes 
418d3628763SRodney W. Grimes 				    tsep = tcpmux(ctrl);
419d3628763SRodney W. Grimes 				    if (tsep == NULL) {
420dea673e9SRodney W. Grimes 					    close(ctrl);
421dea673e9SRodney W. Grimes 					    continue;
422dea673e9SRodney W. Grimes 				    }
423d3628763SRodney W. Grimes 				    sep = tsep;
424dea673e9SRodney W. Grimes 			    }
425dea673e9SRodney W. Grimes 		    } else
426dea673e9SRodney W. Grimes 			    ctrl = sep->se_fd;
427dea673e9SRodney W. Grimes 		    (void) sigblock(SIGBLOCK);
428dea673e9SRodney W. Grimes 		    pid = 0;
429dea673e9SRodney W. Grimes 		    dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
430dea673e9SRodney W. Grimes 		    if (dofork) {
431dea673e9SRodney W. Grimes 			    if (sep->se_count++ == 0)
432dea673e9SRodney W. Grimes 				(void)gettimeofday(&sep->se_time,
433dea673e9SRodney W. Grimes 				    (struct timezone *)0);
434dea673e9SRodney W. Grimes 			    else if (sep->se_count >= toomany) {
435dea673e9SRodney W. Grimes 				struct timeval now;
436dea673e9SRodney W. Grimes 
437dea673e9SRodney W. Grimes 				(void)gettimeofday(&now, (struct timezone *)0);
438dea673e9SRodney W. Grimes 				if (now.tv_sec - sep->se_time.tv_sec >
439dea673e9SRodney W. Grimes 				    CNT_INTVL) {
440dea673e9SRodney W. Grimes 					sep->se_time = now;
441dea673e9SRodney W. Grimes 					sep->se_count = 1;
442dea673e9SRodney W. Grimes 				} else {
443dea673e9SRodney W. Grimes 					syslog(LOG_ERR,
444dea673e9SRodney W. Grimes 			"%s/%s server failing (looping), service terminated",
445dea673e9SRodney W. Grimes 					    sep->se_service, sep->se_proto);
446dea673e9SRodney W. Grimes 					close_sep(sep);
447dea673e9SRodney W. Grimes 					sigsetmask(0L);
448dea673e9SRodney W. Grimes 					if (!timingout) {
449dea673e9SRodney W. Grimes 						timingout = 1;
450dea673e9SRodney W. Grimes 						alarm(RETRYTIME);
451dea673e9SRodney W. Grimes 					}
452dea673e9SRodney W. Grimes 					continue;
453dea673e9SRodney W. Grimes 				}
454dea673e9SRodney W. Grimes 			    }
455dea673e9SRodney W. Grimes 			    pid = fork();
456dea673e9SRodney W. Grimes 		    }
457dea673e9SRodney W. Grimes 		    if (pid < 0) {
458dea673e9SRodney W. Grimes 			    syslog(LOG_ERR, "fork: %m");
459dea673e9SRodney W. Grimes 			    if (!sep->se_wait &&
460dea673e9SRodney W. Grimes 				sep->se_socktype == SOCK_STREAM)
461dea673e9SRodney W. Grimes 				    close(ctrl);
462dea673e9SRodney W. Grimes 			    sigsetmask(0L);
463dea673e9SRodney W. Grimes 			    sleep(1);
464dea673e9SRodney W. Grimes 			    continue;
465dea673e9SRodney W. Grimes 		    }
466dea673e9SRodney W. Grimes 		    if (pid && sep->se_wait) {
467dea673e9SRodney W. Grimes 			    sep->se_wait = pid;
468dea673e9SRodney W. Grimes 			    if (sep->se_fd >= 0) {
469dea673e9SRodney W. Grimes 				FD_CLR(sep->se_fd, &allsock);
470dea673e9SRodney W. Grimes 			        nsock--;
471dea673e9SRodney W. Grimes 			    }
472dea673e9SRodney W. Grimes 		    }
473dea673e9SRodney W. Grimes 		    sigsetmask(0L);
474dea673e9SRodney W. Grimes 		    if (pid == 0) {
475dea673e9SRodney W. Grimes 			    if (dofork) {
476dea673e9SRodney W. Grimes 				if (debug)
477dea673e9SRodney W. Grimes 					fprintf(stderr, "+ Closing from %d\n",
478dea673e9SRodney W. Grimes 						maxsock);
479dea673e9SRodney W. Grimes 				for (tmpint = maxsock; tmpint > 2; tmpint--)
480dea673e9SRodney W. Grimes 					if (tmpint != ctrl)
481dea673e9SRodney W. Grimes 						close(tmpint);
482dea673e9SRodney W. Grimes 			    }
483dea673e9SRodney W. Grimes 			    if (sep->se_bi)
484dea673e9SRodney W. Grimes 				(*sep->se_bi->bi_fn)(ctrl, sep);
485dea673e9SRodney W. Grimes 			    else {
486dea673e9SRodney W. Grimes 				if (debug)
487dea673e9SRodney W. Grimes 					fprintf(stderr, "%d execl %s\n",
488dea673e9SRodney W. Grimes 					    getpid(), sep->se_server);
489dea673e9SRodney W. Grimes 				dup2(ctrl, 0);
490dea673e9SRodney W. Grimes 				close(ctrl);
491dea673e9SRodney W. Grimes 				dup2(0, 1);
492dea673e9SRodney W. Grimes 				dup2(0, 2);
493dea673e9SRodney W. Grimes 				if ((pwd = getpwnam(sep->se_user)) == NULL) {
494dea673e9SRodney W. Grimes 					syslog(LOG_ERR,
495dea673e9SRodney W. Grimes 					    "%s/%s: %s: No such user",
496dea673e9SRodney W. Grimes 						sep->se_service, sep->se_proto,
497dea673e9SRodney W. Grimes 						sep->se_user);
498dea673e9SRodney W. Grimes 					if (sep->se_socktype != SOCK_STREAM)
499dea673e9SRodney W. Grimes 						recv(0, buf, sizeof (buf), 0);
500dea673e9SRodney W. Grimes 					_exit(1);
501dea673e9SRodney W. Grimes 				}
50284c60f0dSPeter Wemm 				if (setsid() < 0) {
50384c60f0dSPeter Wemm 					syslog(LOG_ERR,
50484c60f0dSPeter Wemm 						"%s: can't setsid(): %m",
50584c60f0dSPeter Wemm 						 sep->se_service);
50684c60f0dSPeter Wemm 					/* _exit(1); not fatal yet */
50784c60f0dSPeter Wemm 				}
508dea673e9SRodney W. Grimes 				if (pwd->pw_uid) {
50984c60f0dSPeter Wemm 					if (setlogin(sep->se_user) < 0) {
51084c60f0dSPeter Wemm 						syslog(LOG_ERR,
51184c60f0dSPeter Wemm 						 "%s: can't setlogin(%s): %m",
51284c60f0dSPeter Wemm 						 sep->se_service, sep->se_user);
51384c60f0dSPeter Wemm 						/* _exit(1); not fatal yet */
51484c60f0dSPeter Wemm 					}
515dea673e9SRodney W. Grimes 					if (setgid(pwd->pw_gid) < 0) {
516dea673e9SRodney W. Grimes 						syslog(LOG_ERR,
517dea673e9SRodney W. Grimes 						  "%s: can't set gid %d: %m",
518dea673e9SRodney W. Grimes 						  sep->se_service, pwd->pw_gid);
519dea673e9SRodney W. Grimes 						_exit(1);
520dea673e9SRodney W. Grimes 					}
521dea673e9SRodney W. Grimes 					(void) initgroups(pwd->pw_name,
522dea673e9SRodney W. Grimes 							pwd->pw_gid);
523dea673e9SRodney W. Grimes 					if (setuid(pwd->pw_uid) < 0) {
524dea673e9SRodney W. Grimes 						syslog(LOG_ERR,
525dea673e9SRodney W. Grimes 						  "%s: can't set uid %d: %m",
526dea673e9SRodney W. Grimes 						  sep->se_service, pwd->pw_uid);
527dea673e9SRodney W. Grimes 						_exit(1);
528dea673e9SRodney W. Grimes 					}
529dea673e9SRodney W. Grimes 				}
530dea673e9SRodney W. Grimes 				execv(sep->se_server, sep->se_argv);
531dea673e9SRodney W. Grimes 				if (sep->se_socktype != SOCK_STREAM)
532dea673e9SRodney W. Grimes 					recv(0, buf, sizeof (buf), 0);
533dea673e9SRodney W. Grimes 				syslog(LOG_ERR,
534dea673e9SRodney W. Grimes 				    "cannot execute %s: %m", sep->se_server);
535dea673e9SRodney W. Grimes 				_exit(1);
536dea673e9SRodney W. Grimes 			    }
537dea673e9SRodney W. Grimes 		    }
538dea673e9SRodney W. Grimes 		    if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
539dea673e9SRodney W. Grimes 			    close(ctrl);
540dea673e9SRodney W. Grimes 		}
541dea673e9SRodney W. Grimes 	}
542dea673e9SRodney W. Grimes }
543dea673e9SRodney W. Grimes 
544dea673e9SRodney W. Grimes void
545dea673e9SRodney W. Grimes reapchild(signo)
546dea673e9SRodney W. Grimes 	int signo;
547dea673e9SRodney W. Grimes {
548dea673e9SRodney W. Grimes 	int status;
549dea673e9SRodney W. Grimes 	pid_t pid;
550dea673e9SRodney W. Grimes 	struct servtab *sep;
551dea673e9SRodney W. Grimes 
552dea673e9SRodney W. Grimes 	for (;;) {
553dea673e9SRodney W. Grimes 		pid = wait3(&status, WNOHANG, (struct rusage *)0);
554dea673e9SRodney W. Grimes 		if (pid <= 0)
555dea673e9SRodney W. Grimes 			break;
556dea673e9SRodney W. Grimes 		if (debug)
557dea673e9SRodney W. Grimes 			fprintf(stderr, "%d reaped, status %#x\n",
558dea673e9SRodney W. Grimes 				pid, status);
559dea673e9SRodney W. Grimes 		for (sep = servtab; sep; sep = sep->se_next)
560dea673e9SRodney W. Grimes 			if (sep->se_wait == pid) {
561dea673e9SRodney W. Grimes 				if (status)
562dea673e9SRodney W. Grimes 					syslog(LOG_WARNING,
563dea673e9SRodney W. Grimes 					    "%s: exit status 0x%x",
564dea673e9SRodney W. Grimes 					    sep->se_server, status);
565dea673e9SRodney W. Grimes 				if (debug)
566dea673e9SRodney W. Grimes 					fprintf(stderr, "restored %s, fd %d\n",
567dea673e9SRodney W. Grimes 					    sep->se_service, sep->se_fd);
568dea673e9SRodney W. Grimes 				FD_SET(sep->se_fd, &allsock);
569dea673e9SRodney W. Grimes 				nsock++;
570dea673e9SRodney W. Grimes 				sep->se_wait = 1;
571dea673e9SRodney W. Grimes 			}
572dea673e9SRodney W. Grimes 	}
573dea673e9SRodney W. Grimes }
574dea673e9SRodney W. Grimes 
575dea673e9SRodney W. Grimes void
576dea673e9SRodney W. Grimes config(signo)
577dea673e9SRodney W. Grimes 	int signo;
578dea673e9SRodney W. Grimes {
579dea673e9SRodney W. Grimes 	struct servtab *sep, *cp, **sepp;
580dea673e9SRodney W. Grimes 	struct passwd *pwd;
581dea673e9SRodney W. Grimes 	long omask;
582dea673e9SRodney W. Grimes 
583dea673e9SRodney W. Grimes 	if (!setconfig()) {
584dea673e9SRodney W. Grimes 		syslog(LOG_ERR, "%s: %m", CONFIG);
585dea673e9SRodney W. Grimes 		return;
586dea673e9SRodney W. Grimes 	}
587dea673e9SRodney W. Grimes 	for (sep = servtab; sep; sep = sep->se_next)
588dea673e9SRodney W. Grimes 		sep->se_checked = 0;
589dea673e9SRodney W. Grimes 	while (cp = getconfigent()) {
590dea673e9SRodney W. Grimes 		if ((pwd = getpwnam(cp->se_user)) == NULL) {
591dea673e9SRodney W. Grimes 			syslog(LOG_ERR,
592dea673e9SRodney W. Grimes 				"%s/%s: No such user '%s', service ignored",
593dea673e9SRodney W. Grimes 				cp->se_service, cp->se_proto, cp->se_user);
594dea673e9SRodney W. Grimes 			continue;
595dea673e9SRodney W. Grimes 		}
596dea673e9SRodney W. Grimes 		for (sep = servtab; sep; sep = sep->se_next)
597dea673e9SRodney W. Grimes 			if (strcmp(sep->se_service, cp->se_service) == 0 &&
598dea673e9SRodney W. Grimes 			    strcmp(sep->se_proto, cp->se_proto) == 0)
599dea673e9SRodney W. Grimes 				break;
600dea673e9SRodney W. Grimes 		if (sep != 0) {
601dea673e9SRodney W. Grimes 			int i;
602dea673e9SRodney W. Grimes 
603dea673e9SRodney W. Grimes 			omask = sigblock(SIGBLOCK);
604dea673e9SRodney W. Grimes 			/*
605dea673e9SRodney W. Grimes 			 * sep->se_wait may be holding the pid of a daemon
606dea673e9SRodney W. Grimes 			 * that we're waiting for.  If so, don't overwrite
607dea673e9SRodney W. Grimes 			 * it unless the config file explicitly says don't
608dea673e9SRodney W. Grimes 			 * wait.
609dea673e9SRodney W. Grimes 			 */
610dea673e9SRodney W. Grimes 			if (cp->se_bi == 0 &&
611dea673e9SRodney W. Grimes 			    (sep->se_wait == 1 || cp->se_wait == 0))
612dea673e9SRodney W. Grimes 				sep->se_wait = cp->se_wait;
613dea673e9SRodney W. Grimes #define SWAP(a, b) { char *c = a; a = b; b = c; }
614dea673e9SRodney W. Grimes 			if (cp->se_user)
615dea673e9SRodney W. Grimes 				SWAP(sep->se_user, cp->se_user);
616dea673e9SRodney W. Grimes 			if (cp->se_server)
617dea673e9SRodney W. Grimes 				SWAP(sep->se_server, cp->se_server);
618dea673e9SRodney W. Grimes 			for (i = 0; i < MAXARGV; i++)
619dea673e9SRodney W. Grimes 				SWAP(sep->se_argv[i], cp->se_argv[i]);
620dea673e9SRodney W. Grimes 			sigsetmask(omask);
621dea673e9SRodney W. Grimes 			freeconfig(cp);
622dea673e9SRodney W. Grimes 			if (debug)
623dea673e9SRodney W. Grimes 				print_service("REDO", sep);
624dea673e9SRodney W. Grimes 		} else {
625dea673e9SRodney W. Grimes 			sep = enter(cp);
626dea673e9SRodney W. Grimes 			if (debug)
627dea673e9SRodney W. Grimes 				print_service("ADD ", sep);
628dea673e9SRodney W. Grimes 		}
629dea673e9SRodney W. Grimes 		sep->se_checked = 1;
630dea673e9SRodney W. Grimes 		if (ISMUX(sep)) {
631dea673e9SRodney W. Grimes 			sep->se_fd = -1;
632dea673e9SRodney W. Grimes 			continue;
633dea673e9SRodney W. Grimes 		}
63455b91f3aSGeoff Rehmet 		if (!sep->se_rpc) {
635dea673e9SRodney W. Grimes 			sp = getservbyname(sep->se_service, sep->se_proto);
636dea673e9SRodney W. Grimes 			if (sp == 0) {
637dea673e9SRodney W. Grimes 				syslog(LOG_ERR, "%s/%s: unknown service",
638dea673e9SRodney W. Grimes 			    	sep->se_service, sep->se_proto);
639dea673e9SRodney W. Grimes 				sep->se_checked = 0;
640dea673e9SRodney W. Grimes 				continue;
641dea673e9SRodney W. Grimes 			}
642dea673e9SRodney W. Grimes 			if (sp->s_port != sep->se_ctrladdr.sin_port) {
643dea673e9SRodney W. Grimes 				sep->se_ctrladdr.sin_family = AF_INET;
644dea673e9SRodney W. Grimes 				sep->se_ctrladdr.sin_port = sp->s_port;
645dea673e9SRodney W. Grimes 				if (sep->se_fd >= 0)
646dea673e9SRodney W. Grimes 					close_sep(sep);
647dea673e9SRodney W. Grimes 			}
64855b91f3aSGeoff Rehmet 		} else {
64955b91f3aSGeoff Rehmet 			rpc = getrpcbyname(sep->se_service);
65055b91f3aSGeoff Rehmet 			if (rpc == 0) {
65155b91f3aSGeoff Rehmet 				syslog(LOG_ERR, "%s/%s unknown RPC service.",
65255b91f3aSGeoff Rehmet 					sep->se_service, sep->se_proto);
65355b91f3aSGeoff Rehmet 				if (sep->se_fd != -1)
65455b91f3aSGeoff Rehmet 					(void) close(sep->se_fd);
65555b91f3aSGeoff Rehmet 				sep->se_fd = -1;
65655b91f3aSGeoff Rehmet 					continue;
65755b91f3aSGeoff Rehmet 			}
65855b91f3aSGeoff Rehmet 			if (rpc->r_number != sep->se_rpc_prog) {
65955b91f3aSGeoff Rehmet 				if (sep->se_rpc_prog)
66055b91f3aSGeoff Rehmet 					unregisterrpc(sep);
66155b91f3aSGeoff Rehmet 				sep->se_rpc_prog = rpc->r_number;
66255b91f3aSGeoff Rehmet 				if (sep->se_fd != -1)
66355b91f3aSGeoff Rehmet 					(void) close(sep->se_fd);
66455b91f3aSGeoff Rehmet 				sep->se_fd = -1;
66555b91f3aSGeoff Rehmet 			}
66655b91f3aSGeoff Rehmet 		}
667dea673e9SRodney W. Grimes 		if (sep->se_fd == -1)
668dea673e9SRodney W. Grimes 			setup(sep);
669dea673e9SRodney W. Grimes 	}
670dea673e9SRodney W. Grimes 	endconfig();
671dea673e9SRodney W. Grimes 	/*
672dea673e9SRodney W. Grimes 	 * Purge anything not looked at above.
673dea673e9SRodney W. Grimes 	 */
674dea673e9SRodney W. Grimes 	omask = sigblock(SIGBLOCK);
675dea673e9SRodney W. Grimes 	sepp = &servtab;
676dea673e9SRodney W. Grimes 	while (sep = *sepp) {
677dea673e9SRodney W. Grimes 		if (sep->se_checked) {
678dea673e9SRodney W. Grimes 			sepp = &sep->se_next;
679dea673e9SRodney W. Grimes 			continue;
680dea673e9SRodney W. Grimes 		}
681dea673e9SRodney W. Grimes 		*sepp = sep->se_next;
682dea673e9SRodney W. Grimes 		if (sep->se_fd >= 0)
683dea673e9SRodney W. Grimes 			close_sep(sep);
684dea673e9SRodney W. Grimes 		if (debug)
685dea673e9SRodney W. Grimes 			print_service("FREE", sep);
68655b91f3aSGeoff Rehmet 		if (sep->se_rpc && sep->se_rpc_prog > 0)
68755b91f3aSGeoff Rehmet 			unregisterrpc(sep);
688dea673e9SRodney W. Grimes 		freeconfig(sep);
689dea673e9SRodney W. Grimes 		free((char *)sep);
690dea673e9SRodney W. Grimes 	}
691dea673e9SRodney W. Grimes 	(void) sigsetmask(omask);
692dea673e9SRodney W. Grimes }
693dea673e9SRodney W. Grimes 
694dea673e9SRodney W. Grimes void
69555b91f3aSGeoff Rehmet unregisterrpc(sep)
69655b91f3aSGeoff Rehmet 	struct servtab *sep;
69755b91f3aSGeoff Rehmet {
69855b91f3aSGeoff Rehmet         int i;
69955b91f3aSGeoff Rehmet         struct servtab *sepp;
70055b91f3aSGeoff Rehmet 	long omask;
70155b91f3aSGeoff Rehmet 
70255b91f3aSGeoff Rehmet 	omask = sigblock(SIGBLOCK);
70355b91f3aSGeoff Rehmet         for (sepp = servtab; sepp; sepp = sepp->se_next) {
70455b91f3aSGeoff Rehmet                 if (sepp == sep)
70555b91f3aSGeoff Rehmet                         continue;
70655b91f3aSGeoff Rehmet 		if (sep->se_checked == 0 ||
70755b91f3aSGeoff Rehmet                     !sepp->se_rpc ||
70855b91f3aSGeoff Rehmet                     sep->se_rpc_prog != sepp->se_rpc_prog)
70955b91f3aSGeoff Rehmet 			continue;
71055b91f3aSGeoff Rehmet                 return;
71155b91f3aSGeoff Rehmet         }
71255b91f3aSGeoff Rehmet         if (debug)
71355b91f3aSGeoff Rehmet                 print_service("UNREG", sep);
71455b91f3aSGeoff Rehmet         for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
71555b91f3aSGeoff Rehmet                 pmap_unset(sep->se_rpc_prog, i);
71655b91f3aSGeoff Rehmet         if (sep->se_fd != -1)
71755b91f3aSGeoff Rehmet                 (void) close(sep->se_fd);
71855b91f3aSGeoff Rehmet         sep->se_fd = -1;
71955b91f3aSGeoff Rehmet 	(void) sigsetmask(omask);
72055b91f3aSGeoff Rehmet }
72155b91f3aSGeoff Rehmet 
72255b91f3aSGeoff Rehmet void
723dea673e9SRodney W. Grimes retry(signo)
724dea673e9SRodney W. Grimes 	int signo;
725dea673e9SRodney W. Grimes {
726dea673e9SRodney W. Grimes 	struct servtab *sep;
727dea673e9SRodney W. Grimes 
728dea673e9SRodney W. Grimes 	timingout = 0;
729dea673e9SRodney W. Grimes 	for (sep = servtab; sep; sep = sep->se_next)
730dea673e9SRodney W. Grimes 		if (sep->se_fd == -1)
731dea673e9SRodney W. Grimes 			setup(sep);
732dea673e9SRodney W. Grimes }
733dea673e9SRodney W. Grimes 
734dea673e9SRodney W. Grimes void
735dea673e9SRodney W. Grimes setup(sep)
736dea673e9SRodney W. Grimes 	struct servtab *sep;
737dea673e9SRodney W. Grimes {
738dea673e9SRodney W. Grimes 	int on = 1;
739dea673e9SRodney W. Grimes 
740dea673e9SRodney W. Grimes 	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
741dea673e9SRodney W. Grimes 		if (debug)
742dea673e9SRodney W. Grimes 			fprintf(stderr, "socket failed on %s/%s: %s\n",
743dea673e9SRodney W. Grimes 				sep->se_service, sep->se_proto,
744dea673e9SRodney W. Grimes 				strerror(errno));
745dea673e9SRodney W. Grimes 		syslog(LOG_ERR, "%s/%s: socket: %m",
746dea673e9SRodney W. Grimes 		    sep->se_service, sep->se_proto);
747dea673e9SRodney W. Grimes 		return;
748dea673e9SRodney W. Grimes 	}
749dea673e9SRodney W. Grimes #define	turnon(fd, opt) \
750dea673e9SRodney W. Grimes setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
751dea673e9SRodney W. Grimes 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
752dea673e9SRodney W. Grimes 	    turnon(sep->se_fd, SO_DEBUG) < 0)
753dea673e9SRodney W. Grimes 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
754dea673e9SRodney W. Grimes 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
755dea673e9SRodney W. Grimes 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
756e50d7759SGarrett Wollman 	if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
757e50d7759SGarrett Wollman 		syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
758dea673e9SRodney W. Grimes #undef turnon
759dea673e9SRodney W. Grimes 	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
760dea673e9SRodney W. Grimes 	    sizeof (sep->se_ctrladdr)) < 0) {
761dea673e9SRodney W. Grimes 		if (debug)
762dea673e9SRodney W. Grimes 			fprintf(stderr, "bind failed on %s/%s: %s\n",
763dea673e9SRodney W. Grimes 				sep->se_service, sep->se_proto,
764dea673e9SRodney W. Grimes 				strerror(errno));
765dea673e9SRodney W. Grimes 		syslog(LOG_ERR, "%s/%s: bind: %m",
766dea673e9SRodney W. Grimes 		    sep->se_service, sep->se_proto);
767dea673e9SRodney W. Grimes 		(void) close(sep->se_fd);
768dea673e9SRodney W. Grimes 		sep->se_fd = -1;
769dea673e9SRodney W. Grimes 		if (!timingout) {
770dea673e9SRodney W. Grimes 			timingout = 1;
771dea673e9SRodney W. Grimes 			alarm(RETRYTIME);
772dea673e9SRodney W. Grimes 		}
773dea673e9SRodney W. Grimes 		return;
774dea673e9SRodney W. Grimes 	}
77555b91f3aSGeoff Rehmet         if (sep->se_rpc) {
77655b91f3aSGeoff Rehmet                 int i, len = sizeof(struct sockaddr);
77755b91f3aSGeoff Rehmet 
77855b91f3aSGeoff Rehmet                 if (getsockname(sep->se_fd,
77955b91f3aSGeoff Rehmet 				(struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
78055b91f3aSGeoff Rehmet                         syslog(LOG_ERR, "%s/%s: getsockname: %m",
78155b91f3aSGeoff Rehmet                                sep->se_service, sep->se_proto);
78255b91f3aSGeoff Rehmet                         (void) close(sep->se_fd);
78355b91f3aSGeoff Rehmet                         sep->se_fd = -1;
78455b91f3aSGeoff Rehmet                         return;
78555b91f3aSGeoff Rehmet                 }
78655b91f3aSGeoff Rehmet                 if (debug)
78755b91f3aSGeoff Rehmet                         print_service("REG ", sep);
78855b91f3aSGeoff Rehmet                 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
78955b91f3aSGeoff Rehmet                         pmap_unset(sep->se_rpc_prog, i);
79055b91f3aSGeoff Rehmet                         pmap_set(sep->se_rpc_prog, i,
79155b91f3aSGeoff Rehmet                                  (sep->se_socktype == SOCK_DGRAM)
79255b91f3aSGeoff Rehmet                                  ? IPPROTO_UDP : IPPROTO_TCP,
79355b91f3aSGeoff Rehmet                                  ntohs(sep->se_ctrladdr.sin_port));
79455b91f3aSGeoff Rehmet                 }
79555b91f3aSGeoff Rehmet 
79655b91f3aSGeoff Rehmet         }
797dea673e9SRodney W. Grimes 	if (sep->se_socktype == SOCK_STREAM)
798e2894535SDavid Greenman 		listen(sep->se_fd, 64);
799dea673e9SRodney W. Grimes 	FD_SET(sep->se_fd, &allsock);
800dea673e9SRodney W. Grimes 	nsock++;
801dea673e9SRodney W. Grimes 	if (sep->se_fd > maxsock)
802dea673e9SRodney W. Grimes 		maxsock = sep->se_fd;
803dea673e9SRodney W. Grimes 	if (debug) {
804dea673e9SRodney W. Grimes 		fprintf(stderr, "registered %s on %d\n",
805dea673e9SRodney W. Grimes 			sep->se_server, sep->se_fd);
806dea673e9SRodney W. Grimes 	}
807dea673e9SRodney W. Grimes }
808dea673e9SRodney W. Grimes 
809dea673e9SRodney W. Grimes /*
810dea673e9SRodney W. Grimes  * Finish with a service and its socket.
811dea673e9SRodney W. Grimes  */
812dea673e9SRodney W. Grimes void
813dea673e9SRodney W. Grimes close_sep(sep)
814dea673e9SRodney W. Grimes 	struct servtab *sep;
815dea673e9SRodney W. Grimes {
816dea673e9SRodney W. Grimes 	if (sep->se_fd >= 0) {
817dea673e9SRodney W. Grimes 		nsock--;
818dea673e9SRodney W. Grimes 		FD_CLR(sep->se_fd, &allsock);
819dea673e9SRodney W. Grimes 		(void) close(sep->se_fd);
820dea673e9SRodney W. Grimes 		sep->se_fd = -1;
821dea673e9SRodney W. Grimes 	}
822dea673e9SRodney W. Grimes 	sep->se_count = 0;
823dea673e9SRodney W. Grimes 	/*
824dea673e9SRodney W. Grimes 	 * Don't keep the pid of this running deamon: when reapchild()
825dea673e9SRodney W. Grimes 	 * reaps this pid, it would erroneously increment nsock.
826dea673e9SRodney W. Grimes 	 */
827dea673e9SRodney W. Grimes 	if (sep->se_wait > 1)
828dea673e9SRodney W. Grimes 		sep->se_wait = 1;
829dea673e9SRodney W. Grimes }
830dea673e9SRodney W. Grimes 
831dea673e9SRodney W. Grimes struct servtab *
832dea673e9SRodney W. Grimes enter(cp)
833dea673e9SRodney W. Grimes 	struct servtab *cp;
834dea673e9SRodney W. Grimes {
835dea673e9SRodney W. Grimes 	struct servtab *sep;
836dea673e9SRodney W. Grimes 	long omask;
837dea673e9SRodney W. Grimes 
838dea673e9SRodney W. Grimes 	sep = (struct servtab *)malloc(sizeof (*sep));
839dea673e9SRodney W. Grimes 	if (sep == (struct servtab *)0) {
840dea673e9SRodney W. Grimes 		syslog(LOG_ERR, "Out of memory.");
841dea673e9SRodney W. Grimes 		exit(-1);
842dea673e9SRodney W. Grimes 	}
843dea673e9SRodney W. Grimes 	*sep = *cp;
844dea673e9SRodney W. Grimes 	sep->se_fd = -1;
845dea673e9SRodney W. Grimes 	omask = sigblock(SIGBLOCK);
846dea673e9SRodney W. Grimes 	sep->se_next = servtab;
847dea673e9SRodney W. Grimes 	servtab = sep;
848dea673e9SRodney W. Grimes 	sigsetmask(omask);
849dea673e9SRodney W. Grimes 	return (sep);
850dea673e9SRodney W. Grimes }
851dea673e9SRodney W. Grimes 
852dea673e9SRodney W. Grimes FILE	*fconfig = NULL;
853dea673e9SRodney W. Grimes struct	servtab serv;
854dea673e9SRodney W. Grimes char	line[LINE_MAX];
855dea673e9SRodney W. Grimes 
856dea673e9SRodney W. Grimes int
857dea673e9SRodney W. Grimes setconfig()
858dea673e9SRodney W. Grimes {
859dea673e9SRodney W. Grimes 
860dea673e9SRodney W. Grimes 	if (fconfig != NULL) {
861dea673e9SRodney W. Grimes 		fseek(fconfig, 0L, SEEK_SET);
862dea673e9SRodney W. Grimes 		return (1);
863dea673e9SRodney W. Grimes 	}
864dea673e9SRodney W. Grimes 	fconfig = fopen(CONFIG, "r");
865dea673e9SRodney W. Grimes 	return (fconfig != NULL);
866dea673e9SRodney W. Grimes }
867dea673e9SRodney W. Grimes 
868dea673e9SRodney W. Grimes void
869dea673e9SRodney W. Grimes endconfig()
870dea673e9SRodney W. Grimes {
871dea673e9SRodney W. Grimes 	if (fconfig) {
872dea673e9SRodney W. Grimes 		(void) fclose(fconfig);
873dea673e9SRodney W. Grimes 		fconfig = NULL;
874dea673e9SRodney W. Grimes 	}
875dea673e9SRodney W. Grimes }
876dea673e9SRodney W. Grimes 
877dea673e9SRodney W. Grimes struct servtab *
878dea673e9SRodney W. Grimes getconfigent()
879dea673e9SRodney W. Grimes {
880dea673e9SRodney W. Grimes 	struct servtab *sep = &serv;
881dea673e9SRodney W. Grimes 	int argc;
882dea673e9SRodney W. Grimes 	char *cp, *arg;
88355b91f3aSGeoff Rehmet 	char *versp;
884dea673e9SRodney W. Grimes 	static char TCPMUX_TOKEN[] = "tcpmux/";
885dea673e9SRodney W. Grimes #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
886dea673e9SRodney W. Grimes 
887dea673e9SRodney W. Grimes more:
888dea673e9SRodney W. Grimes 	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
889dea673e9SRodney W. Grimes 		;
890dea673e9SRodney W. Grimes 	if (cp == NULL)
891dea673e9SRodney W. Grimes 		return ((struct servtab *)0);
892dea673e9SRodney W. Grimes 	/*
893dea673e9SRodney W. Grimes 	 * clear the static buffer, since some fields (se_ctrladdr,
894dea673e9SRodney W. Grimes 	 * for example) don't get initialized here.
895dea673e9SRodney W. Grimes 	 */
896dea673e9SRodney W. Grimes 	memset((caddr_t)sep, 0, sizeof *sep);
897dea673e9SRodney W. Grimes 	arg = skip(&cp);
898dea673e9SRodney W. Grimes 	if (cp == NULL) {
899dea673e9SRodney W. Grimes 		/* got an empty line containing just blanks/tabs. */
900dea673e9SRodney W. Grimes 		goto more;
901dea673e9SRodney W. Grimes 	}
902dea673e9SRodney W. Grimes 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
903dea673e9SRodney W. Grimes 		char *c = arg + MUX_LEN;
904dea673e9SRodney W. Grimes 		if (*c == '+') {
905dea673e9SRodney W. Grimes 			sep->se_type = MUXPLUS_TYPE;
906dea673e9SRodney W. Grimes 			c++;
907dea673e9SRodney W. Grimes 		} else
908dea673e9SRodney W. Grimes 			sep->se_type = MUX_TYPE;
909dea673e9SRodney W. Grimes 		sep->se_service = newstr(c);
910dea673e9SRodney W. Grimes 	} else {
911dea673e9SRodney W. Grimes 		sep->se_service = newstr(arg);
912dea673e9SRodney W. Grimes 		sep->se_type = NORM_TYPE;
913dea673e9SRodney W. Grimes 	}
914dea673e9SRodney W. Grimes 	arg = sskip(&cp);
915dea673e9SRodney W. Grimes 	if (strcmp(arg, "stream") == 0)
916dea673e9SRodney W. Grimes 		sep->se_socktype = SOCK_STREAM;
917dea673e9SRodney W. Grimes 	else if (strcmp(arg, "dgram") == 0)
918dea673e9SRodney W. Grimes 		sep->se_socktype = SOCK_DGRAM;
919dea673e9SRodney W. Grimes 	else if (strcmp(arg, "rdm") == 0)
920dea673e9SRodney W. Grimes 		sep->se_socktype = SOCK_RDM;
921dea673e9SRodney W. Grimes 	else if (strcmp(arg, "seqpacket") == 0)
922dea673e9SRodney W. Grimes 		sep->se_socktype = SOCK_SEQPACKET;
923dea673e9SRodney W. Grimes 	else if (strcmp(arg, "raw") == 0)
924dea673e9SRodney W. Grimes 		sep->se_socktype = SOCK_RAW;
925dea673e9SRodney W. Grimes 	else
926dea673e9SRodney W. Grimes 		sep->se_socktype = -1;
927dea673e9SRodney W. Grimes 	sep->se_proto = newstr(sskip(&cp));
92855b91f3aSGeoff Rehmet         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
929d4788da6SJoerg Wunsch                 memmove(sep->se_proto, sep->se_proto + 4,
930d4788da6SJoerg Wunsch                     strlen(sep->se_proto) + 1 - 4);
93155b91f3aSGeoff Rehmet                 sep->se_rpc = 1;
93255b91f3aSGeoff Rehmet                 sep->se_rpc_prog = sep->se_rpc_lowvers =
93355b91f3aSGeoff Rehmet 			sep->se_rpc_lowvers = 0;
93455b91f3aSGeoff Rehmet                 sep->se_ctrladdr.sin_family = AF_INET;
93555b91f3aSGeoff Rehmet                 sep->se_ctrladdr.sin_port = 0;
9367356460fSJulian Elischer                 sep->se_ctrladdr.sin_addr = bind_address;
93755b91f3aSGeoff Rehmet                 if ((versp = rindex(sep->se_service, '/'))) {
93855b91f3aSGeoff Rehmet                         *versp++ = '\0';
93955b91f3aSGeoff Rehmet                         switch (sscanf(versp, "%d-%d",
94055b91f3aSGeoff Rehmet                                        &sep->se_rpc_lowvers,
94155b91f3aSGeoff Rehmet                                        &sep->se_rpc_highvers)) {
94255b91f3aSGeoff Rehmet                         case 2:
94355b91f3aSGeoff Rehmet                                 break;
94455b91f3aSGeoff Rehmet                         case 1:
94555b91f3aSGeoff Rehmet                                 sep->se_rpc_highvers =
94655b91f3aSGeoff Rehmet                                         sep->se_rpc_lowvers;
94755b91f3aSGeoff Rehmet                                 break;
94855b91f3aSGeoff Rehmet                         default:
94955b91f3aSGeoff Rehmet                                 syslog(LOG_ERR,
95055b91f3aSGeoff Rehmet 					"bad RPC version specifier; %s\n",
95155b91f3aSGeoff Rehmet 					sep->se_service);
95255b91f3aSGeoff Rehmet                                 freeconfig(sep);
95355b91f3aSGeoff Rehmet                                 goto more;
95455b91f3aSGeoff Rehmet                         }
95555b91f3aSGeoff Rehmet                 }
95655b91f3aSGeoff Rehmet                 else {
95755b91f3aSGeoff Rehmet                         sep->se_rpc_lowvers =
95855b91f3aSGeoff Rehmet                                 sep->se_rpc_highvers = 1;
95955b91f3aSGeoff Rehmet                 }
96055b91f3aSGeoff Rehmet         }
961dea673e9SRodney W. Grimes 	arg = sskip(&cp);
962dea673e9SRodney W. Grimes 	sep->se_wait = strcmp(arg, "wait") == 0;
963dea673e9SRodney W. Grimes 	if (ISMUX(sep)) {
964dea673e9SRodney W. Grimes 		/*
965dea673e9SRodney W. Grimes 		 * Silently enforce "nowait" for TCPMUX services since
966dea673e9SRodney W. Grimes 		 * they don't have an assigned port to listen on.
967dea673e9SRodney W. Grimes 		 */
968dea673e9SRodney W. Grimes 		sep->se_wait = 0;
969dea673e9SRodney W. Grimes 
970dea673e9SRodney W. Grimes 		if (strcmp(sep->se_proto, "tcp")) {
971dea673e9SRodney W. Grimes 			syslog(LOG_ERR,
972dea673e9SRodney W. Grimes 				"%s: bad protocol for tcpmux service %s",
973dea673e9SRodney W. Grimes 				CONFIG, sep->se_service);
974dea673e9SRodney W. Grimes 			goto more;
975dea673e9SRodney W. Grimes 		}
976dea673e9SRodney W. Grimes 		if (sep->se_socktype != SOCK_STREAM) {
977dea673e9SRodney W. Grimes 			syslog(LOG_ERR,
978dea673e9SRodney W. Grimes 				"%s: bad socket type for tcpmux service %s",
979dea673e9SRodney W. Grimes 				CONFIG, sep->se_service);
980dea673e9SRodney W. Grimes 			goto more;
981dea673e9SRodney W. Grimes 		}
982dea673e9SRodney W. Grimes 	}
983dea673e9SRodney W. Grimes 	sep->se_user = newstr(sskip(&cp));
984dea673e9SRodney W. Grimes 	sep->se_server = newstr(sskip(&cp));
985dea673e9SRodney W. Grimes 	if (strcmp(sep->se_server, "internal") == 0) {
986dea673e9SRodney W. Grimes 		struct biltin *bi;
987dea673e9SRodney W. Grimes 
988dea673e9SRodney W. Grimes 		for (bi = biltins; bi->bi_service; bi++)
989dea673e9SRodney W. Grimes 			if (bi->bi_socktype == sep->se_socktype &&
990dea673e9SRodney W. Grimes 			    strcmp(bi->bi_service, sep->se_service) == 0)
991dea673e9SRodney W. Grimes 				break;
992dea673e9SRodney W. Grimes 		if (bi->bi_service == 0) {
993dea673e9SRodney W. Grimes 			syslog(LOG_ERR, "internal service %s unknown",
994dea673e9SRodney W. Grimes 				sep->se_service);
995dea673e9SRodney W. Grimes 			goto more;
996dea673e9SRodney W. Grimes 		}
997dea673e9SRodney W. Grimes 		sep->se_bi = bi;
998dea673e9SRodney W. Grimes 		sep->se_wait = bi->bi_wait;
999dea673e9SRodney W. Grimes 	} else
1000dea673e9SRodney W. Grimes 		sep->se_bi = NULL;
1001dea673e9SRodney W. Grimes 	argc = 0;
1002dea673e9SRodney W. Grimes 	for (arg = skip(&cp); cp; arg = skip(&cp))
1003dea673e9SRodney W. Grimes 		if (argc < MAXARGV)
1004dea673e9SRodney W. Grimes 			sep->se_argv[argc++] = newstr(arg);
1005dea673e9SRodney W. Grimes 	while (argc <= MAXARGV)
1006dea673e9SRodney W. Grimes 		sep->se_argv[argc++] = NULL;
1007dea673e9SRodney W. Grimes 	return (sep);
1008dea673e9SRodney W. Grimes }
1009dea673e9SRodney W. Grimes 
1010dea673e9SRodney W. Grimes void
1011dea673e9SRodney W. Grimes freeconfig(cp)
1012dea673e9SRodney W. Grimes 	struct servtab *cp;
1013dea673e9SRodney W. Grimes {
1014dea673e9SRodney W. Grimes 	int i;
1015dea673e9SRodney W. Grimes 
1016dea673e9SRodney W. Grimes 	if (cp->se_service)
1017dea673e9SRodney W. Grimes 		free(cp->se_service);
1018dea673e9SRodney W. Grimes 	if (cp->se_proto)
1019dea673e9SRodney W. Grimes 		free(cp->se_proto);
1020dea673e9SRodney W. Grimes 	if (cp->se_user)
1021dea673e9SRodney W. Grimes 		free(cp->se_user);
1022dea673e9SRodney W. Grimes 	if (cp->se_server)
1023dea673e9SRodney W. Grimes 		free(cp->se_server);
1024dea673e9SRodney W. Grimes 	for (i = 0; i < MAXARGV; i++)
1025dea673e9SRodney W. Grimes 		if (cp->se_argv[i])
1026dea673e9SRodney W. Grimes 			free(cp->se_argv[i]);
1027dea673e9SRodney W. Grimes }
1028dea673e9SRodney W. Grimes 
1029dea673e9SRodney W. Grimes 
1030dea673e9SRodney W. Grimes /*
1031dea673e9SRodney W. Grimes  * Safe skip - if skip returns null, log a syntax error in the
1032dea673e9SRodney W. Grimes  * configuration file and exit.
1033dea673e9SRodney W. Grimes  */
1034dea673e9SRodney W. Grimes char *
1035dea673e9SRodney W. Grimes sskip(cpp)
1036dea673e9SRodney W. Grimes 	char **cpp;
1037dea673e9SRodney W. Grimes {
1038dea673e9SRodney W. Grimes 	char *cp;
1039dea673e9SRodney W. Grimes 
1040dea673e9SRodney W. Grimes 	cp = skip(cpp);
1041dea673e9SRodney W. Grimes 	if (cp == NULL) {
1042dea673e9SRodney W. Grimes 		syslog(LOG_ERR, "%s: syntax error", CONFIG);
1043dea673e9SRodney W. Grimes 		exit(-1);
1044dea673e9SRodney W. Grimes 	}
1045dea673e9SRodney W. Grimes 	return (cp);
1046dea673e9SRodney W. Grimes }
1047dea673e9SRodney W. Grimes 
1048dea673e9SRodney W. Grimes char *
1049dea673e9SRodney W. Grimes skip(cpp)
1050dea673e9SRodney W. Grimes 	char **cpp;
1051dea673e9SRodney W. Grimes {
1052dea673e9SRodney W. Grimes 	char *cp = *cpp;
1053dea673e9SRodney W. Grimes 	char *start;
105432b505b2SAdam David 	char quote = '\0';
1055dea673e9SRodney W. Grimes 
1056dea673e9SRodney W. Grimes again:
1057dea673e9SRodney W. Grimes 	while (*cp == ' ' || *cp == '\t')
1058dea673e9SRodney W. Grimes 		cp++;
1059dea673e9SRodney W. Grimes 	if (*cp == '\0') {
1060dea673e9SRodney W. Grimes 		int c;
1061dea673e9SRodney W. Grimes 
1062dea673e9SRodney W. Grimes 		c = getc(fconfig);
1063dea673e9SRodney W. Grimes 		(void) ungetc(c, fconfig);
1064dea673e9SRodney W. Grimes 		if (c == ' ' || c == '\t')
1065dea673e9SRodney W. Grimes 			if (cp = nextline(fconfig))
1066dea673e9SRodney W. Grimes 				goto again;
1067dea673e9SRodney W. Grimes 		*cpp = (char *)0;
1068dea673e9SRodney W. Grimes 		return ((char *)0);
1069dea673e9SRodney W. Grimes 	}
107032b505b2SAdam David 	if (*cp == '"' || *cp == '\'')
107132b505b2SAdam David 		quote = *cp++;
1072dea673e9SRodney W. Grimes 	start = cp;
107332b505b2SAdam David 	if (quote)
107432b505b2SAdam David 		while (*cp && *cp != quote)
107532b505b2SAdam David 			cp++;
107632b505b2SAdam David 	else
1077dea673e9SRodney W. Grimes 		while (*cp && *cp != ' ' && *cp != '\t')
1078dea673e9SRodney W. Grimes 			cp++;
1079dea673e9SRodney W. Grimes 	if (*cp != '\0')
1080dea673e9SRodney W. Grimes 		*cp++ = '\0';
1081dea673e9SRodney W. Grimes 	*cpp = cp;
1082dea673e9SRodney W. Grimes 	return (start);
1083dea673e9SRodney W. Grimes }
1084dea673e9SRodney W. Grimes 
1085dea673e9SRodney W. Grimes char *
1086dea673e9SRodney W. Grimes nextline(fd)
1087dea673e9SRodney W. Grimes 	FILE *fd;
1088dea673e9SRodney W. Grimes {
1089dea673e9SRodney W. Grimes 	char *cp;
1090dea673e9SRodney W. Grimes 
1091dea673e9SRodney W. Grimes 	if (fgets(line, sizeof (line), fd) == NULL)
1092dea673e9SRodney W. Grimes 		return ((char *)0);
1093dea673e9SRodney W. Grimes 	cp = strchr(line, '\n');
1094dea673e9SRodney W. Grimes 	if (cp)
1095dea673e9SRodney W. Grimes 		*cp = '\0';
1096dea673e9SRodney W. Grimes 	return (line);
1097dea673e9SRodney W. Grimes }
1098dea673e9SRodney W. Grimes 
1099dea673e9SRodney W. Grimes char *
1100dea673e9SRodney W. Grimes newstr(cp)
1101dea673e9SRodney W. Grimes 	char *cp;
1102dea673e9SRodney W. Grimes {
1103dea673e9SRodney W. Grimes 	if (cp = strdup(cp ? cp : ""))
1104dea673e9SRodney W. Grimes 		return (cp);
1105dea673e9SRodney W. Grimes 	syslog(LOG_ERR, "strdup: %m");
1106dea673e9SRodney W. Grimes 	exit(-1);
1107dea673e9SRodney W. Grimes }
1108dea673e9SRodney W. Grimes 
1109c1283020SPeter Wemm #ifdef OLD_SETPROCTITLE
1110dea673e9SRodney W. Grimes void
1111c1283020SPeter Wemm inetd_setproctitle(a, s)
1112dea673e9SRodney W. Grimes 	char *a;
1113dea673e9SRodney W. Grimes 	int s;
1114dea673e9SRodney W. Grimes {
1115dea673e9SRodney W. Grimes 	int size;
1116dea673e9SRodney W. Grimes 	char *cp;
1117dea673e9SRodney W. Grimes 	struct sockaddr_in sin;
1118dea673e9SRodney W. Grimes 	char buf[80];
1119dea673e9SRodney W. Grimes 
1120dea673e9SRodney W. Grimes 	cp = Argv[0];
1121dea673e9SRodney W. Grimes 	size = sizeof(sin);
1122dea673e9SRodney W. Grimes 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1123dea673e9SRodney W. Grimes 		(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
1124dea673e9SRodney W. Grimes 	else
1125dea673e9SRodney W. Grimes 		(void) sprintf(buf, "-%s", a);
1126dea673e9SRodney W. Grimes 	strncpy(cp, buf, LastArg - cp);
1127dea673e9SRodney W. Grimes 	cp += strlen(cp);
1128dea673e9SRodney W. Grimes 	while (cp < LastArg)
1129dea673e9SRodney W. Grimes 		*cp++ = ' ';
1130dea673e9SRodney W. Grimes }
1131c1283020SPeter Wemm #else
1132c1283020SPeter Wemm void
1133c1283020SPeter Wemm inetd_setproctitle(a, s)
1134c1283020SPeter Wemm 	char *a;
1135c1283020SPeter Wemm 	int s;
1136c1283020SPeter Wemm {
1137c1283020SPeter Wemm 	int size;
1138c1283020SPeter Wemm 	struct sockaddr_in sin;
1139c1283020SPeter Wemm 	char buf[80];
1140c1283020SPeter Wemm 
1141c1283020SPeter Wemm 	size = sizeof(sin);
1142c1283020SPeter Wemm 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1143c1283020SPeter Wemm 		(void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr));
1144c1283020SPeter Wemm 	else
1145c1283020SPeter Wemm 		(void) sprintf(buf, "%s", a);
1146c1283020SPeter Wemm 	setproctitle("%s", buf);
1147c1283020SPeter Wemm }
1148c1283020SPeter Wemm #endif
1149c1283020SPeter Wemm 
1150dea673e9SRodney W. Grimes 
1151dea673e9SRodney W. Grimes /*
1152dea673e9SRodney W. Grimes  * Internet services provided internally by inetd:
1153dea673e9SRodney W. Grimes  */
1154dea673e9SRodney W. Grimes #define	BUFSIZE	8192
1155dea673e9SRodney W. Grimes 
1156dea673e9SRodney W. Grimes /* ARGSUSED */
1157dea673e9SRodney W. Grimes void
1158dea673e9SRodney W. Grimes echo_stream(s, sep)		/* Echo service -- echo data back */
1159dea673e9SRodney W. Grimes 	int s;
1160dea673e9SRodney W. Grimes 	struct servtab *sep;
1161dea673e9SRodney W. Grimes {
1162dea673e9SRodney W. Grimes 	char buffer[BUFSIZE];
1163dea673e9SRodney W. Grimes 	int i;
1164dea673e9SRodney W. Grimes 
1165c1283020SPeter Wemm 	inetd_setproctitle(sep->se_service, s);
1166dea673e9SRodney W. Grimes 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1167dea673e9SRodney W. Grimes 	    write(s, buffer, i) > 0)
1168dea673e9SRodney W. Grimes 		;
1169dea673e9SRodney W. Grimes 	exit(0);
1170dea673e9SRodney W. Grimes }
1171dea673e9SRodney W. Grimes 
117271704f34SGarrett Wollman int check_loop(sin, sep)
117371704f34SGarrett Wollman 	struct sockaddr_in *sin;
117471704f34SGarrett Wollman 	struct servtab *sep;
117571704f34SGarrett Wollman {
117671704f34SGarrett Wollman 	struct servtab *se2;
117771704f34SGarrett Wollman 
117871704f34SGarrett Wollman 	for (se2 = servtab; se2; se2 = se2->se_next) {
117971704f34SGarrett Wollman 		if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
118071704f34SGarrett Wollman 			continue;
118171704f34SGarrett Wollman 
118271704f34SGarrett Wollman 		if (sin->sin_port == se2->se_ctrladdr.sin_port) {
118371704f34SGarrett Wollman 			syslog(LOG_WARNING,
118471704f34SGarrett Wollman 			       "%s/%s:%s/%s loop request REFUSED from %s",
118571704f34SGarrett Wollman 			       sep->se_service, sep->se_proto,
118671704f34SGarrett Wollman 			       se2->se_service, se2->se_proto,
118771704f34SGarrett Wollman 			       inet_ntoa(sin->sin_addr));
118871704f34SGarrett Wollman 			return 1;
118971704f34SGarrett Wollman 		}
119071704f34SGarrett Wollman 	}
119171704f34SGarrett Wollman 	return 0;
119271704f34SGarrett Wollman }
119371704f34SGarrett Wollman 
1194dea673e9SRodney W. Grimes /* ARGSUSED */
1195dea673e9SRodney W. Grimes void
1196dea673e9SRodney W. Grimes echo_dg(s, sep)			/* Echo service -- echo data back */
1197dea673e9SRodney W. Grimes 	int s;
1198dea673e9SRodney W. Grimes 	struct servtab *sep;
1199dea673e9SRodney W. Grimes {
1200dea673e9SRodney W. Grimes 	char buffer[BUFSIZE];
1201dea673e9SRodney W. Grimes 	int i, size;
120271704f34SGarrett Wollman 	struct sockaddr_in sin;
1203dea673e9SRodney W. Grimes 
120471704f34SGarrett Wollman 	size = sizeof(sin);
120571704f34SGarrett Wollman 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
120671704f34SGarrett Wollman 			  (struct sockaddr *)&sin, &size)) < 0)
1207dea673e9SRodney W. Grimes 		return;
120871704f34SGarrett Wollman 
120971704f34SGarrett Wollman 	if (check_loop(&sin, sep))
121071704f34SGarrett Wollman 		return;
121171704f34SGarrett Wollman 
121271704f34SGarrett Wollman 	(void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin,
121371704f34SGarrett Wollman 		      sizeof(sin));
1214dea673e9SRodney W. Grimes }
1215dea673e9SRodney W. Grimes 
1216dea673e9SRodney W. Grimes /* ARGSUSED */
1217dea673e9SRodney W. Grimes void
1218dea673e9SRodney W. Grimes discard_stream(s, sep)		/* Discard service -- ignore data */
1219dea673e9SRodney W. Grimes 	int s;
1220dea673e9SRodney W. Grimes 	struct servtab *sep;
1221dea673e9SRodney W. Grimes {
1222dea673e9SRodney W. Grimes 	int ret;
1223dea673e9SRodney W. Grimes 	char buffer[BUFSIZE];
1224dea673e9SRodney W. Grimes 
1225c1283020SPeter Wemm 	inetd_setproctitle(sep->se_service, s);
1226dea673e9SRodney W. Grimes 	while (1) {
1227dea673e9SRodney W. Grimes 		while ((ret = read(s, buffer, sizeof(buffer))) > 0)
1228dea673e9SRodney W. Grimes 			;
1229dea673e9SRodney W. Grimes 		if (ret == 0 || errno != EINTR)
1230dea673e9SRodney W. Grimes 			break;
1231dea673e9SRodney W. Grimes 	}
1232dea673e9SRodney W. Grimes 	exit(0);
1233dea673e9SRodney W. Grimes }
1234dea673e9SRodney W. Grimes 
1235dea673e9SRodney W. Grimes /* ARGSUSED */
1236dea673e9SRodney W. Grimes void
1237dea673e9SRodney W. Grimes discard_dg(s, sep)		/* Discard service -- ignore data */
1238dea673e9SRodney W. Grimes 	int s;
1239dea673e9SRodney W. Grimes 	struct servtab *sep;
1240dea673e9SRodney W. Grimes {
1241dea673e9SRodney W. Grimes 	char buffer[BUFSIZE];
1242dea673e9SRodney W. Grimes 
1243dea673e9SRodney W. Grimes 	(void) read(s, buffer, sizeof(buffer));
1244dea673e9SRodney W. Grimes }
1245dea673e9SRodney W. Grimes 
1246dea673e9SRodney W. Grimes #include <ctype.h>
1247dea673e9SRodney W. Grimes #define LINESIZ 72
1248dea673e9SRodney W. Grimes char ring[128];
1249dea673e9SRodney W. Grimes char *endring;
1250dea673e9SRodney W. Grimes 
1251dea673e9SRodney W. Grimes void
1252dea673e9SRodney W. Grimes initring()
1253dea673e9SRodney W. Grimes {
1254dea673e9SRodney W. Grimes 	int i;
1255dea673e9SRodney W. Grimes 
1256dea673e9SRodney W. Grimes 	endring = ring;
1257dea673e9SRodney W. Grimes 
1258dea673e9SRodney W. Grimes 	for (i = 0; i <= 128; ++i)
1259dea673e9SRodney W. Grimes 		if (isprint(i))
1260dea673e9SRodney W. Grimes 			*endring++ = i;
1261dea673e9SRodney W. Grimes }
1262dea673e9SRodney W. Grimes 
1263dea673e9SRodney W. Grimes /* ARGSUSED */
1264dea673e9SRodney W. Grimes void
1265dea673e9SRodney W. Grimes chargen_stream(s, sep)		/* Character generator */
1266dea673e9SRodney W. Grimes 	int s;
1267dea673e9SRodney W. Grimes 	struct servtab *sep;
1268dea673e9SRodney W. Grimes {
1269dea673e9SRodney W. Grimes 	int len;
1270dea673e9SRodney W. Grimes 	char *rs, text[LINESIZ+2];
1271dea673e9SRodney W. Grimes 
1272c1283020SPeter Wemm 	inetd_setproctitle(sep->se_service, s);
1273dea673e9SRodney W. Grimes 
1274dea673e9SRodney W. Grimes 	if (!endring) {
1275dea673e9SRodney W. Grimes 		initring();
1276dea673e9SRodney W. Grimes 		rs = ring;
1277dea673e9SRodney W. Grimes 	}
1278dea673e9SRodney W. Grimes 
1279dea673e9SRodney W. Grimes 	text[LINESIZ] = '\r';
1280dea673e9SRodney W. Grimes 	text[LINESIZ + 1] = '\n';
1281dea673e9SRodney W. Grimes 	for (rs = ring;;) {
1282dea673e9SRodney W. Grimes 		if ((len = endring - rs) >= LINESIZ)
1283dea673e9SRodney W. Grimes 			memmove(text, rs, LINESIZ);
1284dea673e9SRodney W. Grimes 		else {
1285dea673e9SRodney W. Grimes 			memmove(text, rs, len);
1286dea673e9SRodney W. Grimes 			memmove(text + len, ring, LINESIZ - len);
1287dea673e9SRodney W. Grimes 		}
1288dea673e9SRodney W. Grimes 		if (++rs == endring)
1289dea673e9SRodney W. Grimes 			rs = ring;
1290dea673e9SRodney W. Grimes 		if (write(s, text, sizeof(text)) != sizeof(text))
1291dea673e9SRodney W. Grimes 			break;
1292dea673e9SRodney W. Grimes 	}
1293dea673e9SRodney W. Grimes 	exit(0);
1294dea673e9SRodney W. Grimes }
1295dea673e9SRodney W. Grimes 
1296dea673e9SRodney W. Grimes /* ARGSUSED */
1297dea673e9SRodney W. Grimes void
1298dea673e9SRodney W. Grimes chargen_dg(s, sep)		/* Character generator */
1299dea673e9SRodney W. Grimes 	int s;
1300dea673e9SRodney W. Grimes 	struct servtab *sep;
1301dea673e9SRodney W. Grimes {
130271704f34SGarrett Wollman 	struct sockaddr_in sin;
1303dea673e9SRodney W. Grimes 	static char *rs;
1304dea673e9SRodney W. Grimes 	int len, size;
1305dea673e9SRodney W. Grimes 	char text[LINESIZ+2];
1306dea673e9SRodney W. Grimes 
1307dea673e9SRodney W. Grimes 	if (endring == 0) {
1308dea673e9SRodney W. Grimes 		initring();
1309dea673e9SRodney W. Grimes 		rs = ring;
1310dea673e9SRodney W. Grimes 	}
1311dea673e9SRodney W. Grimes 
131271704f34SGarrett Wollman 	size = sizeof(sin);
131371704f34SGarrett Wollman 	if (recvfrom(s, text, sizeof(text), 0,
131471704f34SGarrett Wollman 		     (struct sockaddr *)&sin, &size) < 0)
131571704f34SGarrett Wollman 		return;
131671704f34SGarrett Wollman 
131771704f34SGarrett Wollman 	if (check_loop(&sin, sep))
1318dea673e9SRodney W. Grimes 		return;
1319dea673e9SRodney W. Grimes 
1320dea673e9SRodney W. Grimes 	if ((len = endring - rs) >= LINESIZ)
1321dea673e9SRodney W. Grimes 		memmove(text, rs, LINESIZ);
1322dea673e9SRodney W. Grimes 	else {
1323dea673e9SRodney W. Grimes 		memmove(text, rs, len);
1324dea673e9SRodney W. Grimes 		memmove(text + len, ring, LINESIZ - len);
1325dea673e9SRodney W. Grimes 	}
1326dea673e9SRodney W. Grimes 	if (++rs == endring)
1327dea673e9SRodney W. Grimes 		rs = ring;
1328dea673e9SRodney W. Grimes 	text[LINESIZ] = '\r';
1329dea673e9SRodney W. Grimes 	text[LINESIZ + 1] = '\n';
133071704f34SGarrett Wollman 	(void) sendto(s, text, sizeof(text), 0,
133171704f34SGarrett Wollman 		      (struct sockaddr *)&sin, sizeof(sin));
1332dea673e9SRodney W. Grimes }
1333dea673e9SRodney W. Grimes 
1334dea673e9SRodney W. Grimes /*
1335dea673e9SRodney W. Grimes  * Return a machine readable date and time, in the form of the
1336dea673e9SRodney W. Grimes  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1337dea673e9SRodney W. Grimes  * returns the number of seconds since midnight, Jan 1, 1970,
1338dea673e9SRodney W. Grimes  * we must add 2208988800 seconds to this figure to make up for
1339dea673e9SRodney W. Grimes  * some seventy years Bell Labs was asleep.
1340dea673e9SRodney W. Grimes  */
1341dea673e9SRodney W. Grimes 
1342dea673e9SRodney W. Grimes long
1343dea673e9SRodney W. Grimes machtime()
1344dea673e9SRodney W. Grimes {
1345dea673e9SRodney W. Grimes 	struct timeval tv;
1346dea673e9SRodney W. Grimes 
1347dea673e9SRodney W. Grimes 	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1348dea673e9SRodney W. Grimes 		if (debug)
1349dea673e9SRodney W. Grimes 			fprintf(stderr, "Unable to get time of day\n");
1350dea673e9SRodney W. Grimes 		return (0L);
1351dea673e9SRodney W. Grimes 	}
1352dea673e9SRodney W. Grimes #define	OFFSET ((u_long)25567 * 24*60*60)
1353dea673e9SRodney W. Grimes 	return (htonl((long)(tv.tv_sec + OFFSET)));
1354dea673e9SRodney W. Grimes #undef OFFSET
1355dea673e9SRodney W. Grimes }
1356dea673e9SRodney W. Grimes 
1357dea673e9SRodney W. Grimes /* ARGSUSED */
1358dea673e9SRodney W. Grimes void
1359dea673e9SRodney W. Grimes machtime_stream(s, sep)
1360dea673e9SRodney W. Grimes 	int s;
1361dea673e9SRodney W. Grimes 	struct servtab *sep;
1362dea673e9SRodney W. Grimes {
1363dea673e9SRodney W. Grimes 	long result;
1364dea673e9SRodney W. Grimes 
1365dea673e9SRodney W. Grimes 	result = machtime();
1366dea673e9SRodney W. Grimes 	(void) write(s, (char *) &result, sizeof(result));
1367dea673e9SRodney W. Grimes }
1368dea673e9SRodney W. Grimes 
1369dea673e9SRodney W. Grimes /* ARGSUSED */
1370dea673e9SRodney W. Grimes void
1371dea673e9SRodney W. Grimes machtime_dg(s, sep)
1372dea673e9SRodney W. Grimes 	int s;
1373dea673e9SRodney W. Grimes 	struct servtab *sep;
1374dea673e9SRodney W. Grimes {
1375dea673e9SRodney W. Grimes 	long result;
137671704f34SGarrett Wollman 	struct sockaddr_in sin;
1377dea673e9SRodney W. Grimes 	int size;
1378dea673e9SRodney W. Grimes 
137971704f34SGarrett Wollman 	size = sizeof(sin);
138071704f34SGarrett Wollman 	if (recvfrom(s, (char *)&result, sizeof(result), 0,
138171704f34SGarrett Wollman 		     (struct sockaddr *)&sin, &size) < 0)
1382dea673e9SRodney W. Grimes 		return;
138371704f34SGarrett Wollman 
138471704f34SGarrett Wollman 	if (check_loop(&sin, sep))
138571704f34SGarrett Wollman 		return;
138671704f34SGarrett Wollman 
1387dea673e9SRodney W. Grimes 	result = machtime();
138871704f34SGarrett Wollman 	(void) sendto(s, (char *) &result, sizeof(result), 0,
138971704f34SGarrett Wollman 		      (struct sockaddr *)&sin, sizeof(sin));
1390dea673e9SRodney W. Grimes }
1391dea673e9SRodney W. Grimes 
1392dea673e9SRodney W. Grimes /* ARGSUSED */
1393dea673e9SRodney W. Grimes void
1394dea673e9SRodney W. Grimes daytime_stream(s, sep)		/* Return human-readable time of day */
1395dea673e9SRodney W. Grimes 	int s;
1396dea673e9SRodney W. Grimes 	struct servtab *sep;
1397dea673e9SRodney W. Grimes {
1398dea673e9SRodney W. Grimes 	char buffer[256];
1399dea673e9SRodney W. Grimes 	time_t clock;
1400dea673e9SRodney W. Grimes 
1401dea673e9SRodney W. Grimes 	clock = time((time_t *) 0);
1402dea673e9SRodney W. Grimes 
1403dea673e9SRodney W. Grimes 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1404dea673e9SRodney W. Grimes 	(void) write(s, buffer, strlen(buffer));
1405dea673e9SRodney W. Grimes }
1406dea673e9SRodney W. Grimes 
1407dea673e9SRodney W. Grimes /* ARGSUSED */
1408dea673e9SRodney W. Grimes void
1409dea673e9SRodney W. Grimes daytime_dg(s, sep)		/* Return human-readable time of day */
1410dea673e9SRodney W. Grimes 	int s;
1411dea673e9SRodney W. Grimes 	struct servtab *sep;
1412dea673e9SRodney W. Grimes {
1413dea673e9SRodney W. Grimes 	char buffer[256];
1414dea673e9SRodney W. Grimes 	time_t clock;
141571704f34SGarrett Wollman 	struct sockaddr_in sin;
1416dea673e9SRodney W. Grimes 	int size;
1417dea673e9SRodney W. Grimes 
1418dea673e9SRodney W. Grimes 	clock = time((time_t *) 0);
1419dea673e9SRodney W. Grimes 
142071704f34SGarrett Wollman 	size = sizeof(sin);
142171704f34SGarrett Wollman 	if (recvfrom(s, buffer, sizeof(buffer), 0,
142271704f34SGarrett Wollman 		     (struct sockaddr *)&sin, &size) < 0)
1423dea673e9SRodney W. Grimes 		return;
142471704f34SGarrett Wollman 
142571704f34SGarrett Wollman 	if (check_loop(&sin, sep))
142671704f34SGarrett Wollman 		return;
142771704f34SGarrett Wollman 
1428dea673e9SRodney W. Grimes 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
142971704f34SGarrett Wollman 	(void) sendto(s, buffer, strlen(buffer), 0,
143071704f34SGarrett Wollman 		      (struct sockaddr *)&sin, sizeof(sin));
1431dea673e9SRodney W. Grimes }
1432dea673e9SRodney W. Grimes 
1433dea673e9SRodney W. Grimes /*
1434dea673e9SRodney W. Grimes  * print_service:
1435dea673e9SRodney W. Grimes  *	Dump relevant information to stderr
1436dea673e9SRodney W. Grimes  */
1437dea673e9SRodney W. Grimes void
1438dea673e9SRodney W. Grimes print_service(action, sep)
1439dea673e9SRodney W. Grimes 	char *action;
1440dea673e9SRodney W. Grimes 	struct servtab *sep;
1441dea673e9SRodney W. Grimes {
144255b91f3aSGeoff Rehmet 	if(sep->se_rpc)
1443dea673e9SRodney W. Grimes 		fprintf(stderr,
1444dea673e9SRodney W. Grimes 	    		"%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
1445dea673e9SRodney W. Grimes 	    		action, sep->se_service, sep->se_proto,
144655b91f3aSGeoff Rehmet 	    		sep->se_wait, sep->se_user, (int)sep->se_bi,
144755b91f3aSGeoff Rehmet 			sep->se_server);
144855b91f3aSGeoff Rehmet 	else
144955b91f3aSGeoff Rehmet 		fprintf(stderr,
145055b91f3aSGeoff Rehmet 			"%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
145155b91f3aSGeoff Rehmet 			action, sep->se_service, sep->se_proto,
145255b91f3aSGeoff Rehmet 			sep->se_wait, sep->se_user, (int)sep->se_bi,
145355b91f3aSGeoff Rehmet 			sep->se_server);
1454dea673e9SRodney W. Grimes }
1455dea673e9SRodney W. Grimes 
1456dea673e9SRodney W. Grimes /*
1457dea673e9SRodney W. Grimes  *  Based on TCPMUX.C by Mark K. Lottor November 1988
1458dea673e9SRodney W. Grimes  *  sri-nic::ps:<mkl>tcpmux.c
1459dea673e9SRodney W. Grimes  */
1460dea673e9SRodney W. Grimes 
1461dea673e9SRodney W. Grimes 
1462dea673e9SRodney W. Grimes static int		/* # of characters upto \r,\n or \0 */
1463dea673e9SRodney W. Grimes getline(fd, buf, len)
1464dea673e9SRodney W. Grimes 	int fd;
1465dea673e9SRodney W. Grimes 	char *buf;
1466dea673e9SRodney W. Grimes 	int len;
1467dea673e9SRodney W. Grimes {
1468dea673e9SRodney W. Grimes 	int count = 0, n;
1469dea673e9SRodney W. Grimes 
1470dea673e9SRodney W. Grimes 	do {
1471dea673e9SRodney W. Grimes 		n = read(fd, buf, len-count);
1472dea673e9SRodney W. Grimes 		if (n == 0)
1473dea673e9SRodney W. Grimes 			return (count);
1474dea673e9SRodney W. Grimes 		if (n < 0)
1475dea673e9SRodney W. Grimes 			return (-1);
1476dea673e9SRodney W. Grimes 		while (--n >= 0) {
1477dea673e9SRodney W. Grimes 			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
1478dea673e9SRodney W. Grimes 				return (count);
1479dea673e9SRodney W. Grimes 			count++;
1480dea673e9SRodney W. Grimes 			buf++;
1481dea673e9SRodney W. Grimes 		}
1482dea673e9SRodney W. Grimes 	} while (count < len);
1483dea673e9SRodney W. Grimes 	return (count);
1484dea673e9SRodney W. Grimes }
1485dea673e9SRodney W. Grimes 
1486dea673e9SRodney W. Grimes #define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
1487dea673e9SRodney W. Grimes 
1488dea673e9SRodney W. Grimes #define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
1489dea673e9SRodney W. Grimes 
1490dea673e9SRodney W. Grimes struct servtab *
1491dea673e9SRodney W. Grimes tcpmux(s)
1492dea673e9SRodney W. Grimes 	int s;
1493dea673e9SRodney W. Grimes {
1494dea673e9SRodney W. Grimes 	struct servtab *sep;
1495dea673e9SRodney W. Grimes 	char service[MAX_SERV_LEN+1];
1496dea673e9SRodney W. Grimes 	int len;
1497dea673e9SRodney W. Grimes 
1498dea673e9SRodney W. Grimes 	/* Get requested service name */
1499dea673e9SRodney W. Grimes 	if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
1500dea673e9SRodney W. Grimes 		strwrite(s, "-Error reading service name\r\n");
1501dea673e9SRodney W. Grimes 		return (NULL);
1502dea673e9SRodney W. Grimes 	}
1503dea673e9SRodney W. Grimes 	service[len] = '\0';
1504dea673e9SRodney W. Grimes 
1505dea673e9SRodney W. Grimes 	if (debug)
1506dea673e9SRodney W. Grimes 		fprintf(stderr, "tcpmux: someone wants %s\n", service);
1507dea673e9SRodney W. Grimes 
1508dea673e9SRodney W. Grimes 	/*
1509dea673e9SRodney W. Grimes 	 * Help is a required command, and lists available services,
1510dea673e9SRodney W. Grimes 	 * one per line.
1511dea673e9SRodney W. Grimes 	 */
1512dea673e9SRodney W. Grimes 	if (!strcasecmp(service, "help")) {
1513dea673e9SRodney W. Grimes 		for (sep = servtab; sep; sep = sep->se_next) {
1514dea673e9SRodney W. Grimes 			if (!ISMUX(sep))
1515dea673e9SRodney W. Grimes 				continue;
1516dea673e9SRodney W. Grimes 			(void)write(s,sep->se_service,strlen(sep->se_service));
1517dea673e9SRodney W. Grimes 			strwrite(s, "\r\n");
1518dea673e9SRodney W. Grimes 		}
1519dea673e9SRodney W. Grimes 		return (NULL);
1520dea673e9SRodney W. Grimes 	}
1521dea673e9SRodney W. Grimes 
1522dea673e9SRodney W. Grimes 	/* Try matching a service in inetd.conf with the request */
1523dea673e9SRodney W. Grimes 	for (sep = servtab; sep; sep = sep->se_next) {
1524dea673e9SRodney W. Grimes 		if (!ISMUX(sep))
1525dea673e9SRodney W. Grimes 			continue;
1526dea673e9SRodney W. Grimes 		if (!strcasecmp(service, sep->se_service)) {
1527dea673e9SRodney W. Grimes 			if (ISMUXPLUS(sep)) {
1528dea673e9SRodney W. Grimes 				strwrite(s, "+Go\r\n");
1529dea673e9SRodney W. Grimes 			}
1530dea673e9SRodney W. Grimes 			return (sep);
1531dea673e9SRodney W. Grimes 		}
1532dea673e9SRodney W. Grimes 	}
1533dea673e9SRodney W. Grimes 	strwrite(s, "-Service not available\r\n");
1534dea673e9SRodney W. Grimes 	return (NULL);
1535dea673e9SRodney W. Grimes }
1536