Bug Summary

File:src/usr.sbin/inetd/inetd.c
Warning:line 1561, column 3
Null pointer passed as 2nd argument to memory copy function

Annotated Source Code

Press '?' to see keyboard shortcuts

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