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

Line Branch Exec Source
1
/*	$OpenBSD: inetd.c,v 1.158 2017/10/04 23:56:48 jca 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
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
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
		if (IN_MULTICAST(in.s_addr))
448
			goto bad;
449
		switch ((in.s_addr & 0xff000000) >> 24) {
450
		case 0: case 127: case 255:
451
			goto bad;
452
		}
453
		if (dg_broadcast(&in))
454
			goto bad;
455
		break;
456
	case AF_INET6:
457
		in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
458
		port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
459
		if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
460
			goto bad;
461
		/*
462
		 * OpenBSD does not support IPv4-mapped and
463
		 * IPv4-compatible IPv6 addresses (RFC2553). We should
464
		 * drop the packet.
465
		 */
466
		if (IN6_IS_ADDR_V4MAPPED(in6) || IN6_IS_ADDR_V4COMPAT(in6))
467
			goto bad;
468
		break;
469
	default:
470
		/* Unsupported AF */
471
		goto bad;
472
	}
473
474
	if (port < IPPORT_RESERVED || port == NFS_PORT)
475
		goto bad;
476
477
	return (0);
478
479
bad:
480
	return (1);
481
}
482
483
int
484
dg_broadcast(struct in_addr *in)
485
{
486
	struct ifaddrs *ifa, *ifap;
487
	struct sockaddr_in *sin;
488
489
	if (getifaddrs(&ifap) < 0)
490
		return (0);
491
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
492
		if (ifa->ifa_addr->sa_family != AF_INET ||
493
		    (ifa->ifa_flags & IFF_BROADCAST) == 0)
494
			continue;
495
		sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
496
		if (sin->sin_addr.s_addr == in->s_addr) {
497
			freeifaddrs(ifap);
498
			return (1);
499
		}
500
	}
501
	freeifaddrs(ifap);
502
	return (0);
503
}
504
505
void
506
reap(int sig, short event, void *arg)
507
{
508
	struct servtab *sep;
509
	int status;
510
	pid_t pid;
511
512
	if (debug)
513
		fprintf(stderr, "reaping asked for\n");
514
515
	for (;;) {
516
		if ((pid = wait3(&status, WNOHANG, NULL)) <= 0) {
517
			if (pid == -1 && errno == EINTR)
518
				continue;
519
			break;
520
		}
521
		if (debug)
522
			fprintf(stderr, "%ld reaped, status %x\n",
523
			    (long)pid, status);
524
		for (sep = servtab; sep; sep = sep->se_next)
525
			if (sep->se_wait == pid) {
526
				if (WIFEXITED(status) && WEXITSTATUS(status))
527
					syslog(LOG_WARNING,
528
					    "%s: exit status %d",
529
					    sep->se_server, WEXITSTATUS(status));
530
				else if (WIFSIGNALED(status))
531
					syslog(LOG_WARNING,
532
					    "%s: exit signal %d",
533
					    sep->se_server, WTERMSIG(status));
534
				sep->se_wait = 1;
535
				event_add(&sep->se_event, NULL);
536
				if (debug)
537
					fprintf(stderr, "restored %s, fd %d\n",
538
					    sep->se_service, sep->se_fd);
539
			}
540
	}
541
}
542
543
void
544
config(int sig, short event, void *arg)
545
{
546
	struct servtab *sep, *cp, **sepp;
547
	int add;
548
	char protoname[11];
549
550
	if (!setconfig()) {
551
		syslog(LOG_ERR, "%s: %m", CONFIG);
552
		exit(1);
553
	}
554
	for (sep = servtab; sep; sep = sep->se_next)
555
		sep->se_checked = 0;
556
	cp = getconfigent();
557
	while (cp != NULL) {
558
		for (sep = servtab; sep; sep = sep->se_next)
559
			if (matchconf(sep, cp))
560
				break;
561
		add = 0;
562
		if (sep != NULL) {
563
			int i;
564
565
#define SWAP(type, a, b) {type c=(type)a; a=(type)b; b=(type)c;}
566
567
			/*
568
			 * sep->se_wait may be holding the pid of a daemon
569
			 * that we're waiting for.  If so, don't overwrite
570
			 * it unless the config file explicitly says don't
571
			 * wait.
572
			 */
573
			if (cp->se_bi == 0 &&
574
			    (sep->se_wait == 1 || cp->se_wait == 0))
575
				sep->se_wait = cp->se_wait;
576
			SWAP(int, cp->se_max, sep->se_max);
577
			SWAP(char *, sep->se_user, cp->se_user);
578
			SWAP(char *, sep->se_group, cp->se_group);
579
			SWAP(char *, sep->se_server, cp->se_server);
580
			for (i = 0; i < MAXARGV; i++)
581
				SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
582
#undef SWAP
583
			if (isrpcservice(sep))
584
				unregister_rpc(sep);
585
			sep->se_rpcversl = cp->se_rpcversl;
586
			sep->se_rpcversh = cp->se_rpcversh;
587
			freeconfig(cp);
588
			add = 1;
589
		} else {
590
			sep = enter(cp);
591
		}
592
		sep->se_checked = 1;
593
594
		switch (sep->se_family) {
595
		case AF_UNIX:
596
			if (sep->se_fd != -1)
597
				break;
598
			sep->se_ctrladdr_size =
599
			    strlcpy(sep->se_ctrladdr_un.sun_path,
600
			    sep->se_service,
601
			    sizeof sep->se_ctrladdr_un.sun_path);
602
			if (sep->se_ctrladdr_size >=
603
			    sizeof sep->se_ctrladdr_un.sun_path) {
604
				syslog(LOG_WARNING, "%s/%s: UNIX domain socket "
605
				    "path too long", sep->se_service,
606
				    sep->se_proto);
607
				goto serv_unknown;
608
			}
609
			sep->se_ctrladdr_un.sun_family = AF_UNIX;
610
			sep->se_ctrladdr_size +=
611
			    1 + sizeof sep->se_ctrladdr_un.sun_family;
612
			(void)unlink(sep->se_service);
613
			setup(sep);
614
			break;
615
		case AF_INET:
616
			sep->se_ctrladdr_in.sin_family = AF_INET;
617
			/* se_ctrladdr_in was set in getconfigent */
618
			sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
619
620
			if (isrpcservice(sep)) {
621
				struct rpcent *rp;
622
623
				sep->se_rpcprog = strtonum(sep->se_service,
624
				    1, USHRT_MAX, NULL);
625
				if (sep->se_rpcprog == 0) {
626
					rp = getrpcbyname(sep->se_service);
627
					if (rp == 0) {
628
						syslog(LOG_ERR,
629
						    "%s: unknown rpc service",
630
						    sep->se_service);
631
						goto serv_unknown;
632
					}
633
					sep->se_rpcprog = rp->r_number;
634
				}
635
				if (sep->se_fd == -1)
636
					setup(sep);
637
				if (sep->se_fd != -1)
638
					register_rpc(sep);
639
			} else {
640
				u_short port = htons(strtonum(sep->se_service,
641
				    1, USHRT_MAX, NULL));
642
643
				if (!port) {
644
					(void)strlcpy(protoname, sep->se_proto,
645
					    sizeof(protoname));
646
					if (isdigit((unsigned char)
647
					    protoname[strlen(protoname) - 1]))
648
						protoname[strlen(protoname) - 1] = '\0';
649
					sp = getservbyname(sep->se_service,
650
					    protoname);
651
					if (sp == 0) {
652
						syslog(LOG_ERR,
653
						    "%s/%s: unknown service",
654
						    sep->se_service, sep->se_proto);
655
						goto serv_unknown;
656
					}
657
					port = sp->s_port;
658
				}
659
				if (port != sep->se_ctrladdr_in.sin_port) {
660
					sep->se_ctrladdr_in.sin_port = port;
661
					if (sep->se_fd != -1) {
662
						event_del(&sep->se_event);
663
						(void) close(sep->se_fd);
664
					}
665
					sep->se_fd = -1;
666
				}
667
				if (sep->se_fd == -1)
668
					setup(sep);
669
			}
670
			break;
671
		case AF_INET6:
672
			sep->se_ctrladdr_in6.sin6_family = AF_INET6;
673
			/* se_ctrladdr_in was set in getconfigent */
674
			sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
675
676
			if (isrpcservice(sep)) {
677
				struct rpcent *rp;
678
679
				sep->se_rpcprog = strtonum(sep->se_service,
680
				    1, USHRT_MAX, NULL);
681
				if (sep->se_rpcprog == 0) {
682
					rp = getrpcbyname(sep->se_service);
683
					if (rp == 0) {
684
						syslog(LOG_ERR,
685
						    "%s: unknown rpc service",
686
						    sep->se_service);
687
						goto serv_unknown;
688
					}
689
					sep->se_rpcprog = rp->r_number;
690
				}
691
				if (sep->se_fd == -1)
692
					setup(sep);
693
				if (sep->se_fd != -1)
694
					register_rpc(sep);
695
			} else {
696
				u_short port = htons(strtonum(sep->se_service,
697
				    1, USHRT_MAX, NULL));
698
699
				if (!port) {
700
					(void)strlcpy(protoname, sep->se_proto,
701
					    sizeof(protoname));
702
					if (isdigit((unsigned char)
703
					    protoname[strlen(protoname) - 1]))
704
						protoname[strlen(protoname) - 1] = '\0';
705
					sp = getservbyname(sep->se_service,
706
					    protoname);
707
					if (sp == 0) {
708
						syslog(LOG_ERR,
709
						    "%s/%s: unknown service",
710
						    sep->se_service, sep->se_proto);
711
						goto serv_unknown;
712
					}
713
					port = sp->s_port;
714
				}
715
				if (port != sep->se_ctrladdr_in6.sin6_port) {
716
					sep->se_ctrladdr_in6.sin6_port = port;
717
					if (sep->se_fd != -1) {
718
						event_del(&sep->se_event);
719
						(void) close(sep->se_fd);
720
					}
721
					sep->se_fd = -1;
722
				}
723
				if (sep->se_fd == -1)
724
					setup(sep);
725
			}
726
			break;
727
		}
728
	serv_unknown:
729
		if (cp->se_next != NULL) {
730
			struct servtab *tmp = cp;
731
732
			cp = cp->se_next;
733
			free(tmp);
734
		} else {
735
			free(cp);
736
			cp = getconfigent();
737
		}
738
		if (debug)
739
			print_service(add ? "REDO" : "ADD", sep);
740
	}
741
	endconfig();
742
	/*
743
	 * Purge anything not looked at above.
744
	 */
745
	sepp = &servtab;
746
	while ((sep = *sepp)) {
747
		if (sep->se_checked) {
748
			sepp = &sep->se_next;
749
			continue;
750
		}
751
		*sepp = sep->se_next;
752
		if (sep->se_fd != -1) {
753
			event_del(&sep->se_event);
754
			(void) close(sep->se_fd);
755
		}
756
		if (isrpcservice(sep))
757
			unregister_rpc(sep);
758
		if (sep->se_family == AF_UNIX)
759
			(void)unlink(sep->se_service);
760
		if (debug)
761
			print_service("FREE", sep);
762
		freeconfig(sep);
763
		free(sep);
764
	}
765
}
766
767
void
768
retry(int sig, short events, void *arg)
769
{
770
	struct servtab *sep;
771
772
	timingout = 0;
773
	for (sep = servtab; sep; sep = sep->se_next) {
774
		if (sep->se_fd == -1) {
775
			switch (sep->se_family) {
776
			case AF_UNIX:
777
			case AF_INET:
778
			case AF_INET6:
779
				setup(sep);
780
				if (sep->se_fd != -1 && isrpcservice(sep))
781
					register_rpc(sep);
782
				break;
783
			}
784
		}
785
	}
786
}
787
788
void
789
die(int sig, short events, void *arg)
790
{
791
	struct servtab *sep;
792
793
	for (sep = servtab; sep; sep = sep->se_next) {
794
		if (sep->se_fd == -1)
795
			continue;
796
797
		switch (sep->se_family) {
798
		case AF_UNIX:
799
			(void)unlink(sep->se_service);
800
			break;
801
		case AF_INET:
802
		case AF_INET6:
803
			if (sep->se_wait == 1 && isrpcservice(sep))
804
				unregister_rpc(sep);
805
			break;
806
		}
807
		(void)close(sep->se_fd);
808
	}
809
	exit(0);
810
}
811
812
void
813
setup(struct servtab *sep)
814
{
815
	int on = 1;
816
	int r;
817
	mode_t mask = 0;
818
819
	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
820
		syslog(LOG_ERR, "%s/%s: socket: %m",
821
		    sep->se_service, sep->se_proto);
822
		return;
823
	}
824
#define	turnon(fd, opt) \
825
setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on))
826
	if (strncmp(sep->se_proto, "tcp", 3) == 0 && debug &&
827
	    turnon(sep->se_fd, SO_DEBUG) < 0)
828
		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
829
	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
830
		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
831
#undef turnon
832
	if (isrpcservice(sep)) {
833
		struct passwd *pwd;
834
835
		/*
836
		 * for RPC services, attempt to use a reserved port
837
		 * if they are going to be running as root.
838
		 *
839
		 * Also, zero out the port for all RPC services; let bind()
840
		 * find one.
841
		 */
842
		sep->se_ctrladdr_in.sin_port = 0;
843
		if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
844
		    pwd->pw_uid == 0 && uid == 0)
845
			r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
846
		else {
847
			r = bind(sep->se_fd, &sep->se_ctrladdr,
848
			    sep->se_ctrladdr_size);
849
			if (r == 0) {
850
				socklen_t len = sep->se_ctrladdr_size;
851
				int saveerrno = errno;
852
853
				/* update se_ctrladdr_in.sin_port */
854
				r = getsockname(sep->se_fd, &sep->se_ctrladdr,
855
				    &len);
856
				if (r <= 0)
857
					errno = saveerrno;
858
			}
859
		}
860
	} else {
861
		if (sep->se_family == AF_UNIX)
862
			mask = umask(0111);
863
		r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
864
		if (sep->se_family == AF_UNIX)
865
			umask(mask);
866
	}
867
	if (r < 0) {
868
		syslog(LOG_ERR, "%s/%s: bind: %m",
869
		    sep->se_service, sep->se_proto);
870
		(void) close(sep->se_fd);
871
		sep->se_fd = -1;
872
		if (!timingout) {
873
			timingout = 1;
874
			alarm(RETRYTIME);
875
		}
876
		return;
877
	}
878
	if (sep->se_socktype == SOCK_STREAM)
879
		listen(sep->se_fd, 10);
880
881
	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
882
		event_set(&sep->se_event, sep->se_fd, EV_READ|EV_PERSIST,
883
		    gettcp, sep);
884
	} else {
885
		event_set(&sep->se_event, sep->se_fd, EV_READ|EV_PERSIST,
886
		    spawn, sep);
887
	}
888
889
	event_add(&sep->se_event, NULL);
890
891
	if (sep->se_fd > maxsock) {
892
		maxsock = sep->se_fd;
893
		if (maxsock > rlim_nofile_cur - FD_MARGIN)
894
			bump_nofile();
895
	}
896
}
897
898
void
899
register_rpc(struct servtab *sep)
900
{
901
	socklen_t n;
902
	struct sockaddr_in sin;
903
	struct protoent *pp;
904
905
	if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
906
		syslog(LOG_ERR, "%s: getproto: %m",
907
		    sep->se_proto);
908
		return;
909
	}
910
	n = sizeof sin;
911
	if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
912
		syslog(LOG_ERR, "%s/%s: getsockname: %m",
913
		    sep->se_service, sep->se_proto);
914
		return;
915
	}
916
917
	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
918
		if (debug)
919
			fprintf(stderr, "pmap_set: %u %u %u %u\n",
920
			    sep->se_rpcprog, n, pp->p_proto,
921
			    ntohs(sin.sin_port));
922
		(void)pmap_unset(sep->se_rpcprog, n);
923
		if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
924
			syslog(LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
925
			    sep->se_service, sep->se_proto,
926
			    sep->se_rpcprog, n, pp->p_proto,
927
			    ntohs(sin.sin_port));
928
	}
929
}
930
931
void
932
unregister_rpc(struct servtab *sep)
933
{
934
	int n;
935
936
	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
937
		if (debug)
938
			fprintf(stderr, "pmap_unset(%u, %u)\n",
939
			    sep->se_rpcprog, n);
940
		if (!pmap_unset(sep->se_rpcprog, n))
941
			syslog(LOG_ERR, "pmap_unset(%u, %u)",
942
			    sep->se_rpcprog, n);
943
	}
944
}
945
946
947
struct servtab *
948
enter(struct servtab *cp)
949
{
950
	struct servtab *sep;
951
952
	sep = malloc(sizeof (*sep));
953
	if (sep == NULL) {
954
		syslog(LOG_ERR, "Out of memory.");
955
		exit(1);
956
	}
957
	*sep = *cp;
958
	sep->se_fd = -1;
959
	sep->se_rpcprog = -1;
960
	sep->se_next = servtab;
961
	servtab = sep;
962
	return (sep);
963
}
964
965
int
966
matchconf(struct servtab *old, struct servtab *new)
967
{
968
	if (strcmp(old->se_service, new->se_service) != 0)
969
		return (0);
970
971
	if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
972
		return (0);
973
974
	if (strcmp(old->se_proto, new->se_proto) != 0)
975
		return (0);
976
977
	/*
978
	 * If the new servtab is bound to a specific address, check that the
979
	 * old servtab is bound to the same entry. If the new service is not
980
	 * bound to a specific address then the check of se_hostaddr above
981
	 * is sufficient.
982
	 */
983
984
	if (old->se_family == AF_INET && new->se_family == AF_INET &&
985
	    bcmp(&old->se_ctrladdr_in.sin_addr,
986
	    &new->se_ctrladdr_in.sin_addr,
987
	    sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
988
		return (0);
989
990
	if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
991
	    bcmp(&old->se_ctrladdr_in6.sin6_addr,
992
	    &new->se_ctrladdr_in6.sin6_addr,
993
	    sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
994
		return (0);
995
	if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
996
	    old->se_ctrladdr_in6.sin6_scope_id !=
997
	    new->se_ctrladdr_in6.sin6_scope_id)
998
		return (0);
999
1000
	return (1);
1001
}
1002
1003
FILE		*fconfig = NULL;
1004
char		line[1024];
1005
char		*defhost;
1006
char		*skip(char **, int);
1007
char		*nextline(FILE *);
1008
char		*newstr(char *);
1009
struct servtab	*dupconfig(struct servtab *);
1010
1011
int
1012
setconfig(void)
1013
{
1014
	free(defhost);
1015
	defhost = newstr("*");
1016
	if (fconfig != NULL) {
1017
		fseek(fconfig, 0L, SEEK_SET);
1018
		return (1);
1019
	}
1020
	fconfig = fopen(CONFIG, "r");
1021
	return (fconfig != NULL);
1022
}
1023
1024
void
1025
endconfig(void)
1026
{
1027
	if (fconfig) {
1028
		(void) fclose(fconfig);
1029
		fconfig = NULL;
1030
	}
1031
	if (defhost) {
1032
		free(defhost);
1033
		defhost = 0;
1034
	}
1035
}
1036
1037
struct servtab *
1038
getconfigent(void)
1039
{
1040
	struct servtab *sep, *tsep;
1041
	char *arg, *cp, *hostdelim, *s;
1042
	int argc;
1043
1044
	sep = calloc(1, sizeof(struct servtab));
1045
	if (sep == NULL) {
1046
		syslog(LOG_ERR, "calloc: %m");
1047
		exit(1);
1048
	}
1049
more:
1050
	freeconfig(sep);
1051
1052
	while ((cp = nextline(fconfig)) && *cp == '#')
1053
		;
1054
	if (cp == NULL) {
1055
		free(sep);
1056
		return (NULL);
1057
	}
1058
1059
	memset(sep, 0, sizeof *sep);
1060
	arg = skip(&cp, 0);
1061
	if (arg == NULL) {
1062
		/* A blank line. */
1063
		goto more;
1064
	}
1065
1066
	/* Check for a host name. */
1067
	hostdelim = strrchr(arg, ':');
1068
	if (hostdelim) {
1069
		*hostdelim = '\0';
1070
		if (arg[0] == '[' && hostdelim > arg && hostdelim[-1] == ']') {
1071
			hostdelim[-1] = '\0';
1072
			sep->se_hostaddr = newstr(arg + 1);
1073
		} else if (hostdelim == arg)
1074
			sep->se_hostaddr = newstr("*");
1075
		else
1076
			sep->se_hostaddr = newstr(arg);
1077
		arg = hostdelim + 1;
1078
		/*
1079
		 * If the line is of the form `host:', then just change the
1080
		 * default host for the following lines.
1081
		 */
1082
		if (*arg == '\0') {
1083
			arg = skip(&cp, 0);
1084
			if (cp == NULL) {
1085
				free(defhost);
1086
				defhost = newstr(sep->se_hostaddr);
1087
				goto more;
1088
			}
1089
		}
1090
	} else
1091
		sep->se_hostaddr = newstr(defhost);
1092
1093
	sep->se_service = newstr(arg);
1094
	if ((arg = skip(&cp, 1)) == NULL)
1095
		goto more;
1096
1097
	if (strcmp(arg, "stream") == 0)
1098
		sep->se_socktype = SOCK_STREAM;
1099
	else if (strcmp(arg, "dgram") == 0)
1100
		sep->se_socktype = SOCK_DGRAM;
1101
	else
1102
		sep->se_socktype = -1;
1103
1104
	if ((arg = skip(&cp, 1)) == NULL)
1105
		goto more;
1106
1107
	sep->se_proto = newstr(arg);
1108
1109
	if (strcmp(sep->se_proto, "unix") == 0) {
1110
		sep->se_family = AF_UNIX;
1111
	} else {
1112
		int s;
1113
1114
		sep->se_family = AF_INET;
1115
		if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
1116
			sep->se_family = AF_INET6;
1117
1118
		/* check if the family is supported */
1119
		s = socket(sep->se_family, SOCK_DGRAM, 0);
1120
		if (s < 0) {
1121
			syslog(LOG_WARNING, "%s/%s: %s: the address family is "
1122
			    "not supported by the kernel", sep->se_service,
1123
			    sep->se_proto, sep->se_hostaddr);
1124
			goto more;
1125
		}
1126
		close(s);
1127
1128
		if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1129
			char *cp, *ccp;
1130
			long l;
1131
1132
			cp = strchr(sep->se_service, '/');
1133
			if (cp == 0) {
1134
				syslog(LOG_ERR, "%s: no rpc version",
1135
				    sep->se_service);
1136
				goto more;
1137
			}
1138
			*cp++ = '\0';
1139
			l = strtol(cp, &ccp, 0);
1140
			if (ccp == cp || l < 0 || l > INT_MAX) {
1141
		badafterall:
1142
				syslog(LOG_ERR, "%s/%s: bad rpc version",
1143
				    sep->se_service, cp);
1144
				goto more;
1145
			}
1146
			sep->se_rpcversl = sep->se_rpcversh = l;
1147
			if (*ccp == '-') {
1148
				cp = ccp + 1;
1149
				l = strtol(cp, &ccp, 0);
1150
				if (ccp == cp || l < 0 || l > INT_MAX ||
1151
				    l < sep->se_rpcversl || *ccp)
1152
					goto badafterall;
1153
				sep->se_rpcversh = l;
1154
			} else if (*ccp != '\0')
1155
				goto badafterall;
1156
		}
1157
	}
1158
	arg = skip(&cp, 1);
1159
	if (arg == NULL)
1160
		goto more;
1161
1162
	s = strchr(arg, '.');
1163
	if (s) {
1164
		char *p;
1165
1166
		*s++ = '\0';
1167
		sep->se_max = strtoul(s, &p, 0);
1168
		if (sep->se_max < 1 || *p) {
1169
			syslog(LOG_ERR,
1170
			    "%s: illegal max field \"%s\", setting to %d",
1171
			    sep->se_service, s, toomany);
1172
			sep->se_max = toomany;
1173
		}
1174
	} else
1175
		sep->se_max = toomany;
1176
1177
	sep->se_wait = strcmp(arg, "wait") == 0;
1178
	if ((arg = skip(&cp, 1)) == NULL)
1179
		goto more;
1180
	sep->se_user = newstr(arg);
1181
	arg = strchr(sep->se_user, '.');
1182
	if (arg == NULL)
1183
		arg = strchr(sep->se_user, ':');
1184
	if (arg) {
1185
		*arg++ = '\0';
1186
		sep->se_group = newstr(arg);
1187
	}
1188
	if ((arg = skip(&cp, 1)) == NULL)
1189
		goto more;
1190
1191
	sep->se_server = newstr(arg);
1192
	if (strcmp(sep->se_server, "internal") == 0) {
1193
		struct biltin *bi;
1194
1195
		for (bi = biltins; bi->bi_service; bi++)
1196
			if (bi->bi_socktype == sep->se_socktype &&
1197
			    strcmp(bi->bi_service, sep->se_service) == 0)
1198
				break;
1199
		if (bi->bi_service == 0) {
1200
			syslog(LOG_ERR, "internal service %s unknown",
1201
			    sep->se_service);
1202
			goto more;
1203
		}
1204
		sep->se_bi = bi;
1205
		sep->se_wait = bi->bi_wait;
1206
	} else
1207
		sep->se_bi = NULL;
1208
	argc = 0;
1209
	for (arg = skip(&cp, 0); cp; arg = skip(&cp, 0)) {
1210
		if (argc < MAXARGV)
1211
			sep->se_argv[argc++] = newstr(arg);
1212
	}
1213
	if (argc == 0 && sep->se_bi == NULL) {
1214
		if ((arg = strrchr(sep->se_server, '/')) != NULL)
1215
			arg++;
1216
		else
1217
			arg = sep->se_server;
1218
		sep->se_argv[argc++] = newstr(arg);
1219
	}
1220
	while (argc <= MAXARGV)
1221
		sep->se_argv[argc++] = NULL;
1222
1223
	/*
1224
	 * Resolve each hostname in the se_hostaddr list (if any)
1225
	 * and create a new entry for each resolved address.
1226
	 */
1227
	if (sep->se_hostaddr != NULL && strcmp(sep->se_proto, "unix") != 0) {
1228
		struct addrinfo hints, *res0, *res;
1229
		char *host, *hostlist0, *hostlist, *port;
1230
		int error;
1231
1232
		hostlist = hostlist0 = sep->se_hostaddr;
1233
		sep->se_hostaddr = NULL;
1234
		sep->se_checked = -1;
1235
		while ((host = strsep(&hostlist, ",")) != NULL) {
1236
			if (*host == '\0')
1237
				continue;
1238
1239
			memset(&hints, 0, sizeof(hints));
1240
			hints.ai_family = sep->se_family;
1241
			hints.ai_socktype = sep->se_socktype;
1242
			hints.ai_flags = AI_PASSIVE;
1243
			port = "0";
1244
			error = getaddrinfo(strcmp(host, "*") ? host : NULL,
1245
			    port, &hints, &res0);
1246
			if (error) {
1247
				syslog(LOG_ERR, "%s/%s: %s: %s",
1248
				    sep->se_service, sep->se_proto,
1249
				    host, gai_strerror(error));
1250
				continue;
1251
			}
1252
			for (res = res0; res; res = res->ai_next) {
1253
				if (res->ai_addrlen >
1254
				    sizeof(sep->se_ctrladdr_storage))
1255
					continue;
1256
				/*
1257
				 * If sep is unused, store host in there.
1258
				 * Otherwise, dup a new entry and prepend it.
1259
				 */
1260
				if (sep->se_checked == -1) {
1261
					sep->se_checked = 0;
1262
				} else {
1263
					tsep = dupconfig(sep);
1264
					tsep->se_next = sep;
1265
					sep = tsep;
1266
				}
1267
				sep->se_hostaddr = newstr(host);
1268
				memcpy(&sep->se_ctrladdr_storage,
1269
				    res->ai_addr, res->ai_addrlen);
1270
				sep->se_ctrladdr_size = res->ai_addrlen;
1271
			}
1272
			freeaddrinfo(res0);
1273
		}
1274
		free(hostlist0);
1275
		if (sep->se_checked == -1)
1276
			goto more;	/* no resolvable names/addresses */
1277
	}
1278
1279
	return (sep);
1280
}
1281
1282
void
1283
freeconfig(struct servtab *cp)
1284
{
1285
	int i;
1286
1287
	free(cp->se_hostaddr);
1288
	cp->se_hostaddr = NULL;
1289
	free(cp->se_service);
1290
	cp->se_service = NULL;
1291
	free(cp->se_proto);
1292
	cp->se_proto = NULL;
1293
	free(cp->se_user);
1294
	cp->se_user = NULL;
1295
	free(cp->se_group);
1296
	cp->se_group = NULL;
1297
	free(cp->se_server);
1298
	cp->se_server = NULL;
1299
	for (i = 0; i < MAXARGV; i++) {
1300
		free(cp->se_argv[i]);
1301
		cp->se_argv[i] = NULL;
1302
	}
1303
}
1304
1305
char *
1306
skip(char **cpp, int report)
1307
{
1308
	char *cp = *cpp;
1309
	char *start;
1310
1311
erp:
1312
	if (*cpp == NULL) {
1313
		if (report)
1314
			syslog(LOG_ERR, "syntax error in inetd config file");
1315
		return (NULL);
1316
	}
1317
1318
again:
1319
	while (*cp == ' ' || *cp == '\t')
1320
		cp++;
1321
	if (*cp == '\0') {
1322
		int c;
1323
1324
		c = getc(fconfig);
1325
		(void) ungetc(c, fconfig);
1326
		if (c == ' ' || c == '\t')
1327
			if ((cp = nextline(fconfig)))
1328
				goto again;
1329
		*cpp = NULL;
1330
		goto erp;
1331
	}
1332
	start = cp;
1333
	while (*cp && *cp != ' ' && *cp != '\t')
1334
		cp++;
1335
	if (*cp != '\0')
1336
		*cp++ = '\0';
1337
	if ((*cpp = cp) == NULL)
1338
		goto erp;
1339
1340
	return (start);
1341
}
1342
1343
char *
1344
nextline(FILE *fd)
1345
{
1346
	if (fgets(line, sizeof (line), fd) == NULL)
1347
		return (NULL);
1348
	line[strcspn(line, "\n")] = '\0';
1349
	return (line);
1350
}
1351
1352
char *
1353
newstr(char *cp)
1354
{
1355
	if ((cp = strdup(cp ? cp : "")))
1356
		return(cp);
1357
	syslog(LOG_ERR, "strdup: %m");
1358
	exit(1);
1359
}
1360
1361
struct servtab *
1362
dupconfig(struct servtab *sep)
1363
{
1364
	struct servtab *newtab;
1365
	int argc;
1366
1367
	newtab = calloc(1, sizeof(struct servtab));
1368
1369
	if (newtab == NULL) {
1370
		syslog(LOG_ERR, "calloc: %m");
1371
		exit(1);
1372
	}
1373
1374
	newtab->se_service = sep->se_service ? newstr(sep->se_service) : NULL;
1375
	newtab->se_socktype = sep->se_socktype;
1376
	newtab->se_family = sep->se_family;
1377
	newtab->se_proto = sep->se_proto ? newstr(sep->se_proto) : NULL;
1378
	newtab->se_rpcprog = sep->se_rpcprog;
1379
	newtab->se_rpcversl = sep->se_rpcversl;
1380
	newtab->se_rpcversh = sep->se_rpcversh;
1381
	newtab->se_wait = sep->se_wait;
1382
	newtab->se_user = sep->se_user ? newstr(sep->se_user) : NULL;
1383
	newtab->se_group = sep->se_group ? newstr(sep->se_group) : NULL;
1384
	newtab->se_bi = sep->se_bi;
1385
	newtab->se_server = sep->se_server ? newstr(sep->se_server) : 0;
1386
1387
	for (argc = 0; argc <= MAXARGV; argc++)
1388
		newtab->se_argv[argc] = sep->se_argv[argc] ?
1389
		    newstr(sep->se_argv[argc]) : NULL;
1390
	newtab->se_max = sep->se_max;
1391
1392
	return (newtab);
1393
}
1394
1395
void
1396
inetd_setproctitle(char *a, int s)
1397
{
1398
	socklen_t size;
1399
	struct sockaddr_storage ss;
1400
	char hbuf[NI_MAXHOST];
1401
1402
	size = sizeof(ss);
1403
	if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
1404
		if (getnameinfo((struct sockaddr *)&ss, size, hbuf,
1405
		    sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0)
1406
			setproctitle("-%s [%s]", a, hbuf);
1407
		else
1408
			setproctitle("-%s [?]", a);
1409
	} else
1410
		setproctitle("-%s", a);
1411
}
1412
1413
int
1414
bump_nofile(void)
1415
{
1416
#define FD_CHUNK	32
1417
1418
	struct rlimit rl;
1419
1420
	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1421
		syslog(LOG_ERR, "getrlimit: %m");
1422
		return -1;
1423
	}
1424
	rl.rlim_cur = MINIMUM(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1425
	rl.rlim_cur = MINIMUM(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
1426
	if (rl.rlim_cur <= rlim_nofile_cur) {
1427
		syslog(LOG_ERR,
1428
		    "bump_nofile: cannot extend file limit, max = %d",
1429
		    (int)rl.rlim_cur);
1430
		return -1;
1431
	}
1432
1433
	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1434
		syslog(LOG_ERR, "setrlimit: %m");
1435
		return -1;
1436
	}
1437
1438
	rlim_nofile_cur = rl.rlim_cur;
1439
	return 0;
1440
}
1441
1442
/*
1443
 * Internet services provided internally by inetd:
1444
 */
1445
#define	BUFSIZE	4096
1446
1447
void
1448
echo_stream(int s, struct servtab *sep)
1449
{
1450
	char buffer[BUFSIZE];
1451
	int i;
1452
1453
	inetd_setproctitle(sep->se_service, s);
1454
	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1455
	    write(s, buffer, i) > 0)
1456
		;
1457
	exit(0);
1458
}
1459
1460
void
1461
echo_dg(int s, struct servtab *sep)
1462
{
1463
	char buffer[BUFSIZE];
1464
	int i;
1465
	socklen_t size;
1466
	struct sockaddr_storage ss;
1467
1468
	size = sizeof(ss);
1469
	if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
1470
	    (struct sockaddr *)&ss, &size)) < 0)
1471
		return;
1472
	if (dg_badinput((struct sockaddr *)&ss))
1473
		return;
1474
	(void) sendto(s, buffer, i, 0, (struct sockaddr *)&ss, size);
1475
}
1476
1477
void
1478
discard_stream(int s, struct servtab *sep)
1479
{
1480
	char buffer[BUFSIZE];
1481
1482
	inetd_setproctitle(sep->se_service, s);
1483
	while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1484
	    errno == EINTR)
1485
		;
1486
	exit(0);
1487
}
1488
1489
void
1490
discard_dg(int s, struct servtab *sep)
1491
{
1492
	char buffer[BUFSIZE];
1493
1494
	(void) read(s, buffer, sizeof(buffer));
1495
}
1496
1497
#include <ctype.h>
1498
#define LINESIZ 72
1499
char ring[128];
1500
char *endring;
1501
1502
void
1503
initring(void)
1504
{
1505
	int i;
1506
1507
	endring = ring;
1508
1509
	for (i = 0; i <= sizeof ring; ++i)
1510
		if (isprint((unsigned char)i))
1511
			*endring++ = i;
1512
}
1513
1514
void
1515
chargen_stream(int s, struct servtab *sep)
1516
{
1517
	char *rs;
1518
	int len;
1519
	char text[LINESIZ+2];
1520
1521
	inetd_setproctitle(sep->se_service, s);
1522
1523
	if (!endring) {
1524
		initring();
1525
		rs = ring;
1526
	}
1527
1528
	text[LINESIZ] = '\r';
1529
	text[LINESIZ + 1] = '\n';
1530
	for (rs = ring;;) {
1531
		if ((len = endring - rs) >= LINESIZ)
1532
			memmove(text, rs, LINESIZ);
1533
		else {
1534
			memmove(text, rs, len);
1535
			memmove(text + len, ring, LINESIZ - len);
1536
		}
1537
		if (++rs == endring)
1538
			rs = ring;
1539
		if (write(s, text, sizeof(text)) != sizeof(text))
1540
			break;
1541
	}
1542
	exit(0);
1543
}
1544
1545
void
1546
chargen_dg(int s, struct servtab *sep)
1547
{
1548
	struct sockaddr_storage ss;
1549
	static char *rs;
1550
	int len;
1551
	socklen_t size;
1552
	char text[LINESIZ+2];
1553
1554
	if (endring == 0) {
1555
		initring();
1556
		rs = ring;
1557
	}
1558
1559
	size = sizeof(ss);
1560
	if (recvfrom(s, text, sizeof(text), 0, (struct sockaddr *)&ss,
1561
	    &size) < 0)
1562
		return;
1563
	if (dg_badinput((struct sockaddr *)&ss))
1564
		return;
1565
1566
	if ((len = endring - rs) >= LINESIZ)
1567
		memmove(text, rs, LINESIZ);
1568
	else {
1569
		memmove(text, rs, len);
1570
		memmove(text + len, ring, LINESIZ - len);
1571
	}
1572
	if (++rs == endring)
1573
		rs = ring;
1574
	text[LINESIZ] = '\r';
1575
	text[LINESIZ + 1] = '\n';
1576
	(void) sendto(s, text, sizeof(text), 0, (struct sockaddr *)&ss, size);
1577
}
1578
1579
/*
1580
 * Return a machine readable date and time, in the form of the
1581
 * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1582
 * returns the number of seconds since midnight, Jan 1, 1970,
1583
 * we must add 2208988800 seconds to this figure to make up for
1584
 * some seventy years Bell Labs was asleep.
1585
 */
1586
u_int32_t
1587
machtime(void)
1588
{
1589
	struct timeval tv;
1590
1591
	if (gettimeofday(&tv, NULL) < 0)
1592
		return (0L);
1593
1594
	return (htonl((u_int32_t)tv.tv_sec + 2208988800UL));
1595
}
1596
1597
void
1598
machtime_stream(int s, struct servtab *sep)
1599
{
1600
	u_int32_t result;
1601
1602
	result = machtime();
1603
	(void) write(s, &result, sizeof(result));
1604
}
1605
1606
void
1607
machtime_dg(int s, struct servtab *sep)
1608
{
1609
	u_int32_t result;
1610
	struct sockaddr_storage ss;
1611
	socklen_t size;
1612
1613
	size = sizeof(ss);
1614
	if (recvfrom(s, &result, sizeof(result), 0,
1615
	    (struct sockaddr *)&ss, &size) < 0)
1616
		return;
1617
	if (dg_badinput((struct sockaddr *)&ss))
1618
		return;
1619
	result = machtime();
1620
	(void) sendto(s, &result, sizeof(result), 0,
1621
	    (struct sockaddr *)&ss, size);
1622
}
1623
1624
/* Return human-readable time of day */
1625
void
1626
daytime_stream(int s, struct servtab *sep)
1627
{
1628
	char buffer[256];
1629
	time_t clock;
1630
1631
	clock = time(NULL);
1632
1633
	(void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1634
	(void) write(s, buffer, strlen(buffer));
1635
}
1636
1637
/* Return human-readable time of day */
1638
void
1639
daytime_dg(int s, struct servtab *sep)
1640
{
1641
	char buffer[256];
1642
	time_t clock;
1643
	struct sockaddr_storage ss;
1644
	socklen_t size;
1645
1646
	clock = time(NULL);
1647
1648
	size = sizeof(ss);
1649
	if (recvfrom(s, buffer, sizeof(buffer), 0, (struct sockaddr *)&ss,
1650
	    &size) < 0)
1651
		return;
1652
	if (dg_badinput((struct sockaddr *)&ss))
1653
		return;
1654
	(void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1655
	(void) sendto(s, buffer, strlen(buffer), 0, (struct sockaddr *)&ss,
1656
	    size);
1657
}
1658
1659
/*
1660
 * print_service:
1661
 *	Dump relevant information to stderr
1662
 */
1663
void
1664
print_service(char *action, struct servtab *sep)
1665
{
1666
	if (strcmp(sep->se_hostaddr, "*") == 0)
1667
		fprintf(stderr, "%s: %s ", action, sep->se_service);
1668
	else
1669
		fprintf(stderr, "%s: %s:%s ", action, sep->se_hostaddr,
1670
		    sep->se_service);
1671
1672
	if (isrpcservice(sep))
1673
		fprintf(stderr, "rpcprog=%d, rpcvers=%d/%d, proto=%s,",
1674
		    sep->se_rpcprog, sep->se_rpcversh,
1675
		    sep->se_rpcversl, sep->se_proto);
1676
	else
1677
		fprintf(stderr, "proto=%s,", sep->se_proto);
1678
1679
	fprintf(stderr,
1680
	    " wait.max=%d.%d user:group=%s:%s builtin=%lx server=%s\n",
1681
	    sep->se_wait, sep->se_max, sep->se_user,
1682
	    sep->se_group ? sep->se_group : "wheel",
1683
	    (long)sep->se_bi, sep->se_server);
1684
}
1685
1686
void
1687
spawn(int ctrl, short events, void *xsep)
1688
{
1689
	struct servtab *sep = xsep;
1690
	struct passwd *pwd;
1691
	int tmpint, dofork;
1692
	struct group *grp = NULL;
1693
	char buf[50];
1694
	pid_t pid;
1695
1696
	if (debug)
1697
		fprintf(stderr, "someone wants %s\n", sep->se_service);
1698
1699
	pid = 0;
1700
	dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
1701
	if (dofork) {
1702
		if (sep->se_count++ == 0)
1703
		    (void)gettimeofday(&sep->se_time, NULL);
1704
		else if (sep->se_count >= sep->se_max) {
1705
			struct timeval now;
1706
1707
			(void)gettimeofday(&now, NULL);
1708
			if (now.tv_sec - sep->se_time.tv_sec >
1709
			    CNT_INTVL) {
1710
				sep->se_time = now;
1711
				sep->se_count = 1;
1712
			} else {
1713
				if (!sep->se_wait &&
1714
				    sep->se_socktype == SOCK_STREAM)
1715
					close(ctrl);
1716
				if (sep->se_family == AF_INET &&
1717
				    ntohs(sep->se_ctrladdr_in.sin_port) >=
1718
				    IPPORT_RESERVED) {
1719
					/*
1720
					 * Cannot close it -- there are
1721
					 * thieves on the system.
1722
					 * Simply ignore the connection.
1723
					 */
1724
					--sep->se_count;
1725
					return;
1726
				}
1727
				syslog(LOG_ERR,
1728
				    "%s/%s server failing (looping), service terminated",
1729
				    sep->se_service, sep->se_proto);
1730
				if (!sep->se_wait &&
1731
				    sep->se_socktype == SOCK_STREAM)
1732
					close(ctrl);
1733
				event_del(&sep->se_event);
1734
				(void) close(sep->se_fd);
1735
1736
				sep->se_fd = -1;
1737
				sep->se_count = 0;
1738
				if (!timingout) {
1739
					timingout = 1;
1740
					alarm(RETRYTIME);
1741
				}
1742
				return;
1743
			}
1744
		}
1745
		pid = fork();
1746
	}
1747
	if (pid < 0) {
1748
		syslog(LOG_ERR, "fork: %m");
1749
		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1750
			close(ctrl);
1751
		sleep(1);
1752
		return;
1753
	}
1754
1755
	if (pid && sep->se_wait) {
1756
		sep->se_wait = pid;
1757
		event_del(&sep->se_event);
1758
	}
1759
	if (pid == 0) {
1760
		if (sep->se_bi) {
1761
			if (dofork && pledge("stdio inet flock rpath cpath wpath", NULL) == -1)
1762
				err(1, "pledge");
1763
			(*sep->se_bi->bi_fn)(ctrl, sep);
1764
		} else {
1765
			if ((pwd = getpwnam(sep->se_user)) == NULL) {
1766
				syslog(LOG_ERR,
1767
				    "getpwnam: %s: No such user",
1768
				    sep->se_user);
1769
				if (sep->se_socktype != SOCK_STREAM)
1770
					recv(0, buf, sizeof (buf), 0);
1771
				exit(1);
1772
			}
1773
			if (setsid() <0)
1774
				syslog(LOG_ERR, "%s: setsid: %m",
1775
				    sep->se_service);
1776
			if (sep->se_group &&
1777
			    (grp = getgrnam(sep->se_group)) == NULL) {
1778
				syslog(LOG_ERR,
1779
				    "getgrnam: %s: No such group",
1780
				    sep->se_group);
1781
				if (sep->se_socktype != SOCK_STREAM)
1782
					recv(0, buf, sizeof (buf), 0);
1783
				exit(1);
1784
			}
1785
			if (uid != 0) {
1786
				/* a user running private inetd */
1787
				if (uid != pwd->pw_uid)
1788
					exit(1);
1789
			} else {
1790
				tmpint = LOGIN_SETALL &
1791
				    ~(LOGIN_SETGROUP|LOGIN_SETLOGIN);
1792
				if (pwd->pw_uid)
1793
					tmpint |= LOGIN_SETGROUP|LOGIN_SETLOGIN;
1794
				if (sep->se_group) {
1795
					pwd->pw_gid = grp->gr_gid;
1796
					tmpint |= LOGIN_SETGROUP;
1797
				}
1798
				if (setusercontext(NULL, pwd, pwd->pw_uid,
1799
				    tmpint) < 0) {
1800
					syslog(LOG_ERR,
1801
					    "%s/%s: setusercontext: %m",
1802
					    sep->se_service, sep->se_proto);
1803
					exit(1);
1804
				}
1805
			}
1806
			if (debug)
1807
				fprintf(stderr, "%ld execv %s\n",
1808
				    (long)getpid(), sep->se_server);
1809
			if (ctrl != STDIN_FILENO) {
1810
				dup2(ctrl, STDIN_FILENO);
1811
				close(ctrl);
1812
			}
1813
			dup2(STDIN_FILENO, STDOUT_FILENO);
1814
			dup2(STDIN_FILENO, STDERR_FILENO);
1815
			closelog();
1816
			closefrom(3);
1817
			signal(SIGPIPE, SIG_DFL);
1818
			execv(sep->se_server, sep->se_argv);
1819
			if (sep->se_socktype != SOCK_STREAM)
1820
				recv(0, buf, sizeof (buf), 0);
1821
			syslog(LOG_ERR, "execv %s: %m", sep->se_server);
1822
			exit(1);
1823
		}
1824
	}
1825
	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1826
		close(ctrl);
1827
}