Merge lp:~gandelman-a/ubuntu/oneiric/openbsd-inetd/merge into lp:ubuntu/oneiric/openbsd-inetd

Proposed by Adam Gandelman
Status: Merged
Merged at revision: 11
Proposed branch: lp:~gandelman-a/ubuntu/oneiric/openbsd-inetd/merge
Merge into: lp:ubuntu/oneiric/openbsd-inetd
Diff against target: 24426 lines (+23302/-164)
44 files modified
.pc/.version (+1/-0)
.pc/applied-patches (+11/-0)
.pc/buftuning/inetd.8 (+465/-0)
.pc/buftuning/inetd.c (+2194/-0)
.pc/discard_env/inetd.8 (+419/-0)
.pc/discard_env/inetd.c (+2059/-0)
.pc/global_queuelen/inetd.8 (+455/-0)
.pc/global_queuelen/inetd.c (+2173/-0)
.pc/libwrap/inetd.8 (+427/-0)
.pc/libwrap/inetd.c (+2110/-0)
.pc/misc_portability/inetd.8 (+407/-0)
.pc/misc_portability/inetd.c (+1991/-0)
.pc/nodaemon/inetd.8 (+452/-0)
.pc/nodaemon/inetd.c (+2165/-0)
.pc/print_pause_time/inetd.c (+2179/-0)
.pc/setproctitle/inetd.c (+2056/-0)
.pc/tcp46/inetd.8 (+460/-0)
.pc/tcp46/inetd.c (+2180/-0)
ChangeLog (+37/-0)
Makefile.debian (+16/-0)
bsd-closefrom.c (+115/-0)
debian/changelog (+17/-0)
debian/control (+1/-0)
debian/copyright (+26/-1)
debian/openbsd-inetd.postrm (+10/-0)
debian/openbsd-inetd.preinst (+0/-19)
debian/patches/buftuning (+6/-6)
debian/patches/discard_env (+8/-10)
debian/patches/global_queuelen (+30/-9)
debian/patches/libwrap (+10/-10)
debian/patches/makefile (+1/-1)
debian/patches/misc_portability (+150/-19)
debian/patches/nodaemon (+10/-11)
debian/patches/print_pause_time (+1/-1)
debian/patches/setproctitle (+6/-6)
debian/patches/tcp46 (+2/-2)
debian/rules (+7/-9)
debian/source/format (+1/-0)
inetd.8 (+100/-19)
inetd.c (+316/-41)
setproctitle.c (+146/-0)
setproctitle.h (+4/-0)
strlcpy.c (+63/-0)
test.conf (+15/-0)
To merge this branch: bzr merge lp:~gandelman-a/ubuntu/oneiric/openbsd-inetd/merge
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+66281@code.launchpad.net

Description of the change

Removed delta in debian/rules as hardening is already applied Debian package.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc'
2=== added file '.pc/.version'
3--- .pc/.version 1970-01-01 00:00:00 +0000
4+++ .pc/.version 2011-06-29 11:29:23 +0000
5@@ -0,0 +1,1 @@
6+2
7
8=== added file '.pc/applied-patches'
9--- .pc/applied-patches 1970-01-01 00:00:00 +0000
10+++ .pc/applied-patches 2011-06-29 11:29:23 +0000
11@@ -0,0 +1,11 @@
12+makefile
13+test
14+misc_portability
15+setproctitle
16+discard_env
17+libwrap
18+nodaemon
19+global_queuelen
20+print_pause_time
21+tcp46
22+buftuning
23
24=== added directory '.pc/buftuning'
25=== added file '.pc/buftuning/inetd.8'
26--- .pc/buftuning/inetd.8 1970-01-01 00:00:00 +0000
27+++ .pc/buftuning/inetd.8 2011-06-29 11:29:23 +0000
28@@ -0,0 +1,465 @@
29+.\" $OpenBSD: inetd.8,v 1.33 2008/06/28 10:54:45 sobrado Exp $
30+.\" Copyright (c) 1985, 1991 The Regents of the University of California.
31+.\" All rights reserved.
32+.\"
33+.\" Redistribution and use in source and binary forms, with or without
34+.\" modification, are permitted provided that the following conditions
35+.\" are met:
36+.\" 1. Redistributions of source code must retain the above copyright
37+.\" notice, this list of conditions and the following disclaimer.
38+.\" 2. Redistributions in binary form must reproduce the above copyright
39+.\" notice, this list of conditions and the following disclaimer in the
40+.\" documentation and/or other materials provided with the distribution.
41+.\" 3. Neither the name of the University nor the names of its contributors
42+.\" may be used to endorse or promote products derived from this software
43+.\" without specific prior written permission.
44+.\"
45+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55+.\" SUCH DAMAGE.
56+.\"
57+.\" from: @(#)inetd.8 6.7 (Berkeley) 3/16/91
58+.\"
59+.Dd $Mdocdate: December 29 2009 $
60+.Dt INETD 8
61+.Os
62+.Sh NAME
63+.Nm inetd
64+.Nd internet
65+.Dq super-server
66+.Sh SYNOPSIS
67+.Nm inetd
68+.Op Fl d
69+.Op Fl E
70+.Op Fl i
71+.Op Fl l
72+.Op Fl q Ar length
73+.Op Fl R Ar rate
74+.Op Ar configuration_file
75+.Sh DESCRIPTION
76+.Nm inetd
77+listens for connections on certain internet sockets.
78+When a connection is found on one
79+of its sockets, it decides what service the socket
80+corresponds to, and invokes a program to service the request.
81+After the program is
82+finished, it continues to listen on the socket (except in some cases which
83+will be described below).
84+Essentially,
85+.Nm inetd
86+allows running one daemon to invoke several others,
87+reducing load on the system.
88+.Pp
89+The options are as follows:
90+.Bl -tag -width Ds
91+.It Fl d
92+Turns on debugging.
93+.It Fl E
94+Prevents
95+.Nm inetd
96+from laundering the environment. Without this option a selection of
97+potentially harmful environent variables, including
98+.Pa PATH ,
99+will be removed and not inherited by services.
100+.It Fl i
101+Makes the program not daemonize itself.
102+.It Fl l
103+Turns on libwrap connection logging and access control.
104+Internal services cannot be wrapped. When enabled,
105+.Pa /usr/sbin/tcpd
106+is silently not executed even if present in
107+.Pa /etc/inetd.conf
108+and instead libwrap is called directly by inetd.
109+.It Fl q Ar length
110+Specify the length of the
111+.Xr listen 2
112+connections queue; the default is 128.
113+.It Fl R Ar rate
114+Specify the maximum number of times a service can be invoked
115+in one minute; the default is 256.
116+If a service exceeds this limit,
117+.Nm
118+will log the problem
119+and stop servicing requests for the specific service for ten minutes.
120+See also the wait/nowait configuration fields below.
121+.El
122+.Pp
123+Upon execution,
124+.Nm inetd
125+reads its configuration information from a configuration
126+file which, by default, is
127+.Pa /etc/inetd.conf .
128+There must be an entry for each field of the configuration
129+file, with entries for each field separated by a tab or
130+a space.
131+Comments are denoted by a
132+.Dq #
133+at the beginning
134+of a line.
135+The fields of the configuration file are as follows:
136+.Bd -unfilled -offset indent
137+service name
138+socket type
139+protocol
140+wait/nowait[.max]
141+user[.group] or user[:group]
142+server program
143+server program arguments
144+.Ed
145+.Pp
146+To specify a Sun-RPC
147+based service, the entry would contain these fields.
148+.Bd -unfilled -offset indent
149+service name/version
150+socket type
151+rpc/protocol
152+wait/nowait[.max]
153+user[.group] or user[:group]
154+server program
155+server program arguments
156+.Ed
157+.Pp
158+For internet services, the first field of the line may also have a host
159+address specifier prefixed to it, separated from the service name by a
160+colon.
161+If this is done, the string before the colon in the first field
162+indicates what local address
163+.Nm
164+should use when listening for that service.
165+Multiple local addresses
166+can be specified on the same line, separated by commas.
167+Numeric IP
168+addresses in dotted-quad notation can be used as well as symbolic
169+hostnames.
170+Symbolic hostnames are looked up using
171+.Fn gethostbyname .
172+If a hostname has multiple address mappings, inetd creates a socket
173+to listen on each address.
174+.Pp
175+The single character
176+.Dq \&*
177+indicates
178+.Dv INADDR_ANY ,
179+meaning
180+.Dq all local addresses .
181+To avoid repeating an address that occurs frequently, a line with a
182+host address specifier and colon, but no further fields, causes the
183+host address specifier to be remembered and used for all further lines
184+with no explicit host specifier (until another such line or the end of
185+the file).
186+A line
187+.Dl *:
188+is implicitly provided at the top of the file; thus, traditional
189+configuration files (which have no host address specifiers) will be
190+interpreted in the traditional manner, with all services listened for
191+on all local addresses.
192+If the protocol is
193+.Dq unix ,
194+this value is ignored.
195+.Pp
196+The
197+.Em service name
198+entry is the name of a valid service in
199+the file
200+.Pa /etc/services
201+or a port number.
202+For
203+.Dq internal
204+services (discussed below), the service
205+name
206+.Em must
207+be the official name of the service (that is, the first entry in
208+.Pa /etc/services ) .
209+When used to specify a Sun-RPC
210+based service, this field is a valid RPC service name in
211+the file
212+.Pa /etc/rpc .
213+The part on the right of the
214+.Dq /
215+is the RPC version number.
216+This can simply be a single numeric argument or a range of versions.
217+A range is bounded by the low version to the high version -
218+.Dq rusers/1\-3 .
219+For
220+.Ux Ns -domain
221+sockets this field specifies the path name of the socket.
222+.Pp
223+The
224+.Em socket type
225+should be one of
226+.Dq stream ,
227+.Dq dgram ,
228+.Dq raw ,
229+.Dq rdm ,
230+or
231+.Dq seqpacket ,
232+depending on whether the socket is a stream, datagram, raw,
233+reliably delivered message, or sequenced packet socket.
234+.Pp
235+The
236+.Em protocol
237+must be a valid protocol as given in
238+.Pa /etc/protocols or
239+.Dq unix .
240+Examples might be
241+.Dq tcp
242+or
243+.Dq udp .
244+RPC based services are specified with the
245+.Dq rpc/tcp
246+or
247+.Dq rpc/udp
248+service type.
249+.Dq tcp
250+and
251+.Dq udp
252+will be recognized as
253+.Dq TCP or UDP over default IP version .
254+This is currently IPv4, but in the future it will be IPv6.
255+If you need to specify IPv4 or IPv6 explicitly, use something like
256+.Dq tcp4
257+or
258+.Dq udp6 .
259+A
260+.Em protocol
261+of
262+.Dq unix
263+is used to specify a socket in the
264+.Ux Ns -domain .
265+.Pp
266+The
267+.Em wait/nowait
268+entry is used to tell
269+.Nm
270+if it should wait for the server program to return,
271+or continue processing connections on the socket.
272+If a datagram server connects
273+to its peer, freeing the socket so
274+.Nm inetd
275+can receive further messages on the socket, it is said to be
276+a
277+.Dq multi-threaded
278+server, and should use the
279+.Dq nowait
280+entry.
281+For datagram servers which process all incoming datagrams
282+on a socket and eventually time out, the server is said to be
283+.Dq single-threaded
284+and should use a
285+.Dq wait
286+entry.
287+.Xr comsat 8
288+.Pq Xr biff 1
289+and
290+.Xr talkd 8
291+are both examples of the latter type of
292+datagram server.
293+.Xr tftpd 8
294+is an exception; it is a datagram server that establishes pseudo-connections.
295+It must be listed as
296+.Dq wait
297+in order to avoid a race;
298+the server reads the first packet, creates a new socket,
299+and then forks and exits to allow
300+.Nm inetd
301+to check for new service requests to spawn new servers.
302+The optional
303+.Dq max
304+suffix (separated from
305+.Dq wait
306+or
307+.Dq nowait
308+by a dot) specifies the maximum number of times a service can be invoked
309+in one minute; the default is 256.
310+If a service exceeds this limit,
311+.Nm
312+will log the problem
313+and stop servicing requests for the specific service for ten minutes.
314+See also the
315+.Fl R
316+option above.
317+.Pp
318+Stream servers are usually marked as
319+.Dq nowait
320+but if a single server process is to handle multiple connections, it may be
321+marked as
322+.Dq wait .
323+The master socket will then be passed as fd 0 to the server, which will then
324+need to accept the incoming connection.
325+The server should eventually time
326+out and exit when no more connections are active.
327+.Nm
328+will continue to
329+listen on the master socket for connections, so the server should not close
330+it when it exits.
331+.Pp
332+The
333+.Em user
334+entry should contain the user name of the user as whom the server
335+should run.
336+This allows for servers to be given less permission
337+than root.
338+An optional group name can be specified by appending a dot to
339+the user name followed by the group name.
340+This allows for servers to run with
341+a different (primary) group ID than specified in the password file.
342+If a group
343+is specified and user is not root, the supplementary groups associated with
344+that user will still be set.
345+.Pp
346+The
347+.Em server program
348+entry should contain the pathname of the program which is to be
349+executed by
350+.Nm inetd
351+when a request is found on its socket.
352+If
353+.Nm inetd
354+provides this service internally, this entry should
355+be
356+.Dq internal .
357+.Pp
358+The
359+.Em server program arguments
360+should be just as arguments
361+normally are, starting with argv[0], which is the name of
362+the program.
363+If the service is provided internally, the word
364+.Dq internal
365+should take the place of this entry.
366+.Pp
367+.Nm inetd
368+provides several
369+.Dq trivial
370+services internally by use of routines within itself.
371+These services are
372+.Dq echo ,
373+.Dq discard ,
374+.Dq chargen
375+(character generator),
376+.Dq daytime
377+(human readable time), and
378+.Dq time
379+(machine readable time,
380+in the form of the number of seconds since midnight, January
381+1, 1900).
382+All of these services are TCP based.
383+For details of these services, consult the appropriate
384+.Tn RFC
385+from the Network Information Center.
386+.Pp
387+.Nm inetd
388+rereads its configuration file when it receives a hangup signal,
389+.Dv SIGHUP .
390+Services may be added, deleted or modified when the configuration file
391+is reread.
392+.Nm inetd
393+creates a file
394+.Em /var/run/inetd.pid
395+that contains its process identifier.
396+.Ss libwrap
397+Support for
398+.Tn TCP
399+wrappers is included with
400+.Nm
401+to provide built-in tcpd-like access control functionality.
402+An external tcpd program is not needed.
403+You do not need to change the
404+.Pa /etc/inetd.conf
405+server-program entry to enable this capability.
406+.Nm
407+uses
408+.Pa /etc/hosts.allow
409+and
410+.Pa /etc/hosts.deny
411+for access control facility configurations, as described in
412+.Xr hosts_access 5 .
413+.Ss IPv6 TCP/UDP behavior
414+If you wish to run a server for IPv4 and IPv6 traffic,
415+you'll need to run two separate processes for the same server program,
416+specified as two separate lines in
417+.Pa inetd.conf ,
418+for
419+.Dq tcp4
420+and
421+.Dq tcp6 .
422+.Pp
423+Under various combinations of IPv4/v6 daemon settings,
424+.Nm
425+will behave as follows:
426+.Bl -bullet -compact
427+.It
428+If you have only one server on
429+.Dq tcp4 ,
430+IPv4 traffic will be routed to the server.
431+IPv6 traffic will not be accepted.
432+.It
433+If you have two servers on
434+.Dq tcp4
435+and
436+.Dq tcp6 ,
437+IPv4 traffic will be routed to the server on
438+.Dq tcp4 ,
439+and IPv6 traffic will go to server on
440+.Dq tcp6 .
441+.It
442+If you have only one server on
443+.Dq tcp6 ,
444+only IPv6 traffic will be routed to the server.
445+.Pp
446+The special
447+.Dq tcp46
448+parameter can be used for obsolete servers which require to receive IPv4
449+connections mapped in an IPv6 socket. Its usage is discouraged.
450+.El
451+.Sh SEE ALSO
452+.Xr fingerd 8 ,
453+.Xr ftpd 8 ,
454+.Xr identd 8 ,
455+.Xr rshd 8 ,
456+.Xr talkd 8 ,
457+.Xr tftpd 8
458+.Sh HISTORY
459+The
460+.Nm
461+command appeared in
462+.Bx 4.3 .
463+Support for Sun-RPC
464+based services is modelled after that
465+provided by SunOS 4.1.
466+IPv6 support was added by the KAME project in 1999.
467+.Pp
468+Marco d'Itri ported this code from OpenBSD in summer 2002 and added
469+socket buffers tuning and libwrap support from the NetBSD source tree.
470+.Sh BUGS
471+On Linux systems, the daemon cannot reload its configuration and needs
472+to be restarted when the host address for a service is changed between
473+.Dq \&*
474+and a specific address.
475+.Pp
476+Server programs used with
477+.Dq dgram
478+.Dq udp
479+.Dq nowait
480+must read from the network socket, or
481+.Nm inetd
482+will spawn processes until the maximum is reached.
483+.Pp
484+Host address specifiers, while they make conceptual sense for RPC
485+services, do not work entirely correctly.
486+This is largely because the
487+portmapper interface does not provide a way to register different ports
488+for the same service on different local addresses.
489+Provided you never
490+have more than one entry for a given RPC service, everything should
491+work correctly.
492+(Note that default host address specifiers do apply to
493+RPC lines with no explicit specifier.)
494
495=== added file '.pc/buftuning/inetd.c'
496--- .pc/buftuning/inetd.c 1970-01-01 00:00:00 +0000
497+++ .pc/buftuning/inetd.c 2011-06-29 11:29:23 +0000
498@@ -0,0 +1,2194 @@
499+/* $OpenBSD: inetd.c,v 1.131 2009/10/27 23:59:51 deraadt Exp $ */
500+
501+/*
502+ * Copyright (c) 1983,1991 The Regents of the University of California.
503+ * All rights reserved.
504+ *
505+ * Redistribution and use in source and binary forms, with or without
506+ * modification, are permitted provided that the following conditions
507+ * are met:
508+ * 1. Redistributions of source code must retain the above copyright
509+ * notice, this list of conditions and the following disclaimer.
510+ * 2. Redistributions in binary form must reproduce the above copyright
511+ * notice, this list of conditions and the following disclaimer in the
512+ * documentation and/or other materials provided with the distribution.
513+ * 3. Neither the name of the University nor the names of its contributors
514+ * may be used to endorse or promote products derived from this software
515+ * without specific prior written permission.
516+ *
517+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
518+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
519+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
520+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
521+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
522+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
523+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
524+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
525+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
526+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
527+ * SUCH DAMAGE.
528+ */
529+
530+/*
531+ * Inetd - Internet super-server
532+ *
533+ * This program invokes all internet services as needed.
534+ * connection-oriented services are invoked each time a
535+ * connection is made, by creating a process. This process
536+ * is passed the connection as file descriptor 0 and is
537+ * expected to do a getpeername to find out the source host
538+ * and port.
539+ *
540+ * Datagram oriented services are invoked when a datagram
541+ * arrives; a process is created and passed a pending message
542+ * on file descriptor 0. Datagram servers may either connect
543+ * to their peer, freeing up the original socket for inetd
544+ * to receive further messages on, or ``take over the socket'',
545+ * processing all arriving datagrams and, eventually, timing
546+ * out. The first type of server is said to be ``multi-threaded'';
547+ * the second type of server ``single-threaded''.
548+ *
549+ * Inetd uses a configuration file which is read at startup
550+ * and, possibly, at some later time in response to a hangup signal.
551+ * The configuration file is ``free format'' with fields given in the
552+ * order shown below. Continuation lines for an entry must begin with
553+ * a space or tab. All fields must be present in each entry.
554+ *
555+ * service name must be in /etc/services
556+ * socket type stream/dgram/raw/rdm/seqpacket
557+ * protocol must be in /etc/protocols
558+ * wait/nowait[.max] single-threaded/multi-threaded, max #
559+ * user[.group] or user[:group] user/group to run daemon as
560+ * server program full path name
561+ * server program arguments maximum of MAXARGS (20)
562+ *
563+ * For RPC services
564+ * service name/version must be in /etc/rpc
565+ * socket type stream/dgram/raw/rdm/seqpacket
566+ * protocol must be in /etc/protocols
567+ * wait/nowait[.max] single-threaded/multi-threaded
568+ * user[.group] or user[:group] user to run daemon as
569+ * server program full path name
570+ * server program arguments maximum of MAXARGS (20)
571+ *
572+ * For non-RPC services, the "service name" can be of the form
573+ * hostaddress:servicename, in which case the hostaddress is used
574+ * as the host portion of the address to listen on. If hostaddress
575+ * consists of a single `*' character, INADDR_ANY is used.
576+ *
577+ * A line can also consist of just
578+ * hostaddress:
579+ * where hostaddress is as in the preceding paragraph. Such a line must
580+ * have no further fields; the specified hostaddress is remembered and
581+ * used for all further lines that have no hostaddress specified,
582+ * until the next such line (or EOF). (This is why * is provided to
583+ * allow explicit specification of INADDR_ANY.) A line
584+ * *:
585+ * is implicitly in effect at the beginning of the file.
586+ *
587+ * The hostaddress specifier may (and often will) contain dots;
588+ * the service name must not.
589+ *
590+ * For RPC services, host-address specifiers are accepted and will
591+ * work to some extent; however, because of limitations in the
592+ * portmapper interface, it will not work to try to give more than
593+ * one line for any given RPC service, even if the host-address
594+ * specifiers are different.
595+ *
596+ * Comment lines are indicated by a `#' in column 1.
597+ */
598+
599+/*
600+ * Here's the scoop concerning the user[.:]group feature:
601+ *
602+ * 1) set-group-option off.
603+ *
604+ * a) user = root: NO setuid() or setgid() is done
605+ *
606+ * b) other: setgid(primary group as found in passwd)
607+ * initgroups(name, primary group)
608+ * setuid()
609+ *
610+ * 2) set-group-option on.
611+ *
612+ * a) user = root: setgid(specified group)
613+ * NO initgroups()
614+ * NO setuid()
615+ *
616+ * b) other: setgid(specified group)
617+ * initgroups(name, specified group)
618+ * setuid()
619+ *
620+ */
621+
622+#include <sys/param.h>
623+#include <sys/stat.h>
624+#include <sys/ioctl.h>
625+#include <sys/socket.h>
626+#include <sys/un.h>
627+#include <sys/file.h>
628+#include <sys/wait.h>
629+#include <time.h>
630+#include <sys/time.h>
631+#include <sys/resource.h>
632+
633+#include <net/if.h>
634+#include <netinet/in.h>
635+#include <arpa/inet.h>
636+
637+#include <errno.h>
638+#include <ctype.h>
639+#include <signal.h>
640+#include <netdb.h>
641+#include <syslog.h>
642+#include <pwd.h>
643+#include <grp.h>
644+#include <stdio.h>
645+#include <stdlib.h>
646+#include <unistd.h>
647+#include <string.h>
648+#ifdef HAVE_SETUSERCONTEXT
649+#include <login_cap.h>
650+#endif
651+#ifdef HAVE_GETIFADDRS
652+#include <ifaddrs.h>
653+#endif
654+#include <rpc/rpc.h>
655+#include <rpc/pmap_clnt.h>
656+#include "pathnames.h"
657+#include "setproctitle.h"
658+
659+size_t strlcpy(char *, const char *, size_t);
660+
661+#define TOOMANY 256 /* don't start more than TOOMANY */
662+#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
663+#define RETRYTIME (60*10) /* retry after bind or server fail */
664+
665+#ifdef LIBWRAP
666+# include <tcpd.h>
667+int lflag = 0;
668+#endif
669+
670+int debug = 0;
671+int global_queuelen = 128;
672+int nsock, maxsock;
673+fd_set *allsockp;
674+int allsockn;
675+int toomany = TOOMANY;
676+int options;
677+int timingout;
678+struct servent *sp;
679+uid_t uid;
680+sigset_t blockmask;
681+sigset_t emptymask;
682+
683+#ifndef OPEN_MAX
684+#define OPEN_MAX 64
685+#endif
686+
687+/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
688+#define FD_MARGIN (8)
689+rlim_t rlim_nofile_cur = OPEN_MAX;
690+
691+struct rlimit rlim_nofile;
692+
693+struct servtab {
694+ char *se_hostaddr; /* host address to listen on */
695+ char *se_service; /* name of service */
696+ int se_socktype; /* type of socket to use */
697+ int se_family; /* address family */
698+ char *se_proto; /* protocol used */
699+ int se_rpcprog; /* rpc program number */
700+ int se_rpcversl; /* rpc program lowest version */
701+ int se_rpcversh; /* rpc program highest version */
702+#define isrpcservice(sep) ((sep)->se_rpcversl != 0)
703+ pid_t se_wait; /* single threaded server */
704+ short se_checked; /* looked at during merge */
705+ char *se_user; /* user name to run as */
706+ char *se_group; /* group name to run as */
707+ struct biltin *se_bi; /* if built-in, description */
708+ char *se_server; /* server program */
709+#define MAXARGV 20
710+ char *se_argv[MAXARGV+1]; /* program arguments */
711+ int se_fd; /* open descriptor */
712+ union {
713+ struct sockaddr se_un_ctrladdr;
714+ struct sockaddr_in se_un_ctrladdr_in;
715+ struct sockaddr_in6 se_un_ctrladdr_in6;
716+ struct sockaddr_un se_un_ctrladdr_un;
717+ struct sockaddr_storage se_un_ctrladdr_storage;
718+ } se_un; /* bound address */
719+#define se_ctrladdr se_un.se_un_ctrladdr
720+#define se_ctrladdr_in se_un.se_un_ctrladdr_in
721+#define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
722+#define se_ctrladdr_un se_un.se_un_ctrladdr_un
723+#define se_ctrladdr_storage se_un.se_un_ctrladdr_storage
724+ int se_ctrladdr_size;
725+ int se_max; /* max # of instances of this service */
726+ int se_count; /* number started since se_time */
727+ struct timeval se_time; /* start of se_count */
728+ struct servtab *se_next;
729+} *servtab;
730+
731+void echo_stream(int, struct servtab *);
732+void discard_stream(int, struct servtab *);
733+void machtime_stream(int, struct servtab *);
734+void daytime_stream(int, struct servtab *);
735+void chargen_stream(int, struct servtab *);
736+void echo_dg(int, struct servtab *);
737+void discard_dg(int, struct servtab *);
738+void machtime_dg(int, struct servtab *);
739+void daytime_dg(int, struct servtab *);
740+void chargen_dg(int, struct servtab *);
741+
742+struct biltin {
743+ char *bi_service; /* internally provided service name */
744+ int bi_socktype; /* type of socket supported */
745+ short bi_fork; /* 1 if should fork before call */
746+ short bi_wait; /* 1 if should wait for child */
747+ void (*bi_fn)(int, struct servtab *);
748+} biltins[] = {
749+ /* Echo received data */
750+ { "echo", SOCK_STREAM, 1, 0, echo_stream },
751+ { "echo", SOCK_DGRAM, 0, 0, echo_dg },
752+
753+ /* Internet /dev/null */
754+ { "discard", SOCK_STREAM, 1, 0, discard_stream },
755+ { "discard", SOCK_DGRAM, 0, 0, discard_dg },
756+
757+ /* Return 32 bit time since 1900 */
758+ { "time", SOCK_STREAM, 0, 0, machtime_stream },
759+ { "time", SOCK_DGRAM, 0, 0, machtime_dg },
760+
761+ /* Return human-readable time */
762+ { "daytime", SOCK_STREAM, 0, 0, daytime_stream },
763+ { "daytime", SOCK_DGRAM, 0, 0, daytime_dg },
764+
765+ /* Familiar character generator */
766+ { "chargen", SOCK_STREAM, 1, 0, chargen_stream },
767+ { "chargen", SOCK_DGRAM, 0, 0, chargen_dg },
768+
769+ { 0 }
770+};
771+
772+volatile sig_atomic_t wantretry;
773+volatile sig_atomic_t wantconfig;
774+volatile sig_atomic_t wantreap;
775+volatile sig_atomic_t wantdie;
776+
777+void config(int);
778+void doconfig(void);
779+void reap(int);
780+void doreap(void);
781+void retry(int);
782+void doretry(void);
783+void die(int);
784+void dodie(void);
785+void logpid(void);
786+void spawn(struct servtab *, int);
787+int gettcp(struct servtab *);
788+int setconfig(void);
789+void endconfig(void);
790+void register_rpc(struct servtab *);
791+void unregister_rpc(struct servtab *);
792+void freeconfig(struct servtab *);
793+void print_service(char *, struct servtab *);
794+void setup(struct servtab *);
795+struct servtab *getconfigent(void);
796+int bump_nofile(void);
797+struct servtab *enter(struct servtab *);
798+int matchconf(struct servtab *, struct servtab *);
799+int dg_broadcast(struct in_addr *in);
800+void discard_stupid_environment(void);
801+
802+#define NUMINT (sizeof(intab) / sizeof(struct inent))
803+char *CONFIG = _PATH_INETDCONF;
804+
805+void
806+fd_grow(fd_set **fdsp, int *bytes, int fd)
807+{
808+ caddr_t new;
809+ int newbytes;
810+
811+ newbytes = howmany(fd+1, NFDBITS) * sizeof(fd_mask);
812+ if (newbytes > *bytes) {
813+ newbytes *= 2; /* optimism */
814+ new = realloc(*fdsp, newbytes);
815+ if (new == NULL) {
816+ syslog(LOG_ERR, "Out of memory.");
817+ exit(1);
818+ }
819+ memset(new + *bytes, 0, newbytes - *bytes);
820+ *fdsp = (fd_set *)new;
821+ *bytes = newbytes;
822+ }
823+}
824+
825+struct sigaction sa, sapipe;
826+
827+int
828+main(int argc, char *argv[], char *envp[])
829+{
830+ fd_set *fdsrp = NULL;
831+ int readablen = 0, ch;
832+ int keepenv = 0;
833+ int nodaemon = 0;
834+ struct servtab *sep;
835+ extern char *optarg;
836+ extern int optind;
837+
838+ initsetproctitle(argc, argv, envp);
839+
840+ while ((ch = getopt(argc, argv, "dEilq:R:")) != -1)
841+ switch (ch) {
842+ case 'd':
843+ debug = 1;
844+ break;
845+ case 'E':
846+ keepenv = 1;
847+ break;
848+ case 'i':
849+ nodaemon = 1;
850+ break;
851+ case 'l':
852+#ifdef LIBWRAP
853+ lflag = 1;
854+ break;
855+#else
856+ fprintf(stderr, "%s: libwrap support not enabled",
857+ progname);
858+ exit(1);
859+#endif
860+ case 'q':
861+ global_queuelen = atoi(optarg);
862+ if (global_queuelen < 10)
863+ global_queuelen = 10;
864+ break;
865+ case 'R': { /* invocation rate */
866+ char *p;
867+ int val;
868+
869+ val = strtoul(optarg, &p, 0);
870+ if (val >= 1 && *p == '\0') {
871+ toomany = val;
872+ break;
873+ }
874+ syslog(LOG_ERR,
875+ "-R %s: bad value for service invocation rate",
876+ optarg);
877+ break;
878+ }
879+ case '?':
880+ default:
881+ fprintf(stderr,
882+ "usage: inetd [-dEil] [-q len] [-R rate] [configuration_file]\n");
883+ exit(1);
884+ }
885+ argc -= optind;
886+ argv += optind;
887+
888+ /* This must be called _after_ initsetproctitle and arg parsing */
889+ if (!keepenv)
890+ discard_stupid_environment();
891+
892+ uid = getuid();
893+ if (uid != 0)
894+ CONFIG = NULL;
895+ if (argc > 0)
896+ CONFIG = argv[0];
897+ if (CONFIG == NULL) {
898+ fprintf(stderr, "inetd: non-root must specify a config file\n");
899+ exit(1);
900+ }
901+ if (argc > 1) {
902+ fprintf(stderr, "inetd: more than one argument specified\n");
903+ exit(1);
904+ }
905+
906+ umask(022);
907+ if (debug == 0) {
908+ if (nodaemon == 0)
909+ if (daemon(0, 0) < 0) {
910+ syslog(LOG_ERR, "daemon(0, 0): %m");
911+ exit(1);
912+ }
913+#ifdef HAVE_SETLOGIN
914+ if (uid == 0)
915+ (void) setlogin("");
916+#endif
917+ }
918+ if (debug && uid == 0)
919+ options |= SO_DEBUG;
920+
921+ if (uid == 0) {
922+ gid_t gid = getgid();
923+
924+ /* If run by hand, ensure groups vector gets trashed */
925+ setgroups(1, &gid);
926+ }
927+
928+ openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
929+ logpid();
930+
931+ if (getrlimit(RLIMIT_NOFILE, &rlim_nofile) < 0) {
932+ syslog(LOG_ERR, "getrlimit: %m");
933+ } else {
934+ rlim_nofile_cur = rlim_nofile.rlim_cur;
935+ if (rlim_nofile_cur == RLIM_INFINITY) /* ! */
936+ rlim_nofile_cur = OPEN_MAX;
937+ }
938+
939+ sigemptyset(&emptymask);
940+ sigemptyset(&blockmask);
941+ sigaddset(&blockmask, SIGCHLD);
942+ sigaddset(&blockmask, SIGHUP);
943+ sigaddset(&blockmask, SIGALRM);
944+
945+ memset(&sa, 0, sizeof(sa));
946+ sigemptyset(&sa.sa_mask);
947+ sigaddset(&sa.sa_mask, SIGALRM);
948+ sigaddset(&sa.sa_mask, SIGCHLD);
949+ sigaddset(&sa.sa_mask, SIGHUP);
950+ sa.sa_handler = retry;
951+ sigaction(SIGALRM, &sa, NULL);
952+ doconfig();
953+ sa.sa_handler = config;
954+ sigaction(SIGHUP, &sa, NULL);
955+ sa.sa_handler = reap;
956+ sigaction(SIGCHLD, &sa, NULL);
957+ sa.sa_handler = die;
958+ sigaction(SIGTERM, &sa, NULL);
959+ sa.sa_handler = die;
960+ sigaction(SIGINT, &sa, NULL);
961+ sa.sa_handler = SIG_IGN;
962+ sigaction(SIGPIPE, &sa, &sapipe);
963+
964+ /* space for daemons to overwrite environment for ps */
965+ {
966+#define DUMMYSIZE 100
967+ char dummy[DUMMYSIZE];
968+ memset(dummy, 'x', DUMMYSIZE - 1);
969+ dummy[DUMMYSIZE - 1] = '\0';
970+ setenv("inetd_dummy", dummy, 1);
971+ }
972+
973+ for (;;) {
974+ int n, ctrl = -1;
975+
976+ restart:
977+ if (nsock == 0) {
978+ (void) sigprocmask(SIG_BLOCK, &blockmask, NULL);
979+ while (nsock == 0) {
980+ if (wantretry || wantconfig || wantreap || wantdie)
981+ break;
982+ sigsuspend(&emptymask);
983+ }
984+ (void) sigprocmask(SIG_SETMASK, &emptymask, NULL);
985+ }
986+
987+ while (wantretry || wantconfig || wantreap || wantdie) {
988+ if (wantretry) {
989+ wantretry = 0;
990+ doretry();
991+ }
992+ if (wantconfig) {
993+ wantconfig = 0;
994+ doconfig();
995+ }
996+ if (wantreap) {
997+ wantreap = 0;
998+ doreap();
999+ }
1000+ if (wantdie)
1001+ dodie();
1002+ goto restart;
1003+ }
1004+
1005+ if (readablen != allsockn) {
1006+ if (fdsrp)
1007+ free(fdsrp);
1008+ fdsrp = (fd_set *)calloc(allsockn, 1);
1009+ if (fdsrp == NULL) {
1010+ syslog(LOG_ERR, "Out of memory.");
1011+ exit(1);
1012+ }
1013+ readablen = allsockn;
1014+ }
1015+ bcopy(allsockp, fdsrp, allsockn);
1016+
1017+ if ((n = select(maxsock + 1, fdsrp, NULL, NULL, NULL)) <= 0) {
1018+ if (n < 0 && errno != EINTR) {
1019+ syslog(LOG_WARNING, "select: %m");
1020+ sleep(1);
1021+ }
1022+ continue;
1023+ }
1024+
1025+ for (sep = servtab; n && sep; sep = sep->se_next) {
1026+ if (sep->se_fd != -1 &&
1027+ FD_ISSET(sep->se_fd, fdsrp)) {
1028+ n--;
1029+ if (debug)
1030+ fprintf(stderr, "someone wants %s\n",
1031+ sep->se_service);
1032+ if (!sep->se_wait &&
1033+ sep->se_socktype == SOCK_STREAM) {
1034+ ctrl = gettcp(sep);
1035+ if (ctrl == -1)
1036+ continue;
1037+ } else
1038+ ctrl = sep->se_fd;
1039+ (void) sigprocmask(SIG_BLOCK, &blockmask, NULL);
1040+ spawn(sep, ctrl); /* spawn will unblock */
1041+ }
1042+ }
1043+ }
1044+}
1045+
1046+int
1047+gettcp(struct servtab *sep)
1048+{
1049+ int ctrl;
1050+
1051+ ctrl = accept(sep->se_fd, NULL, NULL);
1052+ if (debug)
1053+ fprintf(stderr, "accept, ctrl %d\n", ctrl);
1054+ if (ctrl < 0) {
1055+ if (errno == EINTR)
1056+ return -1;
1057+ syslog(LOG_WARNING, "accept (for %s): %m", sep->se_service);
1058+ return -1;
1059+ }
1060+ if ((sep->se_family == AF_INET || sep->se_family == AF_INET6) &&
1061+ sep->se_socktype == SOCK_STREAM) {
1062+ struct sockaddr_storage peer;
1063+ socklen_t plen = sizeof(peer);
1064+ char sbuf[NI_MAXSERV];
1065+
1066+ if (getpeername(ctrl, (struct sockaddr *)&peer, &plen) < 0) {
1067+ syslog(LOG_WARNING, "could not getpeername");
1068+ close(ctrl);
1069+ return -1;
1070+ }
1071+ if (getnameinfo((struct sockaddr *)&peer, plen, NULL, 0,
1072+ sbuf, sizeof(sbuf), NI_NUMERICSERV) == 0 &&
1073+ atoi(sbuf) == 20) {
1074+ /*
1075+ * ignore things that look like ftp bounce
1076+ */
1077+ close(ctrl);
1078+ return -1;
1079+ }
1080+ }
1081+ return (ctrl);
1082+}
1083+
1084+
1085+int
1086+dg_badinput(struct sockaddr *sa)
1087+{
1088+ struct in_addr in;
1089+ struct in6_addr *in6;
1090+ u_int16_t port;
1091+
1092+ switch (sa->sa_family) {
1093+ case AF_INET:
1094+ in.s_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
1095+ port = ntohs(((struct sockaddr_in *)sa)->sin_port);
1096+ v4chk:
1097+ if (IN_MULTICAST(in.s_addr))
1098+ goto bad;
1099+ switch ((in.s_addr & 0xff000000) >> 24) {
1100+ case 0: case 127: case 255:
1101+ goto bad;
1102+ }
1103+ if (dg_broadcast(&in))
1104+ goto bad;
1105+ break;
1106+ case AF_INET6:
1107+ in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
1108+ port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
1109+ if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
1110+ goto bad;
1111+ /*
1112+ * OpenBSD does not support IPv4 mapped address (RFC2553
1113+ * inbound behavior) at all. We should drop it.
1114+ */
1115+ if (IN6_IS_ADDR_V4MAPPED(in6))
1116+ goto bad;
1117+ if (IN6_IS_ADDR_V4COMPAT(in6)) {
1118+ memcpy(&in, &in6->s6_addr[12], sizeof(in));
1119+ in.s_addr = ntohl(in.s_addr);
1120+ goto v4chk;
1121+ }
1122+ break;
1123+ default:
1124+ /* XXX unsupported af, is it safe to assume it to be safe? */
1125+ return 0;
1126+ }
1127+
1128+ return (0);
1129+
1130+bad:
1131+ return (1);
1132+}
1133+
1134+int
1135+dg_broadcast(struct in_addr *in)
1136+{
1137+#ifdef HAVE_GETIFADDRS
1138+ struct ifaddrs *ifa, *ifap;
1139+ struct sockaddr_in *sin;
1140+
1141+ if (getifaddrs(&ifap) < 0)
1142+ return (0);
1143+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
1144+ if (ifa->ifa_addr->sa_family != AF_INET ||
1145+ (ifa->ifa_flags & IFF_BROADCAST) == 0)
1146+ continue;
1147+ sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
1148+ if (sin->sin_addr.s_addr == in->s_addr) {
1149+ freeifaddrs(ifap);
1150+ return (1);
1151+ }
1152+ }
1153+ freeifaddrs(ifap);
1154+#endif
1155+ return (0);
1156+}
1157+
1158+/* ARGSUSED */
1159+void
1160+reap(int sig)
1161+{
1162+ wantreap = 1;
1163+}
1164+
1165+void
1166+doreap(void)
1167+{
1168+ struct servtab *sep;
1169+ int status;
1170+ pid_t pid;
1171+
1172+ if (debug)
1173+ fprintf(stderr, "reaping asked for\n");
1174+
1175+ for (;;) {
1176+ if ((pid = wait3(&status, WNOHANG, NULL)) <= 0) {
1177+ if (pid == -1 && errno == EINTR)
1178+ continue;
1179+ break;
1180+ }
1181+ if (debug)
1182+ fprintf(stderr, "%ld reaped, status %x\n",
1183+ (long)pid, status);
1184+ for (sep = servtab; sep; sep = sep->se_next)
1185+ if (sep->se_wait == pid) {
1186+ if (WIFEXITED(status) && WEXITSTATUS(status))
1187+ syslog(LOG_WARNING,
1188+ "%s: exit status %d",
1189+ sep->se_server, WEXITSTATUS(status));
1190+ else if (WIFSIGNALED(status))
1191+ syslog(LOG_WARNING,
1192+ "%s: exit signal %d",
1193+ sep->se_server, WTERMSIG(status));
1194+ sep->se_wait = 1;
1195+ fd_grow(&allsockp, &allsockn, sep->se_fd);
1196+ FD_SET(sep->se_fd, allsockp);
1197+ nsock++;
1198+ if (debug)
1199+ fprintf(stderr, "restored %s, fd %d\n",
1200+ sep->se_service, sep->se_fd);
1201+ }
1202+ }
1203+}
1204+
1205+/* ARGSUSED */
1206+void
1207+config(int sig)
1208+{
1209+ wantconfig = 1;
1210+}
1211+
1212+void
1213+doconfig(void)
1214+{
1215+ struct servtab *sep, *cp, **sepp;
1216+ int add;
1217+ char protoname[10];
1218+ sigset_t omask;
1219+
1220+ if (!setconfig()) {
1221+ syslog(LOG_ERR, "%s: %m", CONFIG);
1222+ exit(1);
1223+ }
1224+ for (sep = servtab; sep; sep = sep->se_next)
1225+ sep->se_checked = 0;
1226+ cp = getconfigent();
1227+ while (cp != NULL) {
1228+ for (sep = servtab; sep; sep = sep->se_next)
1229+ if (matchconf(sep, cp))
1230+ break;
1231+ add = 0;
1232+ if (sep != NULL) {
1233+ int i;
1234+
1235+#define SWAP(type, a, b) {type c=(type)a; a=(type)b; b=(type)c;}
1236+
1237+ sigprocmask(SIG_BLOCK, &blockmask, &omask);
1238+ /*
1239+ * sep->se_wait may be holding the pid of a daemon
1240+ * that we're waiting for. If so, don't overwrite
1241+ * it unless the config file explicitly says don't
1242+ * wait.
1243+ */
1244+ if (cp->se_bi == 0 &&
1245+ (sep->se_wait == 1 || cp->se_wait == 0))
1246+ sep->se_wait = cp->se_wait;
1247+ SWAP(int, cp->se_max, sep->se_max);
1248+ SWAP(char *, sep->se_user, cp->se_user);
1249+ SWAP(char *, sep->se_group, cp->se_group);
1250+ SWAP(char *, sep->se_server, cp->se_server);
1251+ for (i = 0; i < MAXARGV; i++)
1252+ SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
1253+#undef SWAP
1254+ if (isrpcservice(sep))
1255+ unregister_rpc(sep);
1256+ sep->se_rpcversl = cp->se_rpcversl;
1257+ sep->se_rpcversh = cp->se_rpcversh;
1258+ sigprocmask(SIG_SETMASK, &omask, NULL);
1259+ freeconfig(cp);
1260+ add = 1;
1261+ } else {
1262+ sep = enter(cp);
1263+ }
1264+ sep->se_checked = 1;
1265+
1266+ switch (sep->se_family) {
1267+ case AF_UNIX:
1268+ if (sep->se_fd != -1)
1269+ break;
1270+ sep->se_ctrladdr_size =
1271+ strlcpy(sep->se_ctrladdr_un.sun_path,
1272+ sep->se_service,
1273+ sizeof sep->se_ctrladdr_un.sun_path);
1274+ if (sep->se_ctrladdr_size >=
1275+ sizeof sep->se_ctrladdr_un.sun_path) {
1276+ syslog(LOG_WARNING, "%s/%s: UNIX domain socket "
1277+ "path too long", sep->se_service,
1278+ sep->se_proto);
1279+ goto serv_unknown;
1280+ }
1281+ sep->se_ctrladdr_un.sun_family = AF_UNIX;
1282+ sep->se_ctrladdr_size +=
1283+ 1 + sizeof sep->se_ctrladdr_un.sun_family;
1284+ (void)unlink(sep->se_service);
1285+ setup(sep);
1286+ break;
1287+ case AF_INET:
1288+ sep->se_ctrladdr_in.sin_family = AF_INET;
1289+ /* se_ctrladdr_in was set in getconfigent */
1290+ sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
1291+
1292+ if (isrpcservice(sep)) {
1293+ struct rpcent *rp;
1294+
1295+ sep->se_rpcprog = atoi(sep->se_service);
1296+ if (sep->se_rpcprog == 0) {
1297+ rp = getrpcbyname(sep->se_service);
1298+ if (rp == 0) {
1299+ syslog(LOG_ERR,
1300+ "%s: unknown rpc service",
1301+ sep->se_service);
1302+ goto serv_unknown;
1303+ }
1304+ sep->se_rpcprog = rp->r_number;
1305+ }
1306+ if (sep->se_fd == -1)
1307+ setup(sep);
1308+ if (sep->se_fd != -1)
1309+ register_rpc(sep);
1310+ } else {
1311+ u_short port = htons(atoi(sep->se_service));
1312+
1313+ if (!port) {
1314+ /* XXX */
1315+ char *p;
1316+ strncpy(protoname, sep->se_proto,
1317+ sizeof(protoname));
1318+ for (p = protoname; *p; p++)
1319+ if (isdigit(*p)) {
1320+ *p = '\0';
1321+ break;
1322+ }
1323+ sp = getservbyname(sep->se_service,
1324+ protoname);
1325+ if (sp == 0) {
1326+ syslog(LOG_ERR,
1327+ "%s/%s: unknown service",
1328+ sep->se_service, sep->se_proto);
1329+ goto serv_unknown;
1330+ }
1331+ port = sp->s_port;
1332+ }
1333+ if (port != sep->se_ctrladdr_in.sin_port) {
1334+ sep->se_ctrladdr_in.sin_port = port;
1335+ if (sep->se_fd != -1) {
1336+ FD_CLR(sep->se_fd, allsockp);
1337+ nsock--;
1338+ (void) close(sep->se_fd);
1339+ }
1340+ sep->se_fd = -1;
1341+ }
1342+ if (sep->se_fd == -1)
1343+ setup(sep);
1344+ }
1345+ break;
1346+ case AF_INET6:
1347+ sep->se_ctrladdr_in6.sin6_family = AF_INET6;
1348+ /* se_ctrladdr_in was set in getconfigent */
1349+ sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
1350+
1351+ if (isrpcservice(sep)) {
1352+ struct rpcent *rp;
1353+
1354+ sep->se_rpcprog = atoi(sep->se_service);
1355+ if (sep->se_rpcprog == 0) {
1356+ rp = getrpcbyname(sep->se_service);
1357+ if (rp == 0) {
1358+ syslog(LOG_ERR,
1359+ "%s: unknown rpc service",
1360+ sep->se_service);
1361+ goto serv_unknown;
1362+ }
1363+ sep->se_rpcprog = rp->r_number;
1364+ }
1365+ if (sep->se_fd == -1)
1366+ setup(sep);
1367+ if (sep->se_fd != -1)
1368+ register_rpc(sep);
1369+ } else {
1370+ u_short port = htons(atoi(sep->se_service));
1371+
1372+ if (!port) {
1373+ /* XXX */
1374+ strncpy(protoname, sep->se_proto,
1375+ sizeof(protoname));
1376+ if (isdigit(protoname[strlen(protoname) - 1]))
1377+ protoname[strlen(protoname) - 1] = '\0';
1378+ sp = getservbyname(sep->se_service,
1379+ protoname);
1380+ if (sp == 0) {
1381+ syslog(LOG_ERR,
1382+ "%s/%s: unknown service",
1383+ sep->se_service, sep->se_proto);
1384+ goto serv_unknown;
1385+ }
1386+ port = sp->s_port;
1387+ }
1388+ if (port != sep->se_ctrladdr_in6.sin6_port) {
1389+ sep->se_ctrladdr_in6.sin6_port = port;
1390+ if (sep->se_fd != -1) {
1391+ FD_CLR(sep->se_fd, allsockp);
1392+ nsock--;
1393+ (void) close(sep->se_fd);
1394+ }
1395+ sep->se_fd = -1;
1396+ }
1397+ if (sep->se_fd == -1)
1398+ setup(sep);
1399+ }
1400+ break;
1401+ }
1402+ serv_unknown:
1403+ if (cp->se_next != NULL) {
1404+ struct servtab *tmp = cp;
1405+
1406+ cp = cp->se_next;
1407+ free(tmp);
1408+ } else {
1409+ free(cp);
1410+ cp = getconfigent();
1411+ }
1412+ if (debug)
1413+ print_service(add ? "REDO" : "ADD", sep);
1414+ }
1415+ endconfig();
1416+ /*
1417+ * Purge anything not looked at above.
1418+ */
1419+ sigprocmask(SIG_BLOCK, &blockmask, &omask);
1420+ sepp = &servtab;
1421+ while ((sep = *sepp)) {
1422+ if (sep->se_checked) {
1423+ sepp = &sep->se_next;
1424+ continue;
1425+ }
1426+ *sepp = sep->se_next;
1427+ if (sep->se_fd != -1) {
1428+ FD_CLR(sep->se_fd, allsockp);
1429+ nsock--;
1430+ (void) close(sep->se_fd);
1431+ }
1432+ if (isrpcservice(sep))
1433+ unregister_rpc(sep);
1434+ if (sep->se_family == AF_UNIX)
1435+ (void)unlink(sep->se_service);
1436+ if (debug)
1437+ print_service("FREE", sep);
1438+ freeconfig(sep);
1439+ free(sep);
1440+ }
1441+ sigprocmask(SIG_SETMASK, &omask, NULL);
1442+}
1443+
1444+/* ARGSUSED */
1445+void
1446+retry(int sig)
1447+{
1448+ wantretry = 1;
1449+}
1450+
1451+void
1452+doretry(void)
1453+{
1454+ struct servtab *sep;
1455+
1456+ timingout = 0;
1457+ for (sep = servtab; sep; sep = sep->se_next) {
1458+ if (sep->se_fd == -1) {
1459+ switch (sep->se_family) {
1460+ case AF_UNIX:
1461+ case AF_INET:
1462+ case AF_INET6:
1463+ setup(sep);
1464+ if (sep->se_fd != -1 && isrpcservice(sep))
1465+ register_rpc(sep);
1466+ break;
1467+ }
1468+ }
1469+ }
1470+}
1471+
1472+/* ARGSUSED */
1473+void
1474+die(int sig)
1475+{
1476+ wantdie = 1;
1477+}
1478+
1479+void
1480+dodie(void)
1481+{
1482+ struct servtab *sep;
1483+
1484+ for (sep = servtab; sep; sep = sep->se_next) {
1485+ if (sep->se_fd == -1)
1486+ continue;
1487+
1488+ switch (sep->se_family) {
1489+ case AF_UNIX:
1490+ (void)unlink(sep->se_service);
1491+ break;
1492+ case AF_INET:
1493+ case AF_INET6:
1494+ if (sep->se_wait == 1 && isrpcservice(sep))
1495+ unregister_rpc(sep);
1496+ break;
1497+ }
1498+ (void)close(sep->se_fd);
1499+ }
1500+ (void)unlink(_PATH_INETDPID);
1501+ exit(0);
1502+}
1503+
1504+void
1505+setup(struct servtab *sep)
1506+{
1507+ int on = 1;
1508+ int r;
1509+ mode_t mask = 0;
1510+
1511+ if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
1512+ syslog(LOG_ERR, "%s/%s: socket: %m",
1513+ sep->se_service, sep->se_proto);
1514+ return;
1515+ }
1516+ if (strncmp(sep->se_proto, "tcp6", 4) == 0) {
1517+ if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on,
1518+ sizeof (on)) < 0)
1519+ syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m");
1520+ } else if (strncmp(sep->se_proto, "tcp46", 5) == 0) {
1521+ int off = 0;
1522+ if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY, &off,
1523+ sizeof (off)) < 0)
1524+ syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m");
1525+ }
1526+#define turnon(fd, opt) \
1527+setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on))
1528+ if (strncmp(sep->se_proto, "tcp", 3) == 0 && (options & SO_DEBUG) &&
1529+ turnon(sep->se_fd, SO_DEBUG) < 0)
1530+ syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
1531+ if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
1532+ syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
1533+#undef turnon
1534+ if (isrpcservice(sep)) {
1535+ struct passwd *pwd;
1536+
1537+ /*
1538+ * for RPC services, attempt to use a reserved port
1539+ * if they are going to be running as root.
1540+ *
1541+ * Also, zero out the port for all RPC services; let bind()
1542+ * find one.
1543+ */
1544+ sep->se_ctrladdr_in.sin_port = 0;
1545+ if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
1546+ pwd->pw_uid == 0 && uid == 0)
1547+ r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
1548+ else {
1549+ r = bind(sep->se_fd, &sep->se_ctrladdr,
1550+ sep->se_ctrladdr_size);
1551+ if (r == 0) {
1552+ socklen_t len = sep->se_ctrladdr_size;
1553+ int saveerrno = errno;
1554+
1555+ /* update se_ctrladdr_in.sin_port */
1556+ r = getsockname(sep->se_fd, &sep->se_ctrladdr,
1557+ &len);
1558+ if (r <= 0)
1559+ errno = saveerrno;
1560+ }
1561+ }
1562+ } else {
1563+ if (sep->se_family == AF_UNIX)
1564+ mask = umask(0111);
1565+ r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
1566+ if (sep->se_family == AF_UNIX)
1567+ umask(mask);
1568+ }
1569+ if (r < 0) {
1570+ syslog(LOG_ERR, "%s/%s: bind: %m",
1571+ sep->se_service, sep->se_proto);
1572+ (void) close(sep->se_fd);
1573+ sep->se_fd = -1;
1574+ if (!timingout) {
1575+ timingout = 1;
1576+ alarm(RETRYTIME);
1577+ }
1578+ return;
1579+ }
1580+ if (sep->se_socktype == SOCK_STREAM)
1581+ listen(sep->se_fd, global_queuelen);
1582+
1583+ fd_grow(&allsockp, &allsockn, sep->se_fd);
1584+ FD_SET(sep->se_fd, allsockp);
1585+ nsock++;
1586+ if (sep->se_fd > maxsock) {
1587+ maxsock = sep->se_fd;
1588+ if (maxsock > rlim_nofile_cur - FD_MARGIN)
1589+ bump_nofile();
1590+ }
1591+}
1592+
1593+void
1594+register_rpc(struct servtab *sep)
1595+{
1596+ socklen_t n;
1597+ struct sockaddr_in sin;
1598+ struct protoent *pp;
1599+
1600+ if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
1601+ syslog(LOG_ERR, "%s: getproto: %m",
1602+ sep->se_proto);
1603+ return;
1604+ }
1605+ n = sizeof sin;
1606+ if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
1607+ syslog(LOG_ERR, "%s/%s: getsockname: %m",
1608+ sep->se_service, sep->se_proto);
1609+ return;
1610+ }
1611+
1612+ for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1613+ if (debug)
1614+ fprintf(stderr, "pmap_set: %u %u %u %u\n",
1615+ sep->se_rpcprog, n, pp->p_proto,
1616+ ntohs(sin.sin_port));
1617+ (void)pmap_unset(sep->se_rpcprog, n);
1618+ if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
1619+ syslog(LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
1620+ sep->se_service, sep->se_proto,
1621+ sep->se_rpcprog, n, pp->p_proto,
1622+ ntohs(sin.sin_port));
1623+ }
1624+}
1625+
1626+void
1627+unregister_rpc(struct servtab *sep)
1628+{
1629+ int n;
1630+
1631+ for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1632+ if (debug)
1633+ fprintf(stderr, "pmap_unset(%u, %u)\n",
1634+ sep->se_rpcprog, n);
1635+ if (!pmap_unset(sep->se_rpcprog, n))
1636+ syslog(LOG_ERR, "pmap_unset(%u, %u)",
1637+ sep->se_rpcprog, n);
1638+ }
1639+}
1640+
1641+
1642+struct servtab *
1643+enter(struct servtab *cp)
1644+{
1645+ struct servtab *sep;
1646+ sigset_t omask;
1647+
1648+ sep = (struct servtab *)malloc(sizeof (*sep));
1649+ if (sep == NULL) {
1650+ syslog(LOG_ERR, "Out of memory.");
1651+ exit(1);
1652+ }
1653+ *sep = *cp;
1654+ sep->se_fd = -1;
1655+ sep->se_rpcprog = -1;
1656+ sigprocmask(SIG_BLOCK, &blockmask, &omask);
1657+ sep->se_next = servtab;
1658+ servtab = sep;
1659+ sigprocmask(SIG_SETMASK, &omask, NULL);
1660+ return (sep);
1661+}
1662+
1663+int
1664+matchconf(struct servtab *old, struct servtab *new)
1665+{
1666+ if (strcmp(old->se_service, new->se_service) != 0)
1667+ return (0);
1668+
1669+ if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
1670+ return (0);
1671+
1672+ if (strcmp(old->se_proto, new->se_proto) != 0)
1673+ return (0);
1674+
1675+ /*
1676+ * If the new servtab is bound to a specific address, check that the
1677+ * old servtab is bound to the same entry. If the new service is not
1678+ * bound to a specific address then the check of se_hostaddr above
1679+ * is sufficient.
1680+ */
1681+
1682+ if (old->se_family == AF_INET && new->se_family == AF_INET &&
1683+ bcmp(&old->se_ctrladdr_in.sin_addr,
1684+ &new->se_ctrladdr_in.sin_addr,
1685+ sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
1686+ return (0);
1687+
1688+ if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
1689+ bcmp(&old->se_ctrladdr_in6.sin6_addr,
1690+ &new->se_ctrladdr_in6.sin6_addr,
1691+ sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
1692+ return (0);
1693+ if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
1694+ old->se_ctrladdr_in6.sin6_scope_id !=
1695+ new->se_ctrladdr_in6.sin6_scope_id)
1696+ return (0);
1697+
1698+ return (1);
1699+}
1700+
1701+FILE *fconfig = NULL;
1702+char line[1024];
1703+char *defhost;
1704+char *skip(char **, int);
1705+char *nextline(FILE *);
1706+char *newstr(char *);
1707+struct servtab *dupconfig(struct servtab *);
1708+
1709+int
1710+setconfig(void)
1711+{
1712+ if (defhost)
1713+ free(defhost);
1714+ defhost = newstr("*");
1715+ if (fconfig != NULL) {
1716+ fseek(fconfig, 0L, SEEK_SET);
1717+ return (1);
1718+ }
1719+ fconfig = fopen(CONFIG, "r");
1720+ return (fconfig != NULL);
1721+}
1722+
1723+void
1724+endconfig(void)
1725+{
1726+ if (fconfig) {
1727+ (void) fclose(fconfig);
1728+ fconfig = NULL;
1729+ }
1730+ if (defhost) {
1731+ free(defhost);
1732+ defhost = 0;
1733+ }
1734+}
1735+
1736+struct servtab *
1737+getconfigent(void)
1738+{
1739+ struct servtab *sep, *tsep;
1740+ char *arg, *cp, *hostdelim, *s;
1741+ int argc;
1742+
1743+ sep = (struct servtab *) malloc(sizeof(struct servtab));
1744+ if (sep == NULL) {
1745+ syslog(LOG_ERR, "malloc: %m");
1746+ exit(1);
1747+ }
1748+
1749+ memset(sep, 0, sizeof *sep);
1750+more:
1751+ freeconfig(sep);
1752+
1753+ while ((cp = nextline(fconfig)) && *cp == '#')
1754+ ;
1755+ if (cp == NULL) {
1756+ free(sep);
1757+ return (NULL);
1758+ }
1759+
1760+ memset(sep, 0, sizeof *sep);
1761+ arg = skip(&cp, 0);
1762+ if (arg == NULL) {
1763+ /* A blank line. */
1764+ goto more;
1765+ }
1766+
1767+ /* Check for a host name. */
1768+ hostdelim = strrchr(arg, ':');
1769+ if (hostdelim) {
1770+ *hostdelim = '\0';
1771+ if (arg[0] == '[' && hostdelim > arg && hostdelim[-1] == ']') {
1772+ hostdelim[-1] = '\0';
1773+ sep->se_hostaddr = newstr(arg + 1);
1774+ } else if (hostdelim == arg)
1775+ sep->se_hostaddr = newstr("*");
1776+ else
1777+ sep->se_hostaddr = newstr(arg);
1778+ arg = hostdelim + 1;
1779+ /*
1780+ * If the line is of the form `host:', then just change the
1781+ * default host for the following lines.
1782+ */
1783+ if (*arg == '\0') {
1784+ arg = skip(&cp, 0);
1785+ if (cp == NULL) {
1786+ free(defhost);
1787+ defhost = newstr(sep->se_hostaddr);
1788+ goto more;
1789+ }
1790+ }
1791+ } else
1792+ sep->se_hostaddr = newstr(defhost);
1793+
1794+ sep->se_service = newstr(arg);
1795+ if ((arg = skip(&cp, 1)) == NULL)
1796+ goto more;
1797+
1798+ if (strcmp(arg, "stream") == 0)
1799+ sep->se_socktype = SOCK_STREAM;
1800+ else if (strcmp(arg, "dgram") == 0)
1801+ sep->se_socktype = SOCK_DGRAM;
1802+ else if (strcmp(arg, "rdm") == 0)
1803+ sep->se_socktype = SOCK_RDM;
1804+ else if (strcmp(arg, "seqpacket") == 0)
1805+ sep->se_socktype = SOCK_SEQPACKET;
1806+ else if (strcmp(arg, "raw") == 0)
1807+ sep->se_socktype = SOCK_RAW;
1808+ else
1809+ sep->se_socktype = -1;
1810+
1811+ if ((arg = skip(&cp, 1)) == NULL)
1812+ goto more;
1813+
1814+ sep->se_proto = newstr(arg);
1815+
1816+ if (strcmp(sep->se_proto, "unix") == 0) {
1817+ sep->se_family = AF_UNIX;
1818+ } else {
1819+ int s;
1820+
1821+ sep->se_family = AF_INET;
1822+ if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
1823+ sep->se_family = AF_INET6;
1824+
1825+ /* check if the family is supported */
1826+ s = socket(sep->se_family, SOCK_DGRAM, 0);
1827+ if (s < 0) {
1828+ syslog(LOG_WARNING, "%s/%s: %s: the address family is "
1829+ "not supported by the kernel", sep->se_service,
1830+ sep->se_proto, sep->se_hostaddr);
1831+ goto more;
1832+ }
1833+ close(s);
1834+
1835+ if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1836+ char *cp, *ccp;
1837+ long l;
1838+
1839+ cp = strchr(sep->se_service, '/');
1840+ if (cp == 0) {
1841+ syslog(LOG_ERR, "%s: no rpc version",
1842+ sep->se_service);
1843+ goto more;
1844+ }
1845+ *cp++ = '\0';
1846+ l = strtol(cp, &ccp, 0);
1847+ if (ccp == cp || l < 0 || l > INT_MAX) {
1848+ badafterall:
1849+ syslog(LOG_ERR, "%s/%s: bad rpc version",
1850+ sep->se_service, cp);
1851+ goto more;
1852+ }
1853+ sep->se_rpcversl = sep->se_rpcversh = l;
1854+ if (*ccp == '-') {
1855+ cp = ccp + 1;
1856+ l = strtol(cp, &ccp, 0);
1857+ if (ccp == cp || l < 0 || l > INT_MAX ||
1858+ l < sep->se_rpcversl || *ccp)
1859+ goto badafterall;
1860+ sep->se_rpcversh = l;
1861+ } else if (*ccp != '\0')
1862+ goto badafterall;
1863+ }
1864+ }
1865+ arg = skip(&cp, 1);
1866+ if (arg == NULL)
1867+ goto more;
1868+
1869+ s = strchr(arg, '.');
1870+ if (s) {
1871+ char *p;
1872+
1873+ *s++ = '\0';
1874+ sep->se_max = strtoul(s, &p, 0);
1875+ if (sep->se_max < 1 || *p) {
1876+ syslog(LOG_ERR,
1877+ "%s: illegal max field \"%s\", setting to %d",
1878+ sep->se_service, s, toomany);
1879+ sep->se_max = toomany;
1880+ }
1881+ } else
1882+ sep->se_max = toomany;
1883+
1884+ sep->se_wait = strcmp(arg, "wait") == 0;
1885+ if ((arg = skip(&cp, 1)) == NULL)
1886+ goto more;
1887+ sep->se_user = newstr(arg);
1888+ arg = strchr(sep->se_user, '.');
1889+ if (arg == NULL)
1890+ arg = strchr(sep->se_user, ':');
1891+ if (arg) {
1892+ *arg++ = '\0';
1893+ sep->se_group = newstr(arg);
1894+ }
1895+ if ((arg = skip(&cp, 1)) == NULL)
1896+ goto more;
1897+
1898+ sep->se_server = newstr(arg);
1899+ if (strcmp(sep->se_server, "internal") == 0) {
1900+ struct biltin *bi;
1901+
1902+ for (bi = biltins; bi->bi_service; bi++)
1903+ if (bi->bi_socktype == sep->se_socktype &&
1904+ strcmp(bi->bi_service, sep->se_service) == 0)
1905+ break;
1906+ if (bi->bi_service == 0) {
1907+ syslog(LOG_ERR, "internal service %s unknown",
1908+ sep->se_service);
1909+ goto more;
1910+ }
1911+ sep->se_bi = bi;
1912+ sep->se_wait = bi->bi_wait;
1913+ } else
1914+ sep->se_bi = NULL;
1915+ argc = 0;
1916+ for (arg = skip(&cp, 0); cp; arg = skip(&cp, 0)) {
1917+ if (argc < MAXARGV)
1918+ sep->se_argv[argc++] = newstr(arg);
1919+ }
1920+ if (argc == 0 && sep->se_bi == NULL) {
1921+ if ((arg = strrchr(sep->se_server, '/')) != NULL)
1922+ arg++;
1923+ else
1924+ arg = sep->se_server;
1925+ sep->se_argv[argc++] = newstr(arg);
1926+ }
1927+ while (argc <= MAXARGV)
1928+ sep->se_argv[argc++] = NULL;
1929+
1930+ /*
1931+ * Resolve each hostname in the se_hostaddr list (if any)
1932+ * and create a new entry for each resolved address.
1933+ */
1934+ if (sep->se_hostaddr != NULL && strcmp(sep->se_proto, "unix") != 0) {
1935+ struct addrinfo hints, *res0, *res;
1936+ char *host, *hostlist0, *hostlist, *port;
1937+ int error;
1938+
1939+ hostlist = hostlist0 = sep->se_hostaddr;
1940+ sep->se_hostaddr = NULL;
1941+ sep->se_checked = -1;
1942+ while ((host = strsep(&hostlist, ",")) != NULL) {
1943+ if (*host == '\0')
1944+ continue;
1945+
1946+ memset(&hints, 0, sizeof(hints));
1947+ hints.ai_family = sep->se_family;
1948+ hints.ai_socktype = sep->se_socktype;
1949+ hints.ai_flags = AI_PASSIVE;
1950+ port = "0";
1951+ /* XXX shortened IPv4 syntax is now forbidden */
1952+ error = getaddrinfo(strcmp(host, "*") ? host : NULL,
1953+ port, &hints, &res0);
1954+ if (error) {
1955+ syslog(LOG_ERR, "%s/%s: %s: %s",
1956+ sep->se_service, sep->se_proto,
1957+ host, gai_strerror(error));
1958+ continue;
1959+ }
1960+ for (res = res0; res; res = res->ai_next) {
1961+ if (res->ai_addrlen >
1962+ sizeof(sep->se_ctrladdr_storage))
1963+ continue;
1964+ /*
1965+ * If sep is unused, store host in there.
1966+ * Otherwise, dup a new entry and prepend it.
1967+ */
1968+ if (sep->se_checked == -1) {
1969+ sep->se_checked = 0;
1970+ } else {
1971+ tsep = dupconfig(sep);
1972+ tsep->se_next = sep;
1973+ sep = tsep;
1974+ }
1975+ sep->se_hostaddr = newstr(host);
1976+ memcpy(&sep->se_ctrladdr_storage,
1977+ res->ai_addr, res->ai_addrlen);
1978+ sep->se_ctrladdr_size = res->ai_addrlen;
1979+ }
1980+ freeaddrinfo(res0);
1981+ }
1982+ free(hostlist0);
1983+ if (sep->se_checked == -1)
1984+ goto more; /* no resolvable names/addresses */
1985+ }
1986+
1987+ return (sep);
1988+}
1989+
1990+void
1991+freeconfig(struct servtab *cp)
1992+{
1993+ int i;
1994+
1995+ free(cp->se_hostaddr);
1996+ cp->se_hostaddr = NULL;
1997+ free(cp->se_service);
1998+ cp->se_service = NULL;
1999+ free(cp->se_proto);
2000+ cp->se_proto = NULL;
2001+ free(cp->se_user);
2002+ cp->se_user = NULL;
2003+ free(cp->se_group);
2004+ cp->se_group = NULL;
2005+ free(cp->se_server);
2006+ cp->se_server = NULL;
2007+ for (i = 0; i < MAXARGV; i++) {
2008+ free(cp->se_argv[i]);
2009+ cp->se_argv[i] = NULL;
2010+ }
2011+}
2012+
2013+char *
2014+skip(char **cpp, int report)
2015+{
2016+ char *cp = *cpp;
2017+ char *start;
2018+
2019+erp:
2020+ if (*cpp == NULL) {
2021+ if (report)
2022+ syslog(LOG_ERR, "syntax error in inetd config file");
2023+ return (NULL);
2024+ }
2025+
2026+again:
2027+ while (*cp == ' ' || *cp == '\t')
2028+ cp++;
2029+ if (*cp == '\0') {
2030+ int c;
2031+
2032+ c = getc(fconfig);
2033+ (void) ungetc(c, fconfig);
2034+ if (c == ' ' || c == '\t')
2035+ if ((cp = nextline(fconfig)))
2036+ goto again;
2037+ *cpp = NULL;
2038+ goto erp;
2039+ }
2040+ start = cp;
2041+ while (*cp && *cp != ' ' && *cp != '\t')
2042+ cp++;
2043+ if (*cp != '\0')
2044+ *cp++ = '\0';
2045+ if ((*cpp = cp) == NULL)
2046+ goto erp;
2047+
2048+ return (start);
2049+}
2050+
2051+char *
2052+nextline(FILE *fd)
2053+{
2054+ if (fgets(line, sizeof (line), fd) == NULL)
2055+ return (NULL);
2056+ line[strcspn(line, "\n")] = '\0';
2057+ return (line);
2058+}
2059+
2060+char *
2061+newstr(char *cp)
2062+{
2063+ if ((cp = strdup(cp ? cp : "")))
2064+ return(cp);
2065+ syslog(LOG_ERR, "strdup: %m");
2066+ exit(1);
2067+}
2068+
2069+struct servtab *
2070+dupconfig(struct servtab *sep)
2071+{
2072+ struct servtab *newtab;
2073+ int argc;
2074+
2075+ newtab = (struct servtab *) malloc(sizeof(struct servtab));
2076+
2077+ if (newtab == NULL) {
2078+ syslog(LOG_ERR, "malloc: %m");
2079+ exit(1);
2080+ }
2081+
2082+ memset(newtab, 0, sizeof(struct servtab));
2083+
2084+ newtab->se_service = sep->se_service ? newstr(sep->se_service) : NULL;
2085+ newtab->se_socktype = sep->se_socktype;
2086+ newtab->se_family = sep->se_family;
2087+ newtab->se_proto = sep->se_proto ? newstr(sep->se_proto) : NULL;
2088+ newtab->se_rpcprog = sep->se_rpcprog;
2089+ newtab->se_rpcversl = sep->se_rpcversl;
2090+ newtab->se_rpcversh = sep->se_rpcversh;
2091+ newtab->se_wait = sep->se_wait;
2092+ newtab->se_user = sep->se_user ? newstr(sep->se_user) : NULL;
2093+ newtab->se_group = sep->se_group ? newstr(sep->se_group) : NULL;
2094+ newtab->se_bi = sep->se_bi;
2095+ newtab->se_server = sep->se_server ? newstr(sep->se_server) : 0;
2096+
2097+ for (argc = 0; argc <= MAXARGV; argc++)
2098+ newtab->se_argv[argc] = sep->se_argv[argc] ?
2099+ newstr(sep->se_argv[argc]) : NULL;
2100+ newtab->se_max = sep->se_max;
2101+
2102+ return (newtab);
2103+}
2104+
2105+void
2106+inetd_setproctitle(char *a, int s)
2107+{
2108+ socklen_t size;
2109+ struct sockaddr_storage ss;
2110+ char hbuf[NI_MAXHOST];
2111+
2112+ size = sizeof(ss);
2113+ if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
2114+ if (getnameinfo((struct sockaddr *)&ss, size, hbuf,
2115+ sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0)
2116+ setproctitle("-%s [%s]", a, hbuf);
2117+ else
2118+ setproctitle("-%s [?]", a);
2119+ } else
2120+ setproctitle("-%s", a);
2121+}
2122+
2123+void
2124+logpid(void)
2125+{
2126+ FILE *fp;
2127+
2128+ if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
2129+ fprintf(fp, "%ld\n", (long)getpid());
2130+ (void)fclose(fp);
2131+ }
2132+}
2133+
2134+int
2135+bump_nofile(void)
2136+{
2137+#define FD_CHUNK 32
2138+
2139+ struct rlimit rl;
2140+
2141+ if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
2142+ syslog(LOG_ERR, "getrlimit: %m");
2143+ return -1;
2144+ }
2145+ rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
2146+ rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
2147+ if (rl.rlim_cur <= rlim_nofile_cur) {
2148+ syslog(LOG_ERR,
2149+ "bump_nofile: cannot extend file limit, max = %d",
2150+ (int)rl.rlim_cur);
2151+ return -1;
2152+ }
2153+
2154+ if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
2155+ syslog(LOG_ERR, "setrlimit: %m");
2156+ return -1;
2157+ }
2158+
2159+ rlim_nofile_cur = rl.rlim_cur;
2160+ return 0;
2161+}
2162+
2163+/*
2164+ * Internet services provided internally by inetd:
2165+ */
2166+#define BUFSIZE 4096
2167+
2168+/* ARGSUSED */
2169+void
2170+echo_stream(int s, struct servtab *sep)
2171+{
2172+ char buffer[BUFSIZE];
2173+ int i;
2174+
2175+ inetd_setproctitle(sep->se_service, s);
2176+ while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
2177+ write(s, buffer, i) > 0)
2178+ ;
2179+ exit(0);
2180+}
2181+
2182+/* ARGSUSED */
2183+void
2184+echo_dg(int s, struct servtab *sep)
2185+{
2186+ char buffer[BUFSIZE];
2187+ int i;
2188+ socklen_t size;
2189+ struct sockaddr_storage ss;
2190+
2191+ size = sizeof(ss);
2192+ if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
2193+ (struct sockaddr *)&ss, &size)) < 0)
2194+ return;
2195+ if (dg_badinput((struct sockaddr *)&ss))
2196+ return;
2197+ (void) sendto(s, buffer, i, 0, (struct sockaddr *)&ss, size);
2198+}
2199+
2200+/* ARGSUSED */
2201+void
2202+discard_stream(int s, struct servtab *sep)
2203+{
2204+ char buffer[BUFSIZE];
2205+
2206+ inetd_setproctitle(sep->se_service, s);
2207+ while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
2208+ errno == EINTR)
2209+ ;
2210+ exit(0);
2211+}
2212+
2213+/* ARGSUSED */
2214+void
2215+discard_dg(int s, struct servtab *sep)
2216+{
2217+ char buffer[BUFSIZE];
2218+
2219+ (void) read(s, buffer, sizeof(buffer));
2220+}
2221+
2222+#include <ctype.h>
2223+#define LINESIZ 72
2224+char ring[128];
2225+char *endring;
2226+
2227+void
2228+initring(void)
2229+{
2230+ int i;
2231+
2232+ endring = ring;
2233+
2234+ for (i = 0; i <= sizeof ring; ++i)
2235+ if (isprint(i))
2236+ *endring++ = i;
2237+}
2238+
2239+/* ARGSUSED */
2240+void
2241+chargen_stream(int s, struct servtab *sep)
2242+{
2243+ char *rs;
2244+ int len;
2245+ char text[LINESIZ+2];
2246+
2247+ inetd_setproctitle(sep->se_service, s);
2248+
2249+ if (!endring) {
2250+ initring();
2251+ rs = ring;
2252+ }
2253+
2254+ text[LINESIZ] = '\r';
2255+ text[LINESIZ + 1] = '\n';
2256+ for (rs = ring;;) {
2257+ if ((len = endring - rs) >= LINESIZ)
2258+ memmove(text, rs, LINESIZ);
2259+ else {
2260+ memmove(text, rs, len);
2261+ memmove(text + len, ring, LINESIZ - len);
2262+ }
2263+ if (++rs == endring)
2264+ rs = ring;
2265+ if (write(s, text, sizeof(text)) != sizeof(text))
2266+ break;
2267+ }
2268+ exit(0);
2269+}
2270+
2271+/* ARGSUSED */
2272+void
2273+chargen_dg(int s, struct servtab *sep)
2274+{
2275+ struct sockaddr_storage ss;
2276+ static char *rs;
2277+ int len;
2278+ socklen_t size;
2279+ char text[LINESIZ+2];
2280+
2281+ if (endring == 0) {
2282+ initring();
2283+ rs = ring;
2284+ }
2285+
2286+ size = sizeof(ss);
2287+ if (recvfrom(s, text, sizeof(text), 0, (struct sockaddr *)&ss,
2288+ &size) < 0)
2289+ return;
2290+ if (dg_badinput((struct sockaddr *)&ss))
2291+ return;
2292+
2293+ if ((len = endring - rs) >= LINESIZ)
2294+ memmove(text, rs, LINESIZ);
2295+ else {
2296+ memmove(text, rs, len);
2297+ memmove(text + len, ring, LINESIZ - len);
2298+ }
2299+ if (++rs == endring)
2300+ rs = ring;
2301+ text[LINESIZ] = '\r';
2302+ text[LINESIZ + 1] = '\n';
2303+ (void) sendto(s, text, sizeof(text), 0, (struct sockaddr *)&ss, size);
2304+}
2305+
2306+/*
2307+ * Return a machine readable date and time, in the form of the
2308+ * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
2309+ * returns the number of seconds since midnight, Jan 1, 1970,
2310+ * we must add 2208988800 seconds to this figure to make up for
2311+ * some seventy years Bell Labs was asleep.
2312+ */
2313+u_int32_t
2314+machtime(void)
2315+{
2316+ struct timeval tv;
2317+
2318+ if (gettimeofday(&tv, NULL) < 0)
2319+ return (0L);
2320+
2321+ return (htonl((u_int32_t)tv.tv_sec + 2208988800UL));
2322+}
2323+
2324+/* ARGSUSED */
2325+void
2326+machtime_stream(s, sep)
2327+ int s;
2328+ struct servtab *sep;
2329+{
2330+ u_int32_t result;
2331+
2332+ result = machtime();
2333+ (void) write(s, &result, sizeof(result));
2334+}
2335+
2336+/* ARGSUSED */
2337+void
2338+machtime_dg(int s, struct servtab *sep)
2339+{
2340+ u_int32_t result;
2341+ struct sockaddr_storage ss;
2342+ socklen_t size;
2343+
2344+ size = sizeof(ss);
2345+ if (recvfrom(s, &result, sizeof(result), 0,
2346+ (struct sockaddr *)&ss, &size) < 0)
2347+ return;
2348+ if (dg_badinput((struct sockaddr *)&ss))
2349+ return;
2350+ result = machtime();
2351+ (void) sendto(s, &result, sizeof(result), 0,
2352+ (struct sockaddr *)&ss, size);
2353+}
2354+
2355+/* Return human-readable time of day */
2356+/* ARGSUSED */
2357+void
2358+daytime_stream(int s, struct servtab *sep)
2359+{
2360+ char buffer[256];
2361+ time_t clock;
2362+
2363+ clock = time(NULL);
2364+
2365+ (void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
2366+ (void) write(s, buffer, strlen(buffer));
2367+}
2368+
2369+/* Return human-readable time of day */
2370+/* ARGSUSED */
2371+void
2372+daytime_dg(int s, struct servtab *sep)
2373+{
2374+ char buffer[256];
2375+ time_t clock;
2376+ struct sockaddr_storage ss;
2377+ socklen_t size;
2378+
2379+ clock = time(NULL);
2380+
2381+ size = sizeof(ss);
2382+ if (recvfrom(s, buffer, sizeof(buffer), 0, (struct sockaddr *)&ss,
2383+ &size) < 0)
2384+ return;
2385+ if (dg_badinput((struct sockaddr *)&ss))
2386+ return;
2387+ (void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
2388+ (void) sendto(s, buffer, strlen(buffer), 0, (struct sockaddr *)&ss,
2389+ size);
2390+}
2391+
2392+/*
2393+ * print_service:
2394+ * Dump relevant information to stderr
2395+ */
2396+void
2397+print_service(char *action, struct servtab *sep)
2398+{
2399+ if (strcmp(sep->se_hostaddr, "*") == 0)
2400+ fprintf(stderr, "%s: %s ", action, sep->se_service);
2401+ else
2402+ fprintf(stderr, "%s: %s:%s ", action, sep->se_hostaddr,
2403+ sep->se_service);
2404+
2405+ if (isrpcservice(sep))
2406+ fprintf(stderr, "rpcprog=%d, rpcvers=%d/%d, proto=%s,",
2407+ sep->se_rpcprog, sep->se_rpcversh,
2408+ sep->se_rpcversl, sep->se_proto);
2409+ else
2410+ fprintf(stderr, "proto=%s,", sep->se_proto);
2411+
2412+ fprintf(stderr,
2413+ " wait.max=%hd.%d user:group=%s:%s builtin=%lx server=%s\n",
2414+ sep->se_wait, sep->se_max, sep->se_user,
2415+ sep->se_group ? sep->se_group : "(default)",
2416+ (long)sep->se_bi, sep->se_server);
2417+}
2418+
2419+void
2420+spawn(struct servtab *sep, int ctrl)
2421+{
2422+ struct passwd *pwd;
2423+ int tmpint, dofork;
2424+ struct group *grp = NULL;
2425+ char buf[50];
2426+ pid_t pid;
2427+
2428+ pid = 0;
2429+ dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
2430+ if (dofork) {
2431+ if (sep->se_count++ == 0)
2432+ (void)gettimeofday(&sep->se_time, NULL);
2433+ else if (sep->se_count >= sep->se_max) {
2434+ struct timeval now;
2435+
2436+ (void)gettimeofday(&now, NULL);
2437+ if (now.tv_sec - sep->se_time.tv_sec >
2438+ CNT_INTVL) {
2439+ sep->se_time = now;
2440+ sep->se_count = 1;
2441+ } else {
2442+ if (!sep->se_wait &&
2443+ sep->se_socktype == SOCK_STREAM)
2444+ close(ctrl);
2445+ if (sep->se_family == AF_INET &&
2446+ ntohs(sep->se_ctrladdr_in.sin_port) >=
2447+ IPPORT_RESERVED) {
2448+ /*
2449+ * Cannot close it -- there are
2450+ * thieves on the system.
2451+ * Simply ignore the connection.
2452+ */
2453+ --sep->se_count;
2454+ sigprocmask(SIG_SETMASK, &emptymask,
2455+ NULL);
2456+ return;
2457+ }
2458+ syslog(LOG_ERR,
2459+ "%s/%s server failing (looping), service terminated for %d min",
2460+ sep->se_service, sep->se_proto,
2461+ RETRYTIME/60);
2462+ if (!sep->se_wait &&
2463+ sep->se_socktype == SOCK_STREAM)
2464+ close(ctrl);
2465+ FD_CLR(sep->se_fd, allsockp);
2466+ (void) close(sep->se_fd);
2467+ sep->se_fd = -1;
2468+ sep->se_count = 0;
2469+ nsock--;
2470+ sigprocmask(SIG_SETMASK, &emptymask,
2471+ NULL);
2472+ if (!timingout) {
2473+ timingout = 1;
2474+ alarm(RETRYTIME);
2475+ }
2476+ return;
2477+ }
2478+ }
2479+ pid = fork();
2480+ }
2481+ if (pid < 0) {
2482+ syslog(LOG_ERR, "fork: %m");
2483+ if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
2484+ close(ctrl);
2485+ sigprocmask(SIG_SETMASK, &emptymask, NULL);
2486+ sleep(1);
2487+ return;
2488+ }
2489+ if (pid && sep->se_wait) {
2490+ sep->se_wait = pid;
2491+ FD_CLR(sep->se_fd, allsockp);
2492+ nsock--;
2493+ }
2494+ sigprocmask(SIG_SETMASK, &emptymask, NULL);
2495+ if (pid == 0) {
2496+#ifdef LIBWRAP
2497+ if (lflag && !sep->se_wait && sep->se_socktype == SOCK_STREAM) {
2498+ struct request_info req;
2499+ char *service;
2500+
2501+ /* do not execute tcpd if it is in the config */
2502+ if (strcmp(sep->se_server, "/usr/sbin/tcpd") == 0) {
2503+ char *p, *name;
2504+
2505+ free(sep->se_server);
2506+ name = sep->se_server = sep->se_argv[0];
2507+ for (p = name; *p; p++)
2508+ if (*p == '/')
2509+ name = p + 1;
2510+ sep->se_argv[0] = newstr(name);
2511+ }
2512+
2513+ request_init(&req, RQ_DAEMON, sep->se_argv[0],
2514+ RQ_FILE, ctrl, NULL);
2515+ fromhost(&req);
2516+ if (getnameinfo(&sep->se_ctrladdr,
2517+ sizeof(sep->se_ctrladdr), NULL, 0, buf,
2518+ sizeof(buf), 0) != 0) {
2519+ /* shouldn't happen */
2520+ snprintf(buf, sizeof buf, "%d",
2521+ ntohs(sep->se_ctrladdr_in.sin_port));
2522+ }
2523+ service = buf;
2524+ if (!hosts_access(&req)) {
2525+ syslog(deny_severity, "refused connection"
2526+ " from %.500s, service %s (%s)",
2527+ eval_client(&req), service, sep->se_proto);
2528+ if (sep->se_socktype != SOCK_STREAM)
2529+ recv(0, buf, sizeof (buf), 0);
2530+ exit(1);
2531+ }
2532+ syslog(allow_severity,
2533+ "connection from %.500s, service %s (%s)",
2534+ eval_client(&req), service, sep->se_proto);
2535+ }
2536+#endif
2537+ if (sep->se_bi)
2538+ (*sep->se_bi->bi_fn)(ctrl, sep);
2539+ else {
2540+ if ((pwd = getpwnam(sep->se_user)) == NULL) {
2541+ syslog(LOG_ERR,
2542+ "getpwnam: %s: No such user",
2543+ sep->se_user);
2544+ if (sep->se_socktype != SOCK_STREAM)
2545+ recv(0, buf, sizeof (buf), 0);
2546+ exit(1);
2547+ }
2548+ if (setsid() <0)
2549+ syslog(LOG_ERR, "%s: setsid: %m",
2550+ sep->se_service);
2551+ if (sep->se_group &&
2552+ (grp = getgrnam(sep->se_group)) == NULL) {
2553+ syslog(LOG_ERR,
2554+ "getgrnam: %s: No such group",
2555+ sep->se_group);
2556+ if (sep->se_socktype != SOCK_STREAM)
2557+ recv(0, buf, sizeof (buf), 0);
2558+ exit(1);
2559+ }
2560+ if (uid != 0) {
2561+ /* a user running private inetd */
2562+ if (uid != pwd->pw_uid)
2563+ exit(1);
2564+ } else {
2565+#ifdef HAVE_SETUSERCONTEXT
2566+ tmpint = LOGIN_SETALL &
2567+ ~(LOGIN_SETGROUP|LOGIN_SETLOGIN);
2568+ if (pwd->pw_uid)
2569+ tmpint |= LOGIN_SETGROUP|LOGIN_SETLOGIN;
2570+ if (sep->se_group) {
2571+ pwd->pw_gid = grp->gr_gid;
2572+ tmpint |= LOGIN_SETGROUP;
2573+ }
2574+ if (setusercontext(NULL, pwd, pwd->pw_uid,
2575+ tmpint) < 0) {
2576+ syslog(LOG_ERR,
2577+ "%s/%s: setusercontext: %m",
2578+ sep->se_service, sep->se_proto);
2579+ exit(1);
2580+ }
2581+#else
2582+ /* what about setpriority(2), setrlimit(2),
2583+ * and umask(2)? The $PATH is cleared.
2584+ */
2585+ if (pwd->pw_uid) {
2586+ if (sep->se_group)
2587+ pwd->pw_gid = grp->gr_gid;
2588+ if (setgid(pwd->pw_gid) < 0) {
2589+ syslog(LOG_ERR,
2590+ "%s/%s: can't set gid %d: %m",
2591+ sep->se_service, sep->se_proto,
2592+ pwd->pw_gid);
2593+ exit(1);
2594+ }
2595+ if (initgroups(pwd->pw_name, pwd->pw_gid)
2596+ < 0) {
2597+ syslog(LOG_ERR,
2598+ "%s/%s: can't initgroups(%s): %m",
2599+ sep->se_service, sep->se_proto,
2600+ pwd->pw_name);
2601+ exit(1);
2602+ }
2603+ if (setuid(pwd->pw_uid) < 0) {
2604+ syslog(LOG_ERR,
2605+ "%s/%s: can't set uid %d: %m",
2606+ sep->se_service, sep->se_proto,
2607+ pwd->pw_uid);
2608+ exit(1);
2609+ }
2610+ } else if (sep->se_group) {
2611+ if (setgid(pwd->pw_gid) < 0) {
2612+ syslog(LOG_ERR,
2613+ "%s/%s: can't set gid %d: %m",
2614+ sep->se_service, sep->se_proto,
2615+ pwd->pw_gid);
2616+ exit(1);
2617+ }
2618+ if (initgroups(pwd->pw_name, pwd->pw_gid)
2619+ < 0) {
2620+ syslog(LOG_ERR,
2621+ "%s/%s: can't initgroups(%s): %m",
2622+ sep->se_service, sep->se_proto,
2623+ pwd->pw_name);
2624+ exit(1);
2625+ }
2626+ }
2627+#endif
2628+ }
2629+ if (debug)
2630+ fprintf(stderr, "%ld execv %s\n",
2631+ (long)getpid(), sep->se_server);
2632+ if (ctrl != STDIN_FILENO) {
2633+ dup2(ctrl, STDIN_FILENO);
2634+ close(ctrl);
2635+ }
2636+ dup2(STDIN_FILENO, STDOUT_FILENO);
2637+ dup2(STDIN_FILENO, STDERR_FILENO);
2638+ closelog();
2639+ closefrom(3);
2640+ sigaction(SIGPIPE, &sapipe, NULL);
2641+ execv(sep->se_server, sep->se_argv);
2642+ if (sep->se_socktype != SOCK_STREAM)
2643+ recv(0, buf, sizeof (buf), 0);
2644+ syslog(LOG_ERR, "execv %s: %m", sep->se_server);
2645+ exit(1);
2646+ }
2647+ }
2648+ if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
2649+ close(ctrl);
2650+}
2651+
2652+/* from netkit+USAGI */
2653+void
2654+discard_stupid_environment(void)
2655+{
2656+ static const char *const junk[] = {
2657+ /* these are prefixes */
2658+ "CVS",
2659+ "DISPLAY=",
2660+ "EDITOR=",
2661+ "GROUP=",
2662+ "HOME=",
2663+ "IFS=",
2664+ "LD_",
2665+ "LOGNAME=",
2666+ "MAIL=",
2667+ "PATH=",
2668+ "PRINTER=",
2669+ "PWD=",
2670+ "SHELL=",
2671+ "SHLVL=",
2672+ "SSH",
2673+ "TERM",
2674+ "TMP",
2675+ "USER=",
2676+ "VISUAL=",
2677+ NULL
2678+ };
2679+
2680+ int i, k = 0;
2681+
2682+ for (i = 0; __environ[i]; i++) {
2683+ int found = 0, j;
2684+
2685+ for (j = 0; junk[j]; j++)
2686+ if (!strncmp(__environ[i], junk[j], strlen(junk[j])))
2687+ found = 1;
2688+ if (!found)
2689+ __environ[k++] = __environ[i];
2690+ }
2691+ __environ[k] = NULL;
2692+}
2693
2694=== added directory '.pc/discard_env'
2695=== added file '.pc/discard_env/inetd.8'
2696--- .pc/discard_env/inetd.8 1970-01-01 00:00:00 +0000
2697+++ .pc/discard_env/inetd.8 2011-06-29 11:29:23 +0000
2698@@ -0,0 +1,419 @@
2699+.\" $OpenBSD: inetd.8,v 1.33 2008/06/28 10:54:45 sobrado Exp $
2700+.\" Copyright (c) 1985, 1991 The Regents of the University of California.
2701+.\" All rights reserved.
2702+.\"
2703+.\" Redistribution and use in source and binary forms, with or without
2704+.\" modification, are permitted provided that the following conditions
2705+.\" are met:
2706+.\" 1. Redistributions of source code must retain the above copyright
2707+.\" notice, this list of conditions and the following disclaimer.
2708+.\" 2. Redistributions in binary form must reproduce the above copyright
2709+.\" notice, this list of conditions and the following disclaimer in the
2710+.\" documentation and/or other materials provided with the distribution.
2711+.\" 3. Neither the name of the University nor the names of its contributors
2712+.\" may be used to endorse or promote products derived from this software
2713+.\" without specific prior written permission.
2714+.\"
2715+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2716+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2717+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2718+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2719+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2720+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2721+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2722+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2723+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2724+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2725+.\" SUCH DAMAGE.
2726+.\"
2727+.\" from: @(#)inetd.8 6.7 (Berkeley) 3/16/91
2728+.\"
2729+.Dd $Mdocdate: December 29 2009 $
2730+.Dt INETD 8
2731+.Os
2732+.Sh NAME
2733+.Nm inetd
2734+.Nd internet
2735+.Dq super-server
2736+.Sh SYNOPSIS
2737+.Nm inetd
2738+.Op Fl d
2739+.Op Fl R Ar rate
2740+.Op Ar configuration_file
2741+.Sh DESCRIPTION
2742+.Nm inetd
2743+listens for connections on certain internet sockets.
2744+When a connection is found on one
2745+of its sockets, it decides what service the socket
2746+corresponds to, and invokes a program to service the request.
2747+After the program is
2748+finished, it continues to listen on the socket (except in some cases which
2749+will be described below).
2750+Essentially,
2751+.Nm inetd
2752+allows running one daemon to invoke several others,
2753+reducing load on the system.
2754+.Pp
2755+The options are as follows:
2756+.Bl -tag -width Ds
2757+.It Fl d
2758+Turns on debugging.
2759+.It Fl R Ar rate
2760+Specify the maximum number of times a service can be invoked
2761+in one minute; the default is 256.
2762+If a service exceeds this limit,
2763+.Nm
2764+will log the problem
2765+and stop servicing requests for the specific service for ten minutes.
2766+See also the wait/nowait configuration fields below.
2767+.El
2768+.Pp
2769+Upon execution,
2770+.Nm inetd
2771+reads its configuration information from a configuration
2772+file which, by default, is
2773+.Pa /etc/inetd.conf .
2774+There must be an entry for each field of the configuration
2775+file, with entries for each field separated by a tab or
2776+a space.
2777+Comments are denoted by a
2778+.Dq #
2779+at the beginning
2780+of a line.
2781+The fields of the configuration file are as follows:
2782+.Bd -unfilled -offset indent
2783+service name
2784+socket type
2785+protocol
2786+wait/nowait[.max]
2787+user[.group] or user[:group]
2788+server program
2789+server program arguments
2790+.Ed
2791+.Pp
2792+To specify a Sun-RPC
2793+based service, the entry would contain these fields.
2794+.Bd -unfilled -offset indent
2795+service name/version
2796+socket type
2797+rpc/protocol
2798+wait/nowait[.max]
2799+user[.group] or user[:group]
2800+server program
2801+server program arguments
2802+.Ed
2803+.Pp
2804+For internet services, the first field of the line may also have a host
2805+address specifier prefixed to it, separated from the service name by a
2806+colon.
2807+If this is done, the string before the colon in the first field
2808+indicates what local address
2809+.Nm
2810+should use when listening for that service.
2811+Multiple local addresses
2812+can be specified on the same line, separated by commas.
2813+Numeric IP
2814+addresses in dotted-quad notation can be used as well as symbolic
2815+hostnames.
2816+Symbolic hostnames are looked up using
2817+.Fn gethostbyname .
2818+If a hostname has multiple address mappings, inetd creates a socket
2819+to listen on each address.
2820+.Pp
2821+The single character
2822+.Dq \&*
2823+indicates
2824+.Dv INADDR_ANY ,
2825+meaning
2826+.Dq all local addresses .
2827+To avoid repeating an address that occurs frequently, a line with a
2828+host address specifier and colon, but no further fields, causes the
2829+host address specifier to be remembered and used for all further lines
2830+with no explicit host specifier (until another such line or the end of
2831+the file).
2832+A line
2833+.Dl *:
2834+is implicitly provided at the top of the file; thus, traditional
2835+configuration files (which have no host address specifiers) will be
2836+interpreted in the traditional manner, with all services listened for
2837+on all local addresses.
2838+If the protocol is
2839+.Dq unix ,
2840+this value is ignored.
2841+.Pp
2842+The
2843+.Em service name
2844+entry is the name of a valid service in
2845+the file
2846+.Pa /etc/services
2847+or a port number.
2848+For
2849+.Dq internal
2850+services (discussed below), the service
2851+name
2852+.Em must
2853+be the official name of the service (that is, the first entry in
2854+.Pa /etc/services ) .
2855+When used to specify a Sun-RPC
2856+based service, this field is a valid RPC service name in
2857+the file
2858+.Pa /etc/rpc .
2859+The part on the right of the
2860+.Dq /
2861+is the RPC version number.
2862+This can simply be a single numeric argument or a range of versions.
2863+A range is bounded by the low version to the high version -
2864+.Dq rusers/1\-3 .
2865+For
2866+.Ux Ns -domain
2867+sockets this field specifies the path name of the socket.
2868+.Pp
2869+The
2870+.Em socket type
2871+should be one of
2872+.Dq stream ,
2873+.Dq dgram ,
2874+.Dq raw ,
2875+.Dq rdm ,
2876+or
2877+.Dq seqpacket ,
2878+depending on whether the socket is a stream, datagram, raw,
2879+reliably delivered message, or sequenced packet socket.
2880+.Pp
2881+The
2882+.Em protocol
2883+must be a valid protocol as given in
2884+.Pa /etc/protocols or
2885+.Dq unix .
2886+Examples might be
2887+.Dq tcp
2888+or
2889+.Dq udp .
2890+RPC based services are specified with the
2891+.Dq rpc/tcp
2892+or
2893+.Dq rpc/udp
2894+service type.
2895+.Dq tcp
2896+and
2897+.Dq udp
2898+will be recognized as
2899+.Dq TCP or UDP over default IP version .
2900+This is currently IPv4, but in the future it will be IPv6.
2901+If you need to specify IPv4 or IPv6 explicitly, use something like
2902+.Dq tcp4
2903+or
2904+.Dq udp6 .
2905+A
2906+.Em protocol
2907+of
2908+.Dq unix
2909+is used to specify a socket in the
2910+.Ux Ns -domain .
2911+.Pp
2912+The
2913+.Em wait/nowait
2914+entry is used to tell
2915+.Nm
2916+if it should wait for the server program to return,
2917+or continue processing connections on the socket.
2918+If a datagram server connects
2919+to its peer, freeing the socket so
2920+.Nm inetd
2921+can receive further messages on the socket, it is said to be
2922+a
2923+.Dq multi-threaded
2924+server, and should use the
2925+.Dq nowait
2926+entry.
2927+For datagram servers which process all incoming datagrams
2928+on a socket and eventually time out, the server is said to be
2929+.Dq single-threaded
2930+and should use a
2931+.Dq wait
2932+entry.
2933+.Xr comsat 8
2934+.Pq Xr biff 1
2935+and
2936+.Xr talkd 8
2937+are both examples of the latter type of
2938+datagram server.
2939+.Xr tftpd 8
2940+is an exception; it is a datagram server that establishes pseudo-connections.
2941+It must be listed as
2942+.Dq wait
2943+in order to avoid a race;
2944+the server reads the first packet, creates a new socket,
2945+and then forks and exits to allow
2946+.Nm inetd
2947+to check for new service requests to spawn new servers.
2948+The optional
2949+.Dq max
2950+suffix (separated from
2951+.Dq wait
2952+or
2953+.Dq nowait
2954+by a dot) specifies the maximum number of times a service can be invoked
2955+in one minute; the default is 256.
2956+If a service exceeds this limit,
2957+.Nm
2958+will log the problem
2959+and stop servicing requests for the specific service for ten minutes.
2960+See also the
2961+.Fl R
2962+option above.
2963+.Pp
2964+Stream servers are usually marked as
2965+.Dq nowait
2966+but if a single server process is to handle multiple connections, it may be
2967+marked as
2968+.Dq wait .
2969+The master socket will then be passed as fd 0 to the server, which will then
2970+need to accept the incoming connection.
2971+The server should eventually time
2972+out and exit when no more connections are active.
2973+.Nm
2974+will continue to
2975+listen on the master socket for connections, so the server should not close
2976+it when it exits.
2977+.Pp
2978+The
2979+.Em user
2980+entry should contain the user name of the user as whom the server
2981+should run.
2982+This allows for servers to be given less permission
2983+than root.
2984+An optional group name can be specified by appending a dot to
2985+the user name followed by the group name.
2986+This allows for servers to run with
2987+a different (primary) group ID than specified in the password file.
2988+If a group
2989+is specified and user is not root, the supplementary groups associated with
2990+that user will still be set.
2991+.Pp
2992+The
2993+.Em server program
2994+entry should contain the pathname of the program which is to be
2995+executed by
2996+.Nm inetd
2997+when a request is found on its socket.
2998+If
2999+.Nm inetd
3000+provides this service internally, this entry should
3001+be
3002+.Dq internal .
3003+.Pp
3004+The
3005+.Em server program arguments
3006+should be just as arguments
3007+normally are, starting with argv[0], which is the name of
3008+the program.
3009+If the service is provided internally, the word
3010+.Dq internal
3011+should take the place of this entry.
3012+.Pp
3013+.Nm inetd
3014+provides several
3015+.Dq trivial
3016+services internally by use of routines within itself.
3017+These services are
3018+.Dq echo ,
3019+.Dq discard ,
3020+.Dq chargen
3021+(character generator),
3022+.Dq daytime
3023+(human readable time), and
3024+.Dq time
3025+(machine readable time,
3026+in the form of the number of seconds since midnight, January
3027+1, 1900).
3028+All of these services are TCP based.
3029+For details of these services, consult the appropriate
3030+.Tn RFC
3031+from the Network Information Center.
3032+.Pp
3033+.Nm inetd
3034+rereads its configuration file when it receives a hangup signal,
3035+.Dv SIGHUP .
3036+Services may be added, deleted or modified when the configuration file
3037+is reread.
3038+.Nm inetd
3039+creates a file
3040+.Em /var/run/inetd.pid
3041+that contains its process identifier.
3042+.Ss IPv6 TCP/UDP behavior
3043+If you wish to run a server for IPv4 and IPv6 traffic,
3044+you'll need to run two separate processes for the same server program,
3045+specified as two separate lines in
3046+.Pa inetd.conf ,
3047+for
3048+.Dq tcp4
3049+and
3050+.Dq tcp6 .
3051+.Pp
3052+Under various combinations of IPv4/v6 daemon settings,
3053+.Nm
3054+will behave as follows:
3055+.Bl -bullet -compact
3056+.It
3057+If you have only one server on
3058+.Dq tcp4 ,
3059+IPv4 traffic will be routed to the server.
3060+IPv6 traffic will not be accepted.
3061+.It
3062+If you have two servers on
3063+.Dq tcp4
3064+and
3065+.Dq tcp6 ,
3066+IPv4 traffic will be routed to the server on
3067+.Dq tcp4 ,
3068+and IPv6 traffic will go to server on
3069+.Dq tcp6 .
3070+.It
3071+If you have only one server on
3072+.Dq tcp6 ,
3073+only IPv6 traffic will be routed to the server.
3074+.El
3075+.Sh SEE ALSO
3076+.Xr fingerd 8 ,
3077+.Xr ftpd 8 ,
3078+.Xr identd 8 ,
3079+.Xr rshd 8 ,
3080+.Xr talkd 8 ,
3081+.Xr tftpd 8
3082+.Sh HISTORY
3083+The
3084+.Nm
3085+command appeared in
3086+.Bx 4.3 .
3087+Support for Sun-RPC
3088+based services is modelled after that
3089+provided by SunOS 4.1.
3090+IPv6 support was added by the KAME project in 1999.
3091+.Pp
3092+Marco d'Itri ported this code from OpenBSD in summer 2002 and added
3093+socket buffers tuning and libwrap support from the NetBSD source tree.
3094+.Sh BUGS
3095+On Linux systems, the daemon cannot reload its configuration and needs
3096+to be restarted when the host address for a service is changed between
3097+.Dq \&*
3098+and a specific address.
3099+.Pp
3100+Server programs used with
3101+.Dq dgram
3102+.Dq udp
3103+.Dq nowait
3104+must read from the network socket, or
3105+.Nm inetd
3106+will spawn processes until the maximum is reached.
3107+.Pp
3108+Host address specifiers, while they make conceptual sense for RPC
3109+services, do not work entirely correctly.
3110+This is largely because the
3111+portmapper interface does not provide a way to register different ports
3112+for the same service on different local addresses.
3113+Provided you never
3114+have more than one entry for a given RPC service, everything should
3115+work correctly.
3116+(Note that default host address specifiers do apply to
3117+RPC lines with no explicit specifier.)
3118
3119=== added file '.pc/discard_env/inetd.c'
3120--- .pc/discard_env/inetd.c 1970-01-01 00:00:00 +0000
3121+++ .pc/discard_env/inetd.c 2011-06-29 11:29:23 +0000
3122@@ -0,0 +1,2059 @@
3123+/* $OpenBSD: inetd.c,v 1.131 2009/10/27 23:59:51 deraadt Exp $ */
3124+
3125+/*
3126+ * Copyright (c) 1983,1991 The Regents of the University of California.
3127+ * All rights reserved.
3128+ *
3129+ * Redistribution and use in source and binary forms, with or without
3130+ * modification, are permitted provided that the following conditions
3131+ * are met:
3132+ * 1. Redistributions of source code must retain the above copyright
3133+ * notice, this list of conditions and the following disclaimer.
3134+ * 2. Redistributions in binary form must reproduce the above copyright
3135+ * notice, this list of conditions and the following disclaimer in the
3136+ * documentation and/or other materials provided with the distribution.
3137+ * 3. Neither the name of the University nor the names of its contributors
3138+ * may be used to endorse or promote products derived from this software
3139+ * without specific prior written permission.
3140+ *
3141+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3142+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3143+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3144+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3145+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3146+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3147+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3148+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3149+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3150+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3151+ * SUCH DAMAGE.
3152+ */
3153+
3154+/*
3155+ * Inetd - Internet super-server
3156+ *
3157+ * This program invokes all internet services as needed.
3158+ * connection-oriented services are invoked each time a
3159+ * connection is made, by creating a process. This process
3160+ * is passed the connection as file descriptor 0 and is
3161+ * expected to do a getpeername to find out the source host
3162+ * and port.
3163+ *
3164+ * Datagram oriented services are invoked when a datagram
3165+ * arrives; a process is created and passed a pending message
3166+ * on file descriptor 0. Datagram servers may either connect
3167+ * to their peer, freeing up the original socket for inetd
3168+ * to receive further messages on, or ``take over the socket'',
3169+ * processing all arriving datagrams and, eventually, timing
3170+ * out. The first type of server is said to be ``multi-threaded'';
3171+ * the second type of server ``single-threaded''.
3172+ *
3173+ * Inetd uses a configuration file which is read at startup
3174+ * and, possibly, at some later time in response to a hangup signal.
3175+ * The configuration file is ``free format'' with fields given in the
3176+ * order shown below. Continuation lines for an entry must begin with
3177+ * a space or tab. All fields must be present in each entry.
3178+ *
3179+ * service name must be in /etc/services
3180+ * socket type stream/dgram/raw/rdm/seqpacket
3181+ * protocol must be in /etc/protocols
3182+ * wait/nowait[.max] single-threaded/multi-threaded, max #
3183+ * user[.group] or user[:group] user/group to run daemon as
3184+ * server program full path name
3185+ * server program arguments maximum of MAXARGS (20)
3186+ *
3187+ * For RPC services
3188+ * service name/version must be in /etc/rpc
3189+ * socket type stream/dgram/raw/rdm/seqpacket
3190+ * protocol must be in /etc/protocols
3191+ * wait/nowait[.max] single-threaded/multi-threaded
3192+ * user[.group] or user[:group] user to run daemon as
3193+ * server program full path name
3194+ * server program arguments maximum of MAXARGS (20)
3195+ *
3196+ * For non-RPC services, the "service name" can be of the form
3197+ * hostaddress:servicename, in which case the hostaddress is used
3198+ * as the host portion of the address to listen on. If hostaddress
3199+ * consists of a single `*' character, INADDR_ANY is used.
3200+ *
3201+ * A line can also consist of just
3202+ * hostaddress:
3203+ * where hostaddress is as in the preceding paragraph. Such a line must
3204+ * have no further fields; the specified hostaddress is remembered and
3205+ * used for all further lines that have no hostaddress specified,
3206+ * until the next such line (or EOF). (This is why * is provided to
3207+ * allow explicit specification of INADDR_ANY.) A line
3208+ * *:
3209+ * is implicitly in effect at the beginning of the file.
3210+ *
3211+ * The hostaddress specifier may (and often will) contain dots;
3212+ * the service name must not.
3213+ *
3214+ * For RPC services, host-address specifiers are accepted and will
3215+ * work to some extent; however, because of limitations in the
3216+ * portmapper interface, it will not work to try to give more than
3217+ * one line for any given RPC service, even if the host-address
3218+ * specifiers are different.
3219+ *
3220+ * Comment lines are indicated by a `#' in column 1.
3221+ */
3222+
3223+/*
3224+ * Here's the scoop concerning the user[.:]group feature:
3225+ *
3226+ * 1) set-group-option off.
3227+ *
3228+ * a) user = root: NO setuid() or setgid() is done
3229+ *
3230+ * b) other: setgid(primary group as found in passwd)
3231+ * initgroups(name, primary group)
3232+ * setuid()
3233+ *
3234+ * 2) set-group-option on.
3235+ *
3236+ * a) user = root: setgid(specified group)
3237+ * NO initgroups()
3238+ * NO setuid()
3239+ *
3240+ * b) other: setgid(specified group)
3241+ * initgroups(name, specified group)
3242+ * setuid()
3243+ *
3244+ */
3245+
3246+#include <sys/param.h>
3247+#include <sys/stat.h>
3248+#include <sys/ioctl.h>
3249+#include <sys/socket.h>
3250+#include <sys/un.h>
3251+#include <sys/file.h>
3252+#include <sys/wait.h>
3253+#include <time.h>
3254+#include <sys/time.h>
3255+#include <sys/resource.h>
3256+
3257+#include <net/if.h>
3258+#include <netinet/in.h>
3259+#include <arpa/inet.h>
3260+
3261+#include <errno.h>
3262+#include <ctype.h>
3263+#include <signal.h>
3264+#include <netdb.h>
3265+#include <syslog.h>
3266+#include <pwd.h>
3267+#include <grp.h>
3268+#include <stdio.h>
3269+#include <stdlib.h>
3270+#include <unistd.h>
3271+#include <string.h>
3272+#ifdef HAVE_SETUSERCONTEXT
3273+#include <login_cap.h>
3274+#endif
3275+#ifdef HAVE_GETIFADDRS
3276+#include <ifaddrs.h>
3277+#endif
3278+#include <rpc/rpc.h>
3279+#include <rpc/pmap_clnt.h>
3280+#include "pathnames.h"
3281+#include "setproctitle.h"
3282+
3283+size_t strlcpy(char *, const char *, size_t);
3284+
3285+#define TOOMANY 256 /* don't start more than TOOMANY */
3286+#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
3287+#define RETRYTIME (60*10) /* retry after bind or server fail */
3288+
3289+int debug = 0;
3290+int nsock, maxsock;
3291+fd_set *allsockp;
3292+int allsockn;
3293+int toomany = TOOMANY;
3294+int options;
3295+int timingout;
3296+struct servent *sp;
3297+uid_t uid;
3298+sigset_t blockmask;
3299+sigset_t emptymask;
3300+
3301+#ifndef OPEN_MAX
3302+#define OPEN_MAX 64
3303+#endif
3304+
3305+/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
3306+#define FD_MARGIN (8)
3307+rlim_t rlim_nofile_cur = OPEN_MAX;
3308+
3309+struct rlimit rlim_nofile;
3310+
3311+struct servtab {
3312+ char *se_hostaddr; /* host address to listen on */
3313+ char *se_service; /* name of service */
3314+ int se_socktype; /* type of socket to use */
3315+ int se_family; /* address family */
3316+ char *se_proto; /* protocol used */
3317+ int se_rpcprog; /* rpc program number */
3318+ int se_rpcversl; /* rpc program lowest version */
3319+ int se_rpcversh; /* rpc program highest version */
3320+#define isrpcservice(sep) ((sep)->se_rpcversl != 0)
3321+ pid_t se_wait; /* single threaded server */
3322+ short se_checked; /* looked at during merge */
3323+ char *se_user; /* user name to run as */
3324+ char *se_group; /* group name to run as */
3325+ struct biltin *se_bi; /* if built-in, description */
3326+ char *se_server; /* server program */
3327+#define MAXARGV 20
3328+ char *se_argv[MAXARGV+1]; /* program arguments */
3329+ int se_fd; /* open descriptor */
3330+ union {
3331+ struct sockaddr se_un_ctrladdr;
3332+ struct sockaddr_in se_un_ctrladdr_in;
3333+ struct sockaddr_in6 se_un_ctrladdr_in6;
3334+ struct sockaddr_un se_un_ctrladdr_un;
3335+ struct sockaddr_storage se_un_ctrladdr_storage;
3336+ } se_un; /* bound address */
3337+#define se_ctrladdr se_un.se_un_ctrladdr
3338+#define se_ctrladdr_in se_un.se_un_ctrladdr_in
3339+#define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
3340+#define se_ctrladdr_un se_un.se_un_ctrladdr_un
3341+#define se_ctrladdr_storage se_un.se_un_ctrladdr_storage
3342+ int se_ctrladdr_size;
3343+ int se_max; /* max # of instances of this service */
3344+ int se_count; /* number started since se_time */
3345+ struct timeval se_time; /* start of se_count */
3346+ struct servtab *se_next;
3347+} *servtab;
3348+
3349+void echo_stream(int, struct servtab *);
3350+void discard_stream(int, struct servtab *);
3351+void machtime_stream(int, struct servtab *);
3352+void daytime_stream(int, struct servtab *);
3353+void chargen_stream(int, struct servtab *);
3354+void echo_dg(int, struct servtab *);
3355+void discard_dg(int, struct servtab *);
3356+void machtime_dg(int, struct servtab *);
3357+void daytime_dg(int, struct servtab *);
3358+void chargen_dg(int, struct servtab *);
3359+
3360+struct biltin {
3361+ char *bi_service; /* internally provided service name */
3362+ int bi_socktype; /* type of socket supported */
3363+ short bi_fork; /* 1 if should fork before call */
3364+ short bi_wait; /* 1 if should wait for child */
3365+ void (*bi_fn)(int, struct servtab *);
3366+} biltins[] = {
3367+ /* Echo received data */
3368+ { "echo", SOCK_STREAM, 1, 0, echo_stream },
3369+ { "echo", SOCK_DGRAM, 0, 0, echo_dg },
3370+
3371+ /* Internet /dev/null */
3372+ { "discard", SOCK_STREAM, 1, 0, discard_stream },
3373+ { "discard", SOCK_DGRAM, 0, 0, discard_dg },
3374+
3375+ /* Return 32 bit time since 1900 */
3376+ { "time", SOCK_STREAM, 0, 0, machtime_stream },
3377+ { "time", SOCK_DGRAM, 0, 0, machtime_dg },
3378+
3379+ /* Return human-readable time */
3380+ { "daytime", SOCK_STREAM, 0, 0, daytime_stream },
3381+ { "daytime", SOCK_DGRAM, 0, 0, daytime_dg },
3382+
3383+ /* Familiar character generator */
3384+ { "chargen", SOCK_STREAM, 1, 0, chargen_stream },
3385+ { "chargen", SOCK_DGRAM, 0, 0, chargen_dg },
3386+
3387+ { 0 }
3388+};
3389+
3390+volatile sig_atomic_t wantretry;
3391+volatile sig_atomic_t wantconfig;
3392+volatile sig_atomic_t wantreap;
3393+volatile sig_atomic_t wantdie;
3394+
3395+void config(int);
3396+void doconfig(void);
3397+void reap(int);
3398+void doreap(void);
3399+void retry(int);
3400+void doretry(void);
3401+void die(int);
3402+void dodie(void);
3403+void logpid(void);
3404+void spawn(struct servtab *, int);
3405+int gettcp(struct servtab *);
3406+int setconfig(void);
3407+void endconfig(void);
3408+void register_rpc(struct servtab *);
3409+void unregister_rpc(struct servtab *);
3410+void freeconfig(struct servtab *);
3411+void print_service(char *, struct servtab *);
3412+void setup(struct servtab *);
3413+struct servtab *getconfigent(void);
3414+int bump_nofile(void);
3415+struct servtab *enter(struct servtab *);
3416+int matchconf(struct servtab *, struct servtab *);
3417+int dg_broadcast(struct in_addr *in);
3418+
3419+#define NUMINT (sizeof(intab) / sizeof(struct inent))
3420+char *CONFIG = _PATH_INETDCONF;
3421+
3422+void
3423+fd_grow(fd_set **fdsp, int *bytes, int fd)
3424+{
3425+ caddr_t new;
3426+ int newbytes;
3427+
3428+ newbytes = howmany(fd+1, NFDBITS) * sizeof(fd_mask);
3429+ if (newbytes > *bytes) {
3430+ newbytes *= 2; /* optimism */
3431+ new = realloc(*fdsp, newbytes);
3432+ if (new == NULL) {
3433+ syslog(LOG_ERR, "Out of memory.");
3434+ exit(1);
3435+ }
3436+ memset(new + *bytes, 0, newbytes - *bytes);
3437+ *fdsp = (fd_set *)new;
3438+ *bytes = newbytes;
3439+ }
3440+}
3441+
3442+struct sigaction sa, sapipe;
3443+
3444+int
3445+main(int argc, char *argv[], char *envp[])
3446+{
3447+ fd_set *fdsrp = NULL;
3448+ int readablen = 0, ch;
3449+ struct servtab *sep;
3450+ extern char *optarg;
3451+ extern int optind;
3452+
3453+ initsetproctitle(argc, argv, envp);
3454+
3455+ while ((ch = getopt(argc, argv, "dR:")) != -1)
3456+ switch (ch) {
3457+ case 'd':
3458+ debug = 1;
3459+ break;
3460+ case 'R': { /* invocation rate */
3461+ char *p;
3462+ int val;
3463+
3464+ val = strtoul(optarg, &p, 0);
3465+ if (val >= 1 && *p == '\0') {
3466+ toomany = val;
3467+ break;
3468+ }
3469+ syslog(LOG_ERR,
3470+ "-R %s: bad value for service invocation rate",
3471+ optarg);
3472+ break;
3473+ }
3474+ case '?':
3475+ default:
3476+ fprintf(stderr,
3477+ "usage: inetd [-d] [-R rate] [configuration_file]\n");
3478+ exit(1);
3479+ }
3480+ argc -= optind;
3481+ argv += optind;
3482+
3483+ uid = getuid();
3484+ if (uid != 0)
3485+ CONFIG = NULL;
3486+ if (argc > 0)
3487+ CONFIG = argv[0];
3488+ if (CONFIG == NULL) {
3489+ fprintf(stderr, "inetd: non-root must specify a config file\n");
3490+ exit(1);
3491+ }
3492+ if (argc > 1) {
3493+ fprintf(stderr, "inetd: more than one argument specified\n");
3494+ exit(1);
3495+ }
3496+
3497+ umask(022);
3498+ if (debug == 0) {
3499+ daemon(0, 0);
3500+#ifdef HAVE_SETLOGIN
3501+ if (uid == 0)
3502+ (void) setlogin("");
3503+#endif
3504+ }
3505+ if (debug && uid == 0)
3506+ options |= SO_DEBUG;
3507+
3508+ if (uid == 0) {
3509+ gid_t gid = getgid();
3510+
3511+ /* If run by hand, ensure groups vector gets trashed */
3512+ setgroups(1, &gid);
3513+ }
3514+
3515+ openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
3516+ logpid();
3517+
3518+ if (getrlimit(RLIMIT_NOFILE, &rlim_nofile) < 0) {
3519+ syslog(LOG_ERR, "getrlimit: %m");
3520+ } else {
3521+ rlim_nofile_cur = rlim_nofile.rlim_cur;
3522+ if (rlim_nofile_cur == RLIM_INFINITY) /* ! */
3523+ rlim_nofile_cur = OPEN_MAX;
3524+ }
3525+
3526+ sigemptyset(&emptymask);
3527+ sigemptyset(&blockmask);
3528+ sigaddset(&blockmask, SIGCHLD);
3529+ sigaddset(&blockmask, SIGHUP);
3530+ sigaddset(&blockmask, SIGALRM);
3531+
3532+ memset(&sa, 0, sizeof(sa));
3533+ sigemptyset(&sa.sa_mask);
3534+ sigaddset(&sa.sa_mask, SIGALRM);
3535+ sigaddset(&sa.sa_mask, SIGCHLD);
3536+ sigaddset(&sa.sa_mask, SIGHUP);
3537+ sa.sa_handler = retry;
3538+ sigaction(SIGALRM, &sa, NULL);
3539+ doconfig();
3540+ sa.sa_handler = config;
3541+ sigaction(SIGHUP, &sa, NULL);
3542+ sa.sa_handler = reap;
3543+ sigaction(SIGCHLD, &sa, NULL);
3544+ sa.sa_handler = die;
3545+ sigaction(SIGTERM, &sa, NULL);
3546+ sa.sa_handler = die;
3547+ sigaction(SIGINT, &sa, NULL);
3548+ sa.sa_handler = SIG_IGN;
3549+ sigaction(SIGPIPE, &sa, &sapipe);
3550+
3551+ /* space for daemons to overwrite environment for ps */
3552+ {
3553+#define DUMMYSIZE 100
3554+ char dummy[DUMMYSIZE];
3555+ memset(dummy, 'x', DUMMYSIZE - 1);
3556+ dummy[DUMMYSIZE - 1] = '\0';
3557+ setenv("inetd_dummy", dummy, 1);
3558+ }
3559+
3560+ for (;;) {
3561+ int n, ctrl = -1;
3562+
3563+ restart:
3564+ if (nsock == 0) {
3565+ (void) sigprocmask(SIG_BLOCK, &blockmask, NULL);
3566+ while (nsock == 0) {
3567+ if (wantretry || wantconfig || wantreap || wantdie)
3568+ break;
3569+ sigsuspend(&emptymask);
3570+ }
3571+ (void) sigprocmask(SIG_SETMASK, &emptymask, NULL);
3572+ }
3573+
3574+ while (wantretry || wantconfig || wantreap || wantdie) {
3575+ if (wantretry) {
3576+ wantretry = 0;
3577+ doretry();
3578+ }
3579+ if (wantconfig) {
3580+ wantconfig = 0;
3581+ doconfig();
3582+ }
3583+ if (wantreap) {
3584+ wantreap = 0;
3585+ doreap();
3586+ }
3587+ if (wantdie)
3588+ dodie();
3589+ goto restart;
3590+ }
3591+
3592+ if (readablen != allsockn) {
3593+ if (fdsrp)
3594+ free(fdsrp);
3595+ fdsrp = (fd_set *)calloc(allsockn, 1);
3596+ if (fdsrp == NULL) {
3597+ syslog(LOG_ERR, "Out of memory.");
3598+ exit(1);
3599+ }
3600+ readablen = allsockn;
3601+ }
3602+ bcopy(allsockp, fdsrp, allsockn);
3603+
3604+ if ((n = select(maxsock + 1, fdsrp, NULL, NULL, NULL)) <= 0) {
3605+ if (n < 0 && errno != EINTR) {
3606+ syslog(LOG_WARNING, "select: %m");
3607+ sleep(1);
3608+ }
3609+ continue;
3610+ }
3611+
3612+ for (sep = servtab; n && sep; sep = sep->se_next) {
3613+ if (sep->se_fd != -1 &&
3614+ FD_ISSET(sep->se_fd, fdsrp)) {
3615+ n--;
3616+ if (debug)
3617+ fprintf(stderr, "someone wants %s\n",
3618+ sep->se_service);
3619+ if (!sep->se_wait &&
3620+ sep->se_socktype == SOCK_STREAM) {
3621+ ctrl = gettcp(sep);
3622+ if (ctrl == -1)
3623+ continue;
3624+ } else
3625+ ctrl = sep->se_fd;
3626+ (void) sigprocmask(SIG_BLOCK, &blockmask, NULL);
3627+ spawn(sep, ctrl); /* spawn will unblock */
3628+ }
3629+ }
3630+ }
3631+}
3632+
3633+int
3634+gettcp(struct servtab *sep)
3635+{
3636+ int ctrl;
3637+
3638+ ctrl = accept(sep->se_fd, NULL, NULL);
3639+ if (debug)
3640+ fprintf(stderr, "accept, ctrl %d\n", ctrl);
3641+ if (ctrl < 0) {
3642+ if (errno == EINTR)
3643+ return -1;
3644+ syslog(LOG_WARNING, "accept (for %s): %m", sep->se_service);
3645+ return -1;
3646+ }
3647+ if ((sep->se_family == AF_INET || sep->se_family == AF_INET6) &&
3648+ sep->se_socktype == SOCK_STREAM) {
3649+ struct sockaddr_storage peer;
3650+ socklen_t plen = sizeof(peer);
3651+ char sbuf[NI_MAXSERV];
3652+
3653+ if (getpeername(ctrl, (struct sockaddr *)&peer, &plen) < 0) {
3654+ syslog(LOG_WARNING, "could not getpeername");
3655+ close(ctrl);
3656+ return -1;
3657+ }
3658+ if (getnameinfo((struct sockaddr *)&peer, plen, NULL, 0,
3659+ sbuf, sizeof(sbuf), NI_NUMERICSERV) == 0 &&
3660+ atoi(sbuf) == 20) {
3661+ /*
3662+ * ignore things that look like ftp bounce
3663+ */
3664+ close(ctrl);
3665+ return -1;
3666+ }
3667+ }
3668+ return (ctrl);
3669+}
3670+
3671+
3672+int
3673+dg_badinput(struct sockaddr *sa)
3674+{
3675+ struct in_addr in;
3676+ struct in6_addr *in6;
3677+ u_int16_t port;
3678+
3679+ switch (sa->sa_family) {
3680+ case AF_INET:
3681+ in.s_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
3682+ port = ntohs(((struct sockaddr_in *)sa)->sin_port);
3683+ v4chk:
3684+ if (IN_MULTICAST(in.s_addr))
3685+ goto bad;
3686+ switch ((in.s_addr & 0xff000000) >> 24) {
3687+ case 0: case 127: case 255:
3688+ goto bad;
3689+ }
3690+ if (dg_broadcast(&in))
3691+ goto bad;
3692+ break;
3693+ case AF_INET6:
3694+ in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
3695+ port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
3696+ if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
3697+ goto bad;
3698+ /*
3699+ * OpenBSD does not support IPv4 mapped address (RFC2553
3700+ * inbound behavior) at all. We should drop it.
3701+ */
3702+ if (IN6_IS_ADDR_V4MAPPED(in6))
3703+ goto bad;
3704+ if (IN6_IS_ADDR_V4COMPAT(in6)) {
3705+ memcpy(&in, &in6->s6_addr[12], sizeof(in));
3706+ in.s_addr = ntohl(in.s_addr);
3707+ goto v4chk;
3708+ }
3709+ break;
3710+ default:
3711+ /* XXX unsupported af, is it safe to assume it to be safe? */
3712+ return 0;
3713+ }
3714+
3715+ return (0);
3716+
3717+bad:
3718+ return (1);
3719+}
3720+
3721+int
3722+dg_broadcast(struct in_addr *in)
3723+{
3724+#ifdef HAVE_GETIFADDRS
3725+ struct ifaddrs *ifa, *ifap;
3726+ struct sockaddr_in *sin;
3727+
3728+ if (getifaddrs(&ifap) < 0)
3729+ return (0);
3730+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
3731+ if (ifa->ifa_addr->sa_family != AF_INET ||
3732+ (ifa->ifa_flags & IFF_BROADCAST) == 0)
3733+ continue;
3734+ sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
3735+ if (sin->sin_addr.s_addr == in->s_addr) {
3736+ freeifaddrs(ifap);
3737+ return (1);
3738+ }
3739+ }
3740+ freeifaddrs(ifap);
3741+#endif
3742+ return (0);
3743+}
3744+
3745+/* ARGSUSED */
3746+void
3747+reap(int sig)
3748+{
3749+ wantreap = 1;
3750+}
3751+
3752+void
3753+doreap(void)
3754+{
3755+ struct servtab *sep;
3756+ int status;
3757+ pid_t pid;
3758+
3759+ if (debug)
3760+ fprintf(stderr, "reaping asked for\n");
3761+
3762+ for (;;) {
3763+ if ((pid = wait3(&status, WNOHANG, NULL)) <= 0) {
3764+ if (pid == -1 && errno == EINTR)
3765+ continue;
3766+ break;
3767+ }
3768+ if (debug)
3769+ fprintf(stderr, "%ld reaped, status %x\n",
3770+ (long)pid, status);
3771+ for (sep = servtab; sep; sep = sep->se_next)
3772+ if (sep->se_wait == pid) {
3773+ if (WIFEXITED(status) && WEXITSTATUS(status))
3774+ syslog(LOG_WARNING,
3775+ "%s: exit status %d",
3776+ sep->se_server, WEXITSTATUS(status));
3777+ else if (WIFSIGNALED(status))
3778+ syslog(LOG_WARNING,
3779+ "%s: exit signal %d",
3780+ sep->se_server, WTERMSIG(status));
3781+ sep->se_wait = 1;
3782+ fd_grow(&allsockp, &allsockn, sep->se_fd);
3783+ FD_SET(sep->se_fd, allsockp);
3784+ nsock++;
3785+ if (debug)
3786+ fprintf(stderr, "restored %s, fd %d\n",
3787+ sep->se_service, sep->se_fd);
3788+ }
3789+ }
3790+}
3791+
3792+/* ARGSUSED */
3793+void
3794+config(int sig)
3795+{
3796+ wantconfig = 1;
3797+}
3798+
3799+void
3800+doconfig(void)
3801+{
3802+ struct servtab *sep, *cp, **sepp;
3803+ int add;
3804+ char protoname[10];
3805+ sigset_t omask;
3806+
3807+ if (!setconfig()) {
3808+ syslog(LOG_ERR, "%s: %m", CONFIG);
3809+ exit(1);
3810+ }
3811+ for (sep = servtab; sep; sep = sep->se_next)
3812+ sep->se_checked = 0;
3813+ cp = getconfigent();
3814+ while (cp != NULL) {
3815+ for (sep = servtab; sep; sep = sep->se_next)
3816+ if (matchconf(sep, cp))
3817+ break;
3818+ add = 0;
3819+ if (sep != NULL) {
3820+ int i;
3821+
3822+#define SWAP(type, a, b) {type c=(type)a; a=(type)b; b=(type)c;}
3823+
3824+ sigprocmask(SIG_BLOCK, &blockmask, &omask);
3825+ /*
3826+ * sep->se_wait may be holding the pid of a daemon
3827+ * that we're waiting for. If so, don't overwrite
3828+ * it unless the config file explicitly says don't
3829+ * wait.
3830+ */
3831+ if (cp->se_bi == 0 &&
3832+ (sep->se_wait == 1 || cp->se_wait == 0))
3833+ sep->se_wait = cp->se_wait;
3834+ SWAP(int, cp->se_max, sep->se_max);
3835+ SWAP(char *, sep->se_user, cp->se_user);
3836+ SWAP(char *, sep->se_group, cp->se_group);
3837+ SWAP(char *, sep->se_server, cp->se_server);
3838+ for (i = 0; i < MAXARGV; i++)
3839+ SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
3840+#undef SWAP
3841+ if (isrpcservice(sep))
3842+ unregister_rpc(sep);
3843+ sep->se_rpcversl = cp->se_rpcversl;
3844+ sep->se_rpcversh = cp->se_rpcversh;
3845+ sigprocmask(SIG_SETMASK, &omask, NULL);
3846+ freeconfig(cp);
3847+ add = 1;
3848+ } else {
3849+ sep = enter(cp);
3850+ }
3851+ sep->se_checked = 1;
3852+
3853+ switch (sep->se_family) {
3854+ case AF_UNIX:
3855+ if (sep->se_fd != -1)
3856+ break;
3857+ sep->se_ctrladdr_size =
3858+ strlcpy(sep->se_ctrladdr_un.sun_path,
3859+ sep->se_service,
3860+ sizeof sep->se_ctrladdr_un.sun_path);
3861+ if (sep->se_ctrladdr_size >=
3862+ sizeof sep->se_ctrladdr_un.sun_path) {
3863+ syslog(LOG_WARNING, "%s/%s: UNIX domain socket "
3864+ "path too long", sep->se_service,
3865+ sep->se_proto);
3866+ goto serv_unknown;
3867+ }
3868+ sep->se_ctrladdr_un.sun_family = AF_UNIX;
3869+ sep->se_ctrladdr_size +=
3870+ 1 + sizeof sep->se_ctrladdr_un.sun_family;
3871+ (void)unlink(sep->se_service);
3872+ setup(sep);
3873+ break;
3874+ case AF_INET:
3875+ sep->se_ctrladdr_in.sin_family = AF_INET;
3876+ /* se_ctrladdr_in was set in getconfigent */
3877+ sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
3878+
3879+ if (isrpcservice(sep)) {
3880+ struct rpcent *rp;
3881+
3882+ sep->se_rpcprog = atoi(sep->se_service);
3883+ if (sep->se_rpcprog == 0) {
3884+ rp = getrpcbyname(sep->se_service);
3885+ if (rp == 0) {
3886+ syslog(LOG_ERR,
3887+ "%s: unknown rpc service",
3888+ sep->se_service);
3889+ goto serv_unknown;
3890+ }
3891+ sep->se_rpcprog = rp->r_number;
3892+ }
3893+ if (sep->se_fd == -1)
3894+ setup(sep);
3895+ if (sep->se_fd != -1)
3896+ register_rpc(sep);
3897+ } else {
3898+ u_short port = htons(atoi(sep->se_service));
3899+
3900+ if (!port) {
3901+ /* XXX */
3902+ strncpy(protoname, sep->se_proto,
3903+ sizeof(protoname));
3904+ if (isdigit(protoname[strlen(protoname) - 1]))
3905+ protoname[strlen(protoname) - 1] = '\0';
3906+ sp = getservbyname(sep->se_service,
3907+ protoname);
3908+ if (sp == 0) {
3909+ syslog(LOG_ERR,
3910+ "%s/%s: unknown service",
3911+ sep->se_service, sep->se_proto);
3912+ goto serv_unknown;
3913+ }
3914+ port = sp->s_port;
3915+ }
3916+ if (port != sep->se_ctrladdr_in.sin_port) {
3917+ sep->se_ctrladdr_in.sin_port = port;
3918+ if (sep->se_fd != -1) {
3919+ FD_CLR(sep->se_fd, allsockp);
3920+ nsock--;
3921+ (void) close(sep->se_fd);
3922+ }
3923+ sep->se_fd = -1;
3924+ }
3925+ if (sep->se_fd == -1)
3926+ setup(sep);
3927+ }
3928+ break;
3929+ case AF_INET6:
3930+ sep->se_ctrladdr_in6.sin6_family = AF_INET6;
3931+ /* se_ctrladdr_in was set in getconfigent */
3932+ sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
3933+
3934+ if (isrpcservice(sep)) {
3935+ struct rpcent *rp;
3936+
3937+ sep->se_rpcprog = atoi(sep->se_service);
3938+ if (sep->se_rpcprog == 0) {
3939+ rp = getrpcbyname(sep->se_service);
3940+ if (rp == 0) {
3941+ syslog(LOG_ERR,
3942+ "%s: unknown rpc service",
3943+ sep->se_service);
3944+ goto serv_unknown;
3945+ }
3946+ sep->se_rpcprog = rp->r_number;
3947+ }
3948+ if (sep->se_fd == -1)
3949+ setup(sep);
3950+ if (sep->se_fd != -1)
3951+ register_rpc(sep);
3952+ } else {
3953+ u_short port = htons(atoi(sep->se_service));
3954+
3955+ if (!port) {
3956+ /* XXX */
3957+ strncpy(protoname, sep->se_proto,
3958+ sizeof(protoname));
3959+ if (isdigit(protoname[strlen(protoname) - 1]))
3960+ protoname[strlen(protoname) - 1] = '\0';
3961+ sp = getservbyname(sep->se_service,
3962+ protoname);
3963+ if (sp == 0) {
3964+ syslog(LOG_ERR,
3965+ "%s/%s: unknown service",
3966+ sep->se_service, sep->se_proto);
3967+ goto serv_unknown;
3968+ }
3969+ port = sp->s_port;
3970+ }
3971+ if (port != sep->se_ctrladdr_in6.sin6_port) {
3972+ sep->se_ctrladdr_in6.sin6_port = port;
3973+ if (sep->se_fd != -1) {
3974+ FD_CLR(sep->se_fd, allsockp);
3975+ nsock--;
3976+ (void) close(sep->se_fd);
3977+ }
3978+ sep->se_fd = -1;
3979+ }
3980+ if (sep->se_fd == -1)
3981+ setup(sep);
3982+ }
3983+ break;
3984+ }
3985+ serv_unknown:
3986+ if (cp->se_next != NULL) {
3987+ struct servtab *tmp = cp;
3988+
3989+ cp = cp->se_next;
3990+ free(tmp);
3991+ } else {
3992+ free(cp);
3993+ cp = getconfigent();
3994+ }
3995+ if (debug)
3996+ print_service(add ? "REDO" : "ADD", sep);
3997+ }
3998+ endconfig();
3999+ /*
4000+ * Purge anything not looked at above.
4001+ */
4002+ sigprocmask(SIG_BLOCK, &blockmask, &omask);
4003+ sepp = &servtab;
4004+ while ((sep = *sepp)) {
4005+ if (sep->se_checked) {
4006+ sepp = &sep->se_next;
4007+ continue;
4008+ }
4009+ *sepp = sep->se_next;
4010+ if (sep->se_fd != -1) {
4011+ FD_CLR(sep->se_fd, allsockp);
4012+ nsock--;
4013+ (void) close(sep->se_fd);
4014+ }
4015+ if (isrpcservice(sep))
4016+ unregister_rpc(sep);
4017+ if (sep->se_family == AF_UNIX)
4018+ (void)unlink(sep->se_service);
4019+ if (debug)
4020+ print_service("FREE", sep);
4021+ freeconfig(sep);
4022+ free(sep);
4023+ }
4024+ sigprocmask(SIG_SETMASK, &omask, NULL);
4025+}
4026+
4027+/* ARGSUSED */
4028+void
4029+retry(int sig)
4030+{
4031+ wantretry = 1;
4032+}
4033+
4034+void
4035+doretry(void)
4036+{
4037+ struct servtab *sep;
4038+
4039+ timingout = 0;
4040+ for (sep = servtab; sep; sep = sep->se_next) {
4041+ if (sep->se_fd == -1) {
4042+ switch (sep->se_family) {
4043+ case AF_UNIX:
4044+ case AF_INET:
4045+ case AF_INET6:
4046+ setup(sep);
4047+ if (sep->se_fd != -1 && isrpcservice(sep))
4048+ register_rpc(sep);
4049+ break;
4050+ }
4051+ }
4052+ }
4053+}
4054+
4055+/* ARGSUSED */
4056+void
4057+die(int sig)
4058+{
4059+ wantdie = 1;
4060+}
4061+
4062+void
4063+dodie(void)
4064+{
4065+ struct servtab *sep;
4066+
4067+ for (sep = servtab; sep; sep = sep->se_next) {
4068+ if (sep->se_fd == -1)
4069+ continue;
4070+
4071+ switch (sep->se_family) {
4072+ case AF_UNIX:
4073+ (void)unlink(sep->se_service);
4074+ break;
4075+ case AF_INET:
4076+ case AF_INET6:
4077+ if (sep->se_wait == 1 && isrpcservice(sep))
4078+ unregister_rpc(sep);
4079+ break;
4080+ }
4081+ (void)close(sep->se_fd);
4082+ }
4083+ (void)unlink(_PATH_INETDPID);
4084+ exit(0);
4085+}
4086+
4087+void
4088+setup(struct servtab *sep)
4089+{
4090+ int on = 1;
4091+ int r;
4092+ mode_t mask = 0;
4093+
4094+ if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
4095+ syslog(LOG_ERR, "%s/%s: socket: %m",
4096+ sep->se_service, sep->se_proto);
4097+ return;
4098+ }
4099+#define turnon(fd, opt) \
4100+setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on))
4101+ if (strncmp(sep->se_proto, "tcp", 3) == 0 && (options & SO_DEBUG) &&
4102+ turnon(sep->se_fd, SO_DEBUG) < 0)
4103+ syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
4104+ if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
4105+ syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
4106+#undef turnon
4107+ if (isrpcservice(sep)) {
4108+ struct passwd *pwd;
4109+
4110+ /*
4111+ * for RPC services, attempt to use a reserved port
4112+ * if they are going to be running as root.
4113+ *
4114+ * Also, zero out the port for all RPC services; let bind()
4115+ * find one.
4116+ */
4117+ sep->se_ctrladdr_in.sin_port = 0;
4118+ if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
4119+ pwd->pw_uid == 0 && uid == 0)
4120+ r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
4121+ else {
4122+ r = bind(sep->se_fd, &sep->se_ctrladdr,
4123+ sep->se_ctrladdr_size);
4124+ if (r == 0) {
4125+ socklen_t len = sep->se_ctrladdr_size;
4126+ int saveerrno = errno;
4127+
4128+ /* update se_ctrladdr_in.sin_port */
4129+ r = getsockname(sep->se_fd, &sep->se_ctrladdr,
4130+ &len);
4131+ if (r <= 0)
4132+ errno = saveerrno;
4133+ }
4134+ }
4135+ } else {
4136+ if (sep->se_family == AF_UNIX)
4137+ mask = umask(0111);
4138+ r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
4139+ if (sep->se_family == AF_UNIX)
4140+ umask(mask);
4141+ }
4142+ if (r < 0) {
4143+ syslog(LOG_ERR, "%s/%s: bind: %m",
4144+ sep->se_service, sep->se_proto);
4145+ (void) close(sep->se_fd);
4146+ sep->se_fd = -1;
4147+ if (!timingout) {
4148+ timingout = 1;
4149+ alarm(RETRYTIME);
4150+ }
4151+ return;
4152+ }
4153+ if (sep->se_socktype == SOCK_STREAM)
4154+ listen(sep->se_fd, 10);
4155+
4156+ fd_grow(&allsockp, &allsockn, sep->se_fd);
4157+ FD_SET(sep->se_fd, allsockp);
4158+ nsock++;
4159+ if (sep->se_fd > maxsock) {
4160+ maxsock = sep->se_fd;
4161+ if (maxsock > rlim_nofile_cur - FD_MARGIN)
4162+ bump_nofile();
4163+ }
4164+}
4165+
4166+void
4167+register_rpc(struct servtab *sep)
4168+{
4169+ socklen_t n;
4170+ struct sockaddr_in sin;
4171+ struct protoent *pp;
4172+
4173+ if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
4174+ syslog(LOG_ERR, "%s: getproto: %m",
4175+ sep->se_proto);
4176+ return;
4177+ }
4178+ n = sizeof sin;
4179+ if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
4180+ syslog(LOG_ERR, "%s/%s: getsockname: %m",
4181+ sep->se_service, sep->se_proto);
4182+ return;
4183+ }
4184+
4185+ for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
4186+ if (debug)
4187+ fprintf(stderr, "pmap_set: %u %u %u %u\n",
4188+ sep->se_rpcprog, n, pp->p_proto,
4189+ ntohs(sin.sin_port));
4190+ (void)pmap_unset(sep->se_rpcprog, n);
4191+ if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
4192+ syslog(LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
4193+ sep->se_service, sep->se_proto,
4194+ sep->se_rpcprog, n, pp->p_proto,
4195+ ntohs(sin.sin_port));
4196+ }
4197+}
4198+
4199+void
4200+unregister_rpc(struct servtab *sep)
4201+{
4202+ int n;
4203+
4204+ for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
4205+ if (debug)
4206+ fprintf(stderr, "pmap_unset(%u, %u)\n",
4207+ sep->se_rpcprog, n);
4208+ if (!pmap_unset(sep->se_rpcprog, n))
4209+ syslog(LOG_ERR, "pmap_unset(%u, %u)",
4210+ sep->se_rpcprog, n);
4211+ }
4212+}
4213+
4214+
4215+struct servtab *
4216+enter(struct servtab *cp)
4217+{
4218+ struct servtab *sep;
4219+ sigset_t omask;
4220+
4221+ sep = (struct servtab *)malloc(sizeof (*sep));
4222+ if (sep == NULL) {
4223+ syslog(LOG_ERR, "Out of memory.");
4224+ exit(1);
4225+ }
4226+ *sep = *cp;
4227+ sep->se_fd = -1;
4228+ sep->se_rpcprog = -1;
4229+ sigprocmask(SIG_BLOCK, &blockmask, &omask);
4230+ sep->se_next = servtab;
4231+ servtab = sep;
4232+ sigprocmask(SIG_SETMASK, &omask, NULL);
4233+ return (sep);
4234+}
4235+
4236+int
4237+matchconf(struct servtab *old, struct servtab *new)
4238+{
4239+ if (strcmp(old->se_service, new->se_service) != 0)
4240+ return (0);
4241+
4242+ if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
4243+ return (0);
4244+
4245+ if (strcmp(old->se_proto, new->se_proto) != 0)
4246+ return (0);
4247+
4248+ /*
4249+ * If the new servtab is bound to a specific address, check that the
4250+ * old servtab is bound to the same entry. If the new service is not
4251+ * bound to a specific address then the check of se_hostaddr above
4252+ * is sufficient.
4253+ */
4254+
4255+ if (old->se_family == AF_INET && new->se_family == AF_INET &&
4256+ bcmp(&old->se_ctrladdr_in.sin_addr,
4257+ &new->se_ctrladdr_in.sin_addr,
4258+ sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
4259+ return (0);
4260+
4261+ if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
4262+ bcmp(&old->se_ctrladdr_in6.sin6_addr,
4263+ &new->se_ctrladdr_in6.sin6_addr,
4264+ sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
4265+ return (0);
4266+ if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
4267+ old->se_ctrladdr_in6.sin6_scope_id !=
4268+ new->se_ctrladdr_in6.sin6_scope_id)
4269+ return (0);
4270+
4271+ return (1);
4272+}
4273+
4274+FILE *fconfig = NULL;
4275+char line[1024];
4276+char *defhost;
4277+char *skip(char **, int);
4278+char *nextline(FILE *);
4279+char *newstr(char *);
4280+struct servtab *dupconfig(struct servtab *);
4281+
4282+int
4283+setconfig(void)
4284+{
4285+ if (defhost)
4286+ free(defhost);
4287+ defhost = newstr("*");
4288+ if (fconfig != NULL) {
4289+ fseek(fconfig, 0L, SEEK_SET);
4290+ return (1);
4291+ }
4292+ fconfig = fopen(CONFIG, "r");
4293+ return (fconfig != NULL);
4294+}
4295+
4296+void
4297+endconfig(void)
4298+{
4299+ if (fconfig) {
4300+ (void) fclose(fconfig);
4301+ fconfig = NULL;
4302+ }
4303+ if (defhost) {
4304+ free(defhost);
4305+ defhost = 0;
4306+ }
4307+}
4308+
4309+struct servtab *
4310+getconfigent(void)
4311+{
4312+ struct servtab *sep, *tsep;
4313+ char *arg, *cp, *hostdelim, *s;
4314+ int argc;
4315+
4316+ sep = (struct servtab *) malloc(sizeof(struct servtab));
4317+ if (sep == NULL) {
4318+ syslog(LOG_ERR, "malloc: %m");
4319+ exit(1);
4320+ }
4321+
4322+ memset(sep, 0, sizeof *sep);
4323+more:
4324+ freeconfig(sep);
4325+
4326+ while ((cp = nextline(fconfig)) && *cp == '#')
4327+ ;
4328+ if (cp == NULL) {
4329+ free(sep);
4330+ return (NULL);
4331+ }
4332+
4333+ memset(sep, 0, sizeof *sep);
4334+ arg = skip(&cp, 0);
4335+ if (arg == NULL) {
4336+ /* A blank line. */
4337+ goto more;
4338+ }
4339+
4340+ /* Check for a host name. */
4341+ hostdelim = strrchr(arg, ':');
4342+ if (hostdelim) {
4343+ *hostdelim = '\0';
4344+ if (arg[0] == '[' && hostdelim > arg && hostdelim[-1] == ']') {
4345+ hostdelim[-1] = '\0';
4346+ sep->se_hostaddr = newstr(arg + 1);
4347+ } else if (hostdelim == arg)
4348+ sep->se_hostaddr = newstr("*");
4349+ else
4350+ sep->se_hostaddr = newstr(arg);
4351+ arg = hostdelim + 1;
4352+ /*
4353+ * If the line is of the form `host:', then just change the
4354+ * default host for the following lines.
4355+ */
4356+ if (*arg == '\0') {
4357+ arg = skip(&cp, 0);
4358+ if (cp == NULL) {
4359+ free(defhost);
4360+ defhost = newstr(sep->se_hostaddr);
4361+ goto more;
4362+ }
4363+ }
4364+ } else
4365+ sep->se_hostaddr = newstr(defhost);
4366+
4367+ sep->se_service = newstr(arg);
4368+ if ((arg = skip(&cp, 1)) == NULL)
4369+ goto more;
4370+
4371+ if (strcmp(arg, "stream") == 0)
4372+ sep->se_socktype = SOCK_STREAM;
4373+ else if (strcmp(arg, "dgram") == 0)
4374+ sep->se_socktype = SOCK_DGRAM;
4375+ else if (strcmp(arg, "rdm") == 0)
4376+ sep->se_socktype = SOCK_RDM;
4377+ else if (strcmp(arg, "seqpacket") == 0)
4378+ sep->se_socktype = SOCK_SEQPACKET;
4379+ else if (strcmp(arg, "raw") == 0)
4380+ sep->se_socktype = SOCK_RAW;
4381+ else
4382+ sep->se_socktype = -1;
4383+
4384+ if ((arg = skip(&cp, 1)) == NULL)
4385+ goto more;
4386+
4387+ sep->se_proto = newstr(arg);
4388+
4389+ if (strcmp(sep->se_proto, "unix") == 0) {
4390+ sep->se_family = AF_UNIX;
4391+ } else {
4392+ int s;
4393+
4394+ sep->se_family = AF_INET;
4395+ if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
4396+ sep->se_family = AF_INET6;
4397+
4398+ /* check if the family is supported */
4399+ s = socket(sep->se_family, SOCK_DGRAM, 0);
4400+ if (s < 0) {
4401+ syslog(LOG_WARNING, "%s/%s: %s: the address family is "
4402+ "not supported by the kernel", sep->se_service,
4403+ sep->se_proto, sep->se_hostaddr);
4404+ goto more;
4405+ }
4406+ close(s);
4407+
4408+ if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
4409+ char *cp, *ccp;
4410+ long l;
4411+
4412+ cp = strchr(sep->se_service, '/');
4413+ if (cp == 0) {
4414+ syslog(LOG_ERR, "%s: no rpc version",
4415+ sep->se_service);
4416+ goto more;
4417+ }
4418+ *cp++ = '\0';
4419+ l = strtol(cp, &ccp, 0);
4420+ if (ccp == cp || l < 0 || l > INT_MAX) {
4421+ badafterall:
4422+ syslog(LOG_ERR, "%s/%s: bad rpc version",
4423+ sep->se_service, cp);
4424+ goto more;
4425+ }
4426+ sep->se_rpcversl = sep->se_rpcversh = l;
4427+ if (*ccp == '-') {
4428+ cp = ccp + 1;
4429+ l = strtol(cp, &ccp, 0);
4430+ if (ccp == cp || l < 0 || l > INT_MAX ||
4431+ l < sep->se_rpcversl || *ccp)
4432+ goto badafterall;
4433+ sep->se_rpcversh = l;
4434+ } else if (*ccp != '\0')
4435+ goto badafterall;
4436+ }
4437+ }
4438+ arg = skip(&cp, 1);
4439+ if (arg == NULL)
4440+ goto more;
4441+
4442+ s = strchr(arg, '.');
4443+ if (s) {
4444+ char *p;
4445+
4446+ *s++ = '\0';
4447+ sep->se_max = strtoul(s, &p, 0);
4448+ if (sep->se_max < 1 || *p) {
4449+ syslog(LOG_ERR,
4450+ "%s: illegal max field \"%s\", setting to %d",
4451+ sep->se_service, s, toomany);
4452+ sep->se_max = toomany;
4453+ }
4454+ } else
4455+ sep->se_max = toomany;
4456+
4457+ sep->se_wait = strcmp(arg, "wait") == 0;
4458+ if ((arg = skip(&cp, 1)) == NULL)
4459+ goto more;
4460+ sep->se_user = newstr(arg);
4461+ arg = strchr(sep->se_user, '.');
4462+ if (arg == NULL)
4463+ arg = strchr(sep->se_user, ':');
4464+ if (arg) {
4465+ *arg++ = '\0';
4466+ sep->se_group = newstr(arg);
4467+ }
4468+ if ((arg = skip(&cp, 1)) == NULL)
4469+ goto more;
4470+
4471+ sep->se_server = newstr(arg);
4472+ if (strcmp(sep->se_server, "internal") == 0) {
4473+ struct biltin *bi;
4474+
4475+ for (bi = biltins; bi->bi_service; bi++)
4476+ if (bi->bi_socktype == sep->se_socktype &&
4477+ strcmp(bi->bi_service, sep->se_service) == 0)
4478+ break;
4479+ if (bi->bi_service == 0) {
4480+ syslog(LOG_ERR, "internal service %s unknown",
4481+ sep->se_service);
4482+ goto more;
4483+ }
4484+ sep->se_bi = bi;
4485+ sep->se_wait = bi->bi_wait;
4486+ } else
4487+ sep->se_bi = NULL;
4488+ argc = 0;
4489+ for (arg = skip(&cp, 0); cp; arg = skip(&cp, 0)) {
4490+ if (argc < MAXARGV)
4491+ sep->se_argv[argc++] = newstr(arg);
4492+ }
4493+ if (argc == 0 && sep->se_bi == NULL) {
4494+ if ((arg = strrchr(sep->se_server, '/')) != NULL)
4495+ arg++;
4496+ else
4497+ arg = sep->se_server;
4498+ sep->se_argv[argc++] = newstr(arg);
4499+ }
4500+ while (argc <= MAXARGV)
4501+ sep->se_argv[argc++] = NULL;
4502+
4503+ /*
4504+ * Resolve each hostname in the se_hostaddr list (if any)
4505+ * and create a new entry for each resolved address.
4506+ */
4507+ if (sep->se_hostaddr != NULL && strcmp(sep->se_proto, "unix") != 0) {
4508+ struct addrinfo hints, *res0, *res;
4509+ char *host, *hostlist0, *hostlist, *port;
4510+ int error;
4511+
4512+ hostlist = hostlist0 = sep->se_hostaddr;
4513+ sep->se_hostaddr = NULL;
4514+ sep->se_checked = -1;
4515+ while ((host = strsep(&hostlist, ",")) != NULL) {
4516+ if (*host == '\0')
4517+ continue;
4518+
4519+ memset(&hints, 0, sizeof(hints));
4520+ hints.ai_family = sep->se_family;
4521+ hints.ai_socktype = sep->se_socktype;
4522+ hints.ai_flags = AI_PASSIVE;
4523+ port = "0";
4524+ /* XXX shortened IPv4 syntax is now forbidden */
4525+ error = getaddrinfo(strcmp(host, "*") ? host : NULL,
4526+ port, &hints, &res0);
4527+ if (error) {
4528+ syslog(LOG_ERR, "%s/%s: %s: %s",
4529+ sep->se_service, sep->se_proto,
4530+ host, gai_strerror(error));
4531+ continue;
4532+ }
4533+ for (res = res0; res; res = res->ai_next) {
4534+ if (res->ai_addrlen >
4535+ sizeof(sep->se_ctrladdr_storage))
4536+ continue;
4537+ /*
4538+ * If sep is unused, store host in there.
4539+ * Otherwise, dup a new entry and prepend it.
4540+ */
4541+ if (sep->se_checked == -1) {
4542+ sep->se_checked = 0;
4543+ } else {
4544+ tsep = dupconfig(sep);
4545+ tsep->se_next = sep;
4546+ sep = tsep;
4547+ }
4548+ sep->se_hostaddr = newstr(host);
4549+ memcpy(&sep->se_ctrladdr_storage,
4550+ res->ai_addr, res->ai_addrlen);
4551+ sep->se_ctrladdr_size = res->ai_addrlen;
4552+ }
4553+ freeaddrinfo(res0);
4554+ }
4555+ free(hostlist0);
4556+ if (sep->se_checked == -1)
4557+ goto more; /* no resolvable names/addresses */
4558+ }
4559+
4560+ return (sep);
4561+}
4562+
4563+void
4564+freeconfig(struct servtab *cp)
4565+{
4566+ int i;
4567+
4568+ free(cp->se_hostaddr);
4569+ cp->se_hostaddr = NULL;
4570+ free(cp->se_service);
4571+ cp->se_service = NULL;
4572+ free(cp->se_proto);
4573+ cp->se_proto = NULL;
4574+ free(cp->se_user);
4575+ cp->se_user = NULL;
4576+ free(cp->se_group);
4577+ cp->se_group = NULL;
4578+ free(cp->se_server);
4579+ cp->se_server = NULL;
4580+ for (i = 0; i < MAXARGV; i++) {
4581+ free(cp->se_argv[i]);
4582+ cp->se_argv[i] = NULL;
4583+ }
4584+}
4585+
4586+char *
4587+skip(char **cpp, int report)
4588+{
4589+ char *cp = *cpp;
4590+ char *start;
4591+
4592+erp:
4593+ if (*cpp == NULL) {
4594+ if (report)
4595+ syslog(LOG_ERR, "syntax error in inetd config file");
4596+ return (NULL);
4597+ }
4598+
4599+again:
4600+ while (*cp == ' ' || *cp == '\t')
4601+ cp++;
4602+ if (*cp == '\0') {
4603+ int c;
4604+
4605+ c = getc(fconfig);
4606+ (void) ungetc(c, fconfig);
4607+ if (c == ' ' || c == '\t')
4608+ if ((cp = nextline(fconfig)))
4609+ goto again;
4610+ *cpp = NULL;
4611+ goto erp;
4612+ }
4613+ start = cp;
4614+ while (*cp && *cp != ' ' && *cp != '\t')
4615+ cp++;
4616+ if (*cp != '\0')
4617+ *cp++ = '\0';
4618+ if ((*cpp = cp) == NULL)
4619+ goto erp;
4620+
4621+ return (start);
4622+}
4623+
4624+char *
4625+nextline(FILE *fd)
4626+{
4627+ if (fgets(line, sizeof (line), fd) == NULL)
4628+ return (NULL);
4629+ line[strcspn(line, "\n")] = '\0';
4630+ return (line);
4631+}
4632+
4633+char *
4634+newstr(char *cp)
4635+{
4636+ if ((cp = strdup(cp ? cp : "")))
4637+ return(cp);
4638+ syslog(LOG_ERR, "strdup: %m");
4639+ exit(1);
4640+}
4641+
4642+struct servtab *
4643+dupconfig(struct servtab *sep)
4644+{
4645+ struct servtab *newtab;
4646+ int argc;
4647+
4648+ newtab = (struct servtab *) malloc(sizeof(struct servtab));
4649+
4650+ if (newtab == NULL) {
4651+ syslog(LOG_ERR, "malloc: %m");
4652+ exit(1);
4653+ }
4654+
4655+ memset(newtab, 0, sizeof(struct servtab));
4656+
4657+ newtab->se_service = sep->se_service ? newstr(sep->se_service) : NULL;
4658+ newtab->se_socktype = sep->se_socktype;
4659+ newtab->se_family = sep->se_family;
4660+ newtab->se_proto = sep->se_proto ? newstr(sep->se_proto) : NULL;
4661+ newtab->se_rpcprog = sep->se_rpcprog;
4662+ newtab->se_rpcversl = sep->se_rpcversl;
4663+ newtab->se_rpcversh = sep->se_rpcversh;
4664+ newtab->se_wait = sep->se_wait;
4665+ newtab->se_user = sep->se_user ? newstr(sep->se_user) : NULL;
4666+ newtab->se_group = sep->se_group ? newstr(sep->se_group) : NULL;
4667+ newtab->se_bi = sep->se_bi;
4668+ newtab->se_server = sep->se_server ? newstr(sep->se_server) : 0;
4669+
4670+ for (argc = 0; argc <= MAXARGV; argc++)
4671+ newtab->se_argv[argc] = sep->se_argv[argc] ?
4672+ newstr(sep->se_argv[argc]) : NULL;
4673+ newtab->se_max = sep->se_max;
4674+
4675+ return (newtab);
4676+}
4677+
4678+void
4679+inetd_setproctitle(char *a, int s)
4680+{
4681+ socklen_t size;
4682+ struct sockaddr_storage ss;
4683+ char hbuf[NI_MAXHOST];
4684+
4685+ size = sizeof(ss);
4686+ if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
4687+ if (getnameinfo((struct sockaddr *)&ss, size, hbuf,
4688+ sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0)
4689+ setproctitle("-%s [%s]", a, hbuf);
4690+ else
4691+ setproctitle("-%s [?]", a);
4692+ } else
4693+ setproctitle("-%s", a);
4694+}
4695+
4696+void
4697+logpid(void)
4698+{
4699+ FILE *fp;
4700+
4701+ if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
4702+ fprintf(fp, "%ld\n", (long)getpid());
4703+ (void)fclose(fp);
4704+ }
4705+}
4706+
4707+int
4708+bump_nofile(void)
4709+{
4710+#define FD_CHUNK 32
4711+
4712+ struct rlimit rl;
4713+
4714+ if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
4715+ syslog(LOG_ERR, "getrlimit: %m");
4716+ return -1;
4717+ }
4718+ rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
4719+ rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
4720+ if (rl.rlim_cur <= rlim_nofile_cur) {
4721+ syslog(LOG_ERR,
4722+ "bump_nofile: cannot extend file limit, max = %d",
4723+ (int)rl.rlim_cur);
4724+ return -1;
4725+ }
4726+
4727+ if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
4728+ syslog(LOG_ERR, "setrlimit: %m");
4729+ return -1;
4730+ }
4731+
4732+ rlim_nofile_cur = rl.rlim_cur;
4733+ return 0;
4734+}
4735+
4736+/*
4737+ * Internet services provided internally by inetd:
4738+ */
4739+#define BUFSIZE 4096
4740+
4741+/* ARGSUSED */
4742+void
4743+echo_stream(int s, struct servtab *sep)
4744+{
4745+ char buffer[BUFSIZE];
4746+ int i;
4747+
4748+ inetd_setproctitle(sep->se_service, s);
4749+ while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
4750+ write(s, buffer, i) > 0)
4751+ ;
4752+ exit(0);
4753+}
4754+
4755+/* ARGSUSED */
4756+void
4757+echo_dg(int s, struct servtab *sep)
4758+{
4759+ char buffer[BUFSIZE];
4760+ int i;
4761+ socklen_t size;
4762+ struct sockaddr_storage ss;
4763+
4764+ size = sizeof(ss);
4765+ if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
4766+ (struct sockaddr *)&ss, &size)) < 0)
4767+ return;
4768+ if (dg_badinput((struct sockaddr *)&ss))
4769+ return;
4770+ (void) sendto(s, buffer, i, 0, (struct sockaddr *)&ss, size);
4771+}
4772+
4773+/* ARGSUSED */
4774+void
4775+discard_stream(int s, struct servtab *sep)
4776+{
4777+ char buffer[BUFSIZE];
4778+
4779+ inetd_setproctitle(sep->se_service, s);
4780+ while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
4781+ errno == EINTR)
4782+ ;
4783+ exit(0);
4784+}
4785+
4786+/* ARGSUSED */
4787+void
4788+discard_dg(int s, struct servtab *sep)
4789+{
4790+ char buffer[BUFSIZE];
4791+
4792+ (void) read(s, buffer, sizeof(buffer));
4793+}
4794+
4795+#include <ctype.h>
4796+#define LINESIZ 72
4797+char ring[128];
4798+char *endring;
4799+
4800+void
4801+initring(void)
4802+{
4803+ int i;
4804+
4805+ endring = ring;
4806+
4807+ for (i = 0; i <= sizeof ring; ++i)
4808+ if (isprint(i))
4809+ *endring++ = i;
4810+}
4811+
4812+/* ARGSUSED */
4813+void
4814+chargen_stream(int s, struct servtab *sep)
4815+{
4816+ char *rs;
4817+ int len;
4818+ char text[LINESIZ+2];
4819+
4820+ inetd_setproctitle(sep->se_service, s);
4821+
4822+ if (!endring) {
4823+ initring();
4824+ rs = ring;
4825+ }
4826+
4827+ text[LINESIZ] = '\r';
4828+ text[LINESIZ + 1] = '\n';
4829+ for (rs = ring;;) {
4830+ if ((len = endring - rs) >= LINESIZ)
4831+ memmove(text, rs, LINESIZ);
4832+ else {
4833+ memmove(text, rs, len);
4834+ memmove(text + len, ring, LINESIZ - len);
4835+ }
4836+ if (++rs == endring)
4837+ rs = ring;
4838+ if (write(s, text, sizeof(text)) != sizeof(text))
4839+ break;
4840+ }
4841+ exit(0);
4842+}
4843+
4844+/* ARGSUSED */
4845+void
4846+chargen_dg(int s, struct servtab *sep)
4847+{
4848+ struct sockaddr_storage ss;
4849+ static char *rs;
4850+ int len;
4851+ socklen_t size;
4852+ char text[LINESIZ+2];
4853+
4854+ if (endring == 0) {
4855+ initring();
4856+ rs = ring;
4857+ }
4858+
4859+ size = sizeof(ss);
4860+ if (recvfrom(s, text, sizeof(text), 0, (struct sockaddr *)&ss,
4861+ &size) < 0)
4862+ return;
4863+ if (dg_badinput((struct sockaddr *)&ss))
4864+ return;
4865+
4866+ if ((len = endring - rs) >= LINESIZ)
4867+ memmove(text, rs, LINESIZ);
4868+ else {
4869+ memmove(text, rs, len);
4870+ memmove(text + len, ring, LINESIZ - len);
4871+ }
4872+ if (++rs == endring)
4873+ rs = ring;
4874+ text[LINESIZ] = '\r';
4875+ text[LINESIZ + 1] = '\n';
4876+ (void) sendto(s, text, sizeof(text), 0, (struct sockaddr *)&ss, size);
4877+}
4878+
4879+/*
4880+ * Return a machine readable date and time, in the form of the
4881+ * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
4882+ * returns the number of seconds since midnight, Jan 1, 1970,
4883+ * we must add 2208988800 seconds to this figure to make up for
4884+ * some seventy years Bell Labs was asleep.
4885+ */
4886+u_int32_t
4887+machtime(void)
4888+{
4889+ struct timeval tv;
4890+
4891+ if (gettimeofday(&tv, NULL) < 0)
4892+ return (0L);
4893+
4894+ return (htonl((u_int32_t)tv.tv_sec + 2208988800UL));
4895+}
4896+
4897+/* ARGSUSED */
4898+void
4899+machtime_stream(s, sep)
4900+ int s;
4901+ struct servtab *sep;
4902+{
4903+ u_int32_t result;
4904+
4905+ result = machtime();
4906+ (void) write(s, &result, sizeof(result));
4907+}
4908+
4909+/* ARGSUSED */
4910+void
4911+machtime_dg(int s, struct servtab *sep)
4912+{
4913+ u_int32_t result;
4914+ struct sockaddr_storage ss;
4915+ socklen_t size;
4916+
4917+ size = sizeof(ss);
4918+ if (recvfrom(s, &result, sizeof(result), 0,
4919+ (struct sockaddr *)&ss, &size) < 0)
4920+ return;
4921+ if (dg_badinput((struct sockaddr *)&ss))
4922+ return;
4923+ result = machtime();
4924+ (void) sendto(s, &result, sizeof(result), 0,
4925+ (struct sockaddr *)&ss, size);
4926+}
4927+
4928+/* Return human-readable time of day */
4929+/* ARGSUSED */
4930+void
4931+daytime_stream(int s, struct servtab *sep)
4932+{
4933+ char buffer[256];
4934+ time_t clock;
4935+
4936+ clock = time(NULL);
4937+
4938+ (void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
4939+ (void) write(s, buffer, strlen(buffer));
4940+}
4941+
4942+/* Return human-readable time of day */
4943+/* ARGSUSED */
4944+void
4945+daytime_dg(int s, struct servtab *sep)
4946+{
4947+ char buffer[256];
4948+ time_t clock;
4949+ struct sockaddr_storage ss;
4950+ socklen_t size;
4951+
4952+ clock = time(NULL);
4953+
4954+ size = sizeof(ss);
4955+ if (recvfrom(s, buffer, sizeof(buffer), 0, (struct sockaddr *)&ss,
4956+ &size) < 0)
4957+ return;
4958+ if (dg_badinput((struct sockaddr *)&ss))
4959+ return;
4960+ (void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
4961+ (void) sendto(s, buffer, strlen(buffer), 0, (struct sockaddr *)&ss,
4962+ size);
4963+}
4964+
4965+/*
4966+ * print_service:
4967+ * Dump relevant information to stderr
4968+ */
4969+void
4970+print_service(char *action, struct servtab *sep)
4971+{
4972+ if (strcmp(sep->se_hostaddr, "*") == 0)
4973+ fprintf(stderr, "%s: %s ", action, sep->se_service);
4974+ else
4975+ fprintf(stderr, "%s: %s:%s ", action, sep->se_hostaddr,
4976+ sep->se_service);
4977+
4978+ if (isrpcservice(sep))
4979+ fprintf(stderr, "rpcprog=%d, rpcvers=%d/%d, proto=%s,",
4980+ sep->se_rpcprog, sep->se_rpcversh,
4981+ sep->se_rpcversl, sep->se_proto);
4982+ else
4983+ fprintf(stderr, "proto=%s,", sep->se_proto);
4984+
4985+ fprintf(stderr,
4986+ " wait.max=%hd.%d user:group=%s:%s builtin=%lx server=%s\n",
4987+ sep->se_wait, sep->se_max, sep->se_user,
4988+ sep->se_group ? sep->se_group : "(default)",
4989+ (long)sep->se_bi, sep->se_server);
4990+}
4991+
4992+void
4993+spawn(struct servtab *sep, int ctrl)
4994+{
4995+ struct passwd *pwd;
4996+ int tmpint, dofork;
4997+ struct group *grp = NULL;
4998+ char buf[50];
4999+ pid_t pid;
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches