GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/inetd/inetd.c Lines: 0 870 0.0 %
Date: 2017-11-07 Branches: 0 634 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: inetd.c,v 1.154 2016/08/25 05:23:19 tedu Exp $	*/
2
3
/*
4
 * Copyright (c) 1983,1991 The Regents of the University of California.
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 * 3. Neither the name of the University nor the names of its contributors
16
 *    may be used to endorse or promote products derived from this software
17
 *    without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
32
/*
33
 * Inetd - Internet super-server
34
 *
35
 * This program invokes all internet services as needed.
36
 * connection-oriented services are invoked each time a
37
 * connection is made, by creating a process.  This process
38
 * is passed the connection as file descriptor 0 and is
39
 * expected to do a getpeername to find out the source host
40
 * and port.
41
 *
42
 * Datagram oriented services are invoked when a datagram
43
 * arrives; a process is created and passed a pending message
44
 * on file descriptor 0.  Datagram servers may either connect
45
 * to their peer, freeing up the original socket for inetd
46
 * to receive further messages on, or ``take over the socket'',
47
 * processing all arriving datagrams and, eventually, timing
48
 * out.	 The first type of server is said to be ``multi-threaded'';
49
 * the second type of server ``single-threaded''.
50
 *
51
 * Inetd uses a configuration file which is read at startup
52
 * and, possibly, at some later time in response to a hangup signal.
53
 * The configuration file is ``free format'' with fields given in the
54
 * order shown below.  Continuation lines for an entry must begin with
55
 * a space or tab.  All fields must be present in each entry.
56
 *
57
 *	service name			must be in /etc/services
58
 *	socket type			stream/dgram/raw/rdm/seqpacket
59
 *	protocol			must be in /etc/protocols
60
 *	wait/nowait[.max]		single-threaded/multi-threaded, max #
61
 *	user[.group] or user[:group]	user/group to run daemon as
62
 *	server program			full path name
63
 *	server program arguments	maximum of MAXARGS (20)
64
 *
65
 * For RPC services
66
 *      service name/version            must be in /etc/rpc
67
 *	socket type			stream/dgram/raw/rdm/seqpacket
68
 *	protocol			must be in /etc/protocols
69
 *	wait/nowait[.max]		single-threaded/multi-threaded
70
 *	user[.group] or user[:group]	user to run daemon as
71
 *	server program			full path name
72
 *	server program arguments	maximum of MAXARGS (20)
73
 *
74
 * For non-RPC services, the "service name" can be of the form
75
 * hostaddress:servicename, in which case the hostaddress is used
76
 * as the host portion of the address to listen on.  If hostaddress
77
 * consists of a single `*' character, INADDR_ANY is used.
78
 *
79
 * A line can also consist of just
80
 *      hostaddress:
81
 * where hostaddress is as in the preceding paragraph.  Such a line must
82
 * have no further fields; the specified hostaddress is remembered and
83
 * used for all further lines that have no hostaddress specified,
84
 * until the next such line (or EOF).  (This is why * is provided to
85
 * allow explicit specification of INADDR_ANY.)  A line
86
 *      *:
87
 * is implicitly in effect at the beginning of the file.
88
 *
89
 * The hostaddress specifier may (and often will) contain dots;
90
 * the service name must not.
91
 *
92
 * For RPC services, host-address specifiers are accepted and will
93
 * work to some extent; however, because of limitations in the
94
 * portmapper interface, it will not work to try to give more than
95
 * one line for any given RPC service, even if the host-address
96
 * specifiers are different.
97
 *
98
 * Comment lines are indicated by a `#' in column 1.
99
 */
100
101
/*
102
 * Here's the scoop concerning the user[.:]group feature:
103
 *
104
 * 1) set-group-option off.
105
 *
106
 *	a) user = root:	NO setuid() or setgid() is done
107
 *
108
 *	b) other:	setgid(primary group as found in passwd)
109
 *			initgroups(name, primary group)
110
 *			setuid()
111
 *
112
 * 2) set-group-option on.
113
 *
114
 *	a) user = root:	setgid(specified group)
115
 *			NO initgroups()
116
 *			NO setuid()
117
 *
118
 *	b) other:	setgid(specified group)
119
 *			initgroups(name, specified group)
120
 *			setuid()
121
 *
122
 */
123
124
#include <sys/stat.h>
125
#include <sys/ioctl.h>
126
#include <sys/socket.h>
127
#include <sys/un.h>
128
#include <sys/file.h>
129
#include <sys/wait.h>
130
#include <sys/time.h>
131
#include <sys/resource.h>
132
133
#include <net/if.h>
134
#include <netinet/in.h>
135
#include <arpa/inet.h>
136
137
#include <err.h>
138
#include <errno.h>
139
#include <ctype.h>
140
#include <signal.h>
141
#include <netdb.h>
142
#include <syslog.h>
143
#include <pwd.h>
144
#include <grp.h>
145
#include <stdio.h>
146
#include <stdlib.h>
147
#include <unistd.h>
148
#include <limits.h>
149
#include <string.h>
150
#include <login_cap.h>
151
#include <ifaddrs.h>
152
#include <rpc/rpc.h>
153
#include <rpc/pmap_clnt.h>
154
#include <rpcsvc/nfs_prot.h>
155
#include <event.h>
156
#include "pathnames.h"
157
158
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
159
160
#define	TOOMANY		256		/* don't start more than TOOMANY */
161
#define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
162
#define	RETRYTIME	(60*10)		/* retry after bind or server fail */
163
164
int	 debug = 0;
165
int	 maxsock;
166
int	 toomany = TOOMANY;
167
int	 timingout;
168
struct	 servent *sp;
169
uid_t	 uid;
170
171
#ifndef OPEN_MAX
172
#define OPEN_MAX	64
173
#endif
174
175
/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
176
#define FD_MARGIN	(8)
177
rlim_t	rlim_nofile_cur = OPEN_MAX;
178
179
struct rlimit	rlim_nofile;
180
181
struct	servtab {
182
	char	*se_hostaddr;		/* host address to listen on */
183
	char	*se_service;		/* name of service */
184
	int	se_socktype;		/* type of socket to use */
185
	int	se_family;		/* address family */
186
	char	*se_proto;		/* protocol used */
187
	int	se_rpcprog;		/* rpc program number */
188
	int	se_rpcversl;		/* rpc program lowest version */
189
	int	se_rpcversh;		/* rpc program highest version */
190
#define isrpcservice(sep)	((sep)->se_rpcversl != 0)
191
	pid_t	se_wait;		/* single threaded server */
192
	short	se_checked;		/* looked at during merge */
193
	char	*se_user;		/* user name to run as */
194
	char	*se_group;		/* group name to run as */
195
	struct	biltin *se_bi;		/* if built-in, description */
196
	char	*se_server;		/* server program */
197
#define	MAXARGV 20
198
	char	*se_argv[MAXARGV+1];	/* program arguments */
199
	int	se_fd;			/* open descriptor */
200
	union {
201
		struct	sockaddr se_un_ctrladdr;
202
		struct	sockaddr_in se_un_ctrladdr_in;
203
		struct	sockaddr_in6 se_un_ctrladdr_in6;
204
		struct	sockaddr_un se_un_ctrladdr_un;
205
		struct	sockaddr_storage se_un_ctrladdr_storage;
206
	} se_un;			/* bound address */
207
#define se_ctrladdr	se_un.se_un_ctrladdr
208
#define se_ctrladdr_in	se_un.se_un_ctrladdr_in
209
#define se_ctrladdr_in6	se_un.se_un_ctrladdr_in6
210
#define se_ctrladdr_un	se_un.se_un_ctrladdr_un
211
#define se_ctrladdr_storage	se_un.se_un_ctrladdr_storage
212
	int	se_ctrladdr_size;
213
	int	se_max;			/* max # of instances of this service */
214
	int	se_count;		/* number started since se_time */
215
	struct	timeval se_time;	/* start of se_count */
216
	struct	servtab *se_next;
217
	struct	event se_event;
218
} *servtab;
219
220
void echo_stream(int, struct servtab *);
221
void discard_stream(int, struct servtab *);
222
void machtime_stream(int, struct servtab *);
223
void daytime_stream(int, struct servtab *);
224
void chargen_stream(int, struct servtab *);
225
void echo_dg(int, struct servtab *);
226
void discard_dg(int, struct servtab *);
227
void machtime_dg(int, struct servtab *);
228
void daytime_dg(int, struct servtab *);
229
void chargen_dg(int, struct servtab *);
230
231
struct biltin {
232
	char	*bi_service;		/* internally provided service name */
233
	int	bi_socktype;		/* type of socket supported */
234
	short	bi_fork;		/* 1 if should fork before call */
235
	short	bi_wait;		/* 1 if should wait for child */
236
	void	(*bi_fn)(int, struct servtab *);
237
} biltins[] = {
238
	/* Echo received data */
239
	{ "echo",	SOCK_STREAM,	1, 0,	echo_stream },
240
	{ "echo",	SOCK_DGRAM,	0, 0,	echo_dg },
241
242
	/* Internet /dev/null */
243
	{ "discard",	SOCK_STREAM,	1, 0,	discard_stream },
244
	{ "discard",	SOCK_DGRAM,	0, 0,	discard_dg },
245
246
	/* Return 32 bit time since 1900 */
247
	{ "time",	SOCK_STREAM,	0, 0,	machtime_stream },
248
	{ "time",	SOCK_DGRAM,	0, 0,	machtime_dg },
249
250
	/* Return human-readable time */
251
	{ "daytime",	SOCK_STREAM,	0, 0,	daytime_stream },
252
	{ "daytime",	SOCK_DGRAM,	0, 0,	daytime_dg },
253
254
	/* Familiar character generator */
255
	{ "chargen",	SOCK_STREAM,	1, 0,	chargen_stream },
256
	{ "chargen",	SOCK_DGRAM,	0, 0,	chargen_dg },
257
258
	{ 0 }
259
};
260
261
struct event evsig_alrm;
262
struct event evsig_hup;
263
struct event evsig_chld;
264
struct event evsig_term;
265
struct event evsig_int;
266
267
void	config(int, short, void *);
268
void	reap(int, short, void *);
269
void	retry(int, short, void *);
270
void	die(int, short, void *);
271
272
void	spawn(int, short, void *);
273
void	gettcp(int, short, void *);
274
int	setconfig(void);
275
void	endconfig(void);
276
void	register_rpc(struct servtab *);
277
void	unregister_rpc(struct servtab *);
278
void	freeconfig(struct servtab *);
279
void	print_service(char *, struct servtab *);
280
void	setup(struct servtab *);
281
struct servtab *getconfigent(void);
282
int	bump_nofile(void);
283
struct servtab *enter(struct servtab *);
284
int	matchconf(struct servtab *, struct servtab *);
285
int	dg_broadcast(struct in_addr *in);
286
287
#define NUMINT	(sizeof(intab) / sizeof(struct inent))
288
char	*CONFIG = _PATH_INETDCONF;
289
290
int		dg_badinput(struct sockaddr *sa);
291
void		inetd_setproctitle(char *a, int s);
292
void		initring(void);
293
u_int32_t	machtime(void);
294
295
int
296
main(int argc, char *argv[])
297
{
298
	int ch;
299
300
	while ((ch = getopt(argc, argv, "dR:")) != -1)
301
		switch (ch) {
302
		case 'd':
303
			debug = 1;
304
			break;
305
		case 'R': {	/* invocation rate */
306
			char *p;
307
			int val;
308
309
			val = strtoul(optarg, &p, 0);
310
			if (val >= 1 && *p == '\0') {
311
				toomany = val;
312
				break;
313
			}
314
			syslog(LOG_ERR,
315
			    "-R %s: bad value for service invocation rate",
316
			    optarg);
317
			break;
318
		}
319
		case '?':
320
		default:
321
			fprintf(stderr,
322
			    "usage: inetd [-d] [-R rate] [configuration_file]\n");
323
			exit(1);
324
		}
325
	argc -= optind;
326
	argv += optind;
327
328
	uid = getuid();
329
	if (uid != 0)
330
		CONFIG = NULL;
331
	if (argc > 0)
332
		CONFIG = argv[0];
333
	if (CONFIG == NULL) {
334
		fprintf(stderr, "inetd: non-root must specify a config file\n");
335
		exit(1);
336
	}
337
	if (argc > 1) {
338
		fprintf(stderr, "inetd: more than one argument specified\n");
339
		exit(1);
340
	}
341
342
	umask(022);
343
	if (debug == 0) {
344
		daemon(0, 0);
345
		if (uid == 0)
346
			(void) setlogin("");
347
	}
348
349
	if (pledge("stdio rpath cpath getpw dns inet unix proc exec id flock wpath", NULL) == -1)
350
		err(1, "pledge");
351
352
	if (uid == 0) {
353
		gid_t gid = getgid();
354
355
		/* If run by hand, ensure groups vector gets trashed */
356
		setgroups(1, &gid);
357
	}
358
359
	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
360
361
	if (getrlimit(RLIMIT_NOFILE, &rlim_nofile) < 0) {
362
		syslog(LOG_ERR, "getrlimit: %m");
363
	} else {
364
		rlim_nofile_cur = rlim_nofile.rlim_cur;
365
		if (rlim_nofile_cur == RLIM_INFINITY)	/* ! */
366
			rlim_nofile_cur = OPEN_MAX;
367
	}
368
369
	event_init();
370
371
	signal_set(&evsig_alrm, SIGALRM, retry, NULL);
372
	signal_add(&evsig_alrm, NULL);
373
374
	config(0, 0, NULL);
375
376
	signal_set(&evsig_hup, SIGHUP, config, NULL);
377
	signal_add(&evsig_hup, NULL);
378
	signal_set(&evsig_chld, SIGCHLD, reap, NULL);
379
	signal_add(&evsig_chld, NULL);
380
	signal_set(&evsig_term, SIGTERM, die, NULL);
381
	signal_add(&evsig_term, NULL);
382
	signal_set(&evsig_int, SIGINT, die, NULL);
383
	signal_add(&evsig_int, NULL);
384
385
	signal(SIGPIPE, SIG_IGN);
386
387
	event_dispatch();
388
389
	return (0);
390
}
391
392
void
393
gettcp(int fd, short events, void *xsep)
394
{
395
	struct servtab *sep = xsep;
396
	int ctrl;
397
398
	if (debug)
399
		fprintf(stderr, "someone wants %s\n", sep->se_service);
400
401
	ctrl = accept(sep->se_fd, NULL, NULL);
402
	if (debug)
403
		fprintf(stderr, "accept, ctrl %d\n", ctrl);
404
	if (ctrl < 0) {
405
		if (errno != EWOULDBLOCK && errno != EINTR &&
406
		    errno != ECONNABORTED)
407
			syslog(LOG_WARNING, "accept (for %s): %m",
408
			    sep->se_service);
409
		return;
410
	}
411
	if ((sep->se_family == AF_INET || sep->se_family == AF_INET6) &&
412
	    sep->se_socktype == SOCK_STREAM) {
413
		struct sockaddr_storage peer;
414
		socklen_t plen = sizeof(peer);
415
		char sbuf[NI_MAXSERV];
416
417
		if (getpeername(ctrl, (struct sockaddr *)&peer, &plen) < 0) {
418
			syslog(LOG_WARNING, "could not getpeername");
419
			close(ctrl);
420
			return;
421
		}
422
		if (getnameinfo((struct sockaddr *)&peer, plen, NULL, 0,
423
		    sbuf, sizeof(sbuf), NI_NUMERICSERV) == 0 &&
424
		    strtonum(sbuf, 1, USHRT_MAX, NULL) == 20) {
425
			/*
426
			 * ignore things that look like ftp bounce
427
			 */
428
			close(ctrl);
429
			return;
430
		}
431
	}
432
433
	spawn(ctrl, 0, sep);
434
}
435
436
int
437
dg_badinput(struct sockaddr *sa)
438
{
439
	struct in_addr in;
440
	struct in6_addr *in6;
441
	u_int16_t port;
442
443
	switch (sa->sa_family) {
444
	case AF_INET:
445
		in.s_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
446
		port = ntohs(((struct sockaddr_in *)sa)->sin_port);
447
	v4chk:
448
		if (IN_MULTICAST(in.s_addr))
449
			goto bad;
450
		switch ((in.s_addr & 0xff000000) >> 24) {
451
		case 0: case 127: case 255:
452
			goto bad;
453
		}
454
		if (dg_broadcast(&in))
455
			goto bad;
456
		break;
457
	case AF_INET6:
458
		in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
459
		port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
460
		if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
461
			goto bad;
462
		/*
463
		 * OpenBSD does not support IPv4 mapped address (RFC2553
464
		 * inbound behavior) at all.  We should drop it.
465
		 */
466
		if (IN6_IS_ADDR_V4MAPPED(in6))
467
			goto bad;
468
		if (IN6_IS_ADDR_V4COMPAT(in6)) {
469
			memcpy(&in, &in6->s6_addr[12], sizeof(in));
470
			in.s_addr = ntohl(in.s_addr);
471
			goto v4chk;
472
		}
473
		break;
474
	default:
475
		/* Unsupported AF */
476
		goto bad;
477
	}
478
479
	if (port < IPPORT_RESERVED || port == NFS_PORT)
480
		goto bad;
481
482
	return (0);
483
484
bad:
485
	return (1);
486
}
487
488
int
489
dg_broadcast(struct in_addr *in)
490
{
491
	struct ifaddrs *ifa, *ifap;
492
	struct sockaddr_in *sin;
493
494
	if (getifaddrs(&ifap) < 0)
495
		return (0);
496
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
497
		if (ifa->ifa_addr->sa_family != AF_INET ||
498
		    (ifa->ifa_flags & IFF_BROADCAST) == 0)
499
			continue;
500
		sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
501
		if (sin->sin_addr.s_addr == in->s_addr) {
502
			freeifaddrs(ifap);
503
			return (1);
504
		}
505
	}
506
	freeifaddrs(ifap);
507
	return (0);
508
}
509
510
void
511
reap(int sig, short event, void *arg)
512
{
513
	struct servtab *sep;
514
	int status;
515
	pid_t pid;
516
517
	if (debug)
518
		fprintf(stderr, "reaping asked for\n");
519
520
	for (;;) {
521
		if ((pid = wait3(&status, WNOHANG, NULL)) <= 0) {
522
			if (pid == -1 && errno == EINTR)
523
				continue;
524
			break;
525
		}
526
		if (debug)
527
			fprintf(stderr, "%ld reaped, status %x\n",
528
			    (long)pid, status);
529
		for (sep = servtab; sep; sep = sep->se_next)
530
			if (sep->se_wait == pid) {
531
				if (WIFEXITED(status) && WEXITSTATUS(status))
532
					syslog(LOG_WARNING,
533
					    "%s: exit status %d",
534
					    sep->se_server, WEXITSTATUS(status));
535
				else if (WIFSIGNALED(status))
536
					syslog(LOG_WARNING,
537
					    "%s: exit signal %d",
538
					    sep->se_server, WTERMSIG(status));
539
				sep->se_wait = 1;
540
				event_add(&sep->se_event, NULL);
541
				if (debug)
542
					fprintf(stderr, "restored %s, fd %d\n",
543
					    sep->se_service, sep->se_fd);
544
			}
545
	}
546
}
547
548
void
549
config(int sig, short event, void *arg)
550
{
551
	struct servtab *sep, *cp, **sepp;
552
	int add;
553
	char protoname[11];
554
555
	if (!setconfig()) {
556
		syslog(LOG_ERR, "%s: %m", CONFIG);
557
		exit(1);
558
	}
559
	for (sep = servtab; sep; sep = sep->se_next)
560
		sep->se_checked = 0;
561
	cp = getconfigent();
562
	while (cp != NULL) {
563
		for (sep = servtab; sep; sep = sep->se_next)
564
			if (matchconf(sep, cp))
565
				break;
566
		add = 0;
567
		if (sep != NULL) {
568
			int i;
569
570
#define SWAP(type, a, b) {type c=(type)a; a=(type)b; b=(type)c;}
571
572
			/*
573
			 * sep->se_wait may be holding the pid of a daemon
574
			 * that we're waiting for.  If so, don't overwrite
575
			 * it unless the config file explicitly says don't
576
			 * wait.
577
			 */
578
			if (cp->se_bi == 0 &&
579
			    (sep->se_wait == 1 || cp->se_wait == 0))
580
				sep->se_wait = cp->se_wait;
581
			SWAP(int, cp->se_max, sep->se_max);
582
			SWAP(char *, sep->se_user, cp->se_user);
583
			SWAP(char *, sep->se_group, cp->se_group);
584
			SWAP(char *, sep->se_server, cp->se_server);
585
			for (i = 0; i < MAXARGV; i++)
586
				SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
587
#undef SWAP
588
			if (isrpcservice(sep))
589
				unregister_rpc(sep);
590
			sep->se_rpcversl = cp->se_rpcversl;
591
			sep->se_rpcversh = cp->se_rpcversh;
592
			freeconfig(cp);
593
			add = 1;
594
		} else {
595
			sep = enter(cp);
596
		}
597
		sep->se_checked = 1;
598
599
		switch (sep->se_family) {
600
		case AF_UNIX:
601
			if (sep->se_fd != -1)
602
				break;
603
			sep->se_ctrladdr_size =
604
			    strlcpy(sep->se_ctrladdr_un.sun_path,
605
			    sep->se_service,
606
			    sizeof sep->se_ctrladdr_un.sun_path);
607
			if (sep->se_ctrladdr_size >=
608
			    sizeof sep->se_ctrladdr_un.sun_path) {
609
				syslog(LOG_WARNING, "%s/%s: UNIX domain socket "
610
				    "path too long", sep->se_service,
611
				    sep->se_proto);
612
				goto serv_unknown;
613
			}
614
			sep->se_ctrladdr_un.sun_family = AF_UNIX;
615
			sep->se_ctrladdr_size +=
616
			    1 + sizeof sep->se_ctrladdr_un.sun_family;
617
			(void)unlink(sep->se_service);
618
			setup(sep);
619
			break;
620
		case AF_INET:
621
			sep->se_ctrladdr_in.sin_family = AF_INET;
622
			/* se_ctrladdr_in was set in getconfigent */
623
			sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
624
625
			if (isrpcservice(sep)) {
626
				struct rpcent *rp;
627
628
				sep->se_rpcprog = strtonum(sep->se_service,
629
				    1, USHRT_MAX, NULL);
630
				if (sep->se_rpcprog == 0) {
631
					rp = getrpcbyname(sep->se_service);
632
					if (rp == 0) {
633
						syslog(LOG_ERR,
634
						    "%s: unknown rpc service",
635
						    sep->se_service);
636
						goto serv_unknown;
637
					}
638
					sep->se_rpcprog = rp->r_number;
639
				}
640
				if (sep->se_fd == -1)
641
					setup(sep);
642
				if (sep->se_fd != -1)
643
					register_rpc(sep);
644
			} else {
645
				u_short port = htons(strtonum(sep->se_service,
646
				    1, USHRT_MAX, NULL));
647
648
				if (!port) {
649
					(void)strlcpy(protoname, sep->se_proto,
650
					    sizeof(protoname));
651
					if (isdigit((unsigned char)
652
					    protoname[strlen(protoname) - 1]))
653
						protoname[strlen(protoname) - 1] = '\0';
654
					sp = getservbyname(sep->se_service,
655
					    protoname);
656
					if (sp == 0) {
657
						syslog(LOG_ERR,
658
						    "%s/%s: unknown service",
659
						    sep->se_service, sep->se_proto);
660
						goto serv_unknown;
661
					}
662
					port = sp->s_port;
663
				}
664
				if (port != sep->se_ctrladdr_in.sin_port) {
665
					sep->se_ctrladdr_in.sin_port = port;
666
					if (sep->se_fd != -1) {
667
						event_del(&sep->se_event);
668
						(void) close(sep->se_fd);
669
					}
670
					sep->se_fd = -1;
671
				}
672
				if (sep->se_fd == -1)
673
					setup(sep);
674
			}
675
			break;
676
		case AF_INET6:
677
			sep->se_ctrladdr_in6.sin6_family = AF_INET6;
678
			/* se_ctrladdr_in was set in getconfigent */
679
			sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
680
681
			if (isrpcservice(sep)) {
682
				struct rpcent *rp;
683
684
				sep->se_rpcprog = strtonum(sep->se_service,
685
				    1, USHRT_MAX, NULL);
686
				if (sep->se_rpcprog == 0) {
687
					rp = getrpcbyname(sep->se_service);
688
					if (rp == 0) {
689
						syslog(LOG_ERR,
690
						    "%s: unknown rpc service",
691
						    sep->se_service);
692
						goto serv_unknown;
693
					}
694
					sep->se_rpcprog = rp->r_number;
695
				}
696
				if (sep->se_fd == -1)
697
					setup(sep);
698
				if (sep->se_fd != -1)
699
					register_rpc(sep);
700
			} else {
701
				u_short port = htons(strtonum(sep->se_service,
702
				    1, USHRT_MAX, NULL));
703
704
				if (!port) {
705
					(void)strlcpy(protoname, sep->se_proto,
706
					    sizeof(protoname));
707
					if (isdigit((unsigned char)
708
					    protoname[strlen(protoname) - 1]))
709
						protoname[strlen(protoname) - 1] = '\0';
710
					sp = getservbyname(sep->se_service,
711
					    protoname);
712
					if (sp == 0) {
713
						syslog(LOG_ERR,
714
						    "%s/%s: unknown service",
715
						    sep->se_service, sep->se_proto);
716
						goto serv_unknown;
717
					}
718
					port = sp->s_port;
719
				}
720
				if (port != sep->se_ctrladdr_in6.sin6_port) {
721
					sep->se_ctrladdr_in6.sin6_port = port;
722
					if (sep->se_fd != -1) {
723
						event_del(&sep->se_event);
724
						(void) close(sep->se_fd);
725
					}
726
					sep->se_fd = -1;
727
				}
728
				if (sep->se_fd == -1)
729
					setup(sep);
730
			}
731
			break;
732
		}
733
	serv_unknown:
734
		if (cp->se_next != NULL) {
735
			struct servtab *tmp = cp;
736
737
			cp = cp->se_next;
738
			free(tmp);
739
		} else {
740
			free(cp);
741
			cp = getconfigent();
742
		}
743
		if (debug)
744
			print_service(add ? "REDO" : "ADD", sep);
745
	}
746
	endconfig();
747
	/*
748
	 * Purge anything not looked at above.
749
	 */
750
	sepp = &servtab;
751
	while ((sep = *sepp)) {
752
		if (sep->se_checked) {
753
			sepp = &sep->se_next;
754
			continue;
755
		}
756
		*sepp = sep->se_next;
757
		if (sep->se_fd != -1) {
758
			event_del(&sep->se_event);
759
			(void) close(sep->se_fd);
760
		}
761
		if (isrpcservice(sep))
762
			unregister_rpc(sep);
763
		if (sep->se_family == AF_UNIX)
764
			(void)unlink(sep->se_service);
765
		if (debug)
766
			print_service("FREE", sep);
767
		freeconfig(sep);
768
		free(sep);
769
	}
770
}
771
772
void
773
retry(int sig, short events, void *arg)
774
{
775
	struct servtab *sep;
776
777
	timingout = 0;
778
	for (sep = servtab; sep; sep = sep->se_next) {
779
		if (sep->se_fd == -1) {
780
			switch (sep->se_family) {
781
			case AF_UNIX:
782
			case AF_INET:
783
			case AF_INET6:
784
				setup(sep);
785
				if (sep->se_fd != -1 && isrpcservice(sep))
786
					register_rpc(sep);
787
				break;
788
			}
789
		}
790
	}
791
}
792
793
void
794
die(int sig, short events, void *arg)
795
{
796
	struct servtab *sep;
797
798
	for (sep = servtab; sep; sep = sep->se_next) {
799
		if (sep->se_fd == -1)
800
			continue;
801
802
		switch (sep->se_family) {
803
		case AF_UNIX:
804
			(void)unlink(sep->se_service);
805
			break;
806
		case AF_INET:
807
		case AF_INET6:
808
			if (sep->se_wait == 1 && isrpcservice(sep))
809
				unregister_rpc(sep);
810
			break;
811
		}
812
		(void)close(sep->se_fd);
813
	}
814
	exit(0);
815
}
816
817
void
818
setup(struct servtab *sep)
819
{
820
	int on = 1;
821
	int r;
822
	mode_t mask = 0;
823
824
	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
825
		syslog(LOG_ERR, "%s/%s: socket: %m",
826
		    sep->se_service, sep->se_proto);
827
		return;
828
	}
829
#define	turnon(fd, opt) \
830
setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on))
831
	if (strncmp(sep->se_proto, "tcp", 3) == 0 && debug &&
832
	    turnon(sep->se_fd, SO_DEBUG) < 0)
833
		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
834
	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
835
		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
836
#undef turnon
837
	if (isrpcservice(sep)) {
838
		struct passwd *pwd;
839
840
		/*
841
		 * for RPC services, attempt to use a reserved port
842
		 * if they are going to be running as root.
843
		 *
844
		 * Also, zero out the port for all RPC services; let bind()
845
		 * find one.
846
		 */
847
		sep->se_ctrladdr_in.sin_port = 0;
848
		if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
849
		    pwd->pw_uid == 0 && uid == 0)
850
			r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
851
		else {
852
			r = bind(sep->se_fd, &sep->se_ctrladdr,
853
			    sep->se_ctrladdr_size);
854
			if (r == 0) {
855
				socklen_t len = sep->se_ctrladdr_size;
856
				int saveerrno = errno;
857
858
				/* update se_ctrladdr_in.sin_port */
859
				r = getsockname(sep->se_fd, &sep->se_ctrladdr,
860
				    &len);
861
				if (r <= 0)
862
					errno = saveerrno;
863
			}
864
		}
865
	} else {
866
		if (sep->se_family == AF_UNIX)
867
			mask = umask(0111);
868
		r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
869
		if (sep->se_family == AF_UNIX)
870
			umask(mask);
871
	}
872
	if (r < 0) {
873
		syslog(LOG_ERR, "%s/%s: bind: %m",
874
		    sep->se_service, sep->se_proto);
875
		(void) close(sep->se_fd);
876
		sep->se_fd = -1;
877
		if (!timingout) {
878
			timingout = 1;
879
			alarm(RETRYTIME);
880
		}
881
		return;
882
	}
883
	if (sep->se_socktype == SOCK_STREAM)
884
		listen(sep->se_fd, 10);
885
886
	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
887
		event_set(&sep->se_event, sep->se_fd, EV_READ|EV_PERSIST,
888
		    gettcp, sep);
889
	} else {
890
		event_set(&sep->se_event, sep->se_fd, EV_READ|EV_PERSIST,
891
		    spawn, sep);
892
	}
893
894
	event_add(&sep->se_event, NULL);
895
896
	if (sep->se_fd > maxsock) {
897
		maxsock = sep->se_fd;
898
		if (maxsock > rlim_nofile_cur - FD_MARGIN)
899
			bump_nofile();
900
	}
901
}
902
903
void
904
register_rpc(struct servtab *sep)
905
{
906
	socklen_t n;
907
	struct sockaddr_in sin;
908
	struct protoent *pp;
909
910
	if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
911
		syslog(LOG_ERR, "%s: getproto: %m",
912
		    sep->se_proto);
913
		return;
914
	}
915
	n = sizeof sin;
916
	if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
917
		syslog(LOG_ERR, "%s/%s: getsockname: %m",
918
		    sep->se_service, sep->se_proto);
919
		return;
920
	}
921
922
	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
923
		if (debug)
924
			fprintf(stderr, "pmap_set: %u %u %u %u\n",
925
			    sep->se_rpcprog, n, pp->p_proto,
926
			    ntohs(sin.sin_port));
927
		(void)pmap_unset(sep->se_rpcprog, n);
928
		if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
929
			syslog(LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
930
			    sep->se_service, sep->se_proto,
931
			    sep->se_rpcprog, n, pp->p_proto,
932
			    ntohs(sin.sin_port));
933
	}
934
}
935
936
void
937
unregister_rpc(struct servtab *sep)
938
{
939
	int n;
940
941
	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
942
		if (debug)
943
			fprintf(stderr, "pmap_unset(%u, %u)\n",
944
			    sep->se_rpcprog, n);
945
		if (!pmap_unset(sep->se_rpcprog, n))
946
			syslog(LOG_ERR, "pmap_unset(%u, %u)",
947
			    sep->se_rpcprog, n);
948
	}
949
}
950
951
952
struct servtab *
953
enter(struct servtab *cp)
954
{
955
	struct servtab *sep;
956
957
	sep = malloc(sizeof (*sep));
958
	if (sep == NULL) {
959
		syslog(LOG_ERR, "Out of memory.");
960
		exit(1);
961
	}
962
	*sep = *cp;
963
	sep->se_fd = -1;
964
	sep->se_rpcprog = -1;
965
	sep->se_next = servtab;
966
	servtab = sep;
967
	return (sep);
968
}
969
970
int
971
matchconf(struct servtab *old, struct servtab *new)
972
{
973
	if (strcmp(old->se_service, new->se_service) != 0)
974
		return (0);
975
976
	if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
977
		return (0);
978
979
	if (strcmp(old->se_proto, new->se_proto) != 0)
980
		return (0);
981
982
	/*
983
	 * If the new servtab is bound to a specific address, check that the
984
	 * old servtab is bound to the same entry. If the new service is not
985
	 * bound to a specific address then the check of se_hostaddr above
986
	 * is sufficient.
987
	 */
988
989
	if (old->se_family == AF_INET && new->se_family == AF_INET &&
990
	    bcmp(&old->se_ctrladdr_in.sin_addr,
991
	    &new->se_ctrladdr_in.sin_addr,
992
	    sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
993
		return (0);
994
995
	if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
996
	    bcmp(&old->se_ctrladdr_in6.sin6_addr,
997
	    &new->se_ctrladdr_in6.sin6_addr,
998
	    sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
999
		return (0);
1000
	if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
1001
	    old->se_ctrladdr_in6.sin6_scope_id !=
1002
	    new->se_ctrladdr_in6.sin6_scope_id)
1003
		return (0);
1004
1005
	return (1);
1006
}
1007
1008
FILE		*fconfig = NULL;
1009
char		line[1024];
1010
char		*defhost;
1011
char		*skip(char **, int);
1012
char		*nextline(FILE *);
1013
char		*newstr(char *);
1014
struct servtab	*dupconfig(struct servtab *);
1015
1016
int
1017
setconfig(void)
1018
{
1019
	free(defhost);
1020
	defhost = newstr("*");
1021
	if (fconfig != NULL) {
1022
		fseek(fconfig, 0L, SEEK_SET);
1023
		return (1);
1024
	}
1025
	fconfig = fopen(CONFIG, "r");
1026
	return (fconfig != NULL);
1027
}
1028
1029
void
1030
endconfig(void)
1031
{
1032
	if (fconfig) {
1033
		(void) fclose(fconfig);
1034
		fconfig = NULL;
1035
	}
1036
	if (defhost) {
1037
		free(defhost);
1038
		defhost = 0;
1039
	}
1040
}
1041
1042
struct servtab *
1043
getconfigent(void)
1044
{
1045
	struct servtab *sep, *tsep;
1046
	char *arg, *cp, *hostdelim, *s;
1047
	int argc;
1048
1049
	sep = calloc(1, sizeof(struct servtab));
1050
	if (sep == NULL) {
1051
		syslog(LOG_ERR, "calloc: %m");
1052
		exit(1);
1053
	}
1054
more:
1055
	freeconfig(sep);
1056
1057
	while ((cp = nextline(fconfig)) && *cp == '#')
1058
		;
1059
	if (cp == NULL) {
1060
		free(sep);
1061
		return (NULL);
1062
	}
1063
1064
	memset(sep, 0, sizeof *sep);
1065
	arg = skip(&cp, 0);
1066
	if (arg == NULL) {
1067
		/* A blank line. */
1068
		goto more;
1069
	}
1070
1071
	/* Check for a host name. */
1072
	hostdelim = strrchr(arg, ':');
1073
	if (hostdelim) {
1074
		*hostdelim = '\0';
1075
		if (arg[0] == '[' && hostdelim > arg && hostdelim[-1] == ']') {
1076
			hostdelim[-1] = '\0';
1077
			sep->se_hostaddr = newstr(arg + 1);
1078
		} else if (hostdelim == arg)
1079
			sep->se_hostaddr = newstr("*");
1080
		else
1081
			sep->se_hostaddr = newstr(arg);
1082
		arg = hostdelim + 1;
1083
		/*
1084
		 * If the line is of the form `host:', then just change the
1085
		 * default host for the following lines.
1086
		 */
1087
		if (*arg == '\0') {
1088
			arg = skip(&cp, 0);
1089
			if (cp == NULL) {
1090
				free(defhost);
1091
				defhost = newstr(sep->se_hostaddr);
1092
				goto more;
1093
			}
1094
		}
1095
	} else
1096
		sep->se_hostaddr = newstr(defhost);
1097
1098
	sep->se_service = newstr(arg);
1099
	if ((arg = skip(&cp, 1)) == NULL)
1100
		goto more;
1101
1102
	if (strcmp(arg, "stream") == 0)
1103
		sep->se_socktype = SOCK_STREAM;
1104
	else if (strcmp(arg, "dgram") == 0)
1105
		sep->se_socktype = SOCK_DGRAM;
1106
	else if (strcmp(arg, "rdm") == 0)
1107
		sep->se_socktype = SOCK_RDM;
1108
	else if (strcmp(arg, "seqpacket") == 0)
1109
		sep->se_socktype = SOCK_SEQPACKET;
1110
	else if (strcmp(arg, "raw") == 0)
1111
		sep->se_socktype = SOCK_RAW;
1112
	else
1113
		sep->se_socktype = -1;
1114
1115
	if ((arg = skip(&cp, 1)) == NULL)
1116
		goto more;
1117
1118
	sep->se_proto = newstr(arg);
1119
1120
	if (strcmp(sep->se_proto, "unix") == 0) {
1121
		sep->se_family = AF_UNIX;
1122
	} else {
1123
		int s;
1124
1125
		sep->se_family = AF_INET;
1126
		if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
1127
			sep->se_family = AF_INET6;
1128
1129
		/* check if the family is supported */
1130
		s = socket(sep->se_family, SOCK_DGRAM, 0);
1131
		if (s < 0) {
1132
			syslog(LOG_WARNING, "%s/%s: %s: the address family is "
1133
			    "not supported by the kernel", sep->se_service,
1134
			    sep->se_proto, sep->se_hostaddr);
1135
			goto more;
1136
		}
1137
		close(s);
1138
1139
		if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1140
			char *cp, *ccp;
1141
			long l;
1142
1143
			cp = strchr(sep->se_service, '/');
1144
			if (cp == 0) {
1145
				syslog(LOG_ERR, "%s: no rpc version",
1146
				    sep->se_service);
1147
				goto more;
1148
			}
1149
			*cp++ = '\0';
1150
			l = strtol(cp, &ccp, 0);
1151
			if (ccp == cp || l < 0 || l > INT_MAX) {
1152
		badafterall:
1153
				syslog(LOG_ERR, "%s/%s: bad rpc version",
1154
				    sep->se_service, cp);
1155
				goto more;
1156
			}
1157
			sep->se_rpcversl = sep->se_rpcversh = l;
1158
			if (*ccp == '-') {
1159
				cp = ccp + 1;
1160
				l = strtol(cp, &ccp, 0);
1161
				if (ccp == cp || l < 0 || l > INT_MAX ||
1162
				    l < sep->se_rpcversl || *ccp)
1163
					goto badafterall;
1164
				sep->se_rpcversh = l;
1165
			} else if (*ccp != '\0')
1166
				goto badafterall;
1167
		}
1168
	}
1169
	arg = skip(&cp, 1);
1170
	if (arg == NULL)
1171
		goto more;
1172
1173
	s = strchr(arg, '.');
1174
	if (s) {
1175
		char *p;
1176
1177
		*s++ = '\0';
1178
		sep->se_max = strtoul(s, &p, 0);
1179
		if (sep->se_max < 1 || *p) {
1180
			syslog(LOG_ERR,
1181
			    "%s: illegal max field \"%s\", setting to %d",
1182
			    sep->se_service, s, toomany);
1183
			sep->se_max = toomany;
1184
		}
1185
	} else
1186
		sep->se_max = toomany;
1187
1188
	sep->se_wait = strcmp(arg, "wait") == 0;
1189
	if ((arg = skip(&cp, 1)) == NULL)
1190
		goto more;
1191
	sep->se_user = newstr(arg);
1192
	arg = strchr(sep->se_user, '.');
1193
	if (arg == NULL)
1194
		arg = strchr(sep->se_user, ':');
1195
	if (arg) {
1196
		*arg++ = '\0';
1197
		sep->se_group = newstr(arg);
1198
	}
1199
	if ((arg = skip(&cp, 1)) == NULL)
1200
		goto more;
1201
1202
	sep->se_server = newstr(arg);
1203
	if (strcmp(sep->se_server, "internal") == 0) {
1204
		struct biltin *bi;
1205
1206
		for (bi = biltins; bi->bi_service; bi++)
1207
			if (bi->bi_socktype == sep->se_socktype &&
1208
			    strcmp(bi->bi_service, sep->se_service) == 0)
1209
				break;
1210
		if (bi->bi_service == 0) {
1211
			syslog(LOG_ERR, "internal service %s unknown",
1212
			    sep->se_service);
1213
			goto more;
1214
		}
1215
		sep->se_bi = bi;
1216
		sep->se_wait = bi->bi_wait;
1217
	} else
1218
		sep->se_bi = NULL;
1219
	argc = 0;
1220
	for (arg = skip(&cp, 0); cp; arg = skip(&cp, 0)) {
1221
		if (argc < MAXARGV)
1222
			sep->se_argv[argc++] = newstr(arg);
1223
	}
1224
	if (argc == 0 && sep->se_bi == NULL) {
1225
		if ((arg = strrchr(sep->se_server, '/')) != NULL)
1226
			arg++;
1227
		else
1228
			arg = sep->se_server;
1229
		sep->se_argv[argc++] = newstr(arg);
1230
	}
1231
	while (argc <= MAXARGV)
1232
		sep->se_argv[argc++] = NULL;
1233
1234
	/*
1235
	 * Resolve each hostname in the se_hostaddr list (if any)
1236
	 * and create a new entry for each resolved address.
1237
	 */
1238
	if (sep->se_hostaddr != NULL && strcmp(sep->se_proto, "unix") != 0) {
1239
		struct addrinfo hints, *res0, *res;
1240
		char *host, *hostlist0, *hostlist, *port;
1241
		int error;
1242
1243
		hostlist = hostlist0 = sep->se_hostaddr;
1244
		sep->se_hostaddr = NULL;
1245
		sep->se_checked = -1;
1246
		while ((host = strsep(&hostlist, ",")) != NULL) {
1247
			if (*host == '\0')
1248
				continue;
1249
1250
			memset(&hints, 0, sizeof(hints));
1251
			hints.ai_family = sep->se_family;
1252
			hints.ai_socktype = sep->se_socktype;
1253
			hints.ai_flags = AI_PASSIVE;
1254
			port = "0";
1255
			error = getaddrinfo(strcmp(host, "*") ? host : NULL,
1256
			    port, &hints, &res0);
1257
			if (error) {
1258
				syslog(LOG_ERR, "%s/%s: %s: %s",
1259
				    sep->se_service, sep->se_proto,
1260
				    host, gai_strerror(error));
1261
				continue;
1262
			}
1263
			for (res = res0; res; res = res->ai_next) {
1264
				if (res->ai_addrlen >
1265
				    sizeof(sep->se_ctrladdr_storage))
1266
					continue;
1267
				/*
1268
				 * If sep is unused, store host in there.
1269
				 * Otherwise, dup a new entry and prepend it.
1270
				 */
1271
				if (sep->se_checked == -1) {
1272
					sep->se_checked = 0;
1273
				} else {
1274
					tsep = dupconfig(sep);
1275
					tsep->se_next = sep;
1276
					sep = tsep;
1277
				}
1278
				sep->se_hostaddr = newstr(host);
1279
				memcpy(&sep->se_ctrladdr_storage,
1280
				    res->ai_addr, res->ai_addrlen);
1281
				sep->se_ctrladdr_size = res->ai_addrlen;
1282
			}
1283
			freeaddrinfo(res0);
1284
		}
1285
		free(hostlist0);
1286
		if (sep->se_checked == -1)
1287
			goto more;	/* no resolvable names/addresses */
1288
	}
1289
1290
	return (sep);
1291
}
1292
1293
void
1294
freeconfig(struct servtab *cp)
1295
{
1296
	int i;
1297
1298
	free(cp->se_hostaddr);
1299
	cp->se_hostaddr = NULL;
1300
	free(cp->se_service);
1301
	cp->se_service = NULL;
1302
	free(cp->se_proto);
1303
	cp->se_proto = NULL;
1304
	free(cp->se_user);
1305
	cp->se_user = NULL;
1306
	free(cp->se_group);
1307
	cp->se_group = NULL;
1308
	free(cp->se_server);
1309
	cp->se_server = NULL;
1310
	for (i = 0; i < MAXARGV; i++) {
1311
		free(cp->se_argv[i]);
1312
		cp->se_argv[i] = NULL;
1313
	}
1314
}
1315
1316
char *
1317
skip(char **cpp, int report)
1318
{
1319
	char *cp = *cpp;
1320
	char *start;
1321
1322
erp:
1323
	if (*cpp == NULL) {
1324
		if (report)
1325
			syslog(LOG_ERR, "syntax error in inetd config file");
1326
		return (NULL);
1327
	}
1328
1329
again:
1330
	while (*cp == ' ' || *cp == '\t')
1331
		cp++;
1332
	if (*cp == '\0') {
1333
		int c;
1334
1335
		c = getc(fconfig);
1336
		(void) ungetc(c, fconfig);
1337
		if (c == ' ' || c == '\t')
1338
			if ((cp = nextline(fconfig)))
1339
				goto again;
1340
		*cpp = NULL;
1341
		goto erp;
1342
	}
1343
	start = cp;
1344
	while (*cp && *cp != ' ' && *cp != '\t')
1345
		cp++;
1346
	if (*cp != '\0')
1347
		*cp++ = '\0';
1348
	if ((*cpp = cp) == NULL)
1349
		goto erp;
1350
1351
	return (start);
1352
}
1353
1354
char *
1355
nextline(FILE *fd)
1356
{
1357
	if (fgets(line, sizeof (line), fd) == NULL)
1358
		return (NULL);
1359
	line[strcspn(line, "\n")] = '\0';
1360
	return (line);
1361
}
1362
1363
char *
1364
newstr(char *cp)
1365
{
1366
	if ((cp = strdup(cp ? cp : "")))
1367
		return(cp);
1368
	syslog(LOG_ERR, "strdup: %m");
1369
	exit(1);
1370
}
1371
1372
struct servtab *
1373
dupconfig(struct servtab *sep)
1374
{
1375
	struct servtab *newtab;
1376
	int argc;
1377
1378
	newtab = calloc(1, sizeof(struct servtab));
1379
1380
	if (newtab == NULL) {
1381
		syslog(LOG_ERR, "calloc: %m");
1382
		exit(1);
1383
	}
1384
1385
	newtab->se_service = sep->se_service ? newstr(sep->se_service) : NULL;
1386
	newtab->se_socktype = sep->se_socktype;
1387
	newtab->se_family = sep->se_family;
1388
	newtab->se_proto = sep->se_proto ? newstr(sep->se_proto) : NULL;
1389
	newtab->se_rpcprog = sep->se_rpcprog;
1390
	newtab->se_rpcversl = sep->se_rpcversl;
1391
	newtab->se_rpcversh = sep->se_rpcversh;
1392
	newtab->se_wait = sep->se_wait;
1393
	newtab->se_user = sep->se_user ? newstr(sep->se_user) : NULL;
1394
	newtab->se_group = sep->se_group ? newstr(sep->se_group) : NULL;
1395
	newtab->se_bi = sep->se_bi;
1396
	newtab->se_server = sep->se_server ? newstr(sep->se_server) : 0;
1397
1398
	for (argc = 0; argc <= MAXARGV; argc++)
1399
		newtab->se_argv[argc] = sep->se_argv[argc] ?
1400
		    newstr(sep->se_argv[argc]) : NULL;
1401
	newtab->se_max = sep->se_max;
1402
1403
	return (newtab);
1404
}
1405
1406
void
1407
inetd_setproctitle(char *a, int s)
1408
{
1409
	socklen_t size;
1410
	struct sockaddr_storage ss;
1411
	char hbuf[NI_MAXHOST];
1412
1413
	size = sizeof(ss);
1414
	if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
1415
		if (getnameinfo((struct sockaddr *)&ss, size, hbuf,
1416
		    sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0)
1417
			setproctitle("-%s [%s]", a, hbuf);
1418
		else
1419
			setproctitle("-%s [?]", a);
1420
	} else
1421
		setproctitle("-%s", a);
1422
}
1423
1424
int
1425
bump_nofile(void)
1426
{
1427
#define FD_CHUNK	32
1428
1429
	struct rlimit rl;
1430
1431
	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1432
		syslog(LOG_ERR, "getrlimit: %m");
1433
		return -1;
1434
	}
1435
	rl.rlim_cur = MINIMUM(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1436
	rl.rlim_cur = MINIMUM(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
1437
	if (rl.rlim_cur <= rlim_nofile_cur) {
1438
		syslog(LOG_ERR,
1439
		    "bump_nofile: cannot extend file limit, max = %d",
1440
		    (int)rl.rlim_cur);
1441
		return -1;
1442
	}
1443
1444
	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1445
		syslog(LOG_ERR, "setrlimit: %m");
1446
		return -1;
1447
	}
1448
1449
	rlim_nofile_cur = rl.rlim_cur;
1450
	return 0;
1451
}
1452
1453
/*
1454
 * Internet services provided internally by inetd:
1455
 */
1456
#define	BUFSIZE	4096
1457
1458
void
1459
echo_stream(int s, struct servtab *sep)
1460
{
1461
	char buffer[BUFSIZE];
1462
	int i;
1463
1464
	inetd_setproctitle(sep->se_service, s);
1465
	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1466
	    write(s, buffer, i) > 0)
1467
		;
1468
	exit(0);
1469
}
1470
1471
void
1472
echo_dg(int s, struct servtab *sep)
1473
{
1474
	char buffer[BUFSIZE];
1475
	int i;
1476
	socklen_t size;
1477
	struct sockaddr_storage ss;
1478
1479
	size = sizeof(ss);
1480
	if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
1481
	    (struct sockaddr *)&ss, &size)) < 0)
1482
		return;
1483
	if (dg_badinput((struct sockaddr *)&ss))
1484
		return;
1485
	(void) sendto(s, buffer, i, 0, (struct sockaddr *)&ss, size);
1486
}
1487
1488
void
1489
discard_stream(int s, struct servtab *sep)
1490
{
1491
	char buffer[BUFSIZE];
1492
1493
	inetd_setproctitle(sep->se_service, s);
1494
	while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1495
	    errno == EINTR)
1496
		;
1497
	exit(0);
1498
}
1499
1500
void
1501
discard_dg(int s, struct servtab *sep)
1502
{
1503
	char buffer[BUFSIZE];
1504
1505
	(void) read(s, buffer, sizeof(buffer));
1506
}
1507
1508
#include <ctype.h>
1509
#define LINESIZ 72
1510
char ring[128];
1511
char *endring;
1512
1513
void
1514
initring(void)
1515
{
1516
	int i;
1517
1518
	endring = ring;
1519
1520
	for (i = 0; i <= sizeof ring; ++i)
1521
		if (isprint((unsigned char)i))
1522
			*endring++ = i;
1523
}
1524
1525
void
1526
chargen_stream(int s, struct servtab *sep)
1527
{
1528
	char *rs;
1529
	int len;
1530
	char text[LINESIZ+2];
1531
1532
	inetd_setproctitle(sep->se_service, s);
1533
1534
	if (!endring) {
1535
		initring();
1536
		rs = ring;
1537
	}
1538
1539
	text[LINESIZ] = '\r';
1540
	text[LINESIZ + 1] = '\n';
1541
	for (rs = ring;;) {
1542
		if ((len = endring - rs) >= LINESIZ)
1543
			memmove(text, rs, LINESIZ);
1544
		else {
1545
			memmove(text, rs, len);
1546
			memmove(text + len, ring, LINESIZ - len);
1547
		}
1548
		if (++rs == endring)
1549
			rs = ring;
1550
		if (write(s, text, sizeof(text)) != sizeof(text))
1551
			break;
1552
	}
1553
	exit(0);
1554
}
1555
1556
void
1557
chargen_dg(int s, struct servtab *sep)
1558
{
1559
	struct sockaddr_storage ss;
1560
	static char *rs;
1561
	int len;
1562
	socklen_t size;
1563
	char text[LINESIZ+2];
1564
1565
	if (endring == 0) {
1566
		initring();
1567
		rs = ring;
1568
	}
1569
1570
	size = sizeof(ss);
1571
	if (recvfrom(s, text, sizeof(text), 0, (struct sockaddr *)&ss,
1572
	    &size) < 0)
1573
		return;
1574
	if (dg_badinput((struct sockaddr *)&ss))
1575
		return;
1576
1577
	if ((len = endring - rs) >= LINESIZ)
1578
		memmove(text, rs, LINESIZ);
1579
	else {
1580
		memmove(text, rs, len);
1581
		memmove(text + len, ring, LINESIZ - len);
1582
	}
1583
	if (++rs == endring)
1584
		rs = ring;
1585
	text[LINESIZ] = '\r';
1586
	text[LINESIZ + 1] = '\n';
1587
	(void) sendto(s, text, sizeof(text), 0, (struct sockaddr *)&ss, size);
1588
}
1589
1590
/*
1591
 * Return a machine readable date and time, in the form of the
1592
 * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1593
 * returns the number of seconds since midnight, Jan 1, 1970,
1594
 * we must add 2208988800 seconds to this figure to make up for
1595
 * some seventy years Bell Labs was asleep.
1596
 */
1597
u_int32_t
1598
machtime(void)
1599
{
1600
	struct timeval tv;
1601
1602
	if (gettimeofday(&tv, NULL) < 0)
1603
		return (0L);
1604
1605
	return (htonl((u_int32_t)tv.tv_sec + 2208988800UL));
1606
}
1607
1608
void
1609
machtime_stream(int s, struct servtab *sep)
1610
{
1611
	u_int32_t result;
1612
1613
	result = machtime();
1614
	(void) write(s, &result, sizeof(result));
1615
}
1616
1617
void
1618
machtime_dg(int s, struct servtab *sep)
1619
{
1620
	u_int32_t result;
1621
	struct sockaddr_storage ss;
1622
	socklen_t size;
1623
1624
	size = sizeof(ss);
1625
	if (recvfrom(s, &result, sizeof(result), 0,
1626
	    (struct sockaddr *)&ss, &size) < 0)
1627
		return;
1628
	if (dg_badinput((struct sockaddr *)&ss))
1629
		return;
1630
	result = machtime();
1631
	(void) sendto(s, &result, sizeof(result), 0,
1632
	    (struct sockaddr *)&ss, size);
1633
}
1634
1635
/* Return human-readable time of day */
1636
void
1637
daytime_stream(int s, struct servtab *sep)
1638
{
1639
	char buffer[256];
1640
	time_t clock;
1641
1642
	clock = time(NULL);
1643
1644
	(void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1645
	(void) write(s, buffer, strlen(buffer));
1646
}
1647
1648
/* Return human-readable time of day */
1649
void
1650
daytime_dg(int s, struct servtab *sep)
1651
{
1652
	char buffer[256];
1653
	time_t clock;
1654
	struct sockaddr_storage ss;
1655
	socklen_t size;
1656
1657
	clock = time(NULL);
1658
1659
	size = sizeof(ss);
1660
	if (recvfrom(s, buffer, sizeof(buffer), 0, (struct sockaddr *)&ss,
1661
	    &size) < 0)
1662
		return;
1663
	if (dg_badinput((struct sockaddr *)&ss))
1664
		return;
1665
	(void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1666
	(void) sendto(s, buffer, strlen(buffer), 0, (struct sockaddr *)&ss,
1667
	    size);
1668
}
1669
1670
/*
1671
 * print_service:
1672
 *	Dump relevant information to stderr
1673
 */
1674
void
1675
print_service(char *action, struct servtab *sep)
1676
{
1677
	if (strcmp(sep->se_hostaddr, "*") == 0)
1678
		fprintf(stderr, "%s: %s ", action, sep->se_service);
1679
	else
1680
		fprintf(stderr, "%s: %s:%s ", action, sep->se_hostaddr,
1681
		    sep->se_service);
1682
1683
	if (isrpcservice(sep))
1684
		fprintf(stderr, "rpcprog=%d, rpcvers=%d/%d, proto=%s,",
1685
		    sep->se_rpcprog, sep->se_rpcversh,
1686
		    sep->se_rpcversl, sep->se_proto);
1687
	else
1688
		fprintf(stderr, "proto=%s,", sep->se_proto);
1689
1690
	fprintf(stderr,
1691
	    " wait.max=%d.%d user:group=%s:%s builtin=%lx server=%s\n",
1692
	    sep->se_wait, sep->se_max, sep->se_user,
1693
	    sep->se_group ? sep->se_group : "wheel",
1694
	    (long)sep->se_bi, sep->se_server);
1695
}
1696
1697
void
1698
spawn(int ctrl, short events, void *xsep)
1699
{
1700
	struct servtab *sep = xsep;
1701
	struct passwd *pwd;
1702
	int tmpint, dofork;
1703
	struct group *grp = NULL;
1704
	char buf[50];
1705
	pid_t pid;
1706
1707
	if (debug)
1708
		fprintf(stderr, "someone wants %s\n", sep->se_service);
1709
1710
	pid = 0;
1711
	dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
1712
	if (dofork) {
1713
		if (sep->se_count++ == 0)
1714
		    (void)gettimeofday(&sep->se_time, NULL);
1715
		else if (sep->se_count >= sep->se_max) {
1716
			struct timeval now;
1717
1718
			(void)gettimeofday(&now, NULL);
1719
			if (now.tv_sec - sep->se_time.tv_sec >
1720
			    CNT_INTVL) {
1721
				sep->se_time = now;
1722
				sep->se_count = 1;
1723
			} else {
1724
				if (!sep->se_wait &&
1725
				    sep->se_socktype == SOCK_STREAM)
1726
					close(ctrl);
1727
				if (sep->se_family == AF_INET &&
1728
				    ntohs(sep->se_ctrladdr_in.sin_port) >=
1729
				    IPPORT_RESERVED) {
1730
					/*
1731
					 * Cannot close it -- there are
1732
					 * thieves on the system.
1733
					 * Simply ignore the connection.
1734
					 */
1735
					--sep->se_count;
1736
					return;
1737
				}
1738
				syslog(LOG_ERR,
1739
				    "%s/%s server failing (looping), service terminated",
1740
				    sep->se_service, sep->se_proto);
1741
				if (!sep->se_wait &&
1742
				    sep->se_socktype == SOCK_STREAM)
1743
					close(ctrl);
1744
				event_del(&sep->se_event);
1745
				(void) close(sep->se_fd);
1746
1747
				sep->se_fd = -1;
1748
				sep->se_count = 0;
1749
				if (!timingout) {
1750
					timingout = 1;
1751
					alarm(RETRYTIME);
1752
				}
1753
				return;
1754
			}
1755
		}
1756
		pid = fork();
1757
	}
1758
	if (pid < 0) {
1759
		syslog(LOG_ERR, "fork: %m");
1760
		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1761
			close(ctrl);
1762
		sleep(1);
1763
		return;
1764
	}
1765
1766
	if (pledge("stdio rpath getpw inet proc exec id flock cpath wpath", NULL) == -1)
1767
		err(1, "pledge");
1768
1769
	if (pid && sep->se_wait) {
1770
		sep->se_wait = pid;
1771
		event_del(&sep->se_event);
1772
	}
1773
	if (pid == 0) {
1774
		if (sep->se_bi)
1775
			(*sep->se_bi->bi_fn)(ctrl, sep);
1776
		else {
1777
			if ((pwd = getpwnam(sep->se_user)) == NULL) {
1778
				syslog(LOG_ERR,
1779
				    "getpwnam: %s: No such user",
1780
				    sep->se_user);
1781
				if (sep->se_socktype != SOCK_STREAM)
1782
					recv(0, buf, sizeof (buf), 0);
1783
				exit(1);
1784
			}
1785
			if (setsid() <0)
1786
				syslog(LOG_ERR, "%s: setsid: %m",
1787
				    sep->se_service);
1788
			if (sep->se_group &&
1789
			    (grp = getgrnam(sep->se_group)) == NULL) {
1790
				syslog(LOG_ERR,
1791
				    "getgrnam: %s: No such group",
1792
				    sep->se_group);
1793
				if (sep->se_socktype != SOCK_STREAM)
1794
					recv(0, buf, sizeof (buf), 0);
1795
				exit(1);
1796
			}
1797
			if (uid != 0) {
1798
				/* a user running private inetd */
1799
				if (uid != pwd->pw_uid)
1800
					exit(1);
1801
			} else {
1802
				tmpint = LOGIN_SETALL &
1803
				    ~(LOGIN_SETGROUP|LOGIN_SETLOGIN);
1804
				if (pwd->pw_uid)
1805
					tmpint |= LOGIN_SETGROUP|LOGIN_SETLOGIN;
1806
				if (sep->se_group) {
1807
					pwd->pw_gid = grp->gr_gid;
1808
					tmpint |= LOGIN_SETGROUP;
1809
				}
1810
				if (setusercontext(NULL, pwd, pwd->pw_uid,
1811
				    tmpint) < 0) {
1812
					syslog(LOG_ERR,
1813
					    "%s/%s: setusercontext: %m",
1814
					    sep->se_service, sep->se_proto);
1815
					exit(1);
1816
				}
1817
			}
1818
			if (debug)
1819
				fprintf(stderr, "%ld execv %s\n",
1820
				    (long)getpid(), sep->se_server);
1821
			if (ctrl != STDIN_FILENO) {
1822
				dup2(ctrl, STDIN_FILENO);
1823
				close(ctrl);
1824
			}
1825
			dup2(STDIN_FILENO, STDOUT_FILENO);
1826
			dup2(STDIN_FILENO, STDERR_FILENO);
1827
			closelog();
1828
			closefrom(3);
1829
			signal(SIGPIPE, SIG_DFL);
1830
			execv(sep->se_server, sep->se_argv);
1831
			if (sep->se_socktype != SOCK_STREAM)
1832
				recv(0, buf, sizeof (buf), 0);
1833
			syslog(LOG_ERR, "execv %s: %m", sep->se_server);
1834
			exit(1);
1835
		}
1836
	}
1837
	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1838
		close(ctrl);
1839
}