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
=== added directory '.pc'
=== added file '.pc/.version'
--- .pc/.version 1970-01-01 00:00:00 +0000
+++ .pc/.version 2011-06-29 11:29:23 +0000
@@ -0,0 +1,1 @@
12
02
=== added file '.pc/applied-patches'
--- .pc/applied-patches 1970-01-01 00:00:00 +0000
+++ .pc/applied-patches 2011-06-29 11:29:23 +0000
@@ -0,0 +1,11 @@
1makefile
2test
3misc_portability
4setproctitle
5discard_env
6libwrap
7nodaemon
8global_queuelen
9print_pause_time
10tcp46
11buftuning
012
=== added directory '.pc/buftuning'
=== added file '.pc/buftuning/inetd.8'
--- .pc/buftuning/inetd.8 1970-01-01 00:00:00 +0000
+++ .pc/buftuning/inetd.8 2011-06-29 11:29:23 +0000
@@ -0,0 +1,465 @@
1.\" $OpenBSD: inetd.8,v 1.33 2008/06/28 10:54:45 sobrado Exp $
2.\" Copyright (c) 1985, 1991 The Regents of the University of California.
3.\" All rights reserved.
4.\"
5.\" Redistribution and use in source and binary forms, with or without
6.\" modification, are permitted provided that the following conditions
7.\" are met:
8.\" 1. Redistributions of source code must retain the above copyright
9.\" notice, this list of conditions and the following disclaimer.
10.\" 2. Redistributions in binary form must reproduce the above copyright
11.\" notice, this list of conditions and the following disclaimer in the
12.\" documentation and/or other materials provided with the distribution.
13.\" 3. Neither the name of the University nor the names of its contributors
14.\" may be used to endorse or promote products derived from this software
15.\" without specific prior written permission.
16.\"
17.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27.\" SUCH DAMAGE.
28.\"
29.\" from: @(#)inetd.8 6.7 (Berkeley) 3/16/91
30.\"
31.Dd $Mdocdate: December 29 2009 $
32.Dt INETD 8
33.Os
34.Sh NAME
35.Nm inetd
36.Nd internet
37.Dq super-server
38.Sh SYNOPSIS
39.Nm inetd
40.Op Fl d
41.Op Fl E
42.Op Fl i
43.Op Fl l
44.Op Fl q Ar length
45.Op Fl R Ar rate
46.Op Ar configuration_file
47.Sh DESCRIPTION
48.Nm inetd
49listens for connections on certain internet sockets.
50When a connection is found on one
51of its sockets, it decides what service the socket
52corresponds to, and invokes a program to service the request.
53After the program is
54finished, it continues to listen on the socket (except in some cases which
55will be described below).
56Essentially,
57.Nm inetd
58allows running one daemon to invoke several others,
59reducing load on the system.
60.Pp
61The options are as follows:
62.Bl -tag -width Ds
63.It Fl d
64Turns on debugging.
65.It Fl E
66Prevents
67.Nm inetd
68from laundering the environment. Without this option a selection of
69potentially harmful environent variables, including
70.Pa PATH ,
71will be removed and not inherited by services.
72.It Fl i
73Makes the program not daemonize itself.
74.It Fl l
75Turns on libwrap connection logging and access control.
76Internal services cannot be wrapped. When enabled,
77.Pa /usr/sbin/tcpd
78is silently not executed even if present in
79.Pa /etc/inetd.conf
80and instead libwrap is called directly by inetd.
81.It Fl q Ar length
82Specify the length of the
83.Xr listen 2
84connections queue; the default is 128.
85.It Fl R Ar rate
86Specify the maximum number of times a service can be invoked
87in one minute; the default is 256.
88If a service exceeds this limit,
89.Nm
90will log the problem
91and stop servicing requests for the specific service for ten minutes.
92See also the wait/nowait configuration fields below.
93.El
94.Pp
95Upon execution,
96.Nm inetd
97reads its configuration information from a configuration
98file which, by default, is
99.Pa /etc/inetd.conf .
100There must be an entry for each field of the configuration
101file, with entries for each field separated by a tab or
102a space.
103Comments are denoted by a
104.Dq #
105at the beginning
106of a line.
107The fields of the configuration file are as follows:
108.Bd -unfilled -offset indent
109service name
110socket type
111protocol
112wait/nowait[.max]
113user[.group] or user[:group]
114server program
115server program arguments
116.Ed
117.Pp
118To specify a Sun-RPC
119based service, the entry would contain these fields.
120.Bd -unfilled -offset indent
121service name/version
122socket type
123rpc/protocol
124wait/nowait[.max]
125user[.group] or user[:group]
126server program
127server program arguments
128.Ed
129.Pp
130For internet services, the first field of the line may also have a host
131address specifier prefixed to it, separated from the service name by a
132colon.
133If this is done, the string before the colon in the first field
134indicates what local address
135.Nm
136should use when listening for that service.
137Multiple local addresses
138can be specified on the same line, separated by commas.
139Numeric IP
140addresses in dotted-quad notation can be used as well as symbolic
141hostnames.
142Symbolic hostnames are looked up using
143.Fn gethostbyname .
144If a hostname has multiple address mappings, inetd creates a socket
145to listen on each address.
146.Pp
147The single character
148.Dq \&*
149indicates
150.Dv INADDR_ANY ,
151meaning
152.Dq all local addresses .
153To avoid repeating an address that occurs frequently, a line with a
154host address specifier and colon, but no further fields, causes the
155host address specifier to be remembered and used for all further lines
156with no explicit host specifier (until another such line or the end of
157the file).
158A line
159.Dl *:
160is implicitly provided at the top of the file; thus, traditional
161configuration files (which have no host address specifiers) will be
162interpreted in the traditional manner, with all services listened for
163on all local addresses.
164If the protocol is
165.Dq unix ,
166this value is ignored.
167.Pp
168The
169.Em service name
170entry is the name of a valid service in
171the file
172.Pa /etc/services
173or a port number.
174For
175.Dq internal
176services (discussed below), the service
177name
178.Em must
179be the official name of the service (that is, the first entry in
180.Pa /etc/services ) .
181When used to specify a Sun-RPC
182based service, this field is a valid RPC service name in
183the file
184.Pa /etc/rpc .
185The part on the right of the
186.Dq /
187is the RPC version number.
188This can simply be a single numeric argument or a range of versions.
189A range is bounded by the low version to the high version -
190.Dq rusers/1\-3 .
191For
192.Ux Ns -domain
193sockets this field specifies the path name of the socket.
194.Pp
195The
196.Em socket type
197should be one of
198.Dq stream ,
199.Dq dgram ,
200.Dq raw ,
201.Dq rdm ,
202or
203.Dq seqpacket ,
204depending on whether the socket is a stream, datagram, raw,
205reliably delivered message, or sequenced packet socket.
206.Pp
207The
208.Em protocol
209must be a valid protocol as given in
210.Pa /etc/protocols or
211.Dq unix .
212Examples might be
213.Dq tcp
214or
215.Dq udp .
216RPC based services are specified with the
217.Dq rpc/tcp
218or
219.Dq rpc/udp
220service type.
221.Dq tcp
222and
223.Dq udp
224will be recognized as
225.Dq TCP or UDP over default IP version .
226This is currently IPv4, but in the future it will be IPv6.
227If you need to specify IPv4 or IPv6 explicitly, use something like
228.Dq tcp4
229or
230.Dq udp6 .
231A
232.Em protocol
233of
234.Dq unix
235is used to specify a socket in the
236.Ux Ns -domain .
237.Pp
238The
239.Em wait/nowait
240entry is used to tell
241.Nm
242if it should wait for the server program to return,
243or continue processing connections on the socket.
244If a datagram server connects
245to its peer, freeing the socket so
246.Nm inetd
247can receive further messages on the socket, it is said to be
248a
249.Dq multi-threaded
250server, and should use the
251.Dq nowait
252entry.
253For datagram servers which process all incoming datagrams
254on a socket and eventually time out, the server is said to be
255.Dq single-threaded
256and should use a
257.Dq wait
258entry.
259.Xr comsat 8
260.Pq Xr biff 1
261and
262.Xr talkd 8
263are both examples of the latter type of
264datagram server.
265.Xr tftpd 8
266is an exception; it is a datagram server that establishes pseudo-connections.
267It must be listed as
268.Dq wait
269in order to avoid a race;
270the server reads the first packet, creates a new socket,
271and then forks and exits to allow
272.Nm inetd
273to check for new service requests to spawn new servers.
274The optional
275.Dq max
276suffix (separated from
277.Dq wait
278or
279.Dq nowait
280by a dot) specifies the maximum number of times a service can be invoked
281in one minute; the default is 256.
282If a service exceeds this limit,
283.Nm
284will log the problem
285and stop servicing requests for the specific service for ten minutes.
286See also the
287.Fl R
288option above.
289.Pp
290Stream servers are usually marked as
291.Dq nowait
292but if a single server process is to handle multiple connections, it may be
293marked as
294.Dq wait .
295The master socket will then be passed as fd 0 to the server, which will then
296need to accept the incoming connection.
297The server should eventually time
298out and exit when no more connections are active.
299.Nm
300will continue to
301listen on the master socket for connections, so the server should not close
302it when it exits.
303.Pp
304The
305.Em user
306entry should contain the user name of the user as whom the server
307should run.
308This allows for servers to be given less permission
309than root.
310An optional group name can be specified by appending a dot to
311the user name followed by the group name.
312This allows for servers to run with
313a different (primary) group ID than specified in the password file.
314If a group
315is specified and user is not root, the supplementary groups associated with
316that user will still be set.
317.Pp
318The
319.Em server program
320entry should contain the pathname of the program which is to be
321executed by
322.Nm inetd
323when a request is found on its socket.
324If
325.Nm inetd
326provides this service internally, this entry should
327be
328.Dq internal .
329.Pp
330The
331.Em server program arguments
332should be just as arguments
333normally are, starting with argv[0], which is the name of
334the program.
335If the service is provided internally, the word
336.Dq internal
337should take the place of this entry.
338.Pp
339.Nm inetd
340provides several
341.Dq trivial
342services internally by use of routines within itself.
343These services are
344.Dq echo ,
345.Dq discard ,
346.Dq chargen
347(character generator),
348.Dq daytime
349(human readable time), and
350.Dq time
351(machine readable time,
352in the form of the number of seconds since midnight, January
3531, 1900).
354All of these services are TCP based.
355For details of these services, consult the appropriate
356.Tn RFC
357from the Network Information Center.
358.Pp
359.Nm inetd
360rereads its configuration file when it receives a hangup signal,
361.Dv SIGHUP .
362Services may be added, deleted or modified when the configuration file
363is reread.
364.Nm inetd
365creates a file
366.Em /var/run/inetd.pid
367that contains its process identifier.
368.Ss libwrap
369Support for
370.Tn TCP
371wrappers is included with
372.Nm
373to provide built-in tcpd-like access control functionality.
374An external tcpd program is not needed.
375You do not need to change the
376.Pa /etc/inetd.conf
377server-program entry to enable this capability.
378.Nm
379uses
380.Pa /etc/hosts.allow
381and
382.Pa /etc/hosts.deny
383for access control facility configurations, as described in
384.Xr hosts_access 5 .
385.Ss IPv6 TCP/UDP behavior
386If you wish to run a server for IPv4 and IPv6 traffic,
387you'll need to run two separate processes for the same server program,
388specified as two separate lines in
389.Pa inetd.conf ,
390for
391.Dq tcp4
392and
393.Dq tcp6 .
394.Pp
395Under various combinations of IPv4/v6 daemon settings,
396.Nm
397will behave as follows:
398.Bl -bullet -compact
399.It
400If you have only one server on
401.Dq tcp4 ,
402IPv4 traffic will be routed to the server.
403IPv6 traffic will not be accepted.
404.It
405If you have two servers on
406.Dq tcp4
407and
408.Dq tcp6 ,
409IPv4 traffic will be routed to the server on
410.Dq tcp4 ,
411and IPv6 traffic will go to server on
412.Dq tcp6 .
413.It
414If you have only one server on
415.Dq tcp6 ,
416only IPv6 traffic will be routed to the server.
417.Pp
418The special
419.Dq tcp46
420parameter can be used for obsolete servers which require to receive IPv4
421connections mapped in an IPv6 socket. Its usage is discouraged.
422.El
423.Sh SEE ALSO
424.Xr fingerd 8 ,
425.Xr ftpd 8 ,
426.Xr identd 8 ,
427.Xr rshd 8 ,
428.Xr talkd 8 ,
429.Xr tftpd 8
430.Sh HISTORY
431The
432.Nm
433command appeared in
434.Bx 4.3 .
435Support for Sun-RPC
436based services is modelled after that
437provided by SunOS 4.1.
438IPv6 support was added by the KAME project in 1999.
439.Pp
440Marco d'Itri ported this code from OpenBSD in summer 2002 and added
441socket buffers tuning and libwrap support from the NetBSD source tree.
442.Sh BUGS
443On Linux systems, the daemon cannot reload its configuration and needs
444to be restarted when the host address for a service is changed between
445.Dq \&*
446and a specific address.
447.Pp
448Server programs used with
449.Dq dgram
450.Dq udp
451.Dq nowait
452must read from the network socket, or
453.Nm inetd
454will spawn processes until the maximum is reached.
455.Pp
456Host address specifiers, while they make conceptual sense for RPC
457services, do not work entirely correctly.
458This is largely because the
459portmapper interface does not provide a way to register different ports
460for the same service on different local addresses.
461Provided you never
462have more than one entry for a given RPC service, everything should
463work correctly.
464(Note that default host address specifiers do apply to
465RPC lines with no explicit specifier.)
0466
=== added file '.pc/buftuning/inetd.c'
--- .pc/buftuning/inetd.c 1970-01-01 00:00:00 +0000
+++ .pc/buftuning/inetd.c 2011-06-29 11:29:23 +0000
@@ -0,0 +1,2194 @@
1/* $OpenBSD: inetd.c,v 1.131 2009/10/27 23:59:51 deraadt Exp $ */
2
3/*
4 * Copyright (c) 1983,1991 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * Inetd - Internet super-server
34 *
35 * This program invokes all internet services as needed.
36 * connection-oriented services are invoked each time a
37 * connection is made, by creating a process. This process
38 * is passed the connection as file descriptor 0 and is
39 * expected to do a getpeername to find out the source host
40 * and port.
41 *
42 * Datagram oriented services are invoked when a datagram
43 * arrives; a process is created and passed a pending message
44 * on file descriptor 0. Datagram servers may either connect
45 * to their peer, freeing up the original socket for inetd
46 * to receive further messages on, or ``take over the socket'',
47 * processing all arriving datagrams and, eventually, timing
48 * out. The first type of server is said to be ``multi-threaded'';
49 * the second type of server ``single-threaded''.
50 *
51 * Inetd uses a configuration file which is read at startup
52 * and, possibly, at some later time in response to a hangup signal.
53 * The configuration file is ``free format'' with fields given in the
54 * order shown below. Continuation lines for an entry must begin with
55 * a space or tab. All fields must be present in each entry.
56 *
57 * service name must be in /etc/services
58 * socket type stream/dgram/raw/rdm/seqpacket
59 * protocol must be in /etc/protocols
60 * wait/nowait[.max] single-threaded/multi-threaded, max #
61 * user[.group] or user[:group] user/group to run daemon as
62 * server program full path name
63 * server program arguments maximum of MAXARGS (20)
64 *
65 * For RPC services
66 * service name/version must be in /etc/rpc
67 * socket type stream/dgram/raw/rdm/seqpacket
68 * protocol must be in /etc/protocols
69 * wait/nowait[.max] single-threaded/multi-threaded
70 * user[.group] or user[:group] user to run daemon as
71 * server program full path name
72 * server program arguments maximum of MAXARGS (20)
73 *
74 * For non-RPC services, the "service name" can be of the form
75 * hostaddress:servicename, in which case the hostaddress is used
76 * as the host portion of the address to listen on. If hostaddress
77 * consists of a single `*' character, INADDR_ANY is used.
78 *
79 * A line can also consist of just
80 * hostaddress:
81 * where hostaddress is as in the preceding paragraph. Such a line must
82 * have no further fields; the specified hostaddress is remembered and
83 * used for all further lines that have no hostaddress specified,
84 * until the next such line (or EOF). (This is why * is provided to
85 * allow explicit specification of INADDR_ANY.) A line
86 * *:
87 * is implicitly in effect at the beginning of the file.
88 *
89 * The hostaddress specifier may (and often will) contain dots;
90 * the service name must not.
91 *
92 * For RPC services, host-address specifiers are accepted and will
93 * work to some extent; however, because of limitations in the
94 * portmapper interface, it will not work to try to give more than
95 * one line for any given RPC service, even if the host-address
96 * specifiers are different.
97 *
98 * Comment lines are indicated by a `#' in column 1.
99 */
100
101/*
102 * Here's the scoop concerning the user[.:]group feature:
103 *
104 * 1) set-group-option off.
105 *
106 * a) user = root: NO setuid() or setgid() is done
107 *
108 * b) other: setgid(primary group as found in passwd)
109 * initgroups(name, primary group)
110 * setuid()
111 *
112 * 2) set-group-option on.
113 *
114 * a) user = root: setgid(specified group)
115 * NO initgroups()
116 * NO setuid()
117 *
118 * b) other: setgid(specified group)
119 * initgroups(name, specified group)
120 * setuid()
121 *
122 */
123
124#include <sys/param.h>
125#include <sys/stat.h>
126#include <sys/ioctl.h>
127#include <sys/socket.h>
128#include <sys/un.h>
129#include <sys/file.h>
130#include <sys/wait.h>
131#include <time.h>
132#include <sys/time.h>
133#include <sys/resource.h>
134
135#include <net/if.h>
136#include <netinet/in.h>
137#include <arpa/inet.h>
138
139#include <errno.h>
140#include <ctype.h>
141#include <signal.h>
142#include <netdb.h>
143#include <syslog.h>
144#include <pwd.h>
145#include <grp.h>
146#include <stdio.h>
147#include <stdlib.h>
148#include <unistd.h>
149#include <string.h>
150#ifdef HAVE_SETUSERCONTEXT
151#include <login_cap.h>
152#endif
153#ifdef HAVE_GETIFADDRS
154#include <ifaddrs.h>
155#endif
156#include <rpc/rpc.h>
157#include <rpc/pmap_clnt.h>
158#include "pathnames.h"
159#include "setproctitle.h"
160
161size_t strlcpy(char *, const char *, size_t);
162
163#define TOOMANY 256 /* don't start more than TOOMANY */
164#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
165#define RETRYTIME (60*10) /* retry after bind or server fail */
166
167#ifdef LIBWRAP
168# include <tcpd.h>
169int lflag = 0;
170#endif
171
172int debug = 0;
173int global_queuelen = 128;
174int nsock, maxsock;
175fd_set *allsockp;
176int allsockn;
177int toomany = TOOMANY;
178int options;
179int timingout;
180struct servent *sp;
181uid_t uid;
182sigset_t blockmask;
183sigset_t emptymask;
184
185#ifndef OPEN_MAX
186#define OPEN_MAX 64
187#endif
188
189/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
190#define FD_MARGIN (8)
191rlim_t rlim_nofile_cur = OPEN_MAX;
192
193struct rlimit rlim_nofile;
194
195struct servtab {
196 char *se_hostaddr; /* host address to listen on */
197 char *se_service; /* name of service */
198 int se_socktype; /* type of socket to use */
199 int se_family; /* address family */
200 char *se_proto; /* protocol used */
201 int se_rpcprog; /* rpc program number */
202 int se_rpcversl; /* rpc program lowest version */
203 int se_rpcversh; /* rpc program highest version */
204#define isrpcservice(sep) ((sep)->se_rpcversl != 0)
205 pid_t se_wait; /* single threaded server */
206 short se_checked; /* looked at during merge */
207 char *se_user; /* user name to run as */
208 char *se_group; /* group name to run as */
209 struct biltin *se_bi; /* if built-in, description */
210 char *se_server; /* server program */
211#define MAXARGV 20
212 char *se_argv[MAXARGV+1]; /* program arguments */
213 int se_fd; /* open descriptor */
214 union {
215 struct sockaddr se_un_ctrladdr;
216 struct sockaddr_in se_un_ctrladdr_in;
217 struct sockaddr_in6 se_un_ctrladdr_in6;
218 struct sockaddr_un se_un_ctrladdr_un;
219 struct sockaddr_storage se_un_ctrladdr_storage;
220 } se_un; /* bound address */
221#define se_ctrladdr se_un.se_un_ctrladdr
222#define se_ctrladdr_in se_un.se_un_ctrladdr_in
223#define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
224#define se_ctrladdr_un se_un.se_un_ctrladdr_un
225#define se_ctrladdr_storage se_un.se_un_ctrladdr_storage
226 int se_ctrladdr_size;
227 int se_max; /* max # of instances of this service */
228 int se_count; /* number started since se_time */
229 struct timeval se_time; /* start of se_count */
230 struct servtab *se_next;
231} *servtab;
232
233void echo_stream(int, struct servtab *);
234void discard_stream(int, struct servtab *);
235void machtime_stream(int, struct servtab *);
236void daytime_stream(int, struct servtab *);
237void chargen_stream(int, struct servtab *);
238void echo_dg(int, struct servtab *);
239void discard_dg(int, struct servtab *);
240void machtime_dg(int, struct servtab *);
241void daytime_dg(int, struct servtab *);
242void chargen_dg(int, struct servtab *);
243
244struct biltin {
245 char *bi_service; /* internally provided service name */
246 int bi_socktype; /* type of socket supported */
247 short bi_fork; /* 1 if should fork before call */
248 short bi_wait; /* 1 if should wait for child */
249 void (*bi_fn)(int, struct servtab *);
250} biltins[] = {
251 /* Echo received data */
252 { "echo", SOCK_STREAM, 1, 0, echo_stream },
253 { "echo", SOCK_DGRAM, 0, 0, echo_dg },
254
255 /* Internet /dev/null */
256 { "discard", SOCK_STREAM, 1, 0, discard_stream },
257 { "discard", SOCK_DGRAM, 0, 0, discard_dg },
258
259 /* Return 32 bit time since 1900 */
260 { "time", SOCK_STREAM, 0, 0, machtime_stream },
261 { "time", SOCK_DGRAM, 0, 0, machtime_dg },
262
263 /* Return human-readable time */
264 { "daytime", SOCK_STREAM, 0, 0, daytime_stream },
265 { "daytime", SOCK_DGRAM, 0, 0, daytime_dg },
266
267 /* Familiar character generator */
268 { "chargen", SOCK_STREAM, 1, 0, chargen_stream },
269 { "chargen", SOCK_DGRAM, 0, 0, chargen_dg },
270
271 { 0 }
272};
273
274volatile sig_atomic_t wantretry;
275volatile sig_atomic_t wantconfig;
276volatile sig_atomic_t wantreap;
277volatile sig_atomic_t wantdie;
278
279void config(int);
280void doconfig(void);
281void reap(int);
282void doreap(void);
283void retry(int);
284void doretry(void);
285void die(int);
286void dodie(void);
287void logpid(void);
288void spawn(struct servtab *, int);
289int gettcp(struct servtab *);
290int setconfig(void);
291void endconfig(void);
292void register_rpc(struct servtab *);
293void unregister_rpc(struct servtab *);
294void freeconfig(struct servtab *);
295void print_service(char *, struct servtab *);
296void setup(struct servtab *);
297struct servtab *getconfigent(void);
298int bump_nofile(void);
299struct servtab *enter(struct servtab *);
300int matchconf(struct servtab *, struct servtab *);
301int dg_broadcast(struct in_addr *in);
302void discard_stupid_environment(void);
303
304#define NUMINT (sizeof(intab) / sizeof(struct inent))
305char *CONFIG = _PATH_INETDCONF;
306
307void
308fd_grow(fd_set **fdsp, int *bytes, int fd)
309{
310 caddr_t new;
311 int newbytes;
312
313 newbytes = howmany(fd+1, NFDBITS) * sizeof(fd_mask);
314 if (newbytes > *bytes) {
315 newbytes *= 2; /* optimism */
316 new = realloc(*fdsp, newbytes);
317 if (new == NULL) {
318 syslog(LOG_ERR, "Out of memory.");
319 exit(1);
320 }
321 memset(new + *bytes, 0, newbytes - *bytes);
322 *fdsp = (fd_set *)new;
323 *bytes = newbytes;
324 }
325}
326
327struct sigaction sa, sapipe;
328
329int
330main(int argc, char *argv[], char *envp[])
331{
332 fd_set *fdsrp = NULL;
333 int readablen = 0, ch;
334 int keepenv = 0;
335 int nodaemon = 0;
336 struct servtab *sep;
337 extern char *optarg;
338 extern int optind;
339
340 initsetproctitle(argc, argv, envp);
341
342 while ((ch = getopt(argc, argv, "dEilq:R:")) != -1)
343 switch (ch) {
344 case 'd':
345 debug = 1;
346 break;
347 case 'E':
348 keepenv = 1;
349 break;
350 case 'i':
351 nodaemon = 1;
352 break;
353 case 'l':
354#ifdef LIBWRAP
355 lflag = 1;
356 break;
357#else
358 fprintf(stderr, "%s: libwrap support not enabled",
359 progname);
360 exit(1);
361#endif
362 case 'q':
363 global_queuelen = atoi(optarg);
364 if (global_queuelen < 10)
365 global_queuelen = 10;
366 break;
367 case 'R': { /* invocation rate */
368 char *p;
369 int val;
370
371 val = strtoul(optarg, &p, 0);
372 if (val >= 1 && *p == '\0') {
373 toomany = val;
374 break;
375 }
376 syslog(LOG_ERR,
377 "-R %s: bad value for service invocation rate",
378 optarg);
379 break;
380 }
381 case '?':
382 default:
383 fprintf(stderr,
384 "usage: inetd [-dEil] [-q len] [-R rate] [configuration_file]\n");
385 exit(1);
386 }
387 argc -= optind;
388 argv += optind;
389
390 /* This must be called _after_ initsetproctitle and arg parsing */
391 if (!keepenv)
392 discard_stupid_environment();
393
394 uid = getuid();
395 if (uid != 0)
396 CONFIG = NULL;
397 if (argc > 0)
398 CONFIG = argv[0];
399 if (CONFIG == NULL) {
400 fprintf(stderr, "inetd: non-root must specify a config file\n");
401 exit(1);
402 }
403 if (argc > 1) {
404 fprintf(stderr, "inetd: more than one argument specified\n");
405 exit(1);
406 }
407
408 umask(022);
409 if (debug == 0) {
410 if (nodaemon == 0)
411 if (daemon(0, 0) < 0) {
412 syslog(LOG_ERR, "daemon(0, 0): %m");
413 exit(1);
414 }
415#ifdef HAVE_SETLOGIN
416 if (uid == 0)
417 (void) setlogin("");
418#endif
419 }
420 if (debug && uid == 0)
421 options |= SO_DEBUG;
422
423 if (uid == 0) {
424 gid_t gid = getgid();
425
426 /* If run by hand, ensure groups vector gets trashed */
427 setgroups(1, &gid);
428 }
429
430 openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
431 logpid();
432
433 if (getrlimit(RLIMIT_NOFILE, &rlim_nofile) < 0) {
434 syslog(LOG_ERR, "getrlimit: %m");
435 } else {
436 rlim_nofile_cur = rlim_nofile.rlim_cur;
437 if (rlim_nofile_cur == RLIM_INFINITY) /* ! */
438 rlim_nofile_cur = OPEN_MAX;
439 }
440
441 sigemptyset(&emptymask);
442 sigemptyset(&blockmask);
443 sigaddset(&blockmask, SIGCHLD);
444 sigaddset(&blockmask, SIGHUP);
445 sigaddset(&blockmask, SIGALRM);
446
447 memset(&sa, 0, sizeof(sa));
448 sigemptyset(&sa.sa_mask);
449 sigaddset(&sa.sa_mask, SIGALRM);
450 sigaddset(&sa.sa_mask, SIGCHLD);
451 sigaddset(&sa.sa_mask, SIGHUP);
452 sa.sa_handler = retry;
453 sigaction(SIGALRM, &sa, NULL);
454 doconfig();
455 sa.sa_handler = config;
456 sigaction(SIGHUP, &sa, NULL);
457 sa.sa_handler = reap;
458 sigaction(SIGCHLD, &sa, NULL);
459 sa.sa_handler = die;
460 sigaction(SIGTERM, &sa, NULL);
461 sa.sa_handler = die;
462 sigaction(SIGINT, &sa, NULL);
463 sa.sa_handler = SIG_IGN;
464 sigaction(SIGPIPE, &sa, &sapipe);
465
466 /* space for daemons to overwrite environment for ps */
467 {
468#define DUMMYSIZE 100
469 char dummy[DUMMYSIZE];
470 memset(dummy, 'x', DUMMYSIZE - 1);
471 dummy[DUMMYSIZE - 1] = '\0';
472 setenv("inetd_dummy", dummy, 1);
473 }
474
475 for (;;) {
476 int n, ctrl = -1;
477
478 restart:
479 if (nsock == 0) {
480 (void) sigprocmask(SIG_BLOCK, &blockmask, NULL);
481 while (nsock == 0) {
482 if (wantretry || wantconfig || wantreap || wantdie)
483 break;
484 sigsuspend(&emptymask);
485 }
486 (void) sigprocmask(SIG_SETMASK, &emptymask, NULL);
487 }
488
489 while (wantretry || wantconfig || wantreap || wantdie) {
490 if (wantretry) {
491 wantretry = 0;
492 doretry();
493 }
494 if (wantconfig) {
495 wantconfig = 0;
496 doconfig();
497 }
498 if (wantreap) {
499 wantreap = 0;
500 doreap();
501 }
502 if (wantdie)
503 dodie();
504 goto restart;
505 }
506
507 if (readablen != allsockn) {
508 if (fdsrp)
509 free(fdsrp);
510 fdsrp = (fd_set *)calloc(allsockn, 1);
511 if (fdsrp == NULL) {
512 syslog(LOG_ERR, "Out of memory.");
513 exit(1);
514 }
515 readablen = allsockn;
516 }
517 bcopy(allsockp, fdsrp, allsockn);
518
519 if ((n = select(maxsock + 1, fdsrp, NULL, NULL, NULL)) <= 0) {
520 if (n < 0 && errno != EINTR) {
521 syslog(LOG_WARNING, "select: %m");
522 sleep(1);
523 }
524 continue;
525 }
526
527 for (sep = servtab; n && sep; sep = sep->se_next) {
528 if (sep->se_fd != -1 &&
529 FD_ISSET(sep->se_fd, fdsrp)) {
530 n--;
531 if (debug)
532 fprintf(stderr, "someone wants %s\n",
533 sep->se_service);
534 if (!sep->se_wait &&
535 sep->se_socktype == SOCK_STREAM) {
536 ctrl = gettcp(sep);
537 if (ctrl == -1)
538 continue;
539 } else
540 ctrl = sep->se_fd;
541 (void) sigprocmask(SIG_BLOCK, &blockmask, NULL);
542 spawn(sep, ctrl); /* spawn will unblock */
543 }
544 }
545 }
546}
547
548int
549gettcp(struct servtab *sep)
550{
551 int ctrl;
552
553 ctrl = accept(sep->se_fd, NULL, NULL);
554 if (debug)
555 fprintf(stderr, "accept, ctrl %d\n", ctrl);
556 if (ctrl < 0) {
557 if (errno == EINTR)
558 return -1;
559 syslog(LOG_WARNING, "accept (for %s): %m", sep->se_service);
560 return -1;
561 }
562 if ((sep->se_family == AF_INET || sep->se_family == AF_INET6) &&
563 sep->se_socktype == SOCK_STREAM) {
564 struct sockaddr_storage peer;
565 socklen_t plen = sizeof(peer);
566 char sbuf[NI_MAXSERV];
567
568 if (getpeername(ctrl, (struct sockaddr *)&peer, &plen) < 0) {
569 syslog(LOG_WARNING, "could not getpeername");
570 close(ctrl);
571 return -1;
572 }
573 if (getnameinfo((struct sockaddr *)&peer, plen, NULL, 0,
574 sbuf, sizeof(sbuf), NI_NUMERICSERV) == 0 &&
575 atoi(sbuf) == 20) {
576 /*
577 * ignore things that look like ftp bounce
578 */
579 close(ctrl);
580 return -1;
581 }
582 }
583 return (ctrl);
584}
585
586
587int
588dg_badinput(struct sockaddr *sa)
589{
590 struct in_addr in;
591 struct in6_addr *in6;
592 u_int16_t port;
593
594 switch (sa->sa_family) {
595 case AF_INET:
596 in.s_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
597 port = ntohs(((struct sockaddr_in *)sa)->sin_port);
598 v4chk:
599 if (IN_MULTICAST(in.s_addr))
600 goto bad;
601 switch ((in.s_addr & 0xff000000) >> 24) {
602 case 0: case 127: case 255:
603 goto bad;
604 }
605 if (dg_broadcast(&in))
606 goto bad;
607 break;
608 case AF_INET6:
609 in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
610 port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
611 if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
612 goto bad;
613 /*
614 * OpenBSD does not support IPv4 mapped address (RFC2553
615 * inbound behavior) at all. We should drop it.
616 */
617 if (IN6_IS_ADDR_V4MAPPED(in6))
618 goto bad;
619 if (IN6_IS_ADDR_V4COMPAT(in6)) {
620 memcpy(&in, &in6->s6_addr[12], sizeof(in));
621 in.s_addr = ntohl(in.s_addr);
622 goto v4chk;
623 }
624 break;
625 default:
626 /* XXX unsupported af, is it safe to assume it to be safe? */
627 return 0;
628 }
629
630 return (0);
631
632bad:
633 return (1);
634}
635
636int
637dg_broadcast(struct in_addr *in)
638{
639#ifdef HAVE_GETIFADDRS
640 struct ifaddrs *ifa, *ifap;
641 struct sockaddr_in *sin;
642
643 if (getifaddrs(&ifap) < 0)
644 return (0);
645 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
646 if (ifa->ifa_addr->sa_family != AF_INET ||
647 (ifa->ifa_flags & IFF_BROADCAST) == 0)
648 continue;
649 sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
650 if (sin->sin_addr.s_addr == in->s_addr) {
651 freeifaddrs(ifap);
652 return (1);
653 }
654 }
655 freeifaddrs(ifap);
656#endif
657 return (0);
658}
659
660/* ARGSUSED */
661void
662reap(int sig)
663{
664 wantreap = 1;
665}
666
667void
668doreap(void)
669{
670 struct servtab *sep;
671 int status;
672 pid_t pid;
673
674 if (debug)
675 fprintf(stderr, "reaping asked for\n");
676
677 for (;;) {
678 if ((pid = wait3(&status, WNOHANG, NULL)) <= 0) {
679 if (pid == -1 && errno == EINTR)
680 continue;
681 break;
682 }
683 if (debug)
684 fprintf(stderr, "%ld reaped, status %x\n",
685 (long)pid, status);
686 for (sep = servtab; sep; sep = sep->se_next)
687 if (sep->se_wait == pid) {
688 if (WIFEXITED(status) && WEXITSTATUS(status))
689 syslog(LOG_WARNING,
690 "%s: exit status %d",
691 sep->se_server, WEXITSTATUS(status));
692 else if (WIFSIGNALED(status))
693 syslog(LOG_WARNING,
694 "%s: exit signal %d",
695 sep->se_server, WTERMSIG(status));
696 sep->se_wait = 1;
697 fd_grow(&allsockp, &allsockn, sep->se_fd);
698 FD_SET(sep->se_fd, allsockp);
699 nsock++;
700 if (debug)
701 fprintf(stderr, "restored %s, fd %d\n",
702 sep->se_service, sep->se_fd);
703 }
704 }
705}
706
707/* ARGSUSED */
708void
709config(int sig)
710{
711 wantconfig = 1;
712}
713
714void
715doconfig(void)
716{
717 struct servtab *sep, *cp, **sepp;
718 int add;
719 char protoname[10];
720 sigset_t omask;
721
722 if (!setconfig()) {
723 syslog(LOG_ERR, "%s: %m", CONFIG);
724 exit(1);
725 }
726 for (sep = servtab; sep; sep = sep->se_next)
727 sep->se_checked = 0;
728 cp = getconfigent();
729 while (cp != NULL) {
730 for (sep = servtab; sep; sep = sep->se_next)
731 if (matchconf(sep, cp))
732 break;
733 add = 0;
734 if (sep != NULL) {
735 int i;
736
737#define SWAP(type, a, b) {type c=(type)a; a=(type)b; b=(type)c;}
738
739 sigprocmask(SIG_BLOCK, &blockmask, &omask);
740 /*
741 * sep->se_wait may be holding the pid of a daemon
742 * that we're waiting for. If so, don't overwrite
743 * it unless the config file explicitly says don't
744 * wait.
745 */
746 if (cp->se_bi == 0 &&
747 (sep->se_wait == 1 || cp->se_wait == 0))
748 sep->se_wait = cp->se_wait;
749 SWAP(int, cp->se_max, sep->se_max);
750 SWAP(char *, sep->se_user, cp->se_user);
751 SWAP(char *, sep->se_group, cp->se_group);
752 SWAP(char *, sep->se_server, cp->se_server);
753 for (i = 0; i < MAXARGV; i++)
754 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
755#undef SWAP
756 if (isrpcservice(sep))
757 unregister_rpc(sep);
758 sep->se_rpcversl = cp->se_rpcversl;
759 sep->se_rpcversh = cp->se_rpcversh;
760 sigprocmask(SIG_SETMASK, &omask, NULL);
761 freeconfig(cp);
762 add = 1;
763 } else {
764 sep = enter(cp);
765 }
766 sep->se_checked = 1;
767
768 switch (sep->se_family) {
769 case AF_UNIX:
770 if (sep->se_fd != -1)
771 break;
772 sep->se_ctrladdr_size =
773 strlcpy(sep->se_ctrladdr_un.sun_path,
774 sep->se_service,
775 sizeof sep->se_ctrladdr_un.sun_path);
776 if (sep->se_ctrladdr_size >=
777 sizeof sep->se_ctrladdr_un.sun_path) {
778 syslog(LOG_WARNING, "%s/%s: UNIX domain socket "
779 "path too long", sep->se_service,
780 sep->se_proto);
781 goto serv_unknown;
782 }
783 sep->se_ctrladdr_un.sun_family = AF_UNIX;
784 sep->se_ctrladdr_size +=
785 1 + sizeof sep->se_ctrladdr_un.sun_family;
786 (void)unlink(sep->se_service);
787 setup(sep);
788 break;
789 case AF_INET:
790 sep->se_ctrladdr_in.sin_family = AF_INET;
791 /* se_ctrladdr_in was set in getconfigent */
792 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
793
794 if (isrpcservice(sep)) {
795 struct rpcent *rp;
796
797 sep->se_rpcprog = atoi(sep->se_service);
798 if (sep->se_rpcprog == 0) {
799 rp = getrpcbyname(sep->se_service);
800 if (rp == 0) {
801 syslog(LOG_ERR,
802 "%s: unknown rpc service",
803 sep->se_service);
804 goto serv_unknown;
805 }
806 sep->se_rpcprog = rp->r_number;
807 }
808 if (sep->se_fd == -1)
809 setup(sep);
810 if (sep->se_fd != -1)
811 register_rpc(sep);
812 } else {
813 u_short port = htons(atoi(sep->se_service));
814
815 if (!port) {
816 /* XXX */
817 char *p;
818 strncpy(protoname, sep->se_proto,
819 sizeof(protoname));
820 for (p = protoname; *p; p++)
821 if (isdigit(*p)) {
822 *p = '\0';
823 break;
824 }
825 sp = getservbyname(sep->se_service,
826 protoname);
827 if (sp == 0) {
828 syslog(LOG_ERR,
829 "%s/%s: unknown service",
830 sep->se_service, sep->se_proto);
831 goto serv_unknown;
832 }
833 port = sp->s_port;
834 }
835 if (port != sep->se_ctrladdr_in.sin_port) {
836 sep->se_ctrladdr_in.sin_port = port;
837 if (sep->se_fd != -1) {
838 FD_CLR(sep->se_fd, allsockp);
839 nsock--;
840 (void) close(sep->se_fd);
841 }
842 sep->se_fd = -1;
843 }
844 if (sep->se_fd == -1)
845 setup(sep);
846 }
847 break;
848 case AF_INET6:
849 sep->se_ctrladdr_in6.sin6_family = AF_INET6;
850 /* se_ctrladdr_in was set in getconfigent */
851 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
852
853 if (isrpcservice(sep)) {
854 struct rpcent *rp;
855
856 sep->se_rpcprog = atoi(sep->se_service);
857 if (sep->se_rpcprog == 0) {
858 rp = getrpcbyname(sep->se_service);
859 if (rp == 0) {
860 syslog(LOG_ERR,
861 "%s: unknown rpc service",
862 sep->se_service);
863 goto serv_unknown;
864 }
865 sep->se_rpcprog = rp->r_number;
866 }
867 if (sep->se_fd == -1)
868 setup(sep);
869 if (sep->se_fd != -1)
870 register_rpc(sep);
871 } else {
872 u_short port = htons(atoi(sep->se_service));
873
874 if (!port) {
875 /* XXX */
876 strncpy(protoname, sep->se_proto,
877 sizeof(protoname));
878 if (isdigit(protoname[strlen(protoname) - 1]))
879 protoname[strlen(protoname) - 1] = '\0';
880 sp = getservbyname(sep->se_service,
881 protoname);
882 if (sp == 0) {
883 syslog(LOG_ERR,
884 "%s/%s: unknown service",
885 sep->se_service, sep->se_proto);
886 goto serv_unknown;
887 }
888 port = sp->s_port;
889 }
890 if (port != sep->se_ctrladdr_in6.sin6_port) {
891 sep->se_ctrladdr_in6.sin6_port = port;
892 if (sep->se_fd != -1) {
893 FD_CLR(sep->se_fd, allsockp);
894 nsock--;
895 (void) close(sep->se_fd);
896 }
897 sep->se_fd = -1;
898 }
899 if (sep->se_fd == -1)
900 setup(sep);
901 }
902 break;
903 }
904 serv_unknown:
905 if (cp->se_next != NULL) {
906 struct servtab *tmp = cp;
907
908 cp = cp->se_next;
909 free(tmp);
910 } else {
911 free(cp);
912 cp = getconfigent();
913 }
914 if (debug)
915 print_service(add ? "REDO" : "ADD", sep);
916 }
917 endconfig();
918 /*
919 * Purge anything not looked at above.
920 */
921 sigprocmask(SIG_BLOCK, &blockmask, &omask);
922 sepp = &servtab;
923 while ((sep = *sepp)) {
924 if (sep->se_checked) {
925 sepp = &sep->se_next;
926 continue;
927 }
928 *sepp = sep->se_next;
929 if (sep->se_fd != -1) {
930 FD_CLR(sep->se_fd, allsockp);
931 nsock--;
932 (void) close(sep->se_fd);
933 }
934 if (isrpcservice(sep))
935 unregister_rpc(sep);
936 if (sep->se_family == AF_UNIX)
937 (void)unlink(sep->se_service);
938 if (debug)
939 print_service("FREE", sep);
940 freeconfig(sep);
941 free(sep);
942 }
943 sigprocmask(SIG_SETMASK, &omask, NULL);
944}
945
946/* ARGSUSED */
947void
948retry(int sig)
949{
950 wantretry = 1;
951}
952
953void
954doretry(void)
955{
956 struct servtab *sep;
957
958 timingout = 0;
959 for (sep = servtab; sep; sep = sep->se_next) {
960 if (sep->se_fd == -1) {
961 switch (sep->se_family) {
962 case AF_UNIX:
963 case AF_INET:
964 case AF_INET6:
965 setup(sep);
966 if (sep->se_fd != -1 && isrpcservice(sep))
967 register_rpc(sep);
968 break;
969 }
970 }
971 }
972}
973
974/* ARGSUSED */
975void
976die(int sig)
977{
978 wantdie = 1;
979}
980
981void
982dodie(void)
983{
984 struct servtab *sep;
985
986 for (sep = servtab; sep; sep = sep->se_next) {
987 if (sep->se_fd == -1)
988 continue;
989
990 switch (sep->se_family) {
991 case AF_UNIX:
992 (void)unlink(sep->se_service);
993 break;
994 case AF_INET:
995 case AF_INET6:
996 if (sep->se_wait == 1 && isrpcservice(sep))
997 unregister_rpc(sep);
998 break;
999 }
1000 (void)close(sep->se_fd);
1001 }
1002 (void)unlink(_PATH_INETDPID);
1003 exit(0);
1004}
1005
1006void
1007setup(struct servtab *sep)
1008{
1009 int on = 1;
1010 int r;
1011 mode_t mask = 0;
1012
1013 if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
1014 syslog(LOG_ERR, "%s/%s: socket: %m",
1015 sep->se_service, sep->se_proto);
1016 return;
1017 }
1018 if (strncmp(sep->se_proto, "tcp6", 4) == 0) {
1019 if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY, &on,
1020 sizeof (on)) < 0)
1021 syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m");
1022 } else if (strncmp(sep->se_proto, "tcp46", 5) == 0) {
1023 int off = 0;
1024 if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY, &off,
1025 sizeof (off)) < 0)
1026 syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m");
1027 }
1028#define turnon(fd, opt) \
1029setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on))
1030 if (strncmp(sep->se_proto, "tcp", 3) == 0 && (options & SO_DEBUG) &&
1031 turnon(sep->se_fd, SO_DEBUG) < 0)
1032 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
1033 if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
1034 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
1035#undef turnon
1036 if (isrpcservice(sep)) {
1037 struct passwd *pwd;
1038
1039 /*
1040 * for RPC services, attempt to use a reserved port
1041 * if they are going to be running as root.
1042 *
1043 * Also, zero out the port for all RPC services; let bind()
1044 * find one.
1045 */
1046 sep->se_ctrladdr_in.sin_port = 0;
1047 if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
1048 pwd->pw_uid == 0 && uid == 0)
1049 r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
1050 else {
1051 r = bind(sep->se_fd, &sep->se_ctrladdr,
1052 sep->se_ctrladdr_size);
1053 if (r == 0) {
1054 socklen_t len = sep->se_ctrladdr_size;
1055 int saveerrno = errno;
1056
1057 /* update se_ctrladdr_in.sin_port */
1058 r = getsockname(sep->se_fd, &sep->se_ctrladdr,
1059 &len);
1060 if (r <= 0)
1061 errno = saveerrno;
1062 }
1063 }
1064 } else {
1065 if (sep->se_family == AF_UNIX)
1066 mask = umask(0111);
1067 r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
1068 if (sep->se_family == AF_UNIX)
1069 umask(mask);
1070 }
1071 if (r < 0) {
1072 syslog(LOG_ERR, "%s/%s: bind: %m",
1073 sep->se_service, sep->se_proto);
1074 (void) close(sep->se_fd);
1075 sep->se_fd = -1;
1076 if (!timingout) {
1077 timingout = 1;
1078 alarm(RETRYTIME);
1079 }
1080 return;
1081 }
1082 if (sep->se_socktype == SOCK_STREAM)
1083 listen(sep->se_fd, global_queuelen);
1084
1085 fd_grow(&allsockp, &allsockn, sep->se_fd);
1086 FD_SET(sep->se_fd, allsockp);
1087 nsock++;
1088 if (sep->se_fd > maxsock) {
1089 maxsock = sep->se_fd;
1090 if (maxsock > rlim_nofile_cur - FD_MARGIN)
1091 bump_nofile();
1092 }
1093}
1094
1095void
1096register_rpc(struct servtab *sep)
1097{
1098 socklen_t n;
1099 struct sockaddr_in sin;
1100 struct protoent *pp;
1101
1102 if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
1103 syslog(LOG_ERR, "%s: getproto: %m",
1104 sep->se_proto);
1105 return;
1106 }
1107 n = sizeof sin;
1108 if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
1109 syslog(LOG_ERR, "%s/%s: getsockname: %m",
1110 sep->se_service, sep->se_proto);
1111 return;
1112 }
1113
1114 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1115 if (debug)
1116 fprintf(stderr, "pmap_set: %u %u %u %u\n",
1117 sep->se_rpcprog, n, pp->p_proto,
1118 ntohs(sin.sin_port));
1119 (void)pmap_unset(sep->se_rpcprog, n);
1120 if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
1121 syslog(LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
1122 sep->se_service, sep->se_proto,
1123 sep->se_rpcprog, n, pp->p_proto,
1124 ntohs(sin.sin_port));
1125 }
1126}
1127
1128void
1129unregister_rpc(struct servtab *sep)
1130{
1131 int n;
1132
1133 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1134 if (debug)
1135 fprintf(stderr, "pmap_unset(%u, %u)\n",
1136 sep->se_rpcprog, n);
1137 if (!pmap_unset(sep->se_rpcprog, n))
1138 syslog(LOG_ERR, "pmap_unset(%u, %u)",
1139 sep->se_rpcprog, n);
1140 }
1141}
1142
1143
1144struct servtab *
1145enter(struct servtab *cp)
1146{
1147 struct servtab *sep;
1148 sigset_t omask;
1149
1150 sep = (struct servtab *)malloc(sizeof (*sep));
1151 if (sep == NULL) {
1152 syslog(LOG_ERR, "Out of memory.");
1153 exit(1);
1154 }
1155 *sep = *cp;
1156 sep->se_fd = -1;
1157 sep->se_rpcprog = -1;
1158 sigprocmask(SIG_BLOCK, &blockmask, &omask);
1159 sep->se_next = servtab;
1160 servtab = sep;
1161 sigprocmask(SIG_SETMASK, &omask, NULL);
1162 return (sep);
1163}
1164
1165int
1166matchconf(struct servtab *old, struct servtab *new)
1167{
1168 if (strcmp(old->se_service, new->se_service) != 0)
1169 return (0);
1170
1171 if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
1172 return (0);
1173
1174 if (strcmp(old->se_proto, new->se_proto) != 0)
1175 return (0);
1176
1177 /*
1178 * If the new servtab is bound to a specific address, check that the
1179 * old servtab is bound to the same entry. If the new service is not
1180 * bound to a specific address then the check of se_hostaddr above
1181 * is sufficient.
1182 */
1183
1184 if (old->se_family == AF_INET && new->se_family == AF_INET &&
1185 bcmp(&old->se_ctrladdr_in.sin_addr,
1186 &new->se_ctrladdr_in.sin_addr,
1187 sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
1188 return (0);
1189
1190 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
1191 bcmp(&old->se_ctrladdr_in6.sin6_addr,
1192 &new->se_ctrladdr_in6.sin6_addr,
1193 sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
1194 return (0);
1195 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
1196 old->se_ctrladdr_in6.sin6_scope_id !=
1197 new->se_ctrladdr_in6.sin6_scope_id)
1198 return (0);
1199
1200 return (1);
1201}
1202
1203FILE *fconfig = NULL;
1204char line[1024];
1205char *defhost;
1206char *skip(char **, int);
1207char *nextline(FILE *);
1208char *newstr(char *);
1209struct servtab *dupconfig(struct servtab *);
1210
1211int
1212setconfig(void)
1213{
1214 if (defhost)
1215 free(defhost);
1216 defhost = newstr("*");
1217 if (fconfig != NULL) {
1218 fseek(fconfig, 0L, SEEK_SET);
1219 return (1);
1220 }
1221 fconfig = fopen(CONFIG, "r");
1222 return (fconfig != NULL);
1223}
1224
1225void
1226endconfig(void)
1227{
1228 if (fconfig) {
1229 (void) fclose(fconfig);
1230 fconfig = NULL;
1231 }
1232 if (defhost) {
1233 free(defhost);
1234 defhost = 0;
1235 }
1236}
1237
1238struct servtab *
1239getconfigent(void)
1240{
1241 struct servtab *sep, *tsep;
1242 char *arg, *cp, *hostdelim, *s;
1243 int argc;
1244
1245 sep = (struct servtab *) malloc(sizeof(struct servtab));
1246 if (sep == NULL) {
1247 syslog(LOG_ERR, "malloc: %m");
1248 exit(1);
1249 }
1250
1251 memset(sep, 0, sizeof *sep);
1252more:
1253 freeconfig(sep);
1254
1255 while ((cp = nextline(fconfig)) && *cp == '#')
1256 ;
1257 if (cp == NULL) {
1258 free(sep);
1259 return (NULL);
1260 }
1261
1262 memset(sep, 0, sizeof *sep);
1263 arg = skip(&cp, 0);
1264 if (arg == NULL) {
1265 /* A blank line. */
1266 goto more;
1267 }
1268
1269 /* Check for a host name. */
1270 hostdelim = strrchr(arg, ':');
1271 if (hostdelim) {
1272 *hostdelim = '\0';
1273 if (arg[0] == '[' && hostdelim > arg && hostdelim[-1] == ']') {
1274 hostdelim[-1] = '\0';
1275 sep->se_hostaddr = newstr(arg + 1);
1276 } else if (hostdelim == arg)
1277 sep->se_hostaddr = newstr("*");
1278 else
1279 sep->se_hostaddr = newstr(arg);
1280 arg = hostdelim + 1;
1281 /*
1282 * If the line is of the form `host:', then just change the
1283 * default host for the following lines.
1284 */
1285 if (*arg == '\0') {
1286 arg = skip(&cp, 0);
1287 if (cp == NULL) {
1288 free(defhost);
1289 defhost = newstr(sep->se_hostaddr);
1290 goto more;
1291 }
1292 }
1293 } else
1294 sep->se_hostaddr = newstr(defhost);
1295
1296 sep->se_service = newstr(arg);
1297 if ((arg = skip(&cp, 1)) == NULL)
1298 goto more;
1299
1300 if (strcmp(arg, "stream") == 0)
1301 sep->se_socktype = SOCK_STREAM;
1302 else if (strcmp(arg, "dgram") == 0)
1303 sep->se_socktype = SOCK_DGRAM;
1304 else if (strcmp(arg, "rdm") == 0)
1305 sep->se_socktype = SOCK_RDM;
1306 else if (strcmp(arg, "seqpacket") == 0)
1307 sep->se_socktype = SOCK_SEQPACKET;
1308 else if (strcmp(arg, "raw") == 0)
1309 sep->se_socktype = SOCK_RAW;
1310 else
1311 sep->se_socktype = -1;
1312
1313 if ((arg = skip(&cp, 1)) == NULL)
1314 goto more;
1315
1316 sep->se_proto = newstr(arg);
1317
1318 if (strcmp(sep->se_proto, "unix") == 0) {
1319 sep->se_family = AF_UNIX;
1320 } else {
1321 int s;
1322
1323 sep->se_family = AF_INET;
1324 if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
1325 sep->se_family = AF_INET6;
1326
1327 /* check if the family is supported */
1328 s = socket(sep->se_family, SOCK_DGRAM, 0);
1329 if (s < 0) {
1330 syslog(LOG_WARNING, "%s/%s: %s: the address family is "
1331 "not supported by the kernel", sep->se_service,
1332 sep->se_proto, sep->se_hostaddr);
1333 goto more;
1334 }
1335 close(s);
1336
1337 if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1338 char *cp, *ccp;
1339 long l;
1340
1341 cp = strchr(sep->se_service, '/');
1342 if (cp == 0) {
1343 syslog(LOG_ERR, "%s: no rpc version",
1344 sep->se_service);
1345 goto more;
1346 }
1347 *cp++ = '\0';
1348 l = strtol(cp, &ccp, 0);
1349 if (ccp == cp || l < 0 || l > INT_MAX) {
1350 badafterall:
1351 syslog(LOG_ERR, "%s/%s: bad rpc version",
1352 sep->se_service, cp);
1353 goto more;
1354 }
1355 sep->se_rpcversl = sep->se_rpcversh = l;
1356 if (*ccp == '-') {
1357 cp = ccp + 1;
1358 l = strtol(cp, &ccp, 0);
1359 if (ccp == cp || l < 0 || l > INT_MAX ||
1360 l < sep->se_rpcversl || *ccp)
1361 goto badafterall;
1362 sep->se_rpcversh = l;
1363 } else if (*ccp != '\0')
1364 goto badafterall;
1365 }
1366 }
1367 arg = skip(&cp, 1);
1368 if (arg == NULL)
1369 goto more;
1370
1371 s = strchr(arg, '.');
1372 if (s) {
1373 char *p;
1374
1375 *s++ = '\0';
1376 sep->se_max = strtoul(s, &p, 0);
1377 if (sep->se_max < 1 || *p) {
1378 syslog(LOG_ERR,
1379 "%s: illegal max field \"%s\", setting to %d",
1380 sep->se_service, s, toomany);
1381 sep->se_max = toomany;
1382 }
1383 } else
1384 sep->se_max = toomany;
1385
1386 sep->se_wait = strcmp(arg, "wait") == 0;
1387 if ((arg = skip(&cp, 1)) == NULL)
1388 goto more;
1389 sep->se_user = newstr(arg);
1390 arg = strchr(sep->se_user, '.');
1391 if (arg == NULL)
1392 arg = strchr(sep->se_user, ':');
1393 if (arg) {
1394 *arg++ = '\0';
1395 sep->se_group = newstr(arg);
1396 }
1397 if ((arg = skip(&cp, 1)) == NULL)
1398 goto more;
1399
1400 sep->se_server = newstr(arg);
1401 if (strcmp(sep->se_server, "internal") == 0) {
1402 struct biltin *bi;
1403
1404 for (bi = biltins; bi->bi_service; bi++)
1405 if (bi->bi_socktype == sep->se_socktype &&
1406 strcmp(bi->bi_service, sep->se_service) == 0)
1407 break;
1408 if (bi->bi_service == 0) {
1409 syslog(LOG_ERR, "internal service %s unknown",
1410 sep->se_service);
1411 goto more;
1412 }
1413 sep->se_bi = bi;
1414 sep->se_wait = bi->bi_wait;
1415 } else
1416 sep->se_bi = NULL;
1417 argc = 0;
1418 for (arg = skip(&cp, 0); cp; arg = skip(&cp, 0)) {
1419 if (argc < MAXARGV)
1420 sep->se_argv[argc++] = newstr(arg);
1421 }
1422 if (argc == 0 && sep->se_bi == NULL) {
1423 if ((arg = strrchr(sep->se_server, '/')) != NULL)
1424 arg++;
1425 else
1426 arg = sep->se_server;
1427 sep->se_argv[argc++] = newstr(arg);
1428 }
1429 while (argc <= MAXARGV)
1430 sep->se_argv[argc++] = NULL;
1431
1432 /*
1433 * Resolve each hostname in the se_hostaddr list (if any)
1434 * and create a new entry for each resolved address.
1435 */
1436 if (sep->se_hostaddr != NULL && strcmp(sep->se_proto, "unix") != 0) {
1437 struct addrinfo hints, *res0, *res;
1438 char *host, *hostlist0, *hostlist, *port;
1439 int error;
1440
1441 hostlist = hostlist0 = sep->se_hostaddr;
1442 sep->se_hostaddr = NULL;
1443 sep->se_checked = -1;
1444 while ((host = strsep(&hostlist, ",")) != NULL) {
1445 if (*host == '\0')
1446 continue;
1447
1448 memset(&hints, 0, sizeof(hints));
1449 hints.ai_family = sep->se_family;
1450 hints.ai_socktype = sep->se_socktype;
1451 hints.ai_flags = AI_PASSIVE;
1452 port = "0";
1453 /* XXX shortened IPv4 syntax is now forbidden */
1454 error = getaddrinfo(strcmp(host, "*") ? host : NULL,
1455 port, &hints, &res0);
1456 if (error) {
1457 syslog(LOG_ERR, "%s/%s: %s: %s",
1458 sep->se_service, sep->se_proto,
1459 host, gai_strerror(error));
1460 continue;
1461 }
1462 for (res = res0; res; res = res->ai_next) {
1463 if (res->ai_addrlen >
1464 sizeof(sep->se_ctrladdr_storage))
1465 continue;
1466 /*
1467 * If sep is unused, store host in there.
1468 * Otherwise, dup a new entry and prepend it.
1469 */
1470 if (sep->se_checked == -1) {
1471 sep->se_checked = 0;
1472 } else {
1473 tsep = dupconfig(sep);
1474 tsep->se_next = sep;
1475 sep = tsep;
1476 }
1477 sep->se_hostaddr = newstr(host);
1478 memcpy(&sep->se_ctrladdr_storage,
1479 res->ai_addr, res->ai_addrlen);
1480 sep->se_ctrladdr_size = res->ai_addrlen;
1481 }
1482 freeaddrinfo(res0);
1483 }
1484 free(hostlist0);
1485 if (sep->se_checked == -1)
1486 goto more; /* no resolvable names/addresses */
1487 }
1488
1489 return (sep);
1490}
1491
1492void
1493freeconfig(struct servtab *cp)
1494{
1495 int i;
1496
1497 free(cp->se_hostaddr);
1498 cp->se_hostaddr = NULL;
1499 free(cp->se_service);
1500 cp->se_service = NULL;
1501 free(cp->se_proto);
1502 cp->se_proto = NULL;
1503 free(cp->se_user);
1504 cp->se_user = NULL;
1505 free(cp->se_group);
1506 cp->se_group = NULL;
1507 free(cp->se_server);
1508 cp->se_server = NULL;
1509 for (i = 0; i < MAXARGV; i++) {
1510 free(cp->se_argv[i]);
1511 cp->se_argv[i] = NULL;
1512 }
1513}
1514
1515char *
1516skip(char **cpp, int report)
1517{
1518 char *cp = *cpp;
1519 char *start;
1520
1521erp:
1522 if (*cpp == NULL) {
1523 if (report)
1524 syslog(LOG_ERR, "syntax error in inetd config file");
1525 return (NULL);
1526 }
1527
1528again:
1529 while (*cp == ' ' || *cp == '\t')
1530 cp++;
1531 if (*cp == '\0') {
1532 int c;
1533
1534 c = getc(fconfig);
1535 (void) ungetc(c, fconfig);
1536 if (c == ' ' || c == '\t')
1537 if ((cp = nextline(fconfig)))
1538 goto again;
1539 *cpp = NULL;
1540 goto erp;
1541 }
1542 start = cp;
1543 while (*cp && *cp != ' ' && *cp != '\t')
1544 cp++;
1545 if (*cp != '\0')
1546 *cp++ = '\0';
1547 if ((*cpp = cp) == NULL)
1548 goto erp;
1549
1550 return (start);
1551}
1552
1553char *
1554nextline(FILE *fd)
1555{
1556 if (fgets(line, sizeof (line), fd) == NULL)
1557 return (NULL);
1558 line[strcspn(line, "\n")] = '\0';
1559 return (line);
1560}
1561
1562char *
1563newstr(char *cp)
1564{
1565 if ((cp = strdup(cp ? cp : "")))
1566 return(cp);
1567 syslog(LOG_ERR, "strdup: %m");
1568 exit(1);
1569}
1570
1571struct servtab *
1572dupconfig(struct servtab *sep)
1573{
1574 struct servtab *newtab;
1575 int argc;
1576
1577 newtab = (struct servtab *) malloc(sizeof(struct servtab));
1578
1579 if (newtab == NULL) {
1580 syslog(LOG_ERR, "malloc: %m");
1581 exit(1);
1582 }
1583
1584 memset(newtab, 0, sizeof(struct servtab));
1585
1586 newtab->se_service = sep->se_service ? newstr(sep->se_service) : NULL;
1587 newtab->se_socktype = sep->se_socktype;
1588 newtab->se_family = sep->se_family;
1589 newtab->se_proto = sep->se_proto ? newstr(sep->se_proto) : NULL;
1590 newtab->se_rpcprog = sep->se_rpcprog;
1591 newtab->se_rpcversl = sep->se_rpcversl;
1592 newtab->se_rpcversh = sep->se_rpcversh;
1593 newtab->se_wait = sep->se_wait;
1594 newtab->se_user = sep->se_user ? newstr(sep->se_user) : NULL;
1595 newtab->se_group = sep->se_group ? newstr(sep->se_group) : NULL;
1596 newtab->se_bi = sep->se_bi;
1597 newtab->se_server = sep->se_server ? newstr(sep->se_server) : 0;
1598
1599 for (argc = 0; argc <= MAXARGV; argc++)
1600 newtab->se_argv[argc] = sep->se_argv[argc] ?
1601 newstr(sep->se_argv[argc]) : NULL;
1602 newtab->se_max = sep->se_max;
1603
1604 return (newtab);
1605}
1606
1607void
1608inetd_setproctitle(char *a, int s)
1609{
1610 socklen_t size;
1611 struct sockaddr_storage ss;
1612 char hbuf[NI_MAXHOST];
1613
1614 size = sizeof(ss);
1615 if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
1616 if (getnameinfo((struct sockaddr *)&ss, size, hbuf,
1617 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0)
1618 setproctitle("-%s [%s]", a, hbuf);
1619 else
1620 setproctitle("-%s [?]", a);
1621 } else
1622 setproctitle("-%s", a);
1623}
1624
1625void
1626logpid(void)
1627{
1628 FILE *fp;
1629
1630 if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
1631 fprintf(fp, "%ld\n", (long)getpid());
1632 (void)fclose(fp);
1633 }
1634}
1635
1636int
1637bump_nofile(void)
1638{
1639#define FD_CHUNK 32
1640
1641 struct rlimit rl;
1642
1643 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1644 syslog(LOG_ERR, "getrlimit: %m");
1645 return -1;
1646 }
1647 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1648 rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
1649 if (rl.rlim_cur <= rlim_nofile_cur) {
1650 syslog(LOG_ERR,
1651 "bump_nofile: cannot extend file limit, max = %d",
1652 (int)rl.rlim_cur);
1653 return -1;
1654 }
1655
1656 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1657 syslog(LOG_ERR, "setrlimit: %m");
1658 return -1;
1659 }
1660
1661 rlim_nofile_cur = rl.rlim_cur;
1662 return 0;
1663}
1664
1665/*
1666 * Internet services provided internally by inetd:
1667 */
1668#define BUFSIZE 4096
1669
1670/* ARGSUSED */
1671void
1672echo_stream(int s, struct servtab *sep)
1673{
1674 char buffer[BUFSIZE];
1675 int i;
1676
1677 inetd_setproctitle(sep->se_service, s);
1678 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1679 write(s, buffer, i) > 0)
1680 ;
1681 exit(0);
1682}
1683
1684/* ARGSUSED */
1685void
1686echo_dg(int s, struct servtab *sep)
1687{
1688 char buffer[BUFSIZE];
1689 int i;
1690 socklen_t size;
1691 struct sockaddr_storage ss;
1692
1693 size = sizeof(ss);
1694 if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
1695 (struct sockaddr *)&ss, &size)) < 0)
1696 return;
1697 if (dg_badinput((struct sockaddr *)&ss))
1698 return;
1699 (void) sendto(s, buffer, i, 0, (struct sockaddr *)&ss, size);
1700}
1701
1702/* ARGSUSED */
1703void
1704discard_stream(int s, struct servtab *sep)
1705{
1706 char buffer[BUFSIZE];
1707
1708 inetd_setproctitle(sep->se_service, s);
1709 while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1710 errno == EINTR)
1711 ;
1712 exit(0);
1713}
1714
1715/* ARGSUSED */
1716void
1717discard_dg(int s, struct servtab *sep)
1718{
1719 char buffer[BUFSIZE];
1720
1721 (void) read(s, buffer, sizeof(buffer));
1722}
1723
1724#include <ctype.h>
1725#define LINESIZ 72
1726char ring[128];
1727char *endring;
1728
1729void
1730initring(void)
1731{
1732 int i;
1733
1734 endring = ring;
1735
1736 for (i = 0; i <= sizeof ring; ++i)
1737 if (isprint(i))
1738 *endring++ = i;
1739}
1740
1741/* ARGSUSED */
1742void
1743chargen_stream(int s, struct servtab *sep)
1744{
1745 char *rs;
1746 int len;
1747 char text[LINESIZ+2];
1748
1749 inetd_setproctitle(sep->se_service, s);
1750
1751 if (!endring) {
1752 initring();
1753 rs = ring;
1754 }
1755
1756 text[LINESIZ] = '\r';
1757 text[LINESIZ + 1] = '\n';
1758 for (rs = ring;;) {
1759 if ((len = endring - rs) >= LINESIZ)
1760 memmove(text, rs, LINESIZ);
1761 else {
1762 memmove(text, rs, len);
1763 memmove(text + len, ring, LINESIZ - len);
1764 }
1765 if (++rs == endring)
1766 rs = ring;
1767 if (write(s, text, sizeof(text)) != sizeof(text))
1768 break;
1769 }
1770 exit(0);
1771}
1772
1773/* ARGSUSED */
1774void
1775chargen_dg(int s, struct servtab *sep)
1776{
1777 struct sockaddr_storage ss;
1778 static char *rs;
1779 int len;
1780 socklen_t size;
1781 char text[LINESIZ+2];
1782
1783 if (endring == 0) {
1784 initring();
1785 rs = ring;
1786 }
1787
1788 size = sizeof(ss);
1789 if (recvfrom(s, text, sizeof(text), 0, (struct sockaddr *)&ss,
1790 &size) < 0)
1791 return;
1792 if (dg_badinput((struct sockaddr *)&ss))
1793 return;
1794
1795 if ((len = endring - rs) >= LINESIZ)
1796 memmove(text, rs, LINESIZ);
1797 else {
1798 memmove(text, rs, len);
1799 memmove(text + len, ring, LINESIZ - len);
1800 }
1801 if (++rs == endring)
1802 rs = ring;
1803 text[LINESIZ] = '\r';
1804 text[LINESIZ + 1] = '\n';
1805 (void) sendto(s, text, sizeof(text), 0, (struct sockaddr *)&ss, size);
1806}
1807
1808/*
1809 * Return a machine readable date and time, in the form of the
1810 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1811 * returns the number of seconds since midnight, Jan 1, 1970,
1812 * we must add 2208988800 seconds to this figure to make up for
1813 * some seventy years Bell Labs was asleep.
1814 */
1815u_int32_t
1816machtime(void)
1817{
1818 struct timeval tv;
1819
1820 if (gettimeofday(&tv, NULL) < 0)
1821 return (0L);
1822
1823 return (htonl((u_int32_t)tv.tv_sec + 2208988800UL));
1824}
1825
1826/* ARGSUSED */
1827void
1828machtime_stream(s, sep)
1829 int s;
1830 struct servtab *sep;
1831{
1832 u_int32_t result;
1833
1834 result = machtime();
1835 (void) write(s, &result, sizeof(result));
1836}
1837
1838/* ARGSUSED */
1839void
1840machtime_dg(int s, struct servtab *sep)
1841{
1842 u_int32_t result;
1843 struct sockaddr_storage ss;
1844 socklen_t size;
1845
1846 size = sizeof(ss);
1847 if (recvfrom(s, &result, sizeof(result), 0,
1848 (struct sockaddr *)&ss, &size) < 0)
1849 return;
1850 if (dg_badinput((struct sockaddr *)&ss))
1851 return;
1852 result = machtime();
1853 (void) sendto(s, &result, sizeof(result), 0,
1854 (struct sockaddr *)&ss, size);
1855}
1856
1857/* Return human-readable time of day */
1858/* ARGSUSED */
1859void
1860daytime_stream(int s, struct servtab *sep)
1861{
1862 char buffer[256];
1863 time_t clock;
1864
1865 clock = time(NULL);
1866
1867 (void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1868 (void) write(s, buffer, strlen(buffer));
1869}
1870
1871/* Return human-readable time of day */
1872/* ARGSUSED */
1873void
1874daytime_dg(int s, struct servtab *sep)
1875{
1876 char buffer[256];
1877 time_t clock;
1878 struct sockaddr_storage ss;
1879 socklen_t size;
1880
1881 clock = time(NULL);
1882
1883 size = sizeof(ss);
1884 if (recvfrom(s, buffer, sizeof(buffer), 0, (struct sockaddr *)&ss,
1885 &size) < 0)
1886 return;
1887 if (dg_badinput((struct sockaddr *)&ss))
1888 return;
1889 (void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1890 (void) sendto(s, buffer, strlen(buffer), 0, (struct sockaddr *)&ss,
1891 size);
1892}
1893
1894/*
1895 * print_service:
1896 * Dump relevant information to stderr
1897 */
1898void
1899print_service(char *action, struct servtab *sep)
1900{
1901 if (strcmp(sep->se_hostaddr, "*") == 0)
1902 fprintf(stderr, "%s: %s ", action, sep->se_service);
1903 else
1904 fprintf(stderr, "%s: %s:%s ", action, sep->se_hostaddr,
1905 sep->se_service);
1906
1907 if (isrpcservice(sep))
1908 fprintf(stderr, "rpcprog=%d, rpcvers=%d/%d, proto=%s,",
1909 sep->se_rpcprog, sep->se_rpcversh,
1910 sep->se_rpcversl, sep->se_proto);
1911 else
1912 fprintf(stderr, "proto=%s,", sep->se_proto);
1913
1914 fprintf(stderr,
1915 " wait.max=%hd.%d user:group=%s:%s builtin=%lx server=%s\n",
1916 sep->se_wait, sep->se_max, sep->se_user,
1917 sep->se_group ? sep->se_group : "(default)",
1918 (long)sep->se_bi, sep->se_server);
1919}
1920
1921void
1922spawn(struct servtab *sep, int ctrl)
1923{
1924 struct passwd *pwd;
1925 int tmpint, dofork;
1926 struct group *grp = NULL;
1927 char buf[50];
1928 pid_t pid;
1929
1930 pid = 0;
1931 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
1932 if (dofork) {
1933 if (sep->se_count++ == 0)
1934 (void)gettimeofday(&sep->se_time, NULL);
1935 else if (sep->se_count >= sep->se_max) {
1936 struct timeval now;
1937
1938 (void)gettimeofday(&now, NULL);
1939 if (now.tv_sec - sep->se_time.tv_sec >
1940 CNT_INTVL) {
1941 sep->se_time = now;
1942 sep->se_count = 1;
1943 } else {
1944 if (!sep->se_wait &&
1945 sep->se_socktype == SOCK_STREAM)
1946 close(ctrl);
1947 if (sep->se_family == AF_INET &&
1948 ntohs(sep->se_ctrladdr_in.sin_port) >=
1949 IPPORT_RESERVED) {
1950 /*
1951 * Cannot close it -- there are
1952 * thieves on the system.
1953 * Simply ignore the connection.
1954 */
1955 --sep->se_count;
1956 sigprocmask(SIG_SETMASK, &emptymask,
1957 NULL);
1958 return;
1959 }
1960 syslog(LOG_ERR,
1961 "%s/%s server failing (looping), service terminated for %d min",
1962 sep->se_service, sep->se_proto,
1963 RETRYTIME/60);
1964 if (!sep->se_wait &&
1965 sep->se_socktype == SOCK_STREAM)
1966 close(ctrl);
1967 FD_CLR(sep->se_fd, allsockp);
1968 (void) close(sep->se_fd);
1969 sep->se_fd = -1;
1970 sep->se_count = 0;
1971 nsock--;
1972 sigprocmask(SIG_SETMASK, &emptymask,
1973 NULL);
1974 if (!timingout) {
1975 timingout = 1;
1976 alarm(RETRYTIME);
1977 }
1978 return;
1979 }
1980 }
1981 pid = fork();
1982 }
1983 if (pid < 0) {
1984 syslog(LOG_ERR, "fork: %m");
1985 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1986 close(ctrl);
1987 sigprocmask(SIG_SETMASK, &emptymask, NULL);
1988 sleep(1);
1989 return;
1990 }
1991 if (pid && sep->se_wait) {
1992 sep->se_wait = pid;
1993 FD_CLR(sep->se_fd, allsockp);
1994 nsock--;
1995 }
1996 sigprocmask(SIG_SETMASK, &emptymask, NULL);
1997 if (pid == 0) {
1998#ifdef LIBWRAP
1999 if (lflag && !sep->se_wait && sep->se_socktype == SOCK_STREAM) {
2000 struct request_info req;
2001 char *service;
2002
2003 /* do not execute tcpd if it is in the config */
2004 if (strcmp(sep->se_server, "/usr/sbin/tcpd") == 0) {
2005 char *p, *name;
2006
2007 free(sep->se_server);
2008 name = sep->se_server = sep->se_argv[0];
2009 for (p = name; *p; p++)
2010 if (*p == '/')
2011 name = p + 1;
2012 sep->se_argv[0] = newstr(name);
2013 }
2014
2015 request_init(&req, RQ_DAEMON, sep->se_argv[0],
2016 RQ_FILE, ctrl, NULL);
2017 fromhost(&req);
2018 if (getnameinfo(&sep->se_ctrladdr,
2019 sizeof(sep->se_ctrladdr), NULL, 0, buf,
2020 sizeof(buf), 0) != 0) {
2021 /* shouldn't happen */
2022 snprintf(buf, sizeof buf, "%d",
2023 ntohs(sep->se_ctrladdr_in.sin_port));
2024 }
2025 service = buf;
2026 if (!hosts_access(&req)) {
2027 syslog(deny_severity, "refused connection"
2028 " from %.500s, service %s (%s)",
2029 eval_client(&req), service, sep->se_proto);
2030 if (sep->se_socktype != SOCK_STREAM)
2031 recv(0, buf, sizeof (buf), 0);
2032 exit(1);
2033 }
2034 syslog(allow_severity,
2035 "connection from %.500s, service %s (%s)",
2036 eval_client(&req), service, sep->se_proto);
2037 }
2038#endif
2039 if (sep->se_bi)
2040 (*sep->se_bi->bi_fn)(ctrl, sep);
2041 else {
2042 if ((pwd = getpwnam(sep->se_user)) == NULL) {
2043 syslog(LOG_ERR,
2044 "getpwnam: %s: No such user",
2045 sep->se_user);
2046 if (sep->se_socktype != SOCK_STREAM)
2047 recv(0, buf, sizeof (buf), 0);
2048 exit(1);
2049 }
2050 if (setsid() <0)
2051 syslog(LOG_ERR, "%s: setsid: %m",
2052 sep->se_service);
2053 if (sep->se_group &&
2054 (grp = getgrnam(sep->se_group)) == NULL) {
2055 syslog(LOG_ERR,
2056 "getgrnam: %s: No such group",
2057 sep->se_group);
2058 if (sep->se_socktype != SOCK_STREAM)
2059 recv(0, buf, sizeof (buf), 0);
2060 exit(1);
2061 }
2062 if (uid != 0) {
2063 /* a user running private inetd */
2064 if (uid != pwd->pw_uid)
2065 exit(1);
2066 } else {
2067#ifdef HAVE_SETUSERCONTEXT
2068 tmpint = LOGIN_SETALL &
2069 ~(LOGIN_SETGROUP|LOGIN_SETLOGIN);
2070 if (pwd->pw_uid)
2071 tmpint |= LOGIN_SETGROUP|LOGIN_SETLOGIN;
2072 if (sep->se_group) {
2073 pwd->pw_gid = grp->gr_gid;
2074 tmpint |= LOGIN_SETGROUP;
2075 }
2076 if (setusercontext(NULL, pwd, pwd->pw_uid,
2077 tmpint) < 0) {
2078 syslog(LOG_ERR,
2079 "%s/%s: setusercontext: %m",
2080 sep->se_service, sep->se_proto);
2081 exit(1);
2082 }
2083#else
2084 /* what about setpriority(2), setrlimit(2),
2085 * and umask(2)? The $PATH is cleared.
2086 */
2087 if (pwd->pw_uid) {
2088 if (sep->se_group)
2089 pwd->pw_gid = grp->gr_gid;
2090 if (setgid(pwd->pw_gid) < 0) {
2091 syslog(LOG_ERR,
2092 "%s/%s: can't set gid %d: %m",
2093 sep->se_service, sep->se_proto,
2094 pwd->pw_gid);
2095 exit(1);
2096 }
2097 if (initgroups(pwd->pw_name, pwd->pw_gid)
2098 < 0) {
2099 syslog(LOG_ERR,
2100 "%s/%s: can't initgroups(%s): %m",
2101 sep->se_service, sep->se_proto,
2102 pwd->pw_name);
2103 exit(1);
2104 }
2105 if (setuid(pwd->pw_uid) < 0) {
2106 syslog(LOG_ERR,
2107 "%s/%s: can't set uid %d: %m",
2108 sep->se_service, sep->se_proto,
2109 pwd->pw_uid);
2110 exit(1);
2111 }
2112 } else if (sep->se_group) {
2113 if (setgid(pwd->pw_gid) < 0) {
2114 syslog(LOG_ERR,
2115 "%s/%s: can't set gid %d: %m",
2116 sep->se_service, sep->se_proto,
2117 pwd->pw_gid);
2118 exit(1);
2119 }
2120 if (initgroups(pwd->pw_name, pwd->pw_gid)
2121 < 0) {
2122 syslog(LOG_ERR,
2123 "%s/%s: can't initgroups(%s): %m",
2124 sep->se_service, sep->se_proto,
2125 pwd->pw_name);
2126 exit(1);
2127 }
2128 }
2129#endif
2130 }
2131 if (debug)
2132 fprintf(stderr, "%ld execv %s\n",
2133 (long)getpid(), sep->se_server);
2134 if (ctrl != STDIN_FILENO) {
2135 dup2(ctrl, STDIN_FILENO);
2136 close(ctrl);
2137 }
2138 dup2(STDIN_FILENO, STDOUT_FILENO);
2139 dup2(STDIN_FILENO, STDERR_FILENO);
2140 closelog();
2141 closefrom(3);
2142 sigaction(SIGPIPE, &sapipe, NULL);
2143 execv(sep->se_server, sep->se_argv);
2144 if (sep->se_socktype != SOCK_STREAM)
2145 recv(0, buf, sizeof (buf), 0);
2146 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
2147 exit(1);
2148 }
2149 }
2150 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
2151 close(ctrl);
2152}
2153
2154/* from netkit+USAGI */
2155void
2156discard_stupid_environment(void)
2157{
2158 static const char *const junk[] = {
2159 /* these are prefixes */
2160 "CVS",
2161 "DISPLAY=",
2162 "EDITOR=",
2163 "GROUP=",
2164 "HOME=",
2165 "IFS=",
2166 "LD_",
2167 "LOGNAME=",
2168 "MAIL=",
2169 "PATH=",
2170 "PRINTER=",
2171 "PWD=",
2172 "SHELL=",
2173 "SHLVL=",
2174 "SSH",
2175 "TERM",
2176 "TMP",
2177 "USER=",
2178 "VISUAL=",
2179 NULL
2180 };
2181
2182 int i, k = 0;
2183
2184 for (i = 0; __environ[i]; i++) {
2185 int found = 0, j;
2186
2187 for (j = 0; junk[j]; j++)
2188 if (!strncmp(__environ[i], junk[j], strlen(junk[j])))
2189 found = 1;
2190 if (!found)
2191 __environ[k++] = __environ[i];
2192 }
2193 __environ[k] = NULL;
2194}
02195
=== added directory '.pc/discard_env'
=== added file '.pc/discard_env/inetd.8'
--- .pc/discard_env/inetd.8 1970-01-01 00:00:00 +0000
+++ .pc/discard_env/inetd.8 2011-06-29 11:29:23 +0000
@@ -0,0 +1,419 @@
1.\" $OpenBSD: inetd.8,v 1.33 2008/06/28 10:54:45 sobrado Exp $
2.\" Copyright (c) 1985, 1991 The Regents of the University of California.
3.\" All rights reserved.
4.\"
5.\" Redistribution and use in source and binary forms, with or without
6.\" modification, are permitted provided that the following conditions
7.\" are met:
8.\" 1. Redistributions of source code must retain the above copyright
9.\" notice, this list of conditions and the following disclaimer.
10.\" 2. Redistributions in binary form must reproduce the above copyright
11.\" notice, this list of conditions and the following disclaimer in the
12.\" documentation and/or other materials provided with the distribution.
13.\" 3. Neither the name of the University nor the names of its contributors
14.\" may be used to endorse or promote products derived from this software
15.\" without specific prior written permission.
16.\"
17.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27.\" SUCH DAMAGE.
28.\"
29.\" from: @(#)inetd.8 6.7 (Berkeley) 3/16/91
30.\"
31.Dd $Mdocdate: December 29 2009 $
32.Dt INETD 8
33.Os
34.Sh NAME
35.Nm inetd
36.Nd internet
37.Dq super-server
38.Sh SYNOPSIS
39.Nm inetd
40.Op Fl d
41.Op Fl R Ar rate
42.Op Ar configuration_file
43.Sh DESCRIPTION
44.Nm inetd
45listens for connections on certain internet sockets.
46When a connection is found on one
47of its sockets, it decides what service the socket
48corresponds to, and invokes a program to service the request.
49After the program is
50finished, it continues to listen on the socket (except in some cases which
51will be described below).
52Essentially,
53.Nm inetd
54allows running one daemon to invoke several others,
55reducing load on the system.
56.Pp
57The options are as follows:
58.Bl -tag -width Ds
59.It Fl d
60Turns on debugging.
61.It Fl R Ar rate
62Specify the maximum number of times a service can be invoked
63in one minute; the default is 256.
64If a service exceeds this limit,
65.Nm
66will log the problem
67and stop servicing requests for the specific service for ten minutes.
68See also the wait/nowait configuration fields below.
69.El
70.Pp
71Upon execution,
72.Nm inetd
73reads its configuration information from a configuration
74file which, by default, is
75.Pa /etc/inetd.conf .
76There must be an entry for each field of the configuration
77file, with entries for each field separated by a tab or
78a space.
79Comments are denoted by a
80.Dq #
81at the beginning
82of a line.
83The fields of the configuration file are as follows:
84.Bd -unfilled -offset indent
85service name
86socket type
87protocol
88wait/nowait[.max]
89user[.group] or user[:group]
90server program
91server program arguments
92.Ed
93.Pp
94To specify a Sun-RPC
95based service, the entry would contain these fields.
96.Bd -unfilled -offset indent
97service name/version
98socket type
99rpc/protocol
100wait/nowait[.max]
101user[.group] or user[:group]
102server program
103server program arguments
104.Ed
105.Pp
106For internet services, the first field of the line may also have a host
107address specifier prefixed to it, separated from the service name by a
108colon.
109If this is done, the string before the colon in the first field
110indicates what local address
111.Nm
112should use when listening for that service.
113Multiple local addresses
114can be specified on the same line, separated by commas.
115Numeric IP
116addresses in dotted-quad notation can be used as well as symbolic
117hostnames.
118Symbolic hostnames are looked up using
119.Fn gethostbyname .
120If a hostname has multiple address mappings, inetd creates a socket
121to listen on each address.
122.Pp
123The single character
124.Dq \&*
125indicates
126.Dv INADDR_ANY ,
127meaning
128.Dq all local addresses .
129To avoid repeating an address that occurs frequently, a line with a
130host address specifier and colon, but no further fields, causes the
131host address specifier to be remembered and used for all further lines
132with no explicit host specifier (until another such line or the end of
133the file).
134A line
135.Dl *:
136is implicitly provided at the top of the file; thus, traditional
137configuration files (which have no host address specifiers) will be
138interpreted in the traditional manner, with all services listened for
139on all local addresses.
140If the protocol is
141.Dq unix ,
142this value is ignored.
143.Pp
144The
145.Em service name
146entry is the name of a valid service in
147the file
148.Pa /etc/services
149or a port number.
150For
151.Dq internal
152services (discussed below), the service
153name
154.Em must
155be the official name of the service (that is, the first entry in
156.Pa /etc/services ) .
157When used to specify a Sun-RPC
158based service, this field is a valid RPC service name in
159the file
160.Pa /etc/rpc .
161The part on the right of the
162.Dq /
163is the RPC version number.
164This can simply be a single numeric argument or a range of versions.
165A range is bounded by the low version to the high version -
166.Dq rusers/1\-3 .
167For
168.Ux Ns -domain
169sockets this field specifies the path name of the socket.
170.Pp
171The
172.Em socket type
173should be one of
174.Dq stream ,
175.Dq dgram ,
176.Dq raw ,
177.Dq rdm ,
178or
179.Dq seqpacket ,
180depending on whether the socket is a stream, datagram, raw,
181reliably delivered message, or sequenced packet socket.
182.Pp
183The
184.Em protocol
185must be a valid protocol as given in
186.Pa /etc/protocols or
187.Dq unix .
188Examples might be
189.Dq tcp
190or
191.Dq udp .
192RPC based services are specified with the
193.Dq rpc/tcp
194or
195.Dq rpc/udp
196service type.
197.Dq tcp
198and
199.Dq udp
200will be recognized as
201.Dq TCP or UDP over default IP version .
202This is currently IPv4, but in the future it will be IPv6.
203If you need to specify IPv4 or IPv6 explicitly, use something like
204.Dq tcp4
205or
206.Dq udp6 .
207A
208.Em protocol
209of
210.Dq unix
211is used to specify a socket in the
212.Ux Ns -domain .
213.Pp
214The
215.Em wait/nowait
216entry is used to tell
217.Nm
218if it should wait for the server program to return,
219or continue processing connections on the socket.
220If a datagram server connects
221to its peer, freeing the socket so
222.Nm inetd
223can receive further messages on the socket, it is said to be
224a
225.Dq multi-threaded
226server, and should use the
227.Dq nowait
228entry.
229For datagram servers which process all incoming datagrams
230on a socket and eventually time out, the server is said to be
231.Dq single-threaded
232and should use a
233.Dq wait
234entry.
235.Xr comsat 8
236.Pq Xr biff 1
237and
238.Xr talkd 8
239are both examples of the latter type of
240datagram server.
241.Xr tftpd 8
242is an exception; it is a datagram server that establishes pseudo-connections.
243It must be listed as
244.Dq wait
245in order to avoid a race;
246the server reads the first packet, creates a new socket,
247and then forks and exits to allow
248.Nm inetd
249to check for new service requests to spawn new servers.
250The optional
251.Dq max
252suffix (separated from
253.Dq wait
254or
255.Dq nowait
256by a dot) specifies the maximum number of times a service can be invoked
257in one minute; the default is 256.
258If a service exceeds this limit,
259.Nm
260will log the problem
261and stop servicing requests for the specific service for ten minutes.
262See also the
263.Fl R
264option above.
265.Pp
266Stream servers are usually marked as
267.Dq nowait
268but if a single server process is to handle multiple connections, it may be
269marked as
270.Dq wait .
271The master socket will then be passed as fd 0 to the server, which will then
272need to accept the incoming connection.
273The server should eventually time
274out and exit when no more connections are active.
275.Nm
276will continue to
277listen on the master socket for connections, so the server should not close
278it when it exits.
279.Pp
280The
281.Em user
282entry should contain the user name of the user as whom the server
283should run.
284This allows for servers to be given less permission
285than root.
286An optional group name can be specified by appending a dot to
287the user name followed by the group name.
288This allows for servers to run with
289a different (primary) group ID than specified in the password file.
290If a group
291is specified and user is not root, the supplementary groups associated with
292that user will still be set.
293.Pp
294The
295.Em server program
296entry should contain the pathname of the program which is to be
297executed by
298.Nm inetd
299when a request is found on its socket.
300If
301.Nm inetd
302provides this service internally, this entry should
303be
304.Dq internal .
305.Pp
306The
307.Em server program arguments
308should be just as arguments
309normally are, starting with argv[0], which is the name of
310the program.
311If the service is provided internally, the word
312.Dq internal
313should take the place of this entry.
314.Pp
315.Nm inetd
316provides several
317.Dq trivial
318services internally by use of routines within itself.
319These services are
320.Dq echo ,
321.Dq discard ,
322.Dq chargen
323(character generator),
324.Dq daytime
325(human readable time), and
326.Dq time
327(machine readable time,
328in the form of the number of seconds since midnight, January
3291, 1900).
330All of these services are TCP based.
331For details of these services, consult the appropriate
332.Tn RFC
333from the Network Information Center.
334.Pp
335.Nm inetd
336rereads its configuration file when it receives a hangup signal,
337.Dv SIGHUP .
338Services may be added, deleted or modified when the configuration file
339is reread.
340.Nm inetd
341creates a file
342.Em /var/run/inetd.pid
343that contains its process identifier.
344.Ss IPv6 TCP/UDP behavior
345If you wish to run a server for IPv4 and IPv6 traffic,
346you'll need to run two separate processes for the same server program,
347specified as two separate lines in
348.Pa inetd.conf ,
349for
350.Dq tcp4
351and
352.Dq tcp6 .
353.Pp
354Under various combinations of IPv4/v6 daemon settings,
355.Nm
356will behave as follows:
357.Bl -bullet -compact
358.It
359If you have only one server on
360.Dq tcp4 ,
361IPv4 traffic will be routed to the server.
362IPv6 traffic will not be accepted.
363.It
364If you have two servers on
365.Dq tcp4
366and
367.Dq tcp6 ,
368IPv4 traffic will be routed to the server on
369.Dq tcp4 ,
370and IPv6 traffic will go to server on
371.Dq tcp6 .
372.It
373If you have only one server on
374.Dq tcp6 ,
375only IPv6 traffic will be routed to the server.
376.El
377.Sh SEE ALSO
378.Xr fingerd 8 ,
379.Xr ftpd 8 ,
380.Xr identd 8 ,
381.Xr rshd 8 ,
382.Xr talkd 8 ,
383.Xr tftpd 8
384.Sh HISTORY
385The
386.Nm
387command appeared in
388.Bx 4.3 .
389Support for Sun-RPC
390based services is modelled after that
391provided by SunOS 4.1.
392IPv6 support was added by the KAME project in 1999.
393.Pp
394Marco d'Itri ported this code from OpenBSD in summer 2002 and added
395socket buffers tuning and libwrap support from the NetBSD source tree.
396.Sh BUGS
397On Linux systems, the daemon cannot reload its configuration and needs
398to be restarted when the host address for a service is changed between
399.Dq \&*
400and a specific address.
401.Pp
402Server programs used with
403.Dq dgram
404.Dq udp
405.Dq nowait
406must read from the network socket, or
407.Nm inetd
408will spawn processes until the maximum is reached.
409.Pp
410Host address specifiers, while they make conceptual sense for RPC
411services, do not work entirely correctly.
412This is largely because the
413portmapper interface does not provide a way to register different ports
414for the same service on different local addresses.
415Provided you never
416have more than one entry for a given RPC service, everything should
417work correctly.
418(Note that default host address specifiers do apply to
419RPC lines with no explicit specifier.)
0420
=== added file '.pc/discard_env/inetd.c'
--- .pc/discard_env/inetd.c 1970-01-01 00:00:00 +0000
+++ .pc/discard_env/inetd.c 2011-06-29 11:29:23 +0000
@@ -0,0 +1,2059 @@
1/* $OpenBSD: inetd.c,v 1.131 2009/10/27 23:59:51 deraadt Exp $ */
2
3/*
4 * Copyright (c) 1983,1991 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * Inetd - Internet super-server
34 *
35 * This program invokes all internet services as needed.
36 * connection-oriented services are invoked each time a
37 * connection is made, by creating a process. This process
38 * is passed the connection as file descriptor 0 and is
39 * expected to do a getpeername to find out the source host
40 * and port.
41 *
42 * Datagram oriented services are invoked when a datagram
43 * arrives; a process is created and passed a pending message
44 * on file descriptor 0. Datagram servers may either connect
45 * to their peer, freeing up the original socket for inetd
46 * to receive further messages on, or ``take over the socket'',
47 * processing all arriving datagrams and, eventually, timing
48 * out. The first type of server is said to be ``multi-threaded'';
49 * the second type of server ``single-threaded''.
50 *
51 * Inetd uses a configuration file which is read at startup
52 * and, possibly, at some later time in response to a hangup signal.
53 * The configuration file is ``free format'' with fields given in the
54 * order shown below. Continuation lines for an entry must begin with
55 * a space or tab. All fields must be present in each entry.
56 *
57 * service name must be in /etc/services
58 * socket type stream/dgram/raw/rdm/seqpacket
59 * protocol must be in /etc/protocols
60 * wait/nowait[.max] single-threaded/multi-threaded, max #
61 * user[.group] or user[:group] user/group to run daemon as
62 * server program full path name
63 * server program arguments maximum of MAXARGS (20)
64 *
65 * For RPC services
66 * service name/version must be in /etc/rpc
67 * socket type stream/dgram/raw/rdm/seqpacket
68 * protocol must be in /etc/protocols
69 * wait/nowait[.max] single-threaded/multi-threaded
70 * user[.group] or user[:group] user to run daemon as
71 * server program full path name
72 * server program arguments maximum of MAXARGS (20)
73 *
74 * For non-RPC services, the "service name" can be of the form
75 * hostaddress:servicename, in which case the hostaddress is used
76 * as the host portion of the address to listen on. If hostaddress
77 * consists of a single `*' character, INADDR_ANY is used.
78 *
79 * A line can also consist of just
80 * hostaddress:
81 * where hostaddress is as in the preceding paragraph. Such a line must
82 * have no further fields; the specified hostaddress is remembered and
83 * used for all further lines that have no hostaddress specified,
84 * until the next such line (or EOF). (This is why * is provided to
85 * allow explicit specification of INADDR_ANY.) A line
86 * *:
87 * is implicitly in effect at the beginning of the file.
88 *
89 * The hostaddress specifier may (and often will) contain dots;
90 * the service name must not.
91 *
92 * For RPC services, host-address specifiers are accepted and will
93 * work to some extent; however, because of limitations in the
94 * portmapper interface, it will not work to try to give more than
95 * one line for any given RPC service, even if the host-address
96 * specifiers are different.
97 *
98 * Comment lines are indicated by a `#' in column 1.
99 */
100
101/*
102 * Here's the scoop concerning the user[.:]group feature:
103 *
104 * 1) set-group-option off.
105 *
106 * a) user = root: NO setuid() or setgid() is done
107 *
108 * b) other: setgid(primary group as found in passwd)
109 * initgroups(name, primary group)
110 * setuid()
111 *
112 * 2) set-group-option on.
113 *
114 * a) user = root: setgid(specified group)
115 * NO initgroups()
116 * NO setuid()
117 *
118 * b) other: setgid(specified group)
119 * initgroups(name, specified group)
120 * setuid()
121 *
122 */
123
124#include <sys/param.h>
125#include <sys/stat.h>
126#include <sys/ioctl.h>
127#include <sys/socket.h>
128#include <sys/un.h>
129#include <sys/file.h>
130#include <sys/wait.h>
131#include <time.h>
132#include <sys/time.h>
133#include <sys/resource.h>
134
135#include <net/if.h>
136#include <netinet/in.h>
137#include <arpa/inet.h>
138
139#include <errno.h>
140#include <ctype.h>
141#include <signal.h>
142#include <netdb.h>
143#include <syslog.h>
144#include <pwd.h>
145#include <grp.h>
146#include <stdio.h>
147#include <stdlib.h>
148#include <unistd.h>
149#include <string.h>
150#ifdef HAVE_SETUSERCONTEXT
151#include <login_cap.h>
152#endif
153#ifdef HAVE_GETIFADDRS
154#include <ifaddrs.h>
155#endif
156#include <rpc/rpc.h>
157#include <rpc/pmap_clnt.h>
158#include "pathnames.h"
159#include "setproctitle.h"
160
161size_t strlcpy(char *, const char *, size_t);
162
163#define TOOMANY 256 /* don't start more than TOOMANY */
164#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
165#define RETRYTIME (60*10) /* retry after bind or server fail */
166
167int debug = 0;
168int nsock, maxsock;
169fd_set *allsockp;
170int allsockn;
171int toomany = TOOMANY;
172int options;
173int timingout;
174struct servent *sp;
175uid_t uid;
176sigset_t blockmask;
177sigset_t emptymask;
178
179#ifndef OPEN_MAX
180#define OPEN_MAX 64
181#endif
182
183/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
184#define FD_MARGIN (8)
185rlim_t rlim_nofile_cur = OPEN_MAX;
186
187struct rlimit rlim_nofile;
188
189struct servtab {
190 char *se_hostaddr; /* host address to listen on */
191 char *se_service; /* name of service */
192 int se_socktype; /* type of socket to use */
193 int se_family; /* address family */
194 char *se_proto; /* protocol used */
195 int se_rpcprog; /* rpc program number */
196 int se_rpcversl; /* rpc program lowest version */
197 int se_rpcversh; /* rpc program highest version */
198#define isrpcservice(sep) ((sep)->se_rpcversl != 0)
199 pid_t se_wait; /* single threaded server */
200 short se_checked; /* looked at during merge */
201 char *se_user; /* user name to run as */
202 char *se_group; /* group name to run as */
203 struct biltin *se_bi; /* if built-in, description */
204 char *se_server; /* server program */
205#define MAXARGV 20
206 char *se_argv[MAXARGV+1]; /* program arguments */
207 int se_fd; /* open descriptor */
208 union {
209 struct sockaddr se_un_ctrladdr;
210 struct sockaddr_in se_un_ctrladdr_in;
211 struct sockaddr_in6 se_un_ctrladdr_in6;
212 struct sockaddr_un se_un_ctrladdr_un;
213 struct sockaddr_storage se_un_ctrladdr_storage;
214 } se_un; /* bound address */
215#define se_ctrladdr se_un.se_un_ctrladdr
216#define se_ctrladdr_in se_un.se_un_ctrladdr_in
217#define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
218#define se_ctrladdr_un se_un.se_un_ctrladdr_un
219#define se_ctrladdr_storage se_un.se_un_ctrladdr_storage
220 int se_ctrladdr_size;
221 int se_max; /* max # of instances of this service */
222 int se_count; /* number started since se_time */
223 struct timeval se_time; /* start of se_count */
224 struct servtab *se_next;
225} *servtab;
226
227void echo_stream(int, struct servtab *);
228void discard_stream(int, struct servtab *);
229void machtime_stream(int, struct servtab *);
230void daytime_stream(int, struct servtab *);
231void chargen_stream(int, struct servtab *);
232void echo_dg(int, struct servtab *);
233void discard_dg(int, struct servtab *);
234void machtime_dg(int, struct servtab *);
235void daytime_dg(int, struct servtab *);
236void chargen_dg(int, struct servtab *);
237
238struct biltin {
239 char *bi_service; /* internally provided service name */
240 int bi_socktype; /* type of socket supported */
241 short bi_fork; /* 1 if should fork before call */
242 short bi_wait; /* 1 if should wait for child */
243 void (*bi_fn)(int, struct servtab *);
244} biltins[] = {
245 /* Echo received data */
246 { "echo", SOCK_STREAM, 1, 0, echo_stream },
247 { "echo", SOCK_DGRAM, 0, 0, echo_dg },
248
249 /* Internet /dev/null */
250 { "discard", SOCK_STREAM, 1, 0, discard_stream },
251 { "discard", SOCK_DGRAM, 0, 0, discard_dg },
252
253 /* Return 32 bit time since 1900 */
254 { "time", SOCK_STREAM, 0, 0, machtime_stream },
255 { "time", SOCK_DGRAM, 0, 0, machtime_dg },
256
257 /* Return human-readable time */
258 { "daytime", SOCK_STREAM, 0, 0, daytime_stream },
259 { "daytime", SOCK_DGRAM, 0, 0, daytime_dg },
260
261 /* Familiar character generator */
262 { "chargen", SOCK_STREAM, 1, 0, chargen_stream },
263 { "chargen", SOCK_DGRAM, 0, 0, chargen_dg },
264
265 { 0 }
266};
267
268volatile sig_atomic_t wantretry;
269volatile sig_atomic_t wantconfig;
270volatile sig_atomic_t wantreap;
271volatile sig_atomic_t wantdie;
272
273void config(int);
274void doconfig(void);
275void reap(int);
276void doreap(void);
277void retry(int);
278void doretry(void);
279void die(int);
280void dodie(void);
281void logpid(void);
282void spawn(struct servtab *, int);
283int gettcp(struct servtab *);
284int setconfig(void);
285void endconfig(void);
286void register_rpc(struct servtab *);
287void unregister_rpc(struct servtab *);
288void freeconfig(struct servtab *);
289void print_service(char *, struct servtab *);
290void setup(struct servtab *);
291struct servtab *getconfigent(void);
292int bump_nofile(void);
293struct servtab *enter(struct servtab *);
294int matchconf(struct servtab *, struct servtab *);
295int dg_broadcast(struct in_addr *in);
296
297#define NUMINT (sizeof(intab) / sizeof(struct inent))
298char *CONFIG = _PATH_INETDCONF;
299
300void
301fd_grow(fd_set **fdsp, int *bytes, int fd)
302{
303 caddr_t new;
304 int newbytes;
305
306 newbytes = howmany(fd+1, NFDBITS) * sizeof(fd_mask);
307 if (newbytes > *bytes) {
308 newbytes *= 2; /* optimism */
309 new = realloc(*fdsp, newbytes);
310 if (new == NULL) {
311 syslog(LOG_ERR, "Out of memory.");
312 exit(1);
313 }
314 memset(new + *bytes, 0, newbytes - *bytes);
315 *fdsp = (fd_set *)new;
316 *bytes = newbytes;
317 }
318}
319
320struct sigaction sa, sapipe;
321
322int
323main(int argc, char *argv[], char *envp[])
324{
325 fd_set *fdsrp = NULL;
326 int readablen = 0, ch;
327 struct servtab *sep;
328 extern char *optarg;
329 extern int optind;
330
331 initsetproctitle(argc, argv, envp);
332
333 while ((ch = getopt(argc, argv, "dR:")) != -1)
334 switch (ch) {
335 case 'd':
336 debug = 1;
337 break;
338 case 'R': { /* invocation rate */
339 char *p;
340 int val;
341
342 val = strtoul(optarg, &p, 0);
343 if (val >= 1 && *p == '\0') {
344 toomany = val;
345 break;
346 }
347 syslog(LOG_ERR,
348 "-R %s: bad value for service invocation rate",
349 optarg);
350 break;
351 }
352 case '?':
353 default:
354 fprintf(stderr,
355 "usage: inetd [-d] [-R rate] [configuration_file]\n");
356 exit(1);
357 }
358 argc -= optind;
359 argv += optind;
360
361 uid = getuid();
362 if (uid != 0)
363 CONFIG = NULL;
364 if (argc > 0)
365 CONFIG = argv[0];
366 if (CONFIG == NULL) {
367 fprintf(stderr, "inetd: non-root must specify a config file\n");
368 exit(1);
369 }
370 if (argc > 1) {
371 fprintf(stderr, "inetd: more than one argument specified\n");
372 exit(1);
373 }
374
375 umask(022);
376 if (debug == 0) {
377 daemon(0, 0);
378#ifdef HAVE_SETLOGIN
379 if (uid == 0)
380 (void) setlogin("");
381#endif
382 }
383 if (debug && uid == 0)
384 options |= SO_DEBUG;
385
386 if (uid == 0) {
387 gid_t gid = getgid();
388
389 /* If run by hand, ensure groups vector gets trashed */
390 setgroups(1, &gid);
391 }
392
393 openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
394 logpid();
395
396 if (getrlimit(RLIMIT_NOFILE, &rlim_nofile) < 0) {
397 syslog(LOG_ERR, "getrlimit: %m");
398 } else {
399 rlim_nofile_cur = rlim_nofile.rlim_cur;
400 if (rlim_nofile_cur == RLIM_INFINITY) /* ! */
401 rlim_nofile_cur = OPEN_MAX;
402 }
403
404 sigemptyset(&emptymask);
405 sigemptyset(&blockmask);
406 sigaddset(&blockmask, SIGCHLD);
407 sigaddset(&blockmask, SIGHUP);
408 sigaddset(&blockmask, SIGALRM);
409
410 memset(&sa, 0, sizeof(sa));
411 sigemptyset(&sa.sa_mask);
412 sigaddset(&sa.sa_mask, SIGALRM);
413 sigaddset(&sa.sa_mask, SIGCHLD);
414 sigaddset(&sa.sa_mask, SIGHUP);
415 sa.sa_handler = retry;
416 sigaction(SIGALRM, &sa, NULL);
417 doconfig();
418 sa.sa_handler = config;
419 sigaction(SIGHUP, &sa, NULL);
420 sa.sa_handler = reap;
421 sigaction(SIGCHLD, &sa, NULL);
422 sa.sa_handler = die;
423 sigaction(SIGTERM, &sa, NULL);
424 sa.sa_handler = die;
425 sigaction(SIGINT, &sa, NULL);
426 sa.sa_handler = SIG_IGN;
427 sigaction(SIGPIPE, &sa, &sapipe);
428
429 /* space for daemons to overwrite environment for ps */
430 {
431#define DUMMYSIZE 100
432 char dummy[DUMMYSIZE];
433 memset(dummy, 'x', DUMMYSIZE - 1);
434 dummy[DUMMYSIZE - 1] = '\0';
435 setenv("inetd_dummy", dummy, 1);
436 }
437
438 for (;;) {
439 int n, ctrl = -1;
440
441 restart:
442 if (nsock == 0) {
443 (void) sigprocmask(SIG_BLOCK, &blockmask, NULL);
444 while (nsock == 0) {
445 if (wantretry || wantconfig || wantreap || wantdie)
446 break;
447 sigsuspend(&emptymask);
448 }
449 (void) sigprocmask(SIG_SETMASK, &emptymask, NULL);
450 }
451
452 while (wantretry || wantconfig || wantreap || wantdie) {
453 if (wantretry) {
454 wantretry = 0;
455 doretry();
456 }
457 if (wantconfig) {
458 wantconfig = 0;
459 doconfig();
460 }
461 if (wantreap) {
462 wantreap = 0;
463 doreap();
464 }
465 if (wantdie)
466 dodie();
467 goto restart;
468 }
469
470 if (readablen != allsockn) {
471 if (fdsrp)
472 free(fdsrp);
473 fdsrp = (fd_set *)calloc(allsockn, 1);
474 if (fdsrp == NULL) {
475 syslog(LOG_ERR, "Out of memory.");
476 exit(1);
477 }
478 readablen = allsockn;
479 }
480 bcopy(allsockp, fdsrp, allsockn);
481
482 if ((n = select(maxsock + 1, fdsrp, NULL, NULL, NULL)) <= 0) {
483 if (n < 0 && errno != EINTR) {
484 syslog(LOG_WARNING, "select: %m");
485 sleep(1);
486 }
487 continue;
488 }
489
490 for (sep = servtab; n && sep; sep = sep->se_next) {
491 if (sep->se_fd != -1 &&
492 FD_ISSET(sep->se_fd, fdsrp)) {
493 n--;
494 if (debug)
495 fprintf(stderr, "someone wants %s\n",
496 sep->se_service);
497 if (!sep->se_wait &&
498 sep->se_socktype == SOCK_STREAM) {
499 ctrl = gettcp(sep);
500 if (ctrl == -1)
501 continue;
502 } else
503 ctrl = sep->se_fd;
504 (void) sigprocmask(SIG_BLOCK, &blockmask, NULL);
505 spawn(sep, ctrl); /* spawn will unblock */
506 }
507 }
508 }
509}
510
511int
512gettcp(struct servtab *sep)
513{
514 int ctrl;
515
516 ctrl = accept(sep->se_fd, NULL, NULL);
517 if (debug)
518 fprintf(stderr, "accept, ctrl %d\n", ctrl);
519 if (ctrl < 0) {
520 if (errno == EINTR)
521 return -1;
522 syslog(LOG_WARNING, "accept (for %s): %m", sep->se_service);
523 return -1;
524 }
525 if ((sep->se_family == AF_INET || sep->se_family == AF_INET6) &&
526 sep->se_socktype == SOCK_STREAM) {
527 struct sockaddr_storage peer;
528 socklen_t plen = sizeof(peer);
529 char sbuf[NI_MAXSERV];
530
531 if (getpeername(ctrl, (struct sockaddr *)&peer, &plen) < 0) {
532 syslog(LOG_WARNING, "could not getpeername");
533 close(ctrl);
534 return -1;
535 }
536 if (getnameinfo((struct sockaddr *)&peer, plen, NULL, 0,
537 sbuf, sizeof(sbuf), NI_NUMERICSERV) == 0 &&
538 atoi(sbuf) == 20) {
539 /*
540 * ignore things that look like ftp bounce
541 */
542 close(ctrl);
543 return -1;
544 }
545 }
546 return (ctrl);
547}
548
549
550int
551dg_badinput(struct sockaddr *sa)
552{
553 struct in_addr in;
554 struct in6_addr *in6;
555 u_int16_t port;
556
557 switch (sa->sa_family) {
558 case AF_INET:
559 in.s_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
560 port = ntohs(((struct sockaddr_in *)sa)->sin_port);
561 v4chk:
562 if (IN_MULTICAST(in.s_addr))
563 goto bad;
564 switch ((in.s_addr & 0xff000000) >> 24) {
565 case 0: case 127: case 255:
566 goto bad;
567 }
568 if (dg_broadcast(&in))
569 goto bad;
570 break;
571 case AF_INET6:
572 in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
573 port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
574 if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
575 goto bad;
576 /*
577 * OpenBSD does not support IPv4 mapped address (RFC2553
578 * inbound behavior) at all. We should drop it.
579 */
580 if (IN6_IS_ADDR_V4MAPPED(in6))
581 goto bad;
582 if (IN6_IS_ADDR_V4COMPAT(in6)) {
583 memcpy(&in, &in6->s6_addr[12], sizeof(in));
584 in.s_addr = ntohl(in.s_addr);
585 goto v4chk;
586 }
587 break;
588 default:
589 /* XXX unsupported af, is it safe to assume it to be safe? */
590 return 0;
591 }
592
593 return (0);
594
595bad:
596 return (1);
597}
598
599int
600dg_broadcast(struct in_addr *in)
601{
602#ifdef HAVE_GETIFADDRS
603 struct ifaddrs *ifa, *ifap;
604 struct sockaddr_in *sin;
605
606 if (getifaddrs(&ifap) < 0)
607 return (0);
608 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
609 if (ifa->ifa_addr->sa_family != AF_INET ||
610 (ifa->ifa_flags & IFF_BROADCAST) == 0)
611 continue;
612 sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
613 if (sin->sin_addr.s_addr == in->s_addr) {
614 freeifaddrs(ifap);
615 return (1);
616 }
617 }
618 freeifaddrs(ifap);
619#endif
620 return (0);
621}
622
623/* ARGSUSED */
624void
625reap(int sig)
626{
627 wantreap = 1;
628}
629
630void
631doreap(void)
632{
633 struct servtab *sep;
634 int status;
635 pid_t pid;
636
637 if (debug)
638 fprintf(stderr, "reaping asked for\n");
639
640 for (;;) {
641 if ((pid = wait3(&status, WNOHANG, NULL)) <= 0) {
642 if (pid == -1 && errno == EINTR)
643 continue;
644 break;
645 }
646 if (debug)
647 fprintf(stderr, "%ld reaped, status %x\n",
648 (long)pid, status);
649 for (sep = servtab; sep; sep = sep->se_next)
650 if (sep->se_wait == pid) {
651 if (WIFEXITED(status) && WEXITSTATUS(status))
652 syslog(LOG_WARNING,
653 "%s: exit status %d",
654 sep->se_server, WEXITSTATUS(status));
655 else if (WIFSIGNALED(status))
656 syslog(LOG_WARNING,
657 "%s: exit signal %d",
658 sep->se_server, WTERMSIG(status));
659 sep->se_wait = 1;
660 fd_grow(&allsockp, &allsockn, sep->se_fd);
661 FD_SET(sep->se_fd, allsockp);
662 nsock++;
663 if (debug)
664 fprintf(stderr, "restored %s, fd %d\n",
665 sep->se_service, sep->se_fd);
666 }
667 }
668}
669
670/* ARGSUSED */
671void
672config(int sig)
673{
674 wantconfig = 1;
675}
676
677void
678doconfig(void)
679{
680 struct servtab *sep, *cp, **sepp;
681 int add;
682 char protoname[10];
683 sigset_t omask;
684
685 if (!setconfig()) {
686 syslog(LOG_ERR, "%s: %m", CONFIG);
687 exit(1);
688 }
689 for (sep = servtab; sep; sep = sep->se_next)
690 sep->se_checked = 0;
691 cp = getconfigent();
692 while (cp != NULL) {
693 for (sep = servtab; sep; sep = sep->se_next)
694 if (matchconf(sep, cp))
695 break;
696 add = 0;
697 if (sep != NULL) {
698 int i;
699
700#define SWAP(type, a, b) {type c=(type)a; a=(type)b; b=(type)c;}
701
702 sigprocmask(SIG_BLOCK, &blockmask, &omask);
703 /*
704 * sep->se_wait may be holding the pid of a daemon
705 * that we're waiting for. If so, don't overwrite
706 * it unless the config file explicitly says don't
707 * wait.
708 */
709 if (cp->se_bi == 0 &&
710 (sep->se_wait == 1 || cp->se_wait == 0))
711 sep->se_wait = cp->se_wait;
712 SWAP(int, cp->se_max, sep->se_max);
713 SWAP(char *, sep->se_user, cp->se_user);
714 SWAP(char *, sep->se_group, cp->se_group);
715 SWAP(char *, sep->se_server, cp->se_server);
716 for (i = 0; i < MAXARGV; i++)
717 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
718#undef SWAP
719 if (isrpcservice(sep))
720 unregister_rpc(sep);
721 sep->se_rpcversl = cp->se_rpcversl;
722 sep->se_rpcversh = cp->se_rpcversh;
723 sigprocmask(SIG_SETMASK, &omask, NULL);
724 freeconfig(cp);
725 add = 1;
726 } else {
727 sep = enter(cp);
728 }
729 sep->se_checked = 1;
730
731 switch (sep->se_family) {
732 case AF_UNIX:
733 if (sep->se_fd != -1)
734 break;
735 sep->se_ctrladdr_size =
736 strlcpy(sep->se_ctrladdr_un.sun_path,
737 sep->se_service,
738 sizeof sep->se_ctrladdr_un.sun_path);
739 if (sep->se_ctrladdr_size >=
740 sizeof sep->se_ctrladdr_un.sun_path) {
741 syslog(LOG_WARNING, "%s/%s: UNIX domain socket "
742 "path too long", sep->se_service,
743 sep->se_proto);
744 goto serv_unknown;
745 }
746 sep->se_ctrladdr_un.sun_family = AF_UNIX;
747 sep->se_ctrladdr_size +=
748 1 + sizeof sep->se_ctrladdr_un.sun_family;
749 (void)unlink(sep->se_service);
750 setup(sep);
751 break;
752 case AF_INET:
753 sep->se_ctrladdr_in.sin_family = AF_INET;
754 /* se_ctrladdr_in was set in getconfigent */
755 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
756
757 if (isrpcservice(sep)) {
758 struct rpcent *rp;
759
760 sep->se_rpcprog = atoi(sep->se_service);
761 if (sep->se_rpcprog == 0) {
762 rp = getrpcbyname(sep->se_service);
763 if (rp == 0) {
764 syslog(LOG_ERR,
765 "%s: unknown rpc service",
766 sep->se_service);
767 goto serv_unknown;
768 }
769 sep->se_rpcprog = rp->r_number;
770 }
771 if (sep->se_fd == -1)
772 setup(sep);
773 if (sep->se_fd != -1)
774 register_rpc(sep);
775 } else {
776 u_short port = htons(atoi(sep->se_service));
777
778 if (!port) {
779 /* XXX */
780 strncpy(protoname, sep->se_proto,
781 sizeof(protoname));
782 if (isdigit(protoname[strlen(protoname) - 1]))
783 protoname[strlen(protoname) - 1] = '\0';
784 sp = getservbyname(sep->se_service,
785 protoname);
786 if (sp == 0) {
787 syslog(LOG_ERR,
788 "%s/%s: unknown service",
789 sep->se_service, sep->se_proto);
790 goto serv_unknown;
791 }
792 port = sp->s_port;
793 }
794 if (port != sep->se_ctrladdr_in.sin_port) {
795 sep->se_ctrladdr_in.sin_port = port;
796 if (sep->se_fd != -1) {
797 FD_CLR(sep->se_fd, allsockp);
798 nsock--;
799 (void) close(sep->se_fd);
800 }
801 sep->se_fd = -1;
802 }
803 if (sep->se_fd == -1)
804 setup(sep);
805 }
806 break;
807 case AF_INET6:
808 sep->se_ctrladdr_in6.sin6_family = AF_INET6;
809 /* se_ctrladdr_in was set in getconfigent */
810 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
811
812 if (isrpcservice(sep)) {
813 struct rpcent *rp;
814
815 sep->se_rpcprog = atoi(sep->se_service);
816 if (sep->se_rpcprog == 0) {
817 rp = getrpcbyname(sep->se_service);
818 if (rp == 0) {
819 syslog(LOG_ERR,
820 "%s: unknown rpc service",
821 sep->se_service);
822 goto serv_unknown;
823 }
824 sep->se_rpcprog = rp->r_number;
825 }
826 if (sep->se_fd == -1)
827 setup(sep);
828 if (sep->se_fd != -1)
829 register_rpc(sep);
830 } else {
831 u_short port = htons(atoi(sep->se_service));
832
833 if (!port) {
834 /* XXX */
835 strncpy(protoname, sep->se_proto,
836 sizeof(protoname));
837 if (isdigit(protoname[strlen(protoname) - 1]))
838 protoname[strlen(protoname) - 1] = '\0';
839 sp = getservbyname(sep->se_service,
840 protoname);
841 if (sp == 0) {
842 syslog(LOG_ERR,
843 "%s/%s: unknown service",
844 sep->se_service, sep->se_proto);
845 goto serv_unknown;
846 }
847 port = sp->s_port;
848 }
849 if (port != sep->se_ctrladdr_in6.sin6_port) {
850 sep->se_ctrladdr_in6.sin6_port = port;
851 if (sep->se_fd != -1) {
852 FD_CLR(sep->se_fd, allsockp);
853 nsock--;
854 (void) close(sep->se_fd);
855 }
856 sep->se_fd = -1;
857 }
858 if (sep->se_fd == -1)
859 setup(sep);
860 }
861 break;
862 }
863 serv_unknown:
864 if (cp->se_next != NULL) {
865 struct servtab *tmp = cp;
866
867 cp = cp->se_next;
868 free(tmp);
869 } else {
870 free(cp);
871 cp = getconfigent();
872 }
873 if (debug)
874 print_service(add ? "REDO" : "ADD", sep);
875 }
876 endconfig();
877 /*
878 * Purge anything not looked at above.
879 */
880 sigprocmask(SIG_BLOCK, &blockmask, &omask);
881 sepp = &servtab;
882 while ((sep = *sepp)) {
883 if (sep->se_checked) {
884 sepp = &sep->se_next;
885 continue;
886 }
887 *sepp = sep->se_next;
888 if (sep->se_fd != -1) {
889 FD_CLR(sep->se_fd, allsockp);
890 nsock--;
891 (void) close(sep->se_fd);
892 }
893 if (isrpcservice(sep))
894 unregister_rpc(sep);
895 if (sep->se_family == AF_UNIX)
896 (void)unlink(sep->se_service);
897 if (debug)
898 print_service("FREE", sep);
899 freeconfig(sep);
900 free(sep);
901 }
902 sigprocmask(SIG_SETMASK, &omask, NULL);
903}
904
905/* ARGSUSED */
906void
907retry(int sig)
908{
909 wantretry = 1;
910}
911
912void
913doretry(void)
914{
915 struct servtab *sep;
916
917 timingout = 0;
918 for (sep = servtab; sep; sep = sep->se_next) {
919 if (sep->se_fd == -1) {
920 switch (sep->se_family) {
921 case AF_UNIX:
922 case AF_INET:
923 case AF_INET6:
924 setup(sep);
925 if (sep->se_fd != -1 && isrpcservice(sep))
926 register_rpc(sep);
927 break;
928 }
929 }
930 }
931}
932
933/* ARGSUSED */
934void
935die(int sig)
936{
937 wantdie = 1;
938}
939
940void
941dodie(void)
942{
943 struct servtab *sep;
944
945 for (sep = servtab; sep; sep = sep->se_next) {
946 if (sep->se_fd == -1)
947 continue;
948
949 switch (sep->se_family) {
950 case AF_UNIX:
951 (void)unlink(sep->se_service);
952 break;
953 case AF_INET:
954 case AF_INET6:
955 if (sep->se_wait == 1 && isrpcservice(sep))
956 unregister_rpc(sep);
957 break;
958 }
959 (void)close(sep->se_fd);
960 }
961 (void)unlink(_PATH_INETDPID);
962 exit(0);
963}
964
965void
966setup(struct servtab *sep)
967{
968 int on = 1;
969 int r;
970 mode_t mask = 0;
971
972 if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
973 syslog(LOG_ERR, "%s/%s: socket: %m",
974 sep->se_service, sep->se_proto);
975 return;
976 }
977#define turnon(fd, opt) \
978setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on))
979 if (strncmp(sep->se_proto, "tcp", 3) == 0 && (options & SO_DEBUG) &&
980 turnon(sep->se_fd, SO_DEBUG) < 0)
981 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
982 if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
983 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
984#undef turnon
985 if (isrpcservice(sep)) {
986 struct passwd *pwd;
987
988 /*
989 * for RPC services, attempt to use a reserved port
990 * if they are going to be running as root.
991 *
992 * Also, zero out the port for all RPC services; let bind()
993 * find one.
994 */
995 sep->se_ctrladdr_in.sin_port = 0;
996 if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
997 pwd->pw_uid == 0 && uid == 0)
998 r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
999 else {
1000 r = bind(sep->se_fd, &sep->se_ctrladdr,
1001 sep->se_ctrladdr_size);
1002 if (r == 0) {
1003 socklen_t len = sep->se_ctrladdr_size;
1004 int saveerrno = errno;
1005
1006 /* update se_ctrladdr_in.sin_port */
1007 r = getsockname(sep->se_fd, &sep->se_ctrladdr,
1008 &len);
1009 if (r <= 0)
1010 errno = saveerrno;
1011 }
1012 }
1013 } else {
1014 if (sep->se_family == AF_UNIX)
1015 mask = umask(0111);
1016 r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
1017 if (sep->se_family == AF_UNIX)
1018 umask(mask);
1019 }
1020 if (r < 0) {
1021 syslog(LOG_ERR, "%s/%s: bind: %m",
1022 sep->se_service, sep->se_proto);
1023 (void) close(sep->se_fd);
1024 sep->se_fd = -1;
1025 if (!timingout) {
1026 timingout = 1;
1027 alarm(RETRYTIME);
1028 }
1029 return;
1030 }
1031 if (sep->se_socktype == SOCK_STREAM)
1032 listen(sep->se_fd, 10);
1033
1034 fd_grow(&allsockp, &allsockn, sep->se_fd);
1035 FD_SET(sep->se_fd, allsockp);
1036 nsock++;
1037 if (sep->se_fd > maxsock) {
1038 maxsock = sep->se_fd;
1039 if (maxsock > rlim_nofile_cur - FD_MARGIN)
1040 bump_nofile();
1041 }
1042}
1043
1044void
1045register_rpc(struct servtab *sep)
1046{
1047 socklen_t n;
1048 struct sockaddr_in sin;
1049 struct protoent *pp;
1050
1051 if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
1052 syslog(LOG_ERR, "%s: getproto: %m",
1053 sep->se_proto);
1054 return;
1055 }
1056 n = sizeof sin;
1057 if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
1058 syslog(LOG_ERR, "%s/%s: getsockname: %m",
1059 sep->se_service, sep->se_proto);
1060 return;
1061 }
1062
1063 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1064 if (debug)
1065 fprintf(stderr, "pmap_set: %u %u %u %u\n",
1066 sep->se_rpcprog, n, pp->p_proto,
1067 ntohs(sin.sin_port));
1068 (void)pmap_unset(sep->se_rpcprog, n);
1069 if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
1070 syslog(LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
1071 sep->se_service, sep->se_proto,
1072 sep->se_rpcprog, n, pp->p_proto,
1073 ntohs(sin.sin_port));
1074 }
1075}
1076
1077void
1078unregister_rpc(struct servtab *sep)
1079{
1080 int n;
1081
1082 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
1083 if (debug)
1084 fprintf(stderr, "pmap_unset(%u, %u)\n",
1085 sep->se_rpcprog, n);
1086 if (!pmap_unset(sep->se_rpcprog, n))
1087 syslog(LOG_ERR, "pmap_unset(%u, %u)",
1088 sep->se_rpcprog, n);
1089 }
1090}
1091
1092
1093struct servtab *
1094enter(struct servtab *cp)
1095{
1096 struct servtab *sep;
1097 sigset_t omask;
1098
1099 sep = (struct servtab *)malloc(sizeof (*sep));
1100 if (sep == NULL) {
1101 syslog(LOG_ERR, "Out of memory.");
1102 exit(1);
1103 }
1104 *sep = *cp;
1105 sep->se_fd = -1;
1106 sep->se_rpcprog = -1;
1107 sigprocmask(SIG_BLOCK, &blockmask, &omask);
1108 sep->se_next = servtab;
1109 servtab = sep;
1110 sigprocmask(SIG_SETMASK, &omask, NULL);
1111 return (sep);
1112}
1113
1114int
1115matchconf(struct servtab *old, struct servtab *new)
1116{
1117 if (strcmp(old->se_service, new->se_service) != 0)
1118 return (0);
1119
1120 if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
1121 return (0);
1122
1123 if (strcmp(old->se_proto, new->se_proto) != 0)
1124 return (0);
1125
1126 /*
1127 * If the new servtab is bound to a specific address, check that the
1128 * old servtab is bound to the same entry. If the new service is not
1129 * bound to a specific address then the check of se_hostaddr above
1130 * is sufficient.
1131 */
1132
1133 if (old->se_family == AF_INET && new->se_family == AF_INET &&
1134 bcmp(&old->se_ctrladdr_in.sin_addr,
1135 &new->se_ctrladdr_in.sin_addr,
1136 sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
1137 return (0);
1138
1139 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
1140 bcmp(&old->se_ctrladdr_in6.sin6_addr,
1141 &new->se_ctrladdr_in6.sin6_addr,
1142 sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
1143 return (0);
1144 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
1145 old->se_ctrladdr_in6.sin6_scope_id !=
1146 new->se_ctrladdr_in6.sin6_scope_id)
1147 return (0);
1148
1149 return (1);
1150}
1151
1152FILE *fconfig = NULL;
1153char line[1024];
1154char *defhost;
1155char *skip(char **, int);
1156char *nextline(FILE *);
1157char *newstr(char *);
1158struct servtab *dupconfig(struct servtab *);
1159
1160int
1161setconfig(void)
1162{
1163 if (defhost)
1164 free(defhost);
1165 defhost = newstr("*");
1166 if (fconfig != NULL) {
1167 fseek(fconfig, 0L, SEEK_SET);
1168 return (1);
1169 }
1170 fconfig = fopen(CONFIG, "r");
1171 return (fconfig != NULL);
1172}
1173
1174void
1175endconfig(void)
1176{
1177 if (fconfig) {
1178 (void) fclose(fconfig);
1179 fconfig = NULL;
1180 }
1181 if (defhost) {
1182 free(defhost);
1183 defhost = 0;
1184 }
1185}
1186
1187struct servtab *
1188getconfigent(void)
1189{
1190 struct servtab *sep, *tsep;
1191 char *arg, *cp, *hostdelim, *s;
1192 int argc;
1193
1194 sep = (struct servtab *) malloc(sizeof(struct servtab));
1195 if (sep == NULL) {
1196 syslog(LOG_ERR, "malloc: %m");
1197 exit(1);
1198 }
1199
1200 memset(sep, 0, sizeof *sep);
1201more:
1202 freeconfig(sep);
1203
1204 while ((cp = nextline(fconfig)) && *cp == '#')
1205 ;
1206 if (cp == NULL) {
1207 free(sep);
1208 return (NULL);
1209 }
1210
1211 memset(sep, 0, sizeof *sep);
1212 arg = skip(&cp, 0);
1213 if (arg == NULL) {
1214 /* A blank line. */
1215 goto more;
1216 }
1217
1218 /* Check for a host name. */
1219 hostdelim = strrchr(arg, ':');
1220 if (hostdelim) {
1221 *hostdelim = '\0';
1222 if (arg[0] == '[' && hostdelim > arg && hostdelim[-1] == ']') {
1223 hostdelim[-1] = '\0';
1224 sep->se_hostaddr = newstr(arg + 1);
1225 } else if (hostdelim == arg)
1226 sep->se_hostaddr = newstr("*");
1227 else
1228 sep->se_hostaddr = newstr(arg);
1229 arg = hostdelim + 1;
1230 /*
1231 * If the line is of the form `host:', then just change the
1232 * default host for the following lines.
1233 */
1234 if (*arg == '\0') {
1235 arg = skip(&cp, 0);
1236 if (cp == NULL) {
1237 free(defhost);
1238 defhost = newstr(sep->se_hostaddr);
1239 goto more;
1240 }
1241 }
1242 } else
1243 sep->se_hostaddr = newstr(defhost);
1244
1245 sep->se_service = newstr(arg);
1246 if ((arg = skip(&cp, 1)) == NULL)
1247 goto more;
1248
1249 if (strcmp(arg, "stream") == 0)
1250 sep->se_socktype = SOCK_STREAM;
1251 else if (strcmp(arg, "dgram") == 0)
1252 sep->se_socktype = SOCK_DGRAM;
1253 else if (strcmp(arg, "rdm") == 0)
1254 sep->se_socktype = SOCK_RDM;
1255 else if (strcmp(arg, "seqpacket") == 0)
1256 sep->se_socktype = SOCK_SEQPACKET;
1257 else if (strcmp(arg, "raw") == 0)
1258 sep->se_socktype = SOCK_RAW;
1259 else
1260 sep->se_socktype = -1;
1261
1262 if ((arg = skip(&cp, 1)) == NULL)
1263 goto more;
1264
1265 sep->se_proto = newstr(arg);
1266
1267 if (strcmp(sep->se_proto, "unix") == 0) {
1268 sep->se_family = AF_UNIX;
1269 } else {
1270 int s;
1271
1272 sep->se_family = AF_INET;
1273 if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
1274 sep->se_family = AF_INET6;
1275
1276 /* check if the family is supported */
1277 s = socket(sep->se_family, SOCK_DGRAM, 0);
1278 if (s < 0) {
1279 syslog(LOG_WARNING, "%s/%s: %s: the address family is "
1280 "not supported by the kernel", sep->se_service,
1281 sep->se_proto, sep->se_hostaddr);
1282 goto more;
1283 }
1284 close(s);
1285
1286 if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1287 char *cp, *ccp;
1288 long l;
1289
1290 cp = strchr(sep->se_service, '/');
1291 if (cp == 0) {
1292 syslog(LOG_ERR, "%s: no rpc version",
1293 sep->se_service);
1294 goto more;
1295 }
1296 *cp++ = '\0';
1297 l = strtol(cp, &ccp, 0);
1298 if (ccp == cp || l < 0 || l > INT_MAX) {
1299 badafterall:
1300 syslog(LOG_ERR, "%s/%s: bad rpc version",
1301 sep->se_service, cp);
1302 goto more;
1303 }
1304 sep->se_rpcversl = sep->se_rpcversh = l;
1305 if (*ccp == '-') {
1306 cp = ccp + 1;
1307 l = strtol(cp, &ccp, 0);
1308 if (ccp == cp || l < 0 || l > INT_MAX ||
1309 l < sep->se_rpcversl || *ccp)
1310 goto badafterall;
1311 sep->se_rpcversh = l;
1312 } else if (*ccp != '\0')
1313 goto badafterall;
1314 }
1315 }
1316 arg = skip(&cp, 1);
1317 if (arg == NULL)
1318 goto more;
1319
1320 s = strchr(arg, '.');
1321 if (s) {
1322 char *p;
1323
1324 *s++ = '\0';
1325 sep->se_max = strtoul(s, &p, 0);
1326 if (sep->se_max < 1 || *p) {
1327 syslog(LOG_ERR,
1328 "%s: illegal max field \"%s\", setting to %d",
1329 sep->se_service, s, toomany);
1330 sep->se_max = toomany;
1331 }
1332 } else
1333 sep->se_max = toomany;
1334
1335 sep->se_wait = strcmp(arg, "wait") == 0;
1336 if ((arg = skip(&cp, 1)) == NULL)
1337 goto more;
1338 sep->se_user = newstr(arg);
1339 arg = strchr(sep->se_user, '.');
1340 if (arg == NULL)
1341 arg = strchr(sep->se_user, ':');
1342 if (arg) {
1343 *arg++ = '\0';
1344 sep->se_group = newstr(arg);
1345 }
1346 if ((arg = skip(&cp, 1)) == NULL)
1347 goto more;
1348
1349 sep->se_server = newstr(arg);
1350 if (strcmp(sep->se_server, "internal") == 0) {
1351 struct biltin *bi;
1352
1353 for (bi = biltins; bi->bi_service; bi++)
1354 if (bi->bi_socktype == sep->se_socktype &&
1355 strcmp(bi->bi_service, sep->se_service) == 0)
1356 break;
1357 if (bi->bi_service == 0) {
1358 syslog(LOG_ERR, "internal service %s unknown",
1359 sep->se_service);
1360 goto more;
1361 }
1362 sep->se_bi = bi;
1363 sep->se_wait = bi->bi_wait;
1364 } else
1365 sep->se_bi = NULL;
1366 argc = 0;
1367 for (arg = skip(&cp, 0); cp; arg = skip(&cp, 0)) {
1368 if (argc < MAXARGV)
1369 sep->se_argv[argc++] = newstr(arg);
1370 }
1371 if (argc == 0 && sep->se_bi == NULL) {
1372 if ((arg = strrchr(sep->se_server, '/')) != NULL)
1373 arg++;
1374 else
1375 arg = sep->se_server;
1376 sep->se_argv[argc++] = newstr(arg);
1377 }
1378 while (argc <= MAXARGV)
1379 sep->se_argv[argc++] = NULL;
1380
1381 /*
1382 * Resolve each hostname in the se_hostaddr list (if any)
1383 * and create a new entry for each resolved address.
1384 */
1385 if (sep->se_hostaddr != NULL && strcmp(sep->se_proto, "unix") != 0) {
1386 struct addrinfo hints, *res0, *res;
1387 char *host, *hostlist0, *hostlist, *port;
1388 int error;
1389
1390 hostlist = hostlist0 = sep->se_hostaddr;
1391 sep->se_hostaddr = NULL;
1392 sep->se_checked = -1;
1393 while ((host = strsep(&hostlist, ",")) != NULL) {
1394 if (*host == '\0')
1395 continue;
1396
1397 memset(&hints, 0, sizeof(hints));
1398 hints.ai_family = sep->se_family;
1399 hints.ai_socktype = sep->se_socktype;
1400 hints.ai_flags = AI_PASSIVE;
1401 port = "0";
1402 /* XXX shortened IPv4 syntax is now forbidden */
1403 error = getaddrinfo(strcmp(host, "*") ? host : NULL,
1404 port, &hints, &res0);
1405 if (error) {
1406 syslog(LOG_ERR, "%s/%s: %s: %s",
1407 sep->se_service, sep->se_proto,
1408 host, gai_strerror(error));
1409 continue;
1410 }
1411 for (res = res0; res; res = res->ai_next) {
1412 if (res->ai_addrlen >
1413 sizeof(sep->se_ctrladdr_storage))
1414 continue;
1415 /*
1416 * If sep is unused, store host in there.
1417 * Otherwise, dup a new entry and prepend it.
1418 */
1419 if (sep->se_checked == -1) {
1420 sep->se_checked = 0;
1421 } else {
1422 tsep = dupconfig(sep);
1423 tsep->se_next = sep;
1424 sep = tsep;
1425 }
1426 sep->se_hostaddr = newstr(host);
1427 memcpy(&sep->se_ctrladdr_storage,
1428 res->ai_addr, res->ai_addrlen);
1429 sep->se_ctrladdr_size = res->ai_addrlen;
1430 }
1431 freeaddrinfo(res0);
1432 }
1433 free(hostlist0);
1434 if (sep->se_checked == -1)
1435 goto more; /* no resolvable names/addresses */
1436 }
1437
1438 return (sep);
1439}
1440
1441void
1442freeconfig(struct servtab *cp)
1443{
1444 int i;
1445
1446 free(cp->se_hostaddr);
1447 cp->se_hostaddr = NULL;
1448 free(cp->se_service);
1449 cp->se_service = NULL;
1450 free(cp->se_proto);
1451 cp->se_proto = NULL;
1452 free(cp->se_user);
1453 cp->se_user = NULL;
1454 free(cp->se_group);
1455 cp->se_group = NULL;
1456 free(cp->se_server);
1457 cp->se_server = NULL;
1458 for (i = 0; i < MAXARGV; i++) {
1459 free(cp->se_argv[i]);
1460 cp->se_argv[i] = NULL;
1461 }
1462}
1463
1464char *
1465skip(char **cpp, int report)
1466{
1467 char *cp = *cpp;
1468 char *start;
1469
1470erp:
1471 if (*cpp == NULL) {
1472 if (report)
1473 syslog(LOG_ERR, "syntax error in inetd config file");
1474 return (NULL);
1475 }
1476
1477again:
1478 while (*cp == ' ' || *cp == '\t')
1479 cp++;
1480 if (*cp == '\0') {
1481 int c;
1482
1483 c = getc(fconfig);
1484 (void) ungetc(c, fconfig);
1485 if (c == ' ' || c == '\t')
1486 if ((cp = nextline(fconfig)))
1487 goto again;
1488 *cpp = NULL;
1489 goto erp;
1490 }
1491 start = cp;
1492 while (*cp && *cp != ' ' && *cp != '\t')
1493 cp++;
1494 if (*cp != '\0')
1495 *cp++ = '\0';
1496 if ((*cpp = cp) == NULL)
1497 goto erp;
1498
1499 return (start);
1500}
1501
1502char *
1503nextline(FILE *fd)
1504{
1505 if (fgets(line, sizeof (line), fd) == NULL)
1506 return (NULL);
1507 line[strcspn(line, "\n")] = '\0';
1508 return (line);
1509}
1510
1511char *
1512newstr(char *cp)
1513{
1514 if ((cp = strdup(cp ? cp : "")))
1515 return(cp);
1516 syslog(LOG_ERR, "strdup: %m");
1517 exit(1);
1518}
1519
1520struct servtab *
1521dupconfig(struct servtab *sep)
1522{
1523 struct servtab *newtab;
1524 int argc;
1525
1526 newtab = (struct servtab *) malloc(sizeof(struct servtab));
1527
1528 if (newtab == NULL) {
1529 syslog(LOG_ERR, "malloc: %m");
1530 exit(1);
1531 }
1532
1533 memset(newtab, 0, sizeof(struct servtab));
1534
1535 newtab->se_service = sep->se_service ? newstr(sep->se_service) : NULL;
1536 newtab->se_socktype = sep->se_socktype;
1537 newtab->se_family = sep->se_family;
1538 newtab->se_proto = sep->se_proto ? newstr(sep->se_proto) : NULL;
1539 newtab->se_rpcprog = sep->se_rpcprog;
1540 newtab->se_rpcversl = sep->se_rpcversl;
1541 newtab->se_rpcversh = sep->se_rpcversh;
1542 newtab->se_wait = sep->se_wait;
1543 newtab->se_user = sep->se_user ? newstr(sep->se_user) : NULL;
1544 newtab->se_group = sep->se_group ? newstr(sep->se_group) : NULL;
1545 newtab->se_bi = sep->se_bi;
1546 newtab->se_server = sep->se_server ? newstr(sep->se_server) : 0;
1547
1548 for (argc = 0; argc <= MAXARGV; argc++)
1549 newtab->se_argv[argc] = sep->se_argv[argc] ?
1550 newstr(sep->se_argv[argc]) : NULL;
1551 newtab->se_max = sep->se_max;
1552
1553 return (newtab);
1554}
1555
1556void
1557inetd_setproctitle(char *a, int s)
1558{
1559 socklen_t size;
1560 struct sockaddr_storage ss;
1561 char hbuf[NI_MAXHOST];
1562
1563 size = sizeof(ss);
1564 if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
1565 if (getnameinfo((struct sockaddr *)&ss, size, hbuf,
1566 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0)
1567 setproctitle("-%s [%s]", a, hbuf);
1568 else
1569 setproctitle("-%s [?]", a);
1570 } else
1571 setproctitle("-%s", a);
1572}
1573
1574void
1575logpid(void)
1576{
1577 FILE *fp;
1578
1579 if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
1580 fprintf(fp, "%ld\n", (long)getpid());
1581 (void)fclose(fp);
1582 }
1583}
1584
1585int
1586bump_nofile(void)
1587{
1588#define FD_CHUNK 32
1589
1590 struct rlimit rl;
1591
1592 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1593 syslog(LOG_ERR, "getrlimit: %m");
1594 return -1;
1595 }
1596 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1597 rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
1598 if (rl.rlim_cur <= rlim_nofile_cur) {
1599 syslog(LOG_ERR,
1600 "bump_nofile: cannot extend file limit, max = %d",
1601 (int)rl.rlim_cur);
1602 return -1;
1603 }
1604
1605 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
1606 syslog(LOG_ERR, "setrlimit: %m");
1607 return -1;
1608 }
1609
1610 rlim_nofile_cur = rl.rlim_cur;
1611 return 0;
1612}
1613
1614/*
1615 * Internet services provided internally by inetd:
1616 */
1617#define BUFSIZE 4096
1618
1619/* ARGSUSED */
1620void
1621echo_stream(int s, struct servtab *sep)
1622{
1623 char buffer[BUFSIZE];
1624 int i;
1625
1626 inetd_setproctitle(sep->se_service, s);
1627 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1628 write(s, buffer, i) > 0)
1629 ;
1630 exit(0);
1631}
1632
1633/* ARGSUSED */
1634void
1635echo_dg(int s, struct servtab *sep)
1636{
1637 char buffer[BUFSIZE];
1638 int i;
1639 socklen_t size;
1640 struct sockaddr_storage ss;
1641
1642 size = sizeof(ss);
1643 if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
1644 (struct sockaddr *)&ss, &size)) < 0)
1645 return;
1646 if (dg_badinput((struct sockaddr *)&ss))
1647 return;
1648 (void) sendto(s, buffer, i, 0, (struct sockaddr *)&ss, size);
1649}
1650
1651/* ARGSUSED */
1652void
1653discard_stream(int s, struct servtab *sep)
1654{
1655 char buffer[BUFSIZE];
1656
1657 inetd_setproctitle(sep->se_service, s);
1658 while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1659 errno == EINTR)
1660 ;
1661 exit(0);
1662}
1663
1664/* ARGSUSED */
1665void
1666discard_dg(int s, struct servtab *sep)
1667{
1668 char buffer[BUFSIZE];
1669
1670 (void) read(s, buffer, sizeof(buffer));
1671}
1672
1673#include <ctype.h>
1674#define LINESIZ 72
1675char ring[128];
1676char *endring;
1677
1678void
1679initring(void)
1680{
1681 int i;
1682
1683 endring = ring;
1684
1685 for (i = 0; i <= sizeof ring; ++i)
1686 if (isprint(i))
1687 *endring++ = i;
1688}
1689
1690/* ARGSUSED */
1691void
1692chargen_stream(int s, struct servtab *sep)
1693{
1694 char *rs;
1695 int len;
1696 char text[LINESIZ+2];
1697
1698 inetd_setproctitle(sep->se_service, s);
1699
1700 if (!endring) {
1701 initring();
1702 rs = ring;
1703 }
1704
1705 text[LINESIZ] = '\r';
1706 text[LINESIZ + 1] = '\n';
1707 for (rs = ring;;) {
1708 if ((len = endring - rs) >= LINESIZ)
1709 memmove(text, rs, LINESIZ);
1710 else {
1711 memmove(text, rs, len);
1712 memmove(text + len, ring, LINESIZ - len);
1713 }
1714 if (++rs == endring)
1715 rs = ring;
1716 if (write(s, text, sizeof(text)) != sizeof(text))
1717 break;
1718 }
1719 exit(0);
1720}
1721
1722/* ARGSUSED */
1723void
1724chargen_dg(int s, struct servtab *sep)
1725{
1726 struct sockaddr_storage ss;
1727 static char *rs;
1728 int len;
1729 socklen_t size;
1730 char text[LINESIZ+2];
1731
1732 if (endring == 0) {
1733 initring();
1734 rs = ring;
1735 }
1736
1737 size = sizeof(ss);
1738 if (recvfrom(s, text, sizeof(text), 0, (struct sockaddr *)&ss,
1739 &size) < 0)
1740 return;
1741 if (dg_badinput((struct sockaddr *)&ss))
1742 return;
1743
1744 if ((len = endring - rs) >= LINESIZ)
1745 memmove(text, rs, LINESIZ);
1746 else {
1747 memmove(text, rs, len);
1748 memmove(text + len, ring, LINESIZ - len);
1749 }
1750 if (++rs == endring)
1751 rs = ring;
1752 text[LINESIZ] = '\r';
1753 text[LINESIZ + 1] = '\n';
1754 (void) sendto(s, text, sizeof(text), 0, (struct sockaddr *)&ss, size);
1755}
1756
1757/*
1758 * Return a machine readable date and time, in the form of the
1759 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1760 * returns the number of seconds since midnight, Jan 1, 1970,
1761 * we must add 2208988800 seconds to this figure to make up for
1762 * some seventy years Bell Labs was asleep.
1763 */
1764u_int32_t
1765machtime(void)
1766{
1767 struct timeval tv;
1768
1769 if (gettimeofday(&tv, NULL) < 0)
1770 return (0L);
1771
1772 return (htonl((u_int32_t)tv.tv_sec + 2208988800UL));
1773}
1774
1775/* ARGSUSED */
1776void
1777machtime_stream(s, sep)
1778 int s;
1779 struct servtab *sep;
1780{
1781 u_int32_t result;
1782
1783 result = machtime();
1784 (void) write(s, &result, sizeof(result));
1785}
1786
1787/* ARGSUSED */
1788void
1789machtime_dg(int s, struct servtab *sep)
1790{
1791 u_int32_t result;
1792 struct sockaddr_storage ss;
1793 socklen_t size;
1794
1795 size = sizeof(ss);
1796 if (recvfrom(s, &result, sizeof(result), 0,
1797 (struct sockaddr *)&ss, &size) < 0)
1798 return;
1799 if (dg_badinput((struct sockaddr *)&ss))
1800 return;
1801 result = machtime();
1802 (void) sendto(s, &result, sizeof(result), 0,
1803 (struct sockaddr *)&ss, size);
1804}
1805
1806/* Return human-readable time of day */
1807/* ARGSUSED */
1808void
1809daytime_stream(int s, struct servtab *sep)
1810{
1811 char buffer[256];
1812 time_t clock;
1813
1814 clock = time(NULL);
1815
1816 (void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1817 (void) write(s, buffer, strlen(buffer));
1818}
1819
1820/* Return human-readable time of day */
1821/* ARGSUSED */
1822void
1823daytime_dg(int s, struct servtab *sep)
1824{
1825 char buffer[256];
1826 time_t clock;
1827 struct sockaddr_storage ss;
1828 socklen_t size;
1829
1830 clock = time(NULL);
1831
1832 size = sizeof(ss);
1833 if (recvfrom(s, buffer, sizeof(buffer), 0, (struct sockaddr *)&ss,
1834 &size) < 0)
1835 return;
1836 if (dg_badinput((struct sockaddr *)&ss))
1837 return;
1838 (void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1839 (void) sendto(s, buffer, strlen(buffer), 0, (struct sockaddr *)&ss,
1840 size);
1841}
1842
1843/*
1844 * print_service:
1845 * Dump relevant information to stderr
1846 */
1847void
1848print_service(char *action, struct servtab *sep)
1849{
1850 if (strcmp(sep->se_hostaddr, "*") == 0)
1851 fprintf(stderr, "%s: %s ", action, sep->se_service);
1852 else
1853 fprintf(stderr, "%s: %s:%s ", action, sep->se_hostaddr,
1854 sep->se_service);
1855
1856 if (isrpcservice(sep))
1857 fprintf(stderr, "rpcprog=%d, rpcvers=%d/%d, proto=%s,",
1858 sep->se_rpcprog, sep->se_rpcversh,
1859 sep->se_rpcversl, sep->se_proto);
1860 else
1861 fprintf(stderr, "proto=%s,", sep->se_proto);
1862
1863 fprintf(stderr,
1864 " wait.max=%hd.%d user:group=%s:%s builtin=%lx server=%s\n",
1865 sep->se_wait, sep->se_max, sep->se_user,
1866 sep->se_group ? sep->se_group : "(default)",
1867 (long)sep->se_bi, sep->se_server);
1868}
1869
1870void
1871spawn(struct servtab *sep, int ctrl)
1872{
1873 struct passwd *pwd;
1874 int tmpint, dofork;
1875 struct group *grp = NULL;
1876 char buf[50];
1877 pid_t pid;
1878
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches