Bug Summary

File:src/usr.sbin/inetd/inetd.c
Warning:line 1521, column 3
Value stored to 'rs' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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