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