inetd.c revision 1.138 1 1.138 rillig /* $NetBSD: inetd.c,v 1.138 2021/10/12 22:51:28 rillig Exp $ */
2 1.42 thorpej
3 1.42 thorpej /*-
4 1.87 tron * Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
5 1.42 thorpej * All rights reserved.
6 1.42 thorpej *
7 1.42 thorpej * This code is derived from software contributed to The NetBSD Foundation
8 1.42 thorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 1.87 tron * NASA Ames Research Center and by Matthias Scheler.
10 1.42 thorpej *
11 1.42 thorpej * Redistribution and use in source and binary forms, with or without
12 1.42 thorpej * modification, are permitted provided that the following conditions
13 1.42 thorpej * are met:
14 1.42 thorpej * 1. Redistributions of source code must retain the above copyright
15 1.42 thorpej * notice, this list of conditions and the following disclaimer.
16 1.42 thorpej * 2. Redistributions in binary form must reproduce the above copyright
17 1.42 thorpej * notice, this list of conditions and the following disclaimer in the
18 1.42 thorpej * documentation and/or other materials provided with the distribution.
19 1.42 thorpej *
20 1.42 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 1.42 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 1.42 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 1.42 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 1.42 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 1.42 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 1.42 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 1.42 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.42 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.42 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 1.42 thorpej * POSSIBILITY OF SUCH DAMAGE.
31 1.42 thorpej */
32 1.20 mycroft
33 1.1 cgd /*
34 1.23 mycroft * Copyright (c) 1983, 1991, 1993, 1994
35 1.23 mycroft * The Regents of the University of California. All rights reserved.
36 1.1 cgd *
37 1.1 cgd * Redistribution and use in source and binary forms, with or without
38 1.1 cgd * modification, are permitted provided that the following conditions
39 1.1 cgd * are met:
40 1.1 cgd * 1. Redistributions of source code must retain the above copyright
41 1.1 cgd * notice, this list of conditions and the following disclaimer.
42 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
43 1.1 cgd * notice, this list of conditions and the following disclaimer in the
44 1.1 cgd * documentation and/or other materials provided with the distribution.
45 1.93 agc * 3. Neither the name of the University nor the names of its contributors
46 1.1 cgd * may be used to endorse or promote products derived from this software
47 1.1 cgd * without specific prior written permission.
48 1.1 cgd *
49 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 1.1 cgd * SUCH DAMAGE.
60 1.1 cgd */
61 1.1 cgd
62 1.36 mrg #include <sys/cdefs.h>
63 1.1 cgd #ifndef lint
64 1.106 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1991, 1993, 1994\
65 1.106 lukem The Regents of the University of California. All rights reserved.");
66 1.23 mycroft #if 0
67 1.23 mycroft static char sccsid[] = "@(#)inetd.c 8.4 (Berkeley) 4/13/94";
68 1.23 mycroft #else
69 1.138 rillig __RCSID("$NetBSD: inetd.c,v 1.138 2021/10/12 22:51:28 rillig Exp $");
70 1.23 mycroft #endif
71 1.1 cgd #endif /* not lint */
72 1.1 cgd
73 1.1 cgd /*
74 1.1 cgd * Inetd - Internet super-server
75 1.1 cgd *
76 1.23 mycroft * This program invokes all internet services as needed. Connection-oriented
77 1.23 mycroft * services are invoked each time a connection is made, by creating a process.
78 1.23 mycroft * This process is passed the connection as file descriptor 0 and is expected
79 1.23 mycroft * to do a getpeername to find out the source host and port.
80 1.1 cgd *
81 1.1 cgd * Datagram oriented services are invoked when a datagram
82 1.1 cgd * arrives; a process is created and passed a pending message
83 1.1 cgd * on file descriptor 0. Datagram servers may either connect
84 1.1 cgd * to their peer, freeing up the original socket for inetd
85 1.1 cgd * to receive further messages on, or ``take over the socket'',
86 1.1 cgd * processing all arriving datagrams and, eventually, timing
87 1.1 cgd * out. The first type of server is said to be ``multi-threaded'';
88 1.16 mouse * the second type of server ``single-threaded''.
89 1.1 cgd *
90 1.1 cgd * Inetd uses a configuration file which is read at startup
91 1.1 cgd * and, possibly, at some later time in response to a hangup signal.
92 1.1 cgd * The configuration file is ``free format'' with fields given in the
93 1.1 cgd * order shown below. Continuation lines for an entry must being with
94 1.1 cgd * a space or tab. All fields must be present in each entry.
95 1.1 cgd *
96 1.23 mycroft * service name must be in /etc/services or must
97 1.23 mycroft * name a tcpmux service
98 1.107 tls * socket type[:accf[,arg]] stream/dgram/raw/rdm/seqpacket,
99 1.107 tls only stream can name an accept filter
100 1.1 cgd * protocol must be in /etc/protocols
101 1.115 tsarna * wait/nowait[:max] single-threaded/multi-threaded, max #
102 1.55 ad * user[:group] user/group to run daemon as
103 1.1 cgd * server program full path name
104 1.125 martin * server program arguments maximum of MAXARGV (64)
105 1.1 cgd *
106 1.2 brezak * For RPC services
107 1.133 rillig * service name/version must be in /etc/rpc
108 1.2 brezak * socket type stream/dgram/raw/rdm/seqpacket
109 1.2 brezak * protocol must be in /etc/protocols
110 1.115 tsarna * wait/nowait[:max] single-threaded/multi-threaded
111 1.55 ad * user[:group] user to run daemon as
112 1.2 brezak * server program full path name
113 1.125 martin * server program arguments maximum of MAXARGV (64)
114 1.5 pk *
115 1.16 mouse * For non-RPC services, the "service name" can be of the form
116 1.16 mouse * hostaddress:servicename, in which case the hostaddress is used
117 1.16 mouse * as the host portion of the address to listen on. If hostaddress
118 1.16 mouse * consists of a single `*' character, INADDR_ANY is used.
119 1.16 mouse *
120 1.16 mouse * A line can also consist of just
121 1.16 mouse * hostaddress:
122 1.16 mouse * where hostaddress is as in the preceding paragraph. Such a line must
123 1.16 mouse * have no further fields; the specified hostaddress is remembered and
124 1.16 mouse * used for all further lines that have no hostaddress specified,
125 1.16 mouse * until the next such line (or EOF). (This is why * is provided to
126 1.16 mouse * allow explicit specification of INADDR_ANY.) A line
127 1.16 mouse * *:
128 1.16 mouse * is implicitly in effect at the beginning of the file.
129 1.16 mouse *
130 1.16 mouse * The hostaddress specifier may (and often will) contain dots;
131 1.16 mouse * the service name must not.
132 1.16 mouse *
133 1.16 mouse * For RPC services, host-address specifiers are accepted and will
134 1.16 mouse * work to some extent; however, because of limitations in the
135 1.16 mouse * portmapper interface, it will not work to try to give more than
136 1.16 mouse * one line for any given RPC service, even if the host-address
137 1.16 mouse * specifiers are different.
138 1.16 mouse *
139 1.23 mycroft * TCP services without official port numbers are handled with the
140 1.23 mycroft * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
141 1.23 mycroft * requests. When a connection is made from a foreign host, the service
142 1.23 mycroft * requested is passed to tcpmux, which looks it up in the servtab list
143 1.23 mycroft * and returns the proper entry for the service. Tcpmux returns a
144 1.23 mycroft * negative reply if the service doesn't exist, otherwise the invoked
145 1.23 mycroft * server is expected to return the positive reply if the service type in
146 1.23 mycroft * inetd.conf file has the prefix "tcpmux/". If the service type has the
147 1.23 mycroft * prefix "tcpmux/+", tcpmux will return the positive reply for the
148 1.23 mycroft * process; this is for compatibility with older server code, and also
149 1.23 mycroft * allows you to invoke programs that use stdin/stdout without putting any
150 1.23 mycroft * special server code in them. Services that use tcpmux are "nowait"
151 1.23 mycroft * because they do not have a well-known port and hence cannot listen
152 1.23 mycroft * for new requests.
153 1.23 mycroft *
154 1.1 cgd * Comment lines are indicated by a `#' in column 1.
155 1.49 itojun *
156 1.49 itojun * #ifdef IPSEC
157 1.49 itojun * Comment lines that start with "#@" denote IPsec policy string, as described
158 1.49 itojun * in ipsec_set_policy(3). This will affect all the following items in
159 1.49 itojun * inetd.conf(8). To reset the policy, just use "#@" line. By default,
160 1.49 itojun * there's no IPsec policy.
161 1.49 itojun * #endif
162 1.1 cgd */
163 1.5 pk
164 1.5 pk /*
165 1.55 ad * Here's the scoop concerning the user:group feature:
166 1.5 pk *
167 1.5 pk * 1) set-group-option off.
168 1.16 mouse *
169 1.5 pk * a) user = root: NO setuid() or setgid() is done
170 1.16 mouse *
171 1.5 pk * b) other: setuid()
172 1.5 pk * setgid(primary group as found in passwd)
173 1.5 pk * initgroups(name, primary group)
174 1.16 mouse *
175 1.5 pk * 2) set-group-option on.
176 1.16 mouse *
177 1.5 pk * a) user = root: NO setuid()
178 1.5 pk * setgid(specified group)
179 1.5 pk * NO initgroups()
180 1.16 mouse *
181 1.5 pk * b) other: setuid()
182 1.5 pk * setgid(specified group)
183 1.5 pk * initgroups(name, specified group)
184 1.16 mouse *
185 1.5 pk */
186 1.5 pk
187 1.5 pk #include <sys/param.h>
188 1.5 pk #include <sys/stat.h>
189 1.5 pk #include <sys/ioctl.h>
190 1.5 pk #include <sys/wait.h>
191 1.5 pk #include <sys/resource.h>
192 1.85 tron #include <sys/event.h>
193 1.127 christos #include <sys/socket.h>
194 1.137 christos #include <sys/queue.h>
195 1.127 christos
196 1.5 pk
197 1.53 sommerfe #ifndef NO_RPC
198 1.5 pk #define RPC
199 1.53 sommerfe #endif
200 1.1 cgd
201 1.82 itojun #include <net/if.h>
202 1.82 itojun
203 1.23 mycroft #ifdef RPC
204 1.23 mycroft #include <rpc/rpc.h>
205 1.62 fvdl #include <rpc/rpcb_clnt.h>
206 1.62 fvdl #include <netconfig.h>
207 1.23 mycroft #endif
208 1.1 cgd
209 1.42 thorpej #include <ctype.h>
210 1.127 christos #include <err.h>
211 1.1 cgd #include <errno.h>
212 1.30 mycroft #include <fcntl.h>
213 1.127 christos #include <glob.h>
214 1.23 mycroft #include <grp.h>
215 1.127 christos #include <libgen.h>
216 1.1 cgd #include <pwd.h>
217 1.23 mycroft #include <signal.h>
218 1.1 cgd #include <stdio.h>
219 1.9 cgd #include <stdlib.h>
220 1.1 cgd #include <string.h>
221 1.23 mycroft #include <syslog.h>
222 1.23 mycroft #include <unistd.h>
223 1.48 thorpej #include <util.h>
224 1.82 itojun #include <ifaddrs.h>
225 1.23 mycroft
226 1.127 christos #include "inetd.h"
227 1.49 itojun
228 1.12 mrg #ifdef LIBWRAP
229 1.12 mrg # include <tcpd.h>
230 1.13 mrg #ifndef LIBWRAP_ALLOW_FACILITY
231 1.17 mouse # define LIBWRAP_ALLOW_FACILITY LOG_AUTH
232 1.13 mrg #endif
233 1.13 mrg #ifndef LIBWRAP_ALLOW_SEVERITY
234 1.13 mrg # define LIBWRAP_ALLOW_SEVERITY LOG_INFO
235 1.13 mrg #endif
236 1.13 mrg #ifndef LIBWRAP_DENY_FACILITY
237 1.17 mouse # define LIBWRAP_DENY_FACILITY LOG_AUTH
238 1.13 mrg #endif
239 1.13 mrg #ifndef LIBWRAP_DENY_SEVERITY
240 1.13 mrg # define LIBWRAP_DENY_SEVERITY LOG_WARNING
241 1.13 mrg #endif
242 1.13 mrg int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
243 1.13 mrg int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
244 1.12 mrg #endif
245 1.12 mrg
246 1.137 christos static bool foreground;
247 1.12 mrg int debug;
248 1.12 mrg #ifdef LIBWRAP
249 1.12 mrg int lflag;
250 1.12 mrg #endif
251 1.88 tron int maxsock;
252 1.85 tron int kq;
253 1.1 cgd int options;
254 1.1 cgd int timingout;
255 1.57 itojun const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
256 1.5 pk
257 1.5 pk #ifndef OPEN_MAX
258 1.5 pk #define OPEN_MAX 64
259 1.5 pk #endif
260 1.5 pk
261 1.5 pk /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
262 1.5 pk #define FD_MARGIN (8)
263 1.70 mycroft rlim_t rlim_ofile_cur = OPEN_MAX;
264 1.5 pk
265 1.5 pk struct rlimit rlim_ofile;
266 1.1 cgd
267 1.87 tron struct kevent changebuf[64];
268 1.87 tron size_t changes;
269 1.87 tron
270 1.127 christos struct servtab *servtab;
271 1.23 mycroft
272 1.87 tron static void chargen_dg(int, struct servtab *);
273 1.87 tron static void chargen_stream(int, struct servtab *);
274 1.87 tron static void daytime_dg(int, struct servtab *);
275 1.87 tron static void daytime_stream(int, struct servtab *);
276 1.87 tron static void discard_dg(int, struct servtab *);
277 1.87 tron static void discard_stream(int, struct servtab *);
278 1.87 tron static void echo_dg(int, struct servtab *);
279 1.87 tron static void echo_stream(int, struct servtab *);
280 1.119 joerg __dead static void goaway(void);
281 1.87 tron static void machtime_dg(int, struct servtab *);
282 1.87 tron static void machtime_stream(int, struct servtab *);
283 1.87 tron static void reapchild(void);
284 1.87 tron static void retry(void);
285 1.105 dholland static void run_service(int, struct servtab *, int);
286 1.87 tron static void tcpmux(int, struct servtab *);
287 1.119 joerg __dead static void usage(void);
288 1.87 tron static void bump_nofile(void);
289 1.87 tron static void inetd_setproctitle(char *, int);
290 1.87 tron static void initring(void);
291 1.87 tron static uint32_t machtime(void);
292 1.87 tron static int port_good_dg(struct sockaddr *);
293 1.127 christos static int dg_broadcast(struct in_addr *);
294 1.127 christos static int my_kevent(const struct kevent *, size_t, struct kevent *, size_t);
295 1.127 christos static struct kevent *allocchange(void);
296 1.113 roy static int get_line(int, char *, int);
297 1.87 tron static void spawn(struct servtab *, int);
298 1.1 cgd
299 1.1 cgd struct biltin {
300 1.110 christos const char *bi_service; /* internally provided service name */
301 1.1 cgd int bi_socktype; /* type of socket supported */
302 1.1 cgd short bi_fork; /* 1 if should fork before call */
303 1.1 cgd short bi_wait; /* 1 if should wait for child */
304 1.86 tron void (*bi_fn)(int, struct servtab *);
305 1.36 mrg /* function which performs it */
306 1.1 cgd } biltins[] = {
307 1.1 cgd /* Echo received data */
308 1.134 rillig { "echo", SOCK_STREAM, true, false, echo_stream },
309 1.134 rillig { "echo", SOCK_DGRAM, false, false, echo_dg },
310 1.1 cgd
311 1.1 cgd /* Internet /dev/null */
312 1.134 rillig { "discard", SOCK_STREAM, true, false, discard_stream },
313 1.134 rillig { "discard", SOCK_DGRAM, false, false, discard_dg },
314 1.1 cgd
315 1.35 mrg /* Return 32 bit time since 1970 */
316 1.134 rillig { "time", SOCK_STREAM, false, false, machtime_stream },
317 1.134 rillig { "time", SOCK_DGRAM, false, false, machtime_dg },
318 1.1 cgd
319 1.1 cgd /* Return human-readable time */
320 1.134 rillig { "daytime", SOCK_STREAM, false, false, daytime_stream },
321 1.134 rillig { "daytime", SOCK_DGRAM, false, false, daytime_dg },
322 1.1 cgd
323 1.1 cgd /* Familiar character generator */
324 1.134 rillig { "chargen", SOCK_STREAM, true, false, chargen_stream },
325 1.134 rillig { "chargen", SOCK_DGRAM, false, false, chargen_dg },
326 1.23 mycroft
327 1.137 christos { "tcpmux", SOCK_STREAM, true, false, tcpmux }
328 1.1 cgd };
329 1.1 cgd
330 1.47 hwr /* list of "bad" ports. I.e. ports that are most obviously used for
331 1.47 hwr * "cycling packets" denial of service attacks. See /etc/services.
332 1.47 hwr * List must end with port number "0".
333 1.47 hwr */
334 1.47 hwr
335 1.79 itojun u_int16_t bad_ports[] = { 7, 9, 13, 19, 37, 0 };
336 1.47 hwr
337 1.47 hwr
338 1.1 cgd #define NUMINT (sizeof(intab) / sizeof(struct inent))
339 1.110 christos const char *CONFIG = _PATH_INETDCONF;
340 1.5 pk
341 1.88 tron static int my_signals[] =
342 1.88 tron { SIGALRM, SIGHUP, SIGCHLD, SIGTERM, SIGINT, SIGPIPE };
343 1.87 tron
344 1.36 mrg int
345 1.87 tron main(int argc, char *argv[])
346 1.1 cgd {
347 1.87 tron int ch, n, reload = 1;
348 1.1 cgd
349 1.12 mrg while ((ch = getopt(argc, argv,
350 1.12 mrg #ifdef LIBWRAP
351 1.137 christos "dfl"
352 1.12 mrg #else
353 1.137 christos "df"
354 1.12 mrg #endif
355 1.38 lukem )) != -1)
356 1.1 cgd switch(ch) {
357 1.1 cgd case 'd':
358 1.137 christos foreground = true;
359 1.134 rillig debug = true;
360 1.1 cgd options |= SO_DEBUG;
361 1.1 cgd break;
362 1.137 christos case 'f':
363 1.137 christos foreground = true;
364 1.137 christos break;
365 1.12 mrg #ifdef LIBWRAP
366 1.12 mrg case 'l':
367 1.134 rillig lflag = true;
368 1.12 mrg break;
369 1.12 mrg #endif
370 1.1 cgd case '?':
371 1.1 cgd default:
372 1.23 mycroft usage();
373 1.1 cgd }
374 1.1 cgd argc -= optind;
375 1.1 cgd argv += optind;
376 1.1 cgd
377 1.1 cgd if (argc > 0)
378 1.1 cgd CONFIG = argv[0];
379 1.5 pk
380 1.137 christos if (!foreground)
381 1.1 cgd daemon(0, 0);
382 1.72 lukem openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
383 1.48 thorpej pidfile(NULL);
384 1.5 pk
385 1.85 tron kq = kqueue();
386 1.85 tron if (kq < 0) {
387 1.85 tron syslog(LOG_ERR, "kqueue: %m");
388 1.85 tron return (EXIT_FAILURE);
389 1.85 tron }
390 1.85 tron
391 1.6 pk if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
392 1.5 pk syslog(LOG_ERR, "getrlimit: %m");
393 1.5 pk } else {
394 1.5 pk rlim_ofile_cur = rlim_ofile.rlim_cur;
395 1.6 pk if (rlim_ofile_cur == RLIM_INFINITY) /* ! */
396 1.6 pk rlim_ofile_cur = OPEN_MAX;
397 1.5 pk }
398 1.5 pk
399 1.127 christos for (n = 0; n < (int)__arraycount(my_signals); n++) {
400 1.88 tron int signum;
401 1.88 tron
402 1.88 tron signum = my_signals[n];
403 1.100 christos if (signum != SIGCHLD)
404 1.100 christos (void) signal(signum, SIG_IGN);
405 1.88 tron
406 1.88 tron if (signum != SIGPIPE) {
407 1.88 tron struct kevent *ev;
408 1.88 tron
409 1.88 tron ev = allocchange();
410 1.88 tron EV_SET(ev, signum, EVFILT_SIGNAL, EV_ADD | EV_ENABLE,
411 1.94 fvdl 0, 0, 0);
412 1.88 tron }
413 1.87 tron }
414 1.1 cgd
415 1.1 cgd for (;;) {
416 1.87 tron int ctrl;
417 1.88 tron struct kevent eventbuf[64], *ev;
418 1.87 tron struct servtab *sep;
419 1.87 tron
420 1.87 tron if (reload) {
421 1.134 rillig reload = false;
422 1.127 christos config_root();
423 1.87 tron }
424 1.1 cgd
425 1.127 christos n = my_kevent(changebuf, changes, eventbuf, __arraycount(eventbuf));
426 1.87 tron changes = 0;
427 1.87 tron
428 1.87 tron for (ev = eventbuf; n > 0; ev++, n--) {
429 1.87 tron if (ev->filter == EVFILT_SIGNAL) {
430 1.87 tron switch (ev->ident) {
431 1.87 tron case SIGALRM:
432 1.87 tron retry();
433 1.87 tron break;
434 1.87 tron case SIGCHLD:
435 1.87 tron reapchild();
436 1.87 tron break;
437 1.87 tron case SIGTERM:
438 1.87 tron case SIGINT:
439 1.87 tron goaway();
440 1.87 tron break;
441 1.87 tron case SIGHUP:
442 1.134 rillig reload = true;
443 1.87 tron break;
444 1.87 tron }
445 1.85 tron continue;
446 1.87 tron }
447 1.87 tron if (ev->filter != EVFILT_READ)
448 1.87 tron continue;
449 1.87 tron sep = (struct servtab *)ev->udata;
450 1.85 tron /* Paranoia */
451 1.102 rillig if ((int)ev->ident != sep->se_fd)
452 1.79 itojun continue;
453 1.127 christos DPRINTF(SERV_FMT ": service requested" , SERV_PARAMS(sep));
454 1.134 rillig if (sep->se_wait == 0 && sep->se_socktype == SOCK_STREAM) {
455 1.96 rumble /* XXX here do the libwrap check-before-accept*/
456 1.85 tron ctrl = accept(sep->se_fd, NULL, NULL);
457 1.130 rillig DPRINTF(SERV_FMT ": accept, ctrl fd %d",
458 1.127 christos SERV_PARAMS(sep), ctrl);
459 1.79 itojun if (ctrl < 0) {
460 1.79 itojun if (errno != EINTR)
461 1.79 itojun syslog(LOG_WARNING,
462 1.127 christos SERV_FMT ": accept: %m",
463 1.127 christos SERV_PARAMS(sep));
464 1.79 itojun continue;
465 1.79 itojun }
466 1.79 itojun } else
467 1.79 itojun ctrl = sep->se_fd;
468 1.79 itojun spawn(sep, ctrl);
469 1.79 itojun }
470 1.79 itojun }
471 1.79 itojun }
472 1.79 itojun
473 1.87 tron static void
474 1.87 tron spawn(struct servtab *sep, int ctrl)
475 1.79 itojun {
476 1.79 itojun int dofork;
477 1.79 itojun pid_t pid;
478 1.79 itojun
479 1.79 itojun pid = 0;
480 1.28 mycroft #ifdef LIBWRAP_INTERNAL
481 1.134 rillig dofork = true;
482 1.26 mycroft #else
483 1.134 rillig dofork = (sep->se_bi == NULL || sep->se_bi->bi_fork);
484 1.26 mycroft #endif
485 1.79 itojun if (dofork) {
486 1.127 christos if (rl_process(sep, ctrl)) {
487 1.127 christos return;
488 1.5 pk }
489 1.79 itojun pid = fork();
490 1.79 itojun if (pid < 0) {
491 1.79 itojun syslog(LOG_ERR, "fork: %m");
492 1.134 rillig if (sep->se_wait == 0 && sep->se_socktype == SOCK_STREAM)
493 1.79 itojun close(ctrl);
494 1.79 itojun sleep(1);
495 1.79 itojun return;
496 1.79 itojun }
497 1.134 rillig if (pid != 0 && sep->se_wait != 0) {
498 1.87 tron struct kevent *ev;
499 1.85 tron
500 1.79 itojun sep->se_wait = pid;
501 1.87 tron ev = allocchange();
502 1.87 tron EV_SET(ev, sep->se_fd, EVFILT_READ,
503 1.85 tron EV_DELETE, 0, 0, 0);
504 1.79 itojun }
505 1.5 pk if (pid == 0) {
506 1.102 rillig size_t n;
507 1.88 tron
508 1.127 christos for (n = 0; n < __arraycount(my_signals); n++)
509 1.88 tron (void) signal(my_signals[n], SIG_DFL);
510 1.137 christos /* Don't put services in terminal session */
511 1.137 christos if (foreground)
512 1.79 itojun setsid();
513 1.30 mycroft }
514 1.30 mycroft }
515 1.79 itojun if (pid == 0) {
516 1.105 dholland run_service(ctrl, sep, dofork);
517 1.79 itojun if (dofork)
518 1.137 christos exit(EXIT_SUCCESS);
519 1.79 itojun }
520 1.134 rillig if (sep->se_wait == 0 && sep->se_socktype == SOCK_STREAM)
521 1.79 itojun close(ctrl);
522 1.30 mycroft }
523 1.30 mycroft
524 1.87 tron static void
525 1.105 dholland run_service(int ctrl, struct servtab *sep, int didfork)
526 1.30 mycroft {
527 1.30 mycroft struct passwd *pwd;
528 1.36 mrg struct group *grp = NULL; /* XXX gcc */
529 1.57 itojun char buf[NI_MAXSERV];
530 1.105 dholland struct servtab *s;
531 1.30 mycroft #ifdef LIBWRAP
532 1.109 christos char abuf[BUFSIZ];
533 1.30 mycroft struct request_info req;
534 1.30 mycroft int denied;
535 1.40 christos char *service = NULL; /* XXX gcc */
536 1.30 mycroft #endif
537 1.30 mycroft
538 1.20 mycroft #ifdef LIBWRAP
539 1.28 mycroft #ifndef LIBWRAP_INTERNAL
540 1.30 mycroft if (sep->se_bi == 0)
541 1.28 mycroft #endif
542 1.134 rillig if (sep->se_wait == 0 && sep->se_socktype == SOCK_STREAM) {
543 1.134 rillig request_init(&req, RQ_DAEMON, sep->se_argv[0] != NULL ?
544 1.30 mycroft sep->se_argv[0] : sep->se_service, RQ_FILE, ctrl, NULL);
545 1.30 mycroft fromhost(&req);
546 1.134 rillig denied = hosts_access(&req) == 0;
547 1.30 mycroft if (denied || lflag) {
548 1.52 itojun if (getnameinfo(&sep->se_ctrladdr,
549 1.110 christos (socklen_t)sep->se_ctrladdr.sa_len, NULL, 0,
550 1.110 christos buf, sizeof(buf), 0) != 0) {
551 1.52 itojun /* shouldn't happen */
552 1.30 mycroft (void)snprintf(buf, sizeof buf, "%d",
553 1.30 mycroft ntohs(sep->se_ctrladdr_in.sin_port));
554 1.52 itojun }
555 1.52 itojun service = buf;
556 1.134 rillig if (req.client->sin != NULL) {
557 1.116 dholland sockaddr_snprintf(abuf, sizeof(abuf), "%a",
558 1.116 dholland req.client->sin);
559 1.116 dholland } else {
560 1.116 dholland strcpy(abuf, "(null)");
561 1.116 dholland }
562 1.30 mycroft }
563 1.30 mycroft if (denied) {
564 1.30 mycroft syslog(deny_severity,
565 1.109 christos "refused connection from %.500s(%s), service %s (%s)",
566 1.109 christos eval_client(&req), abuf, service, sep->se_proto);
567 1.30 mycroft goto reject;
568 1.30 mycroft }
569 1.30 mycroft if (lflag) {
570 1.30 mycroft syslog(allow_severity,
571 1.109 christos "connection from %.500s(%s), service %s (%s)",
572 1.109 christos eval_client(&req), abuf, service, sep->se_proto);
573 1.30 mycroft }
574 1.30 mycroft }
575 1.30 mycroft #endif /* LIBWRAP */
576 1.30 mycroft
577 1.134 rillig if (sep->se_bi != NULL) {
578 1.105 dholland if (didfork) {
579 1.134 rillig for (s = servtab; s != NULL; s = s->se_next)
580 1.110 christos if (s->se_fd != -1 && s->se_fd != ctrl) {
581 1.105 dholland close(s->se_fd);
582 1.110 christos s->se_fd = -1;
583 1.110 christos }
584 1.105 dholland }
585 1.30 mycroft (*sep->se_bi->bi_fn)(ctrl, sep);
586 1.30 mycroft } else {
587 1.30 mycroft if ((pwd = getpwnam(sep->se_user)) == NULL) {
588 1.30 mycroft syslog(LOG_ERR, "%s/%s: %s: No such user",
589 1.30 mycroft sep->se_service, sep->se_proto, sep->se_user);
590 1.30 mycroft goto reject;
591 1.30 mycroft }
592 1.134 rillig if (sep->se_group != NULL &&
593 1.30 mycroft (grp = getgrnam(sep->se_group)) == NULL) {
594 1.30 mycroft syslog(LOG_ERR, "%s/%s: %s: No such group",
595 1.30 mycroft sep->se_service, sep->se_proto, sep->se_group);
596 1.30 mycroft goto reject;
597 1.30 mycroft }
598 1.134 rillig if (pwd->pw_uid != 0) {
599 1.134 rillig if (sep->se_group != NULL)
600 1.30 mycroft pwd->pw_gid = grp->gr_gid;
601 1.30 mycroft if (setgid(pwd->pw_gid) < 0) {
602 1.30 mycroft syslog(LOG_ERR,
603 1.30 mycroft "%s/%s: can't set gid %d: %m", sep->se_service,
604 1.30 mycroft sep->se_proto, pwd->pw_gid);
605 1.30 mycroft goto reject;
606 1.20 mycroft }
607 1.30 mycroft (void) initgroups(pwd->pw_name,
608 1.30 mycroft pwd->pw_gid);
609 1.30 mycroft if (setuid(pwd->pw_uid) < 0) {
610 1.30 mycroft syslog(LOG_ERR,
611 1.30 mycroft "%s/%s: can't set uid %d: %m", sep->se_service,
612 1.30 mycroft sep->se_proto, pwd->pw_uid);
613 1.22 mycroft goto reject;
614 1.20 mycroft }
615 1.134 rillig } else if (sep->se_group != NULL) {
616 1.30 mycroft (void) setgid((gid_t)grp->gr_gid);
617 1.30 mycroft }
618 1.130 rillig DPRINTF("%d execl %s",
619 1.127 christos getpid(), sep->se_server);
620 1.30 mycroft /* Set our control descriptor to not close-on-exec... */
621 1.30 mycroft if (fcntl(ctrl, F_SETFD, 0) < 0)
622 1.110 christos syslog(LOG_ERR, "fcntl (%d, F_SETFD, 0): %m", ctrl);
623 1.30 mycroft /* ...and dup it to stdin, stdout, and stderr. */
624 1.30 mycroft if (ctrl != 0) {
625 1.30 mycroft dup2(ctrl, 0);
626 1.30 mycroft close(ctrl);
627 1.30 mycroft ctrl = 0;
628 1.30 mycroft }
629 1.30 mycroft dup2(0, 1);
630 1.30 mycroft dup2(0, 2);
631 1.30 mycroft if (rlim_ofile.rlim_cur != rlim_ofile_cur &&
632 1.30 mycroft setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
633 1.30 mycroft syslog(LOG_ERR, "setrlimit: %m");
634 1.30 mycroft execv(sep->se_server, sep->se_argv);
635 1.30 mycroft syslog(LOG_ERR, "cannot execute %s: %m", sep->se_server);
636 1.30 mycroft reject:
637 1.30 mycroft if (sep->se_socktype != SOCK_STREAM)
638 1.30 mycroft recv(ctrl, buf, sizeof (buf), 0);
639 1.127 christos _exit(EXIT_FAILURE);
640 1.1 cgd }
641 1.1 cgd }
642 1.1 cgd
643 1.87 tron static void
644 1.87 tron reapchild(void)
645 1.1 cgd {
646 1.1 cgd int status;
647 1.23 mycroft pid_t pid;
648 1.23 mycroft struct servtab *sep;
649 1.1 cgd
650 1.1 cgd for (;;) {
651 1.85 tron pid = wait3(&status, WNOHANG, NULL);
652 1.1 cgd if (pid <= 0)
653 1.1 cgd break;
654 1.127 christos DPRINTF("%d reaped, status %#x", pid, status);
655 1.85 tron for (sep = servtab; sep != NULL; sep = sep->se_next)
656 1.1 cgd if (sep->se_wait == pid) {
657 1.87 tron struct kevent *ev;
658 1.85 tron
659 1.5 pk if (WIFEXITED(status) && WEXITSTATUS(status))
660 1.1 cgd syslog(LOG_WARNING,
661 1.122 khorben "%s: exit status %u",
662 1.5 pk sep->se_server, WEXITSTATUS(status));
663 1.5 pk else if (WIFSIGNALED(status))
664 1.5 pk syslog(LOG_WARNING,
665 1.122 khorben "%s: exit signal %u",
666 1.5 pk sep->se_server, WTERMSIG(status));
667 1.5 pk sep->se_wait = 1;
668 1.87 tron ev = allocchange();
669 1.87 tron EV_SET(ev, sep->se_fd, EVFILT_READ,
670 1.85 tron EV_ADD | EV_ENABLE, 0, 0, (intptr_t)sep);
671 1.127 christos DPRINTF("restored %s, fd %d",
672 1.127 christos sep->se_service, sep->se_fd);
673 1.1 cgd }
674 1.1 cgd }
675 1.1 cgd }
676 1.1 cgd
677 1.87 tron static void
678 1.87 tron retry(void)
679 1.5 pk {
680 1.23 mycroft struct servtab *sep;
681 1.2 brezak
682 1.134 rillig timingout = false;
683 1.85 tron for (sep = servtab; sep != NULL; sep = sep->se_next) {
684 1.23 mycroft if (sep->se_fd == -1 && !ISMUX(sep)) {
685 1.5 pk switch (sep->se_family) {
686 1.44 lukem case AF_LOCAL:
687 1.5 pk case AF_INET:
688 1.58 itojun #ifdef INET6
689 1.49 itojun case AF_INET6:
690 1.58 itojun #endif
691 1.5 pk setup(sep);
692 1.110 christos if (sep->se_fd >= 0 && isrpcservice(sep))
693 1.5 pk register_rpc(sep);
694 1.5 pk break;
695 1.5 pk }
696 1.5 pk }
697 1.5 pk }
698 1.2 brezak }
699 1.2 brezak
700 1.87 tron static void
701 1.87 tron goaway(void)
702 1.1 cgd {
703 1.36 mrg struct servtab *sep;
704 1.1 cgd
705 1.85 tron for (sep = servtab; sep != NULL; sep = sep->se_next) {
706 1.1 cgd if (sep->se_fd == -1)
707 1.5 pk continue;
708 1.130 rillig
709 1.5 pk switch (sep->se_family) {
710 1.44 lukem case AF_LOCAL:
711 1.5 pk (void)unlink(sep->se_service);
712 1.5 pk break;
713 1.5 pk case AF_INET:
714 1.58 itojun #ifdef INET6
715 1.49 itojun case AF_INET6:
716 1.58 itojun #endif
717 1.5 pk if (sep->se_wait == 1 && isrpcservice(sep))
718 1.5 pk unregister_rpc(sep);
719 1.5 pk break;
720 1.5 pk }
721 1.5 pk (void)close(sep->se_fd);
722 1.110 christos sep->se_fd = -1;
723 1.5 pk }
724 1.137 christos
725 1.137 christos DPRINTF("Going away.");
726 1.137 christos
727 1.137 christos exit(EXIT_SUCCESS);
728 1.1 cgd }
729 1.1 cgd
730 1.137 christos void
731 1.87 tron setup(struct servtab *sep)
732 1.1 cgd {
733 1.97 pk int on = 1;
734 1.97 pk #ifdef INET6
735 1.97 pk int off = 0;
736 1.97 pk #endif
737 1.87 tron struct kevent *ev;
738 1.1 cgd
739 1.5 pk if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
740 1.130 rillig DPRINTF("socket failed on " SERV_FMT ": %s",
741 1.127 christos SERV_PARAMS(sep), strerror(errno));
742 1.1 cgd syslog(LOG_ERR, "%s/%s: socket: %m",
743 1.1 cgd sep->se_service, sep->se_proto);
744 1.1 cgd return;
745 1.1 cgd }
746 1.46 mycroft /* Set all listening sockets to close-on-exec. */
747 1.84 mycroft if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) {
748 1.127 christos syslog(LOG_ERR, SERV_FMT ": fcntl(F_SETFD, FD_CLOEXEC): %m",
749 1.127 christos SERV_PARAMS(sep));
750 1.84 mycroft close(sep->se_fd);
751 1.110 christos sep->se_fd = -1;
752 1.84 mycroft return;
753 1.84 mycroft }
754 1.42 thorpej
755 1.1 cgd #define turnon(fd, opt) \
756 1.110 christos setsockopt(fd, SOL_SOCKET, opt, &on, (socklen_t)sizeof(on))
757 1.1 cgd if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
758 1.1 cgd turnon(sep->se_fd, SO_DEBUG) < 0)
759 1.1 cgd syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
760 1.1 cgd if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
761 1.1 cgd syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
762 1.1 cgd #undef turnon
763 1.42 thorpej
764 1.42 thorpej /* Set the socket buffer sizes, if specified. */
765 1.42 thorpej if (sep->se_sndbuf != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
766 1.110 christos SO_SNDBUF, &sep->se_sndbuf, (socklen_t)sizeof(sep->se_sndbuf)) < 0)
767 1.42 thorpej syslog(LOG_ERR, "setsockopt (SO_SNDBUF %d): %m",
768 1.42 thorpej sep->se_sndbuf);
769 1.42 thorpej if (sep->se_rcvbuf != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
770 1.110 christos SO_RCVBUF, &sep->se_rcvbuf, (socklen_t)sizeof(sep->se_rcvbuf)) < 0)
771 1.42 thorpej syslog(LOG_ERR, "setsockopt (SO_RCVBUF %d): %m",
772 1.42 thorpej sep->se_rcvbuf);
773 1.90 itojun #ifdef INET6
774 1.90 itojun if (sep->se_family == AF_INET6) {
775 1.90 itojun int *v;
776 1.90 itojun v = (sep->se_type == FAITH_TYPE) ? &on : &off;
777 1.90 itojun if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH,
778 1.110 christos v, (socklen_t)sizeof(*v)) < 0)
779 1.90 itojun syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m");
780 1.90 itojun }
781 1.90 itojun #endif
782 1.49 itojun #ifdef IPSEC
783 1.124 ozaki /* Avoid setting a policy if a policy specifier doesn't exist. */
784 1.124 ozaki if (sep->se_policy != NULL) {
785 1.124 ozaki int e = ipsecsetup(sep->se_family, sep->se_fd, sep->se_policy);
786 1.124 ozaki if (e < 0) {
787 1.127 christos syslog(LOG_ERR, SERV_FMT ": ipsec setup failed",
788 1.127 christos SERV_PARAMS(sep));
789 1.124 ozaki (void)close(sep->se_fd);
790 1.124 ozaki sep->se_fd = -1;
791 1.124 ozaki return;
792 1.124 ozaki }
793 1.50 itojun }
794 1.49 itojun #endif
795 1.42 thorpej
796 1.127 christos if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
797 1.127 christos DPRINTF(SERV_FMT ": bind failed: %s",
798 1.127 christos SERV_PARAMS(sep), strerror(errno));
799 1.127 christos syslog(LOG_ERR, SERV_FMT ": bind: %m",
800 1.127 christos SERV_PARAMS(sep));
801 1.1 cgd (void) close(sep->se_fd);
802 1.1 cgd sep->se_fd = -1;
803 1.1 cgd if (!timingout) {
804 1.134 rillig timingout = true;
805 1.1 cgd alarm(RETRYTIME);
806 1.1 cgd }
807 1.1 cgd return;
808 1.1 cgd }
809 1.1 cgd if (sep->se_socktype == SOCK_STREAM)
810 1.1 cgd listen(sep->se_fd, 10);
811 1.5 pk
812 1.107 tls /* Set the accept filter, if specified. To be done after listen.*/
813 1.107 tls if (sep->se_accf.af_name[0] != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
814 1.110 christos SO_ACCEPTFILTER, &sep->se_accf,
815 1.110 christos (socklen_t)sizeof(sep->se_accf)) < 0)
816 1.107 tls syslog(LOG_ERR, "setsockopt(SO_ACCEPTFILTER %s): %m",
817 1.107 tls sep->se_accf.af_name);
818 1.107 tls
819 1.87 tron ev = allocchange();
820 1.87 tron EV_SET(ev, sep->se_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0,
821 1.85 tron (intptr_t)sep);
822 1.5 pk if (sep->se_fd > maxsock) {
823 1.1 cgd maxsock = sep->se_fd;
824 1.111 lukem if (maxsock > (int)(rlim_ofile_cur - FD_MARGIN))
825 1.5 pk bump_nofile();
826 1.5 pk }
827 1.127 christos DPRINTF(SERV_FMT ": registered on fd %d", SERV_PARAMS(sep), sep->se_fd);
828 1.23 mycroft }
829 1.23 mycroft
830 1.23 mycroft /*
831 1.23 mycroft * Finish with a service and its socket.
832 1.23 mycroft */
833 1.137 christos void
834 1.87 tron close_sep(struct servtab *sep)
835 1.130 rillig {
836 1.127 christos
837 1.23 mycroft if (sep->se_fd >= 0) {
838 1.23 mycroft (void) close(sep->se_fd);
839 1.23 mycroft sep->se_fd = -1;
840 1.23 mycroft }
841 1.23 mycroft sep->se_count = 0;
842 1.127 christos if (sep->se_ip_max != SERVTAB_UNSPEC_SIZE_T) {
843 1.137 christos rl_clear_ip_list(sep);
844 1.127 christos }
845 1.5 pk }
846 1.5 pk
847 1.137 christos void
848 1.87 tron register_rpc(struct servtab *sep)
849 1.5 pk {
850 1.5 pk #ifdef RPC
851 1.62 fvdl struct netbuf nbuf;
852 1.49 itojun struct sockaddr_storage ss;
853 1.62 fvdl struct netconfig *nconf;
854 1.102 rillig socklen_t socklen;
855 1.102 rillig int n;
856 1.5 pk
857 1.62 fvdl if ((nconf = getnetconfigent(sep->se_proto+4)) == NULL) {
858 1.62 fvdl syslog(LOG_ERR, "%s: getnetconfigent failed",
859 1.5 pk sep->se_proto);
860 1.5 pk return;
861 1.5 pk }
862 1.102 rillig socklen = sizeof ss;
863 1.110 christos if (getsockname(sep->se_fd, (struct sockaddr *)(void *)&ss, &socklen) < 0) {
864 1.127 christos syslog(LOG_ERR, SERV_FMT ": getsockname: %m",
865 1.127 christos SERV_PARAMS(sep));
866 1.5 pk return;
867 1.5 pk }
868 1.5 pk
869 1.62 fvdl nbuf.buf = &ss;
870 1.62 fvdl nbuf.len = ss.ss_len;
871 1.62 fvdl nbuf.maxlen = sizeof (struct sockaddr_storage);
872 1.5 pk for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
873 1.127 christos DPRINTF("rpcb_set: %u %d %s %s",
874 1.127 christos sep->se_rpcprog, n, nconf->nc_netid,
875 1.127 christos taddr2uaddr(nconf, &nbuf));
876 1.110 christos (void)rpcb_unset((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf);
877 1.134 rillig if (rpcb_set((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf, &nbuf) == 0)
878 1.62 fvdl syslog(LOG_ERR, "rpcb_set: %u %d %s %s%s",
879 1.62 fvdl sep->se_rpcprog, n, nconf->nc_netid,
880 1.62 fvdl taddr2uaddr(nconf, &nbuf), clnt_spcreateerror(""));
881 1.5 pk }
882 1.5 pk #endif /* RPC */
883 1.5 pk }
884 1.5 pk
885 1.137 christos void
886 1.87 tron unregister_rpc(struct servtab *sep)
887 1.5 pk {
888 1.5 pk #ifdef RPC
889 1.5 pk int n;
890 1.62 fvdl struct netconfig *nconf;
891 1.62 fvdl
892 1.62 fvdl if ((nconf = getnetconfigent(sep->se_proto+4)) == NULL) {
893 1.62 fvdl syslog(LOG_ERR, "%s: getnetconfigent failed",
894 1.62 fvdl sep->se_proto);
895 1.62 fvdl return;
896 1.62 fvdl }
897 1.5 pk
898 1.5 pk for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
899 1.127 christos DPRINTF("rpcb_unset(%u, %d, %s)",
900 1.127 christos sep->se_rpcprog, n, nconf->nc_netid);
901 1.134 rillig if (rpcb_unset((unsigned int)sep->se_rpcprog, (unsigned int)n, nconf) == 0)
902 1.62 fvdl syslog(LOG_ERR, "rpcb_unset(%u, %d, %s) failed\n",
903 1.62 fvdl sep->se_rpcprog, n, nconf->nc_netid);
904 1.5 pk }
905 1.5 pk #endif /* RPC */
906 1.1 cgd }
907 1.1 cgd
908 1.87 tron static void
909 1.87 tron inetd_setproctitle(char *a, int s)
910 1.1 cgd {
911 1.77 christos socklen_t size;
912 1.49 itojun struct sockaddr_storage ss;
913 1.110 christos char hbuf[NI_MAXHOST];
914 1.110 christos const char *hp;
915 1.110 christos struct sockaddr *sa;
916 1.1 cgd
917 1.49 itojun size = sizeof(ss);
918 1.110 christos sa = (struct sockaddr *)(void *)&ss;
919 1.110 christos if (getpeername(s, sa, &size) == 0) {
920 1.110 christos if (getnameinfo(sa, size, hbuf, (socklen_t)sizeof(hbuf), NULL,
921 1.110 christos 0, niflags) != 0)
922 1.99 christos hp = "?";
923 1.110 christos else
924 1.110 christos hp = hbuf;
925 1.99 christos setproctitle("-%s [%s]", a, hp);
926 1.49 itojun } else
927 1.77 christos setproctitle("-%s", a);
928 1.5 pk }
929 1.5 pk
930 1.87 tron static void
931 1.87 tron bump_nofile(void)
932 1.5 pk {
933 1.5 pk #define FD_CHUNK 32
934 1.5 pk struct rlimit rl;
935 1.5 pk
936 1.6 pk if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
937 1.5 pk syslog(LOG_ERR, "getrlimit: %m");
938 1.36 mrg return;
939 1.5 pk }
940 1.5 pk rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
941 1.5 pk if (rl.rlim_cur <= rlim_ofile_cur) {
942 1.5 pk syslog(LOG_ERR,
943 1.23 mycroft "bump_nofile: cannot extend file limit, max = %d",
944 1.36 mrg (int)rl.rlim_cur);
945 1.36 mrg return;
946 1.5 pk }
947 1.5 pk
948 1.6 pk if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
949 1.5 pk syslog(LOG_ERR, "setrlimit: %m");
950 1.36 mrg return;
951 1.5 pk }
952 1.5 pk
953 1.5 pk rlim_ofile_cur = rl.rlim_cur;
954 1.36 mrg return;
955 1.5 pk }
956 1.5 pk
957 1.1 cgd /*
958 1.1 cgd * Internet services provided internally by inetd:
959 1.1 cgd */
960 1.5 pk #define BUFSIZE 4096
961 1.1 cgd
962 1.1 cgd /* ARGSUSED */
963 1.87 tron static void
964 1.87 tron echo_stream(int s, struct servtab *sep) /* Echo service -- echo data back */
965 1.1 cgd {
966 1.1 cgd char buffer[BUFSIZE];
967 1.110 christos ssize_t i;
968 1.1 cgd
969 1.9 cgd inetd_setproctitle(sep->se_service, s);
970 1.1 cgd while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
971 1.110 christos write(s, buffer, (size_t)i) > 0)
972 1.137 christos continue;
973 1.1 cgd }
974 1.1 cgd
975 1.1 cgd /* ARGSUSED */
976 1.87 tron static void
977 1.87 tron echo_dg(int s, struct servtab *sep) /* Echo service -- echo data back */
978 1.1 cgd {
979 1.1 cgd char buffer[BUFSIZE];
980 1.110 christos ssize_t i;
981 1.78 itojun socklen_t size;
982 1.54 itojun struct sockaddr_storage ss;
983 1.54 itojun struct sockaddr *sa;
984 1.1 cgd
985 1.110 christos sa = (struct sockaddr *)(void *)&ss;
986 1.54 itojun size = sizeof(ss);
987 1.54 itojun if ((i = recvfrom(s, buffer, sizeof(buffer), 0, sa, &size)) < 0)
988 1.1 cgd return;
989 1.54 itojun if (port_good_dg(sa))
990 1.110 christos (void) sendto(s, buffer, (size_t)i, 0, sa, size);
991 1.1 cgd }
992 1.1 cgd
993 1.1 cgd /* ARGSUSED */
994 1.87 tron static void
995 1.87 tron discard_stream(int s, struct servtab *sep) /* Discard service -- ignore data */
996 1.1 cgd {
997 1.1 cgd char buffer[BUFSIZE];
998 1.1 cgd
999 1.9 cgd inetd_setproctitle(sep->se_service, s);
1000 1.5 pk while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1001 1.5 pk errno == EINTR)
1002 1.5 pk ;
1003 1.1 cgd }
1004 1.1 cgd
1005 1.1 cgd /* ARGSUSED */
1006 1.87 tron static void
1007 1.87 tron discard_dg(int s, struct servtab *sep) /* Discard service -- ignore data */
1008 1.130 rillig
1009 1.1 cgd {
1010 1.1 cgd char buffer[BUFSIZE];
1011 1.1 cgd
1012 1.1 cgd (void) read(s, buffer, sizeof(buffer));
1013 1.1 cgd }
1014 1.1 cgd
1015 1.1 cgd #define LINESIZ 72
1016 1.1 cgd char ring[128];
1017 1.1 cgd char *endring;
1018 1.1 cgd
1019 1.87 tron static void
1020 1.87 tron initring(void)
1021 1.1 cgd {
1022 1.23 mycroft int i;
1023 1.1 cgd
1024 1.1 cgd endring = ring;
1025 1.1 cgd
1026 1.1 cgd for (i = 0; i <= 128; ++i)
1027 1.1 cgd if (isprint(i))
1028 1.131 rillig *endring++ = (char)i;
1029 1.1 cgd }
1030 1.1 cgd
1031 1.1 cgd /* ARGSUSED */
1032 1.87 tron static void
1033 1.131 rillig chargen_stream(int s, struct servtab *sep) /* Character generator */
1034 1.1 cgd {
1035 1.110 christos size_t len;
1036 1.23 mycroft char *rs, text[LINESIZ+2];
1037 1.1 cgd
1038 1.9 cgd inetd_setproctitle(sep->se_service, s);
1039 1.1 cgd
1040 1.134 rillig if (endring == NULL) {
1041 1.1 cgd initring();
1042 1.1 cgd rs = ring;
1043 1.1 cgd }
1044 1.1 cgd
1045 1.1 cgd text[LINESIZ] = '\r';
1046 1.1 cgd text[LINESIZ + 1] = '\n';
1047 1.1 cgd for (rs = ring;;) {
1048 1.131 rillig if ((len = (size_t)(endring - rs)) >= LINESIZ)
1049 1.23 mycroft memmove(text, rs, LINESIZ);
1050 1.1 cgd else {
1051 1.23 mycroft memmove(text, rs, len);
1052 1.23 mycroft memmove(text + len, ring, LINESIZ - len);
1053 1.1 cgd }
1054 1.1 cgd if (++rs == endring)
1055 1.1 cgd rs = ring;
1056 1.1 cgd if (write(s, text, sizeof(text)) != sizeof(text))
1057 1.1 cgd break;
1058 1.1 cgd }
1059 1.1 cgd }
1060 1.1 cgd
1061 1.1 cgd /* ARGSUSED */
1062 1.87 tron static void
1063 1.87 tron chargen_dg(int s, struct servtab *sep) /* Character generator */
1064 1.1 cgd {
1065 1.54 itojun struct sockaddr_storage ss;
1066 1.54 itojun struct sockaddr *sa;
1067 1.1 cgd static char *rs;
1068 1.110 christos size_t len;
1069 1.78 itojun socklen_t size;
1070 1.1 cgd char text[LINESIZ+2];
1071 1.1 cgd
1072 1.1 cgd if (endring == 0) {
1073 1.1 cgd initring();
1074 1.1 cgd rs = ring;
1075 1.1 cgd }
1076 1.1 cgd
1077 1.110 christos sa = (struct sockaddr *)(void *)&ss;
1078 1.54 itojun size = sizeof(ss);
1079 1.54 itojun if (recvfrom(s, text, sizeof(text), 0, sa, &size) < 0)
1080 1.1 cgd return;
1081 1.1 cgd
1082 1.54 itojun if (!port_good_dg(sa))
1083 1.47 hwr return;
1084 1.47 hwr
1085 1.131 rillig if ((len = (size_t)(endring - rs)) >= LINESIZ)
1086 1.23 mycroft memmove(text, rs, LINESIZ);
1087 1.1 cgd else {
1088 1.23 mycroft memmove(text, rs, len);
1089 1.23 mycroft memmove(text + len, ring, LINESIZ - len);
1090 1.1 cgd }
1091 1.1 cgd if (++rs == endring)
1092 1.1 cgd rs = ring;
1093 1.1 cgd text[LINESIZ] = '\r';
1094 1.1 cgd text[LINESIZ + 1] = '\n';
1095 1.54 itojun (void) sendto(s, text, sizeof(text), 0, sa, size);
1096 1.1 cgd }
1097 1.1 cgd
1098 1.1 cgd /*
1099 1.1 cgd * Return a machine readable date and time, in the form of the
1100 1.1 cgd * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1101 1.1 cgd * returns the number of seconds since midnight, Jan 1, 1970,
1102 1.1 cgd * we must add 2208988800 seconds to this figure to make up for
1103 1.1 cgd * some seventy years Bell Labs was asleep.
1104 1.1 cgd */
1105 1.1 cgd
1106 1.87 tron static uint32_t
1107 1.87 tron machtime(void)
1108 1.1 cgd {
1109 1.1 cgd struct timeval tv;
1110 1.1 cgd
1111 1.85 tron if (gettimeofday(&tv, NULL) < 0) {
1112 1.127 christos DPRINTF("Unable to get time of day");
1113 1.75 abs return (0);
1114 1.1 cgd }
1115 1.75 abs #define OFFSET ((uint32_t)25567 * 24*60*60)
1116 1.75 abs return (htonl((uint32_t)(tv.tv_sec + OFFSET)));
1117 1.23 mycroft #undef OFFSET
1118 1.1 cgd }
1119 1.1 cgd
1120 1.1 cgd /* ARGSUSED */
1121 1.87 tron static void
1122 1.87 tron machtime_stream(int s, struct servtab *sep)
1123 1.1 cgd {
1124 1.75 abs uint32_t result;
1125 1.1 cgd
1126 1.1 cgd result = machtime();
1127 1.110 christos (void) write(s, &result, sizeof(result));
1128 1.1 cgd }
1129 1.1 cgd
1130 1.1 cgd /* ARGSUSED */
1131 1.23 mycroft void
1132 1.87 tron machtime_dg(int s, struct servtab *sep)
1133 1.1 cgd {
1134 1.75 abs uint32_t result;
1135 1.54 itojun struct sockaddr_storage ss;
1136 1.54 itojun struct sockaddr *sa;
1137 1.78 itojun socklen_t size;
1138 1.1 cgd
1139 1.110 christos sa = (struct sockaddr *)(void *)&ss;
1140 1.54 itojun size = sizeof(ss);
1141 1.110 christos if (recvfrom(s, &result, sizeof(result), 0, sa, &size) < 0)
1142 1.1 cgd return;
1143 1.54 itojun if (!port_good_dg(sa))
1144 1.47 hwr return;
1145 1.1 cgd result = machtime();
1146 1.110 christos (void)sendto(s, &result, sizeof(result), 0, sa, size);
1147 1.1 cgd }
1148 1.1 cgd
1149 1.1 cgd /* ARGSUSED */
1150 1.87 tron static void
1151 1.87 tron daytime_stream(int s,struct servtab *sep)
1152 1.87 tron /* Return human-readable time of day */
1153 1.1 cgd {
1154 1.1 cgd char buffer[256];
1155 1.110 christos time_t clk;
1156 1.12 mrg int len;
1157 1.1 cgd
1158 1.110 christos clk = time((time_t *) 0);
1159 1.1 cgd
1160 1.110 christos len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clk));
1161 1.131 rillig (void) write(s, buffer, (size_t)len);
1162 1.1 cgd }
1163 1.1 cgd
1164 1.1 cgd /* ARGSUSED */
1165 1.23 mycroft void
1166 1.87 tron daytime_dg(int s, struct servtab *sep)
1167 1.87 tron /* Return human-readable time of day */
1168 1.1 cgd {
1169 1.1 cgd char buffer[256];
1170 1.110 christos time_t clk;
1171 1.54 itojun struct sockaddr_storage ss;
1172 1.54 itojun struct sockaddr *sa;
1173 1.78 itojun socklen_t size;
1174 1.78 itojun int len;
1175 1.1 cgd
1176 1.110 christos clk = time((time_t *) 0);
1177 1.1 cgd
1178 1.110 christos sa = (struct sockaddr *)(void *)&ss;
1179 1.54 itojun size = sizeof(ss);
1180 1.54 itojun if (recvfrom(s, buffer, sizeof(buffer), 0, sa, &size) < 0)
1181 1.1 cgd return;
1182 1.54 itojun if (!port_good_dg(sa))
1183 1.47 hwr return;
1184 1.110 christos len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clk));
1185 1.131 rillig (void) sendto(s, buffer, (size_t)len, 0, sa, size);
1186 1.1 cgd }
1187 1.1 cgd
1188 1.87 tron static void
1189 1.87 tron usage(void)
1190 1.23 mycroft {
1191 1.23 mycroft #ifdef LIBWRAP
1192 1.73 cgd (void)fprintf(stderr, "usage: %s [-dl] [conf]\n", getprogname());
1193 1.23 mycroft #else
1194 1.73 cgd (void)fprintf(stderr, "usage: %s [-d] [conf]\n", getprogname());
1195 1.23 mycroft #endif
1196 1.127 christos exit(EXIT_FAILURE);
1197 1.23 mycroft }
1198 1.23 mycroft
1199 1.23 mycroft
1200 1.23 mycroft /*
1201 1.23 mycroft * Based on TCPMUX.C by Mark K. Lottor November 1988
1202 1.23 mycroft * sri-nic::ps:<mkl>tcpmux.c
1203 1.23 mycroft */
1204 1.23 mycroft
1205 1.23 mycroft static int /* # of characters upto \r,\n or \0 */
1206 1.113 roy get_line(int fd, char *buf, int len)
1207 1.23 mycroft {
1208 1.110 christos int count = 0;
1209 1.110 christos ssize_t n;
1210 1.23 mycroft
1211 1.23 mycroft do {
1212 1.131 rillig n = read(fd, buf, (size_t)(len - count));
1213 1.23 mycroft if (n == 0)
1214 1.23 mycroft return (count);
1215 1.23 mycroft if (n < 0)
1216 1.23 mycroft return (-1);
1217 1.23 mycroft while (--n >= 0) {
1218 1.23 mycroft if (*buf == '\r' || *buf == '\n' || *buf == '\0')
1219 1.23 mycroft return (count);
1220 1.23 mycroft count++;
1221 1.23 mycroft buf++;
1222 1.23 mycroft }
1223 1.23 mycroft } while (count < len);
1224 1.23 mycroft return (count);
1225 1.23 mycroft }
1226 1.23 mycroft
1227 1.23 mycroft #define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */
1228 1.23 mycroft
1229 1.23 mycroft #define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1)
1230 1.23 mycroft
1231 1.87 tron static void
1232 1.87 tron tcpmux(int ctrl, struct servtab *sep)
1233 1.23 mycroft {
1234 1.23 mycroft char service[MAX_SERV_LEN+1];
1235 1.23 mycroft int len;
1236 1.23 mycroft
1237 1.23 mycroft /* Get requested service name */
1238 1.113 roy if ((len = get_line(ctrl, service, MAX_SERV_LEN)) < 0) {
1239 1.30 mycroft strwrite(ctrl, "-Error reading service name\r\n");
1240 1.30 mycroft goto reject;
1241 1.23 mycroft }
1242 1.23 mycroft service[len] = '\0';
1243 1.23 mycroft
1244 1.127 christos DPRINTF("tcpmux: %s: service requested", service);
1245 1.23 mycroft
1246 1.23 mycroft /*
1247 1.23 mycroft * Help is a required command, and lists available services,
1248 1.23 mycroft * one per line.
1249 1.23 mycroft */
1250 1.134 rillig if (strcasecmp(service, "help") == 0) {
1251 1.31 mycroft strwrite(ctrl, "+Available services:\r\n");
1252 1.31 mycroft strwrite(ctrl, "help\r\n");
1253 1.85 tron for (sep = servtab; sep != NULL; sep = sep->se_next) {
1254 1.23 mycroft if (!ISMUX(sep))
1255 1.23 mycroft continue;
1256 1.30 mycroft (void)write(ctrl, sep->se_service,
1257 1.30 mycroft strlen(sep->se_service));
1258 1.30 mycroft strwrite(ctrl, "\r\n");
1259 1.23 mycroft }
1260 1.30 mycroft goto reject;
1261 1.23 mycroft }
1262 1.23 mycroft
1263 1.23 mycroft /* Try matching a service in inetd.conf with the request */
1264 1.85 tron for (sep = servtab; sep != NULL; sep = sep->se_next) {
1265 1.23 mycroft if (!ISMUX(sep))
1266 1.23 mycroft continue;
1267 1.134 rillig if (strcasecmp(service, sep->se_service) == 0) {
1268 1.30 mycroft if (ISMUXPLUS(sep))
1269 1.30 mycroft strwrite(ctrl, "+Go\r\n");
1270 1.134 rillig run_service(ctrl, sep, true /* forked */);
1271 1.30 mycroft return;
1272 1.23 mycroft }
1273 1.23 mycroft }
1274 1.30 mycroft strwrite(ctrl, "-Service not available\r\n");
1275 1.30 mycroft reject:
1276 1.127 christos _exit(EXIT_FAILURE);
1277 1.23 mycroft }
1278 1.23 mycroft
1279 1.47 hwr /*
1280 1.71 itojun * check if the address/port where send data to is one of the obvious ports
1281 1.47 hwr * that are used for denial of service attacks like two echo ports
1282 1.47 hwr * just echoing data between them
1283 1.47 hwr */
1284 1.87 tron static int
1285 1.87 tron port_good_dg(struct sockaddr *sa)
1286 1.47 hwr {
1287 1.71 itojun struct in_addr in;
1288 1.110 christos struct sockaddr_in *sin;
1289 1.71 itojun #ifdef INET6
1290 1.71 itojun struct in6_addr *in6;
1291 1.110 christos struct sockaddr_in6 *sin6;
1292 1.71 itojun #endif
1293 1.47 hwr u_int16_t port;
1294 1.110 christos int i;
1295 1.57 itojun char hbuf[NI_MAXHOST];
1296 1.47 hwr
1297 1.54 itojun switch (sa->sa_family) {
1298 1.54 itojun case AF_INET:
1299 1.110 christos sin = (struct sockaddr_in *)(void *)sa;
1300 1.110 christos in.s_addr = ntohl(sin->sin_addr.s_addr);
1301 1.110 christos port = ntohs(sin->sin_port);
1302 1.97 pk #ifdef INET6
1303 1.71 itojun v4chk:
1304 1.97 pk #endif
1305 1.71 itojun if (IN_MULTICAST(in.s_addr))
1306 1.71 itojun goto bad;
1307 1.71 itojun switch ((in.s_addr & 0xff000000) >> 24) {
1308 1.71 itojun case 0: case 127: case 255:
1309 1.71 itojun goto bad;
1310 1.71 itojun }
1311 1.82 itojun if (dg_broadcast(&in))
1312 1.82 itojun goto bad;
1313 1.54 itojun break;
1314 1.58 itojun #ifdef INET6
1315 1.54 itojun case AF_INET6:
1316 1.110 christos sin6 = (struct sockaddr_in6 *)(void *)sa;
1317 1.110 christos in6 = &sin6->sin6_addr;
1318 1.110 christos port = ntohs(sin6->sin6_port);
1319 1.71 itojun if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
1320 1.71 itojun goto bad;
1321 1.71 itojun if (IN6_IS_ADDR_V4MAPPED(in6) || IN6_IS_ADDR_V4COMPAT(in6)) {
1322 1.71 itojun memcpy(&in, &in6->s6_addr[12], sizeof(in));
1323 1.71 itojun in.s_addr = ntohl(in.s_addr);
1324 1.71 itojun goto v4chk;
1325 1.71 itojun }
1326 1.54 itojun break;
1327 1.58 itojun #endif
1328 1.54 itojun default:
1329 1.54 itojun /* XXX unsupported af, is it safe to assume it to be safe? */
1330 1.134 rillig return true;
1331 1.54 itojun }
1332 1.47 hwr
1333 1.71 itojun for (i = 0; bad_ports[i] != 0; i++) {
1334 1.71 itojun if (port == bad_ports[i])
1335 1.71 itojun goto bad;
1336 1.71 itojun }
1337 1.47 hwr
1338 1.134 rillig return true;
1339 1.71 itojun
1340 1.71 itojun bad:
1341 1.110 christos if (getnameinfo(sa, sa->sa_len, hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
1342 1.80 itojun niflags) != 0)
1343 1.92 itojun strlcpy(hbuf, "?", sizeof(hbuf));
1344 1.71 itojun syslog(LOG_WARNING,"Possible DoS attack from %s, Port %d",
1345 1.71 itojun hbuf, port);
1346 1.134 rillig return false;
1347 1.82 itojun }
1348 1.82 itojun
1349 1.82 itojun /* XXX need optimization */
1350 1.87 tron static int
1351 1.87 tron dg_broadcast(struct in_addr *in)
1352 1.82 itojun {
1353 1.82 itojun struct ifaddrs *ifa, *ifap;
1354 1.82 itojun struct sockaddr_in *sin;
1355 1.82 itojun
1356 1.82 itojun if (getifaddrs(&ifap) < 0)
1357 1.134 rillig return false;
1358 1.134 rillig for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
1359 1.82 itojun if (ifa->ifa_addr->sa_family != AF_INET ||
1360 1.82 itojun (ifa->ifa_flags & IFF_BROADCAST) == 0)
1361 1.82 itojun continue;
1362 1.110 christos sin = (struct sockaddr_in *)(void *)ifa->ifa_broadaddr;
1363 1.82 itojun if (sin->sin_addr.s_addr == in->s_addr) {
1364 1.82 itojun freeifaddrs(ifap);
1365 1.134 rillig return true;
1366 1.82 itojun }
1367 1.82 itojun }
1368 1.82 itojun freeifaddrs(ifap);
1369 1.134 rillig return false;
1370 1.85 tron }
1371 1.85 tron
1372 1.85 tron static int
1373 1.85 tron my_kevent(const struct kevent *changelist, size_t nchanges,
1374 1.85 tron struct kevent *eventlist, size_t nevents)
1375 1.85 tron {
1376 1.85 tron int result;
1377 1.85 tron
1378 1.85 tron while ((result = kevent(kq, changelist, nchanges, eventlist, nevents,
1379 1.85 tron NULL)) < 0)
1380 1.85 tron if (errno != EINTR) {
1381 1.85 tron syslog(LOG_ERR, "kevent: %m");
1382 1.85 tron exit(EXIT_FAILURE);
1383 1.85 tron }
1384 1.85 tron
1385 1.85 tron return (result);
1386 1.87 tron }
1387 1.87 tron
1388 1.87 tron static struct kevent *
1389 1.87 tron allocchange(void)
1390 1.87 tron {
1391 1.127 christos if (changes == __arraycount(changebuf)) {
1392 1.127 christos (void) my_kevent(changebuf, __arraycount(changebuf), NULL, 0);
1393 1.87 tron changes = 0;
1394 1.87 tron }
1395 1.87 tron
1396 1.87 tron return (&changebuf[changes++]);
1397 1.47 hwr }
1398 1.127 christos
1399 1.137 christos bool
1400 1.137 christos try_biltin(struct servtab *sep)
1401 1.127 christos {
1402 1.138 rillig for (size_t i = 0; i < __arraycount(biltins); i++) {
1403 1.137 christos if (biltins[i].bi_socktype == sep->se_socktype &&
1404 1.137 christos strcmp(biltins[i].bi_service, sep->se_service) == 0) {
1405 1.137 christos sep->se_bi = &biltins[i];
1406 1.137 christos sep->se_wait = biltins[i].bi_wait;
1407 1.137 christos return true;
1408 1.127 christos }
1409 1.127 christos }
1410 1.137 christos return false;
1411 1.127 christos }
1412