diff options
author | "Vladimir N. Oleynik" <dzo@simtreas.ru> | 2005-10-03 08:08:58 +0000 |
---|---|---|
committer | "Vladimir N. Oleynik" <dzo@simtreas.ru> | 2005-10-03 08:08:58 +0000 |
commit | 1a2f4d9af7b8ec08db75f245e1b513a47c5535d8 (patch) | |
tree | 861e698298dd34d23def9bbf678d18f642cf3977 | |
parent | 7f782da048defae66ad8b602a3cca8e7957a3639 (diff) | |
download | busybox-w32-1a2f4d9af7b8ec08db75f245e1b513a47c5535d8.tar.gz busybox-w32-1a2f4d9af7b8ec08db75f245e1b513a47c5535d8.tar.bz2 busybox-w32-1a2f4d9af7b8ec08db75f245e1b513a47c5535d8.zip |
sync inetd with slackware-10.2 inetd (OpenBSD-1.79), have destroy bug 455
-rw-r--r-- | networking/Config.in | 7 | ||||
-rw-r--r-- | networking/inetd.c | 2397 |
2 files changed, 1494 insertions, 910 deletions
diff --git a/networking/Config.in b/networking/Config.in index 544ee617f..be863d3b6 100644 --- a/networking/Config.in +++ b/networking/Config.in | |||
@@ -305,6 +305,13 @@ config CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN | |||
305 | help | 305 | help |
306 | Familiar character generator internal inetd service | 306 | Familiar character generator internal inetd service |
307 | 307 | ||
308 | config CONFIG_FEATURE_INETD_RPC | ||
309 | bool " Support RPC services" | ||
310 | default n | ||
311 | depends on CONFIG_INETD | ||
312 | help | ||
313 | Suuport Sun-RPC based services | ||
314 | |||
308 | 315 | ||
309 | config CONFIG_IP | 316 | config CONFIG_IP |
310 | bool "ip" | 317 | bool "ip" |
diff --git a/networking/inetd.c b/networking/inetd.c index 0604b14bf..4c16ff375 100644 --- a/networking/inetd.c +++ b/networking/inetd.c | |||
@@ -1,26 +1,38 @@ | |||
1 | /* $Slackware: inetd.c 1.79s 2001/02/06 13:18:00 volkerdi Exp $ */ | ||
2 | /* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */ | ||
3 | /* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */ | ||
4 | /* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */ | ||
1 | /* | 5 | /* |
2 | * Copyright (c) 1983,1991 The Regents of the University of California. | 6 | * Copyright (c) 1983,1991 The Regents of the University of California. |
3 | * All rights reserved. | 7 | * All rights reserved. |
4 | * | 8 | * |
5 | * This code is derived from software contributed to Berkeley by | 9 | * Redistribution and use in source and binary forms, with or without |
6 | * David A. Holland. | 10 | * modification, are permitted provided that the following conditions |
7 | * | 11 | * are met: |
8 | * Busybox port by Vladimir Oleynik (C) 2001-2003 <dzo@simtreas.ru> | 12 | * 1. Redistributions of source code must retain the above copyright |
9 | * | 13 | * notice, this list of conditions and the following disclaimer. |
10 | * This program is free software; you can redistribute it and/or modify | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * it under the terms of the GNU General Public License as published by | 15 | * notice, this list of conditions and the following disclaimer in the |
12 | * the Free Software Foundation; either version 2 of the License, or | 16 | * documentation and/or other materials provided with the distribution. |
13 | * (at your option) any later version. | 17 | * 3. All advertising materials mentioning features or use of this software |
14 | * | 18 | * must display the following acknowledgement: |
15 | * This program is distributed in the hope that it will be useful, | 19 | * This product includes software developed by the University of |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 20 | * California, Berkeley and its contributors. |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 21 | * 4. Neither the name of the University nor the names of its contributors |
18 | * General Public License for more details. | 22 | * may be used to endorse or promote products derived from this software |
19 | * | 23 | * without specific prior written permission. |
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | 24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
35 | * SUCH DAMAGE. | ||
24 | */ | 36 | */ |
25 | 37 | ||
26 | /* | 38 | /* |
@@ -45,70 +57,88 @@ | |||
45 | * Inetd uses a configuration file which is read at startup | 57 | * Inetd uses a configuration file which is read at startup |
46 | * and, possibly, at some later time in response to a hangup signal. | 58 | * and, possibly, at some later time in response to a hangup signal. |
47 | * The configuration file is ``free format'' with fields given in the | 59 | * The configuration file is ``free format'' with fields given in the |
48 | * order shown below. Continuation lines for an entry must being with | 60 | * order shown below. Continuation lines for an entry must begin with |
49 | * a space or tab. All fields must be present in each entry. | 61 | * a space or tab. All fields must be present in each entry. |
50 | * | 62 | * |
51 | * service name must be in /etc/services | 63 | * service name must be in /etc/services |
52 | * socket type stream/dgram/raw/rdm/seqpacket | 64 | * socket type stream/dgram/raw/rdm/seqpacket |
53 | * protocol must be in /etc/protocols | 65 | * protocol must be in /etc/protocols |
54 | * wait/nowait[.max] single-threaded/multi-threaded, max # | 66 | * wait/nowait[.max] single-threaded/multi-threaded, max # |
55 | * user[.group] user/group to run daemon as | 67 | * user[.group] or user[:group] user/group to run daemon as |
68 | * server program full path name | ||
69 | * server program arguments maximum of MAXARGS (20) | ||
70 | * | ||
71 | * For RPC services | ||
72 | * service name/version must be in /etc/rpc | ||
73 | * socket type stream/dgram/raw/rdm/seqpacket | ||
74 | * protocol must be in /etc/protocols | ||
75 | * wait/nowait[.max] single-threaded/multi-threaded | ||
76 | * user[.group] or user[:group] user to run daemon as | ||
56 | * server program full path name | 77 | * server program full path name |
57 | * server program arguments maximum of MAXARGS (20) | 78 | * server program arguments maximum of MAXARGS (20) |
58 | * | 79 | * |
59 | * RPC services unsupported | 80 | * For non-RPC services, the "service name" can be of the form |
81 | * hostaddress:servicename, in which case the hostaddress is used | ||
82 | * as the host portion of the address to listen on. If hostaddress | ||
83 | * consists of a single `*' character, INADDR_ANY is used. | ||
84 | * | ||
85 | * A line can also consist of just | ||
86 | * hostaddress: | ||
87 | * where hostaddress is as in the preceding paragraph. Such a line must | ||
88 | * have no further fields; the specified hostaddress is remembered and | ||
89 | * used for all further lines that have no hostaddress specified, | ||
90 | * until the next such line (or EOF). (This is why * is provided to | ||
91 | * allow explicit specification of INADDR_ANY.) A line | ||
92 | * *: | ||
93 | * is implicitly in effect at the beginning of the file. | ||
94 | * | ||
95 | * The hostaddress specifier may (and often will) contain dots; | ||
96 | * the service name must not. | ||
97 | * | ||
98 | * For RPC services, host-address specifiers are accepted and will | ||
99 | * work to some extent; however, because of limitations in the | ||
100 | * portmapper interface, it will not work to try to give more than | ||
101 | * one line for any given RPC service, even if the host-address | ||
102 | * specifiers are different. | ||
60 | * | 103 | * |
61 | * Comment lines are indicated by a `#' in column 1. | 104 | * Comment lines are indicated by a `#' in column 1. |
62 | */ | 105 | */ |
63 | 106 | ||
64 | /* | 107 | /* |
65 | * Here's the scoop concerning the user.group feature: | 108 | * Here's the scoop concerning the user[.:]group feature: |
66 | * | 109 | * |
67 | * 1) No group listed. | 110 | * 1) set-group-option off. |
68 | * | 111 | * |
69 | * a) for root: NO setuid() or setgid() is done | 112 | * a) user = root: NO setuid() or setgid() is done |
70 | * | 113 | * |
71 | * b) nonroot: setuid() | 114 | * b) other: setgid(primary group as found in passwd) |
72 | * setgid(primary group as found in passwd) | ||
73 | * initgroups(name, primary group) | 115 | * initgroups(name, primary group) |
116 | * setuid() | ||
74 | * | 117 | * |
75 | * 2) set-group-option on. | 118 | * 2) set-group-option on. |
76 | * | 119 | * |
77 | * a) for root: NO setuid() | 120 | * a) user = root: setgid(specified group) |
78 | * setgid(specified group) | 121 | * NO initgroups() |
79 | * setgroups(1, specified group) | 122 | * NO setuid() |
80 | * | 123 | * |
81 | * b) nonroot: setuid() | 124 | * b) other: setgid(specified group) |
82 | * setgid(specified group) | ||
83 | * initgroups(name, specified group) | 125 | * initgroups(name, specified group) |
126 | * setuid() | ||
84 | * | 127 | * |
85 | * All supplementary groups are discarded at startup in case inetd was | ||
86 | * run manually. | ||
87 | */ | 128 | */ |
88 | 129 | ||
89 | #define __USE_BSD_SIGNAL | ||
90 | |||
91 | #include "busybox.h" | ||
92 | |||
93 | |||
94 | #ifndef __linux__ | ||
95 | #ifndef RLIMIT_NOFILE | ||
96 | #define RLIMIT_NOFILE RLIMIT_OFILE | ||
97 | #endif | ||
98 | #endif | ||
99 | |||
100 | #include <sys/file.h> | ||
101 | #include <sys/ioctl.h> | ||
102 | #include <sys/param.h> | 130 | #include <sys/param.h> |
103 | #include <sys/resource.h> | ||
104 | #include <sys/socket.h> | ||
105 | #include <sys/stat.h> | 131 | #include <sys/stat.h> |
106 | #include <sys/time.h> | 132 | #include <sys/ioctl.h> |
133 | #include <sys/socket.h> | ||
107 | #include <sys/un.h> | 134 | #include <sys/un.h> |
135 | #include <sys/file.h> | ||
108 | #include <sys/wait.h> | 136 | #include <sys/wait.h> |
137 | #include <sys/time.h> | ||
138 | #include <sys/resource.h> | ||
139 | |||
109 | 140 | ||
110 | #include <netinet/in.h> | 141 | #include <netinet/in.h> |
111 | #include <netinet/ip.h> | ||
112 | #include <arpa/inet.h> | 142 | #include <arpa/inet.h> |
113 | 143 | ||
114 | #include <errno.h> | 144 | #include <errno.h> |
@@ -117,30 +147,51 @@ | |||
117 | #include <syslog.h> | 147 | #include <syslog.h> |
118 | #include <stdio.h> | 148 | #include <stdio.h> |
119 | #include <stdlib.h> | 149 | #include <stdlib.h> |
120 | #include <string.h> | ||
121 | #include <getopt.h> | ||
122 | #include <unistd.h> | 150 | #include <unistd.h> |
123 | #include <stdarg.h> | 151 | #include <string.h> |
152 | #include <ctype.h> | ||
124 | #include <time.h> | 153 | #include <time.h> |
125 | 154 | ||
126 | #ifndef OPEN_MAX | 155 | #include "busybox.h" |
127 | #define OPEN_MAX 64 | 156 | |
157 | //#define CONFIG_FEATURE_INETD_RPC | ||
158 | //#define CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO | ||
159 | //#define CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD | ||
160 | //#define CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME | ||
161 | //#define CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME | ||
162 | //#define CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN | ||
163 | //#define CONFIG_FEATURE_IPV6 | ||
164 | |||
165 | #ifdef CONFIG_FEATURE_INETD_RPC | ||
166 | #include <rpc/rpc.h> | ||
167 | #include <rpc/pmap_clnt.h> | ||
168 | #include <rpcsvc/nfs_prot.h> | ||
128 | #endif | 169 | #endif |
129 | 170 | ||
130 | #define _PATH_INETDCONF "/etc/inetd.conf" | 171 | #define _PATH_INETDCONF "/etc/inetd.conf" |
131 | #define _PATH_INETDPID "/var/run/inetd.pid" | 172 | #define _PATH_INETDPID "/var/run/inetd.pid" |
132 | 173 | ||
133 | #define TOOMANY 40 /* don't start more than TOOMANY */ | ||
134 | #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ | ||
135 | #define RETRYTIME (60*10) /* retry after bind or server fail */ | ||
136 | #define MAXARGV 20 | ||
137 | 174 | ||
138 | #define se_ctrladdr se_un.se_un_ctrladdr | 175 | #define TOOMANY 0 /* don't start more than TOOMANY */ |
139 | #define se_ctrladdr_in se_un.se_un_ctrladdr_in | 176 | |
140 | #define se_ctrladdr_un se_un.se_un_ctrladdr_un | 177 | #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ |
178 | #define RETRYTIME (60*10) /* retry after bind or server fail */ | ||
179 | |||
180 | #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) | ||
181 | |||
182 | #ifndef RLIMIT_NOFILE | ||
183 | #define RLIMIT_NOFILE RLIMIT_OFILE | ||
184 | #endif | ||
185 | |||
186 | #ifndef OPEN_MAX | ||
187 | #define OPEN_MAX 64 | ||
188 | #endif | ||
141 | 189 | ||
142 | /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */ | 190 | /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */ |
143 | #define FD_MARGIN (8) | 191 | #define FD_MARGIN (8) |
192 | static rlim_t rlim_ofile_cur = OPEN_MAX; | ||
193 | static struct rlimit rlim_ofile; | ||
194 | |||
144 | 195 | ||
145 | /* Check unsupporting builtin */ | 196 | /* Check unsupporting builtin */ |
146 | #if defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO || \ | 197 | #if defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO || \ |
@@ -151,988 +202,1504 @@ | |||
151 | # define INETD_FEATURE_ENABLED | 202 | # define INETD_FEATURE_ENABLED |
152 | #endif | 203 | #endif |
153 | 204 | ||
154 | typedef struct servtab_s { | 205 | #if defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO || \ |
155 | char *se_service; /* name of service */ | 206 | defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD || \ |
156 | int se_socktype; /* type of socket to use */ | 207 | defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN |
157 | int se_family; /* address family */ | 208 | # define INETD_SETPROCTITLE |
158 | char *se_proto; /* protocol used */ | 209 | #endif |
159 | short se_wait; /* single threaded server */ | 210 | |
160 | short se_checked; /* looked at during merge */ | 211 | typedef struct servtab |
161 | char *se_user; /* user name to run as */ | 212 | { |
162 | char *se_group; /* group name to run as */ | 213 | char *se_hostaddr; /* host address to listen on */ |
214 | char *se_service; /* name of service */ | ||
215 | int se_socktype; /* type of socket to use */ | ||
216 | int se_family; /* address family */ | ||
217 | char *se_proto; /* protocol used */ | ||
218 | #ifdef CONFIG_FEATURE_INETD_RPC | ||
219 | int se_rpcprog; /* rpc program number */ | ||
220 | int se_rpcversl; /* rpc program lowest version */ | ||
221 | int se_rpcversh; /* rpc program highest version */ | ||
222 | #define isrpcservice(sep) ((sep)->se_rpcversl != 0) | ||
223 | #else | ||
224 | #define isrpcservice(sep) 0 | ||
225 | #endif | ||
226 | pid_t se_wait; /* single threaded server */ | ||
227 | short se_checked; /* looked at during merge */ | ||
228 | char *se_user; /* user name to run as */ | ||
229 | char *se_group; /* group name to run as */ | ||
163 | #ifdef INETD_FEATURE_ENABLED | 230 | #ifdef INETD_FEATURE_ENABLED |
164 | const struct biltin *se_bi; /* if built-in, description */ | 231 | const struct biltin *se_bi; /* if built-in, description */ |
165 | #endif | 232 | #endif |
166 | char *se_server; /* server program */ | 233 | char *se_server; /* server program */ |
167 | char *se_argv[MAXARGV+1]; /* program arguments */ | 234 | #define MAXARGV 20 |
168 | int se_fd; /* open descriptor */ | 235 | char *se_argv[MAXARGV + 1]; /* program arguments */ |
169 | union { | 236 | int se_fd; /* open descriptor */ |
170 | struct sockaddr se_un_ctrladdr; | 237 | union |
171 | struct sockaddr_in se_un_ctrladdr_in; | 238 | { |
172 | struct sockaddr_un se_un_ctrladdr_un; | 239 | struct sockaddr se_un_ctrladdr; |
173 | } se_un; /* bound address */ | 240 | struct sockaddr_in se_un_ctrladdr_in; |
174 | int se_ctrladdr_size; | 241 | #ifdef CONFIG_FEATURE_IPV6 |
175 | int se_max; /* max # of instances of this service */ | 242 | struct sockaddr_in6 se_un_ctrladdr_in6; |
176 | int se_count; /* number started since se_time */ | 243 | #endif |
177 | struct timeval se_time; /* start of se_count */ | 244 | struct sockaddr_un se_un_ctrladdr_un; |
178 | struct servtab_s *se_next; | 245 | } se_un; /* bound address */ |
246 | #define se_ctrladdr se_un.se_un_ctrladdr | ||
247 | #define se_ctrladdr_in se_un.se_un_ctrladdr_in | ||
248 | #define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6 | ||
249 | #define se_ctrladdr_un se_un.se_un_ctrladdr_un | ||
250 | int se_ctrladdr_size; | ||
251 | int se_max; /* max # of instances of this service */ | ||
252 | int se_count; /* number started since se_time */ | ||
253 | struct timeval se_time; /* start of se_count */ | ||
254 | struct servtab *se_next; | ||
179 | } servtab_t; | 255 | } servtab_t; |
180 | 256 | ||
181 | static servtab_t *servtab; | 257 | static servtab_t *servtab; |
182 | 258 | ||
183 | #ifdef INETD_FEATURE_ENABLED | 259 | #ifdef INETD_FEATURE_ENABLED |
184 | struct biltin { | 260 | struct biltin |
185 | const char *bi_service; /* internally provided service name */ | 261 | { |
186 | int bi_socktype; /* type of socket supported */ | 262 | const char *bi_service; /* internally provided service name */ |
187 | short bi_fork; /* 1 if should fork before call */ | 263 | int bi_socktype; /* type of socket supported */ |
188 | short bi_wait; /* 1 if should wait for child */ | 264 | short bi_fork; /* 1 if should fork before call */ |
189 | void (*bi_fn)(int, servtab_t *); /* fn which performs it */ | 265 | short bi_wait; /* 1 if should wait for child */ |
266 | void (*bi_fn) (int, servtab_t *); | ||
190 | }; | 267 | }; |
191 | 268 | ||
192 | /* Echo received data */ | 269 | /* Echo received data */ |
193 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO | 270 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO |
194 | static void echo_stream(int, servtab_t *); | 271 | static void echo_stream (int, servtab_t *); |
195 | static void echo_dg(int, servtab_t *); | 272 | static void echo_dg (int, servtab_t *); |
196 | #endif | 273 | #endif |
197 | /* Internet /dev/null */ | 274 | /* Internet /dev/null */ |
198 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD | 275 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD |
199 | static void discard_stream(int, servtab_t *); | 276 | static void discard_stream (int, servtab_t *); |
200 | static void discard_dg(int, servtab_t *); | 277 | static void discard_dg (int, servtab_t *); |
201 | #endif | 278 | #endif |
202 | /* Return 32 bit time since 1900 */ | 279 | /* Return 32 bit time since 1900 */ |
203 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME | 280 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME |
204 | static void machtime_stream(int, servtab_t *); | 281 | static void machtime_stream (int, servtab_t *); |
205 | static void machtime_dg(int, servtab_t *); | 282 | static void machtime_dg (int, servtab_t *); |
206 | #endif | 283 | #endif |
207 | /* Return human-readable time */ | 284 | /* Return human-readable time */ |
208 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME | 285 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME |
209 | static void daytime_stream(int, servtab_t *); | 286 | static void daytime_stream (int, servtab_t *); |
210 | static void daytime_dg(int, servtab_t *); | 287 | static void daytime_dg (int, servtab_t *); |
211 | #endif | 288 | #endif |
212 | /* Familiar character generator */ | 289 | /* Familiar character generator */ |
213 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN | 290 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN |
214 | static void chargen_stream(int, servtab_t *); | 291 | static void chargen_stream (int, servtab_t *); |
215 | static void chargen_dg(int, servtab_t *); | 292 | static void chargen_dg (int, servtab_t *); |
216 | #endif | 293 | #endif |
217 | 294 | ||
218 | static const struct biltin biltins[] = { | 295 | static const struct biltin biltins[] = { |
219 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO | 296 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO |
220 | /* Echo received data */ | 297 | /* Echo received data */ |
221 | { "echo", SOCK_STREAM, 1, 0, echo_stream, }, | 298 | {"echo", SOCK_STREAM, 1, 0, echo_stream,}, |
222 | { "echo", SOCK_DGRAM, 0, 0, echo_dg, }, | 299 | {"echo", SOCK_DGRAM, 0, 0, echo_dg,}, |
223 | #endif | 300 | #endif |
224 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD | 301 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD |
225 | /* Internet /dev/null */ | 302 | /* Internet /dev/null */ |
226 | { "discard", SOCK_STREAM, 1, 0, discard_stream, }, | 303 | {"discard", SOCK_STREAM, 1, 0, discard_stream,}, |
227 | { "discard", SOCK_DGRAM, 0, 0, discard_dg, }, | 304 | {"discard", SOCK_DGRAM, 0, 0, discard_dg,}, |
228 | #endif | 305 | #endif |
229 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME | 306 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME |
230 | /* Return 32 bit time since 1900 */ | 307 | /* Return 32 bit time since 1900 */ |
231 | { "time", SOCK_STREAM, 0, 0, machtime_stream, }, | 308 | {"time", SOCK_STREAM, 0, 0, machtime_stream,}, |
232 | { "time", SOCK_DGRAM, 0, 0, machtime_dg, }, | 309 | {"time", SOCK_DGRAM, 0, 0, machtime_dg,}, |
233 | #endif | 310 | #endif |
234 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME | 311 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME |
235 | /* Return human-readable time */ | 312 | /* Return human-readable time */ |
236 | { "daytime", SOCK_STREAM, 0, 0, daytime_stream, }, | 313 | {"daytime", SOCK_STREAM, 0, 0, daytime_stream,}, |
237 | { "daytime", SOCK_DGRAM, 0, 0, daytime_dg, }, | 314 | {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,}, |
238 | #endif | 315 | #endif |
239 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN | 316 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN |
240 | /* Familiar character generator */ | 317 | /* Familiar character generator */ |
241 | { "chargen", SOCK_STREAM, 1, 0, chargen_stream, }, | 318 | {"chargen", SOCK_STREAM, 1, 0, chargen_stream,}, |
242 | { "chargen", SOCK_DGRAM, 0, 0, chargen_dg, }, | 319 | {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,}, |
243 | #endif | 320 | #endif |
244 | { NULL, 0, 0, 0, NULL } | 321 | {NULL, 0, 0, 0, NULL} |
245 | }; | 322 | }; |
246 | #endif /* INETD_FEATURE_ENABLED */ | 323 | #endif /* INETD_FEATURE_ENABLED */ |
247 | 324 | ||
248 | #ifdef RLIMIT_NOFILE | 325 | static int global_queuelen = 128; |
249 | static struct rlimit rlim_ofile; | 326 | static int nsock, maxsock; |
250 | #endif | 327 | static fd_set allsock; |
328 | static int toomany = TOOMANY; | ||
329 | static int timingout; | ||
330 | static struct servent *sp; | ||
331 | static uid_t uid; | ||
251 | 332 | ||
252 | /* Length of socket listen queue. Should be per-service probably. */ | 333 | static char *CONFIG = _PATH_INETDCONF; |
253 | static int global_queuelen = 128; | ||
254 | 334 | ||
255 | static FILE *fconfig; | 335 | static FILE *fconfig; |
256 | static sigset_t blockmask; | 336 | static char line[1024]; |
257 | static sigset_t emptymask; | 337 | static char *defhost; |
258 | static fd_set allsock; | ||
259 | static int nsock; | ||
260 | static int maxsock; | ||
261 | static int timingout; | ||
262 | static int rlim_ofile_cur = OPEN_MAX; | ||
263 | static const char *CONFIG = _PATH_INETDCONF; | ||
264 | 338 | ||
265 | static void | 339 | static char *newstr (char *cp) |
266 | syslog_err_and_discard_dg(int se_socktype, const char *msg, ...) | 340 | { |
267 | __attribute__ ((noreturn, format (printf, 2, 3))); | 341 | if ((cp = strdup (cp ? cp : ""))) |
342 | return (cp); | ||
343 | syslog (LOG_ERR, "strdup: %m"); | ||
344 | exit (1); | ||
345 | } | ||
268 | 346 | ||
269 | static void | 347 | static int setconfig (void) |
270 | syslog_err_and_discard_dg(int se_socktype, const char *msg, ...) | ||
271 | { | 348 | { |
272 | char buf[50]; | 349 | free (defhost); |
273 | va_list p; | 350 | defhost = newstr ("*"); |
274 | 351 | if (fconfig != NULL) { | |
275 | va_start(p, msg); | 352 | fseek (fconfig, 0L, SEEK_SET); |
276 | vsyslog(LOG_ERR, msg, p); | 353 | return (1); |
277 | if (se_socktype != SOCK_STREAM) | 354 | } |
278 | recv(0, buf, sizeof (buf), 0); | 355 | fconfig = fopen (CONFIG, "r"); |
279 | _exit(1); | 356 | return (fconfig != NULL); |
280 | } | 357 | } |
281 | 358 | ||
282 | static char * inetd_strdup(const char *s) | 359 | static void endconfig (void) |
283 | { | 360 | { |
284 | char *ms = strdup(s); | 361 | if (fconfig) { |
362 | (void) fclose (fconfig); | ||
363 | fconfig = NULL; | ||
364 | } | ||
365 | free (defhost); | ||
366 | defhost = 0; | ||
367 | } | ||
285 | 368 | ||
286 | if(ms == NULL) | 369 | #ifdef CONFIG_FEATURE_INETD_RPC |
287 | syslog_err_and_discard_dg(SOCK_STREAM, "strdup: %m"); | 370 | static void register_rpc (servtab_t *sep) |
288 | return ms; | 371 | { |
372 | int n; | ||
373 | struct sockaddr_in ir_sin; | ||
374 | struct protoent *pp; | ||
375 | |||
376 | if ((pp = getprotobyname (sep->se_proto + 4)) == NULL) { | ||
377 | syslog (LOG_ERR, "%s: getproto: %m", sep->se_proto); | ||
378 | return; | ||
379 | } | ||
380 | n = sizeof ir_sin; | ||
381 | if (getsockname (sep->se_fd, (struct sockaddr *) &ir_sin, &n) < 0) { | ||
382 | syslog (LOG_ERR, "%s/%s: getsockname: %m", | ||
383 | sep->se_service, sep->se_proto); | ||
384 | return; | ||
385 | } | ||
386 | |||
387 | for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { | ||
388 | (void) pmap_unset (sep->se_rpcprog, n); | ||
389 | if (!pmap_set (sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port))) | ||
390 | syslog (LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m", | ||
391 | sep->se_service, sep->se_proto, | ||
392 | sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port)); | ||
393 | } | ||
289 | } | 394 | } |
290 | 395 | ||
396 | static void unregister_rpc (servtab_t *sep) | ||
397 | { | ||
398 | int n; | ||
399 | |||
400 | for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) { | ||
401 | if (!pmap_unset (sep->se_rpcprog, n)) | ||
402 | syslog (LOG_ERR, "pmap_unset(%u, %u)", sep->se_rpcprog, n); | ||
403 | } | ||
404 | } | ||
405 | #endif /* CONFIG_FEATURE_INETD_RPC */ | ||
291 | 406 | ||
292 | static servtab_t *getconfigent(void) | 407 | static void freeconfig (servtab_t *cp) |
293 | { | 408 | { |
294 | static servtab_t serv; | 409 | int i; |
295 | servtab_t *sep = &serv; | 410 | |
296 | int argc; | 411 | free (cp->se_hostaddr); |
297 | char *cp = NULL; | 412 | free (cp->se_service); |
298 | char *cp_ptr; | 413 | free (cp->se_proto); |
299 | char *cp_ptr_ptr = NULL; | 414 | free (cp->se_user); |
415 | free (cp->se_group); | ||
416 | free (cp->se_server); | ||
417 | for (i = 0; i < MAXARGV; i++) | ||
418 | if (cp->se_argv[i]) | ||
419 | free (cp->se_argv[i]); | ||
420 | } | ||
300 | 421 | ||
301 | more: | 422 | static int bump_nofile (void) |
302 | free(cp); | 423 | { |
303 | cp = bb_get_chomped_line_from_file(fconfig); | 424 | #define FD_CHUNK 32 |
304 | if (feof(fconfig)) { | 425 | |
305 | free(cp); | 426 | struct rlimit rl; |
306 | return (NULL); | 427 | |
307 | } | 428 | if (getrlimit (RLIMIT_NOFILE, &rl) < 0) { |
308 | if ((cp == NULL) || (*cp == '#')) { | 429 | syslog (LOG_ERR, "getrlimit: %m"); |
309 | goto more; | 430 | return -1; |
310 | } | 431 | } |
311 | /* make bind 0.0.0.0 and other zero default */ | 432 | rl.rlim_cur = MIN (rl.rlim_max, rl.rlim_cur + FD_CHUNK); |
312 | memset((char *)sep, 0, sizeof *sep); | 433 | rl.rlim_cur = MIN (FD_SETSIZE, rl.rlim_cur + FD_CHUNK); |
434 | if (rl.rlim_cur <= rlim_ofile_cur) { | ||
435 | syslog (LOG_ERR, "bump_nofile: cannot extend file limit, max = %d", | ||
436 | (int) rl.rlim_cur); | ||
437 | return -1; | ||
438 | } | ||
439 | |||
440 | if (setrlimit (RLIMIT_NOFILE, &rl) < 0) { | ||
441 | syslog (LOG_ERR, "setrlimit: %m"); | ||
442 | return -1; | ||
443 | } | ||
444 | |||
445 | rlim_ofile_cur = rl.rlim_cur; | ||
446 | return 0; | ||
447 | } | ||
313 | 448 | ||
314 | cp_ptr = strtok_r(cp, " \t", &cp_ptr_ptr); | 449 | static void setup (servtab_t *sep) |
315 | if (cp_ptr == NULL) { | 450 | { |
316 | /* Error */ | 451 | int on = 1; |
317 | goto more; | 452 | int r; |
318 | } | 453 | |
319 | sep->se_service = inetd_strdup(cp_ptr); | 454 | if ((sep->se_fd = socket (sep->se_family, sep->se_socktype, 0)) < 0) { |
455 | syslog (LOG_ERR, "%s/%s: socket: %m", sep->se_service, sep->se_proto); | ||
456 | return; | ||
457 | } | ||
458 | #define turnon(fd, opt) \ | ||
459 | setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on)) | ||
460 | if (turnon (sep->se_fd, SO_REUSEADDR) < 0) | ||
461 | syslog (LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); | ||
462 | #undef turnon | ||
463 | |||
464 | #ifdef CONFIG_FEATURE_INETD_RPC | ||
465 | if (isrpcservice (sep)) { | ||
466 | struct passwd *pwd; | ||
320 | 467 | ||
321 | cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr); | 468 | /* |
322 | if (cp_ptr == NULL) { | 469 | * for RPC services, attempt to use a reserved port |
323 | /* Error */ | 470 | * if they are going to be running as root. |
324 | goto more; | 471 | * |
325 | } | 472 | * Also, zero out the port for all RPC services; let bind() |
326 | if (strcmp(cp_ptr, "stream") == 0) | 473 | * find one. |
327 | sep->se_socktype = SOCK_STREAM; | 474 | */ |
328 | else if (strcmp(cp_ptr, "dgram") == 0) | 475 | sep->se_ctrladdr_in.sin_port = 0; |
329 | sep->se_socktype = SOCK_DGRAM; | 476 | if (sep->se_user && (pwd = getpwnam (sep->se_user)) && |
330 | else if (strcmp(cp_ptr, "rdm") == 0) | 477 | pwd->pw_uid == 0 && uid == 0) |
331 | sep->se_socktype = SOCK_RDM; | 478 | r = bindresvport (sep->se_fd, &sep->se_ctrladdr_in); |
332 | else if (strcmp(cp_ptr, "seqpacket") == 0) | 479 | else { |
333 | sep->se_socktype = SOCK_SEQPACKET; | 480 | r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size); |
334 | else if (strcmp(cp_ptr, "raw") == 0) | 481 | if (r == 0) { |
335 | sep->se_socktype = SOCK_RAW; | 482 | int len = sep->se_ctrladdr_size; |
336 | else | 483 | int saveerrno = errno; |
337 | sep->se_socktype = -1; | 484 | |
338 | 485 | /* update se_ctrladdr_in.sin_port */ | |
339 | cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr); | 486 | r = getsockname (sep->se_fd, &sep->se_ctrladdr, &len); |
340 | if (cp_ptr == NULL) { | 487 | if (r <= 0) |
341 | /* error */ | 488 | errno = saveerrno; |
342 | goto more; | 489 | } |
343 | } | 490 | } |
344 | if (strcmp(cp_ptr, "unix") == 0) { | 491 | } else |
345 | sep->se_family = AF_UNIX; | 492 | #endif |
346 | } else { | 493 | r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size); |
347 | if (strncmp(cp_ptr, "rpc/", 4) == 0) { | 494 | if (r < 0) { |
348 | syslog(LOG_ERR, "%s: rpc services not supported", | 495 | syslog (LOG_ERR, "%s/%s (%d): bind: %m", |
349 | sep->se_service); | 496 | sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family); |
350 | goto more; | 497 | close (sep->se_fd); |
351 | } | 498 | sep->se_fd = -1; |
352 | sep->se_family = AF_INET; | 499 | if (!timingout) { |
500 | timingout = 1; | ||
501 | alarm (RETRYTIME); | ||
353 | } | 502 | } |
354 | sep->se_proto = inetd_strdup(cp_ptr); | 503 | return; |
504 | } | ||
505 | if (sep->se_socktype == SOCK_STREAM) | ||
506 | listen (sep->se_fd, global_queuelen); | ||
507 | |||
508 | FD_SET (sep->se_fd, &allsock); | ||
509 | nsock++; | ||
510 | if (sep->se_fd > maxsock) { | ||
511 | maxsock = sep->se_fd; | ||
512 | if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) | ||
513 | bump_nofile (); | ||
514 | } | ||
515 | } | ||
355 | 516 | ||
356 | cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr); | 517 | static char *nextline (void) |
357 | if (cp_ptr == NULL) { | 518 | { |
358 | /* error */ | 519 | char *cp; |
359 | goto more; | 520 | FILE *fd = fconfig; |
360 | } | 521 | |
361 | { | 522 | if (fgets (line, sizeof (line), fd) == NULL) |
362 | char *s = strchr(cp_ptr, '.'); | 523 | return (NULL); |
363 | if (s) { | 524 | cp = strchr (line, '\n'); |
364 | *s++ = '\0'; | 525 | if (cp) |
365 | sep->se_max = atoi(s); | 526 | *cp = '\0'; |
366 | } else | 527 | return (line); |
367 | sep->se_max = TOOMANY; | 528 | } |
368 | } | ||
369 | sep->se_wait = strcmp(cp_ptr, "wait") == 0; | ||
370 | 529 | ||
371 | cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr); | 530 | static char *skip (char **cpp) /* int report; */ |
372 | if (cp_ptr == NULL) { | 531 | { |
373 | /* error */ | 532 | char *cp = *cpp; |
374 | goto more; | 533 | char *start; |
375 | } | 534 | |
535 | /* erp: */ | ||
536 | if (*cpp == NULL) { | ||
537 | /* if (report) */ | ||
538 | /* syslog(LOG_ERR, "syntax error in inetd config file"); */ | ||
539 | return (NULL); | ||
540 | } | ||
541 | |||
542 | again: | ||
543 | while (*cp == ' ' || *cp == '\t') | ||
544 | cp++; | ||
545 | if (*cp == '\0') { | ||
546 | int c; | ||
547 | |||
548 | c = getc (fconfig); | ||
549 | (void) ungetc (c, fconfig); | ||
550 | if (c == ' ' || c == '\t') | ||
551 | if ((cp = nextline ())) | ||
552 | goto again; | ||
553 | *cpp = NULL; | ||
554 | /* goto erp; */ | ||
555 | return (NULL); | ||
556 | } | ||
557 | start = cp; | ||
558 | while (*cp && *cp != ' ' && *cp != '\t') | ||
559 | cp++; | ||
560 | if (*cp != '\0') | ||
561 | *cp++ = '\0'; | ||
562 | /* if ((*cpp = cp) == NULL) */ | ||
563 | /* goto erp; */ | ||
564 | |||
565 | *cpp = cp; | ||
566 | return (start); | ||
567 | } | ||
376 | 568 | ||
377 | sep->se_user = inetd_strdup(cp_ptr); | 569 | static servtab_t *new_servtab(void) |
378 | { | 570 | { |
379 | char *cp_ptr2 = strchr(sep->se_user, '.'); | 571 | servtab_t *sep; |
572 | |||
573 | sep = (servtab_t *) malloc (sizeof (servtab_t)); | ||
574 | if (sep == NULL) { | ||
575 | syslog (LOG_ERR, bb_msg_memory_exhausted); | ||
576 | exit (1); | ||
577 | } | ||
578 | return sep; | ||
579 | } | ||
380 | 580 | ||
381 | if (cp_ptr2) { | 581 | static servtab_t *dupconfig (servtab_t *sep) |
382 | *cp_ptr2++ = '\0'; | 582 | { |
383 | } | 583 | servtab_t *newtab; |
384 | sep->se_group = cp_ptr2; | 584 | int argc; |
385 | } | 585 | |
586 | newtab = new_servtab(); | ||
587 | memset (newtab, 0, sizeof (servtab_t)); | ||
588 | newtab->se_service = sep->se_service ? newstr (sep->se_service) : NULL; | ||
589 | newtab->se_socktype = sep->se_socktype; | ||
590 | newtab->se_family = sep->se_family; | ||
591 | newtab->se_proto = sep->se_proto ? newstr (sep->se_proto) : NULL; | ||
592 | #ifdef CONFIG_FEATURE_INETD_RPC | ||
593 | newtab->se_rpcprog = sep->se_rpcprog; | ||
594 | newtab->se_rpcversl = sep->se_rpcversl; | ||
595 | newtab->se_rpcversh = sep->se_rpcversh; | ||
596 | #endif | ||
597 | newtab->se_wait = sep->se_wait; | ||
598 | newtab->se_user = sep->se_user ? newstr (sep->se_user) : NULL; | ||
599 | newtab->se_group = sep->se_group ? newstr (sep->se_group) : NULL; | ||
600 | #ifdef INETD_FEATURE_ENABLED | ||
601 | newtab->se_bi = sep->se_bi; | ||
602 | #endif | ||
603 | newtab->se_server = sep->se_server ? newstr (sep->se_server) : 0; | ||
604 | |||
605 | for (argc = 0; argc <= MAXARGV; argc++) | ||
606 | newtab->se_argv[argc] = sep->se_argv[argc] ? | ||
607 | newstr (sep->se_argv[argc]) : NULL; | ||
608 | newtab->se_max = sep->se_max; | ||
386 | 609 | ||
387 | cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr); | 610 | return (newtab); |
388 | if (cp_ptr == NULL) { | 611 | } |
389 | /* error */ | 612 | |
613 | static servtab_t *getconfigent (void) | ||
614 | { | ||
615 | servtab_t *sep; | ||
616 | int argc; | ||
617 | char *cp, *arg; | ||
618 | char *hostdelim; | ||
619 | servtab_t *nsep; | ||
620 | servtab_t *psep; | ||
621 | |||
622 | sep = new_servtab(); | ||
623 | |||
624 | /* memset(sep, 0, sizeof *sep); */ | ||
625 | more: | ||
626 | /* freeconfig(sep); */ | ||
627 | |||
628 | while ((cp = nextline ()) && *cp == '#'); | ||
629 | if (cp == NULL) { | ||
630 | /* free(sep); */ | ||
631 | return (NULL); | ||
632 | } | ||
633 | |||
634 | memset ((char *) sep, 0, sizeof *sep); | ||
635 | arg = skip (&cp); | ||
636 | if (arg == NULL) { | ||
637 | /* A blank line. */ | ||
638 | goto more; | ||
639 | } | ||
640 | |||
641 | /* Check for a host name. */ | ||
642 | hostdelim = strrchr (arg, ':'); | ||
643 | if (hostdelim) { | ||
644 | *hostdelim = '\0'; | ||
645 | sep->se_hostaddr = newstr (arg); | ||
646 | arg = hostdelim + 1; | ||
647 | /* | ||
648 | * If the line is of the form `host:', then just change the | ||
649 | * default host for the following lines. | ||
650 | */ | ||
651 | if (*arg == '\0') { | ||
652 | arg = skip (&cp); | ||
653 | if (cp == NULL) { | ||
654 | free (defhost); | ||
655 | defhost = sep->se_hostaddr; | ||
390 | goto more; | 656 | goto more; |
657 | } | ||
391 | } | 658 | } |
392 | if (strcmp(cp_ptr, "internal") == 0) { | 659 | } else |
393 | #ifdef INETD_FEATURE_ENABLED | 660 | sep->se_hostaddr = newstr (defhost); |
394 | const struct biltin *bi; | 661 | |
395 | 662 | sep->se_service = newstr (arg); | |
396 | for (bi = biltins; bi->bi_service; bi++) { | 663 | arg = skip (&cp); |
397 | if ((bi->bi_socktype == sep->se_socktype) && | 664 | |
398 | (strcmp(bi->bi_service, sep->se_service) == 0)) { | 665 | if (strcmp (arg, "stream") == 0) |
399 | break; | 666 | sep->se_socktype = SOCK_STREAM; |
400 | } | 667 | else if (strcmp (arg, "dgram") == 0) |
401 | } | 668 | sep->se_socktype = SOCK_DGRAM; |
402 | if (bi->bi_service == 0) { | 669 | else if (strcmp (arg, "rdm") == 0) |
403 | syslog(LOG_ERR, "internal service %s unknown", sep->se_service); | 670 | sep->se_socktype = SOCK_RDM; |
404 | goto more; | 671 | else if (strcmp (arg, "seqpacket") == 0) |
405 | } | 672 | sep->se_socktype = SOCK_SEQPACKET; |
406 | sep->se_bi = bi; | 673 | else if (strcmp (arg, "raw") == 0) |
407 | sep->se_wait = bi->bi_wait; | 674 | sep->se_socktype = SOCK_RAW; |
675 | else | ||
676 | sep->se_socktype = -1; | ||
677 | |||
678 | sep->se_proto = newstr (skip (&cp)); | ||
679 | |||
680 | if (strcmp (sep->se_proto, "unix") == 0) { | ||
681 | sep->se_family = AF_UNIX; | ||
682 | } else { | ||
683 | sep->se_family = AF_INET; | ||
684 | if (sep->se_proto[strlen (sep->se_proto) - 1] == '6') | ||
685 | #ifdef CONFIG_FEATURE_IPV6 | ||
686 | sep->se_family = AF_INET6; | ||
408 | #else | 687 | #else |
409 | syslog(LOG_ERR, "internal service %s unknown", cp_ptr); | 688 | syslog (LOG_ERR, "%s: IPV6 not supported", sep->se_proto); |
689 | #endif | ||
690 | if (strncmp (sep->se_proto, "rpc/", 4) == 0) { | ||
691 | #ifdef CONFIG_FEATURE_INETD_RPC | ||
692 | char *p, *ccp; | ||
693 | long l; | ||
694 | |||
695 | p = strchr (sep->se_service, '/'); | ||
696 | if (p == 0) { | ||
697 | syslog (LOG_ERR, "%s: no rpc version", sep->se_service); | ||
698 | goto more; | ||
699 | } | ||
700 | *p++ = '\0'; | ||
701 | l = strtol (p, &ccp, 0); | ||
702 | if (ccp == p || l < 0 || l > INT_MAX) { | ||
703 | badafterall: | ||
704 | syslog (LOG_ERR, "%s/%s: bad rpc version", sep->se_service, p); | ||
410 | goto more; | 705 | goto more; |
706 | } | ||
707 | sep->se_rpcversl = sep->se_rpcversh = l; | ||
708 | if (*ccp == '-') { | ||
709 | p = ccp + 1; | ||
710 | l = strtol (p, &ccp, 0); | ||
711 | if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp) | ||
712 | goto badafterall; | ||
713 | sep->se_rpcversh = l; | ||
714 | } else if (*ccp != '\0') | ||
715 | goto badafterall; | ||
716 | #else | ||
717 | syslog (LOG_ERR, "%s: rpc services not supported", sep->se_service); | ||
411 | #endif | 718 | #endif |
412 | } | 719 | } |
720 | } | ||
721 | arg = skip (&cp); | ||
722 | if (arg == NULL) | ||
723 | goto more; | ||
724 | |||
725 | { | ||
726 | char *s = strchr (arg, '.'); | ||
727 | if (s) { | ||
728 | *s++ = '\0'; | ||
729 | sep->se_max = atoi (s); | ||
730 | } else | ||
731 | sep->se_max = toomany; | ||
732 | } | ||
733 | sep->se_wait = strcmp (arg, "wait") == 0; | ||
734 | /* if ((arg = skip(&cp, 1)) == NULL) */ | ||
735 | /* goto more; */ | ||
736 | sep->se_user = newstr (skip (&cp)); | ||
737 | arg = strchr (sep->se_user, '.'); | ||
738 | if (arg == NULL) | ||
739 | arg = strchr (sep->se_user, ':'); | ||
740 | if (arg) { | ||
741 | *arg++ = '\0'; | ||
742 | sep->se_group = newstr (arg); | ||
743 | } | ||
744 | /* if ((arg = skip(&cp, 1)) == NULL) */ | ||
745 | /* goto more; */ | ||
746 | |||
747 | sep->se_server = newstr (skip (&cp)); | ||
748 | if (strcmp (sep->se_server, "internal") == 0) { | ||
413 | #ifdef INETD_FEATURE_ENABLED | 749 | #ifdef INETD_FEATURE_ENABLED |
414 | else { | 750 | const struct biltin *bi; |
415 | sep->se_bi = NULL; | 751 | |
752 | for (bi = biltins; bi->bi_service; bi++) | ||
753 | if (bi->bi_socktype == sep->se_socktype && | ||
754 | strcmp (bi->bi_service, sep->se_service) == 0) | ||
755 | break; | ||
756 | if (bi->bi_service == 0) { | ||
757 | syslog (LOG_ERR, "internal service %s unknown", sep->se_service); | ||
758 | goto more; | ||
416 | } | 759 | } |
760 | sep->se_bi = bi; | ||
761 | sep->se_wait = bi->bi_wait; | ||
762 | #else | ||
763 | syslog (LOG_ERR, "internal service %s unknown", sep->se_service); | ||
764 | goto more; | ||
765 | #endif | ||
766 | } | ||
767 | #ifdef INETD_FEATURE_ENABLED | ||
768 | else | ||
769 | sep->se_bi = NULL; | ||
417 | #endif | 770 | #endif |
418 | sep->se_server = inetd_strdup(cp_ptr); | 771 | argc = 0; |
772 | for (arg = skip (&cp); cp; arg = skip (&cp)) { | ||
773 | if (argc < MAXARGV) | ||
774 | sep->se_argv[argc++] = newstr (arg); | ||
775 | } | ||
776 | while (argc <= MAXARGV) | ||
777 | sep->se_argv[argc++] = NULL; | ||
778 | |||
779 | /* | ||
780 | * Now that we've processed the entire line, check if the hostname | ||
781 | * specifier was a comma separated list of hostnames. If so | ||
782 | * we'll make new entries for each address. | ||
783 | */ | ||
784 | while ((hostdelim = strrchr (sep->se_hostaddr, ',')) != NULL) { | ||
785 | nsep = dupconfig (sep); | ||
419 | 786 | ||
420 | argc = 0; | 787 | /* |
421 | while ((cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr)) != NULL) { | 788 | * NULL terminate the hostname field of the existing entry, |
422 | if (argc < MAXARGV) { | 789 | * and make a dup for the new entry. |
423 | sep->se_argv[argc++] = inetd_strdup(cp_ptr); | 790 | */ |
791 | *hostdelim++ = '\0'; | ||
792 | nsep->se_hostaddr = newstr (hostdelim); | ||
793 | |||
794 | nsep->se_next = sep->se_next; | ||
795 | sep->se_next = nsep; | ||
796 | } | ||
797 | |||
798 | nsep = sep; | ||
799 | while (nsep != NULL) { | ||
800 | nsep->se_checked = 1; | ||
801 | if (nsep->se_family == AF_INET) { | ||
802 | if (!strcmp (nsep->se_hostaddr, "*")) | ||
803 | nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY; | ||
804 | else if (!inet_aton (nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) { | ||
805 | struct hostent *hp; | ||
806 | |||
807 | hp = gethostbyname (nsep->se_hostaddr); | ||
808 | if (hp == 0) { | ||
809 | syslog (LOG_ERR, "%s: unknown host", nsep->se_hostaddr); | ||
810 | nsep->se_checked = 0; | ||
811 | goto skip; | ||
812 | } else if (hp->h_addrtype != AF_INET) { | ||
813 | syslog (LOG_ERR, | ||
814 | "%s: address isn't an Internet " | ||
815 | "address", nsep->se_hostaddr); | ||
816 | nsep->se_checked = 0; | ||
817 | goto skip; | ||
818 | } else { | ||
819 | int i = 1; | ||
820 | |||
821 | memmove (&nsep->se_ctrladdr_in.sin_addr, | ||
822 | hp->h_addr_list[0], sizeof (struct in_addr)); | ||
823 | while (hp->h_addr_list[i] != NULL) { | ||
824 | psep = dupconfig (nsep); | ||
825 | psep->se_hostaddr = newstr (nsep->se_hostaddr); | ||
826 | psep->se_checked = 1; | ||
827 | memmove (&psep->se_ctrladdr_in.sin_addr, | ||
828 | hp->h_addr_list[i], sizeof (struct in_addr)); | ||
829 | psep->se_ctrladdr_size = sizeof (psep->se_ctrladdr_in); | ||
830 | i++; | ||
831 | /* Prepend to list, don't want to look up its */ | ||
832 | /* hostname again. */ | ||
833 | psep->se_next = sep; | ||
834 | sep = psep; | ||
835 | } | ||
424 | } | 836 | } |
837 | } | ||
838 | } | ||
839 | /* XXX BUG?: is this skip: label supposed to remain? */ | ||
840 | skip: | ||
841 | nsep = nsep->se_next; | ||
842 | } | ||
843 | |||
844 | /* | ||
845 | * Finally, free any entries which failed the gethostbyname | ||
846 | * check. | ||
847 | */ | ||
848 | psep = NULL; | ||
849 | nsep = sep; | ||
850 | while (nsep != NULL) { | ||
851 | servtab_t *tsep; | ||
852 | |||
853 | if (nsep->se_checked == 0) { | ||
854 | tsep = nsep; | ||
855 | if (psep == NULL) { | ||
856 | sep = nsep->se_next; | ||
857 | nsep = sep; | ||
858 | } else { | ||
859 | nsep = nsep->se_next; | ||
860 | psep->se_next = nsep; | ||
861 | } | ||
862 | freeconfig (tsep); | ||
863 | } else { | ||
864 | nsep->se_checked = 0; | ||
865 | psep = nsep; | ||
866 | nsep = nsep->se_next; | ||
425 | } | 867 | } |
426 | free(cp); | 868 | } |
427 | 869 | ||
428 | return (sep); | 870 | return (sep); |
429 | } | 871 | } |
430 | 872 | ||
431 | static void freeconfig(servtab_t *cp) | 873 | static servtab_t *enter (servtab_t *cp) |
432 | { | 874 | { |
433 | int i; | 875 | servtab_t *sep; |
434 | 876 | int omask; | |
435 | free(cp->se_service); | 877 | |
436 | free(cp->se_proto); | 878 | sep = new_servtab(); |
437 | free(cp->se_user); | 879 | *sep = *cp; |
438 | /* Note: se_group is part of the newstr'ed se_user */ | 880 | sep->se_fd = -1; |
439 | free(cp->se_server); | 881 | #ifdef CONFIG_FEATURE_INETD_RPC |
440 | for (i = 0; i < MAXARGV; i++) | 882 | sep->se_rpcprog = -1; |
441 | free(cp->se_argv[i]); | 883 | #endif |
884 | omask = sigblock (SIGBLOCK); | ||
885 | sep->se_next = servtab; | ||
886 | servtab = sep; | ||
887 | sigsetmask (omask); | ||
888 | return (sep); | ||
442 | } | 889 | } |
443 | 890 | ||
444 | #ifdef INETD_FEATURE_ENABLED | 891 | static int matchconf (servtab_t *old, servtab_t *new) |
445 | static char **Argv; | ||
446 | static char *LastArg; | ||
447 | |||
448 | static void setproctitle(char *a, int s) | ||
449 | { | 892 | { |
450 | socklen_t size; | 893 | if (strcmp (old->se_service, new->se_service) != 0) |
451 | char *cp; | 894 | return (0); |
452 | struct sockaddr_in sn; | 895 | |
453 | char buf[80]; | 896 | if (strcmp (old->se_hostaddr, new->se_hostaddr) != 0) |
454 | 897 | return (0); | |
455 | cp = Argv[0]; | 898 | |
456 | size = sizeof(sn); | 899 | if (strcmp (old->se_proto, new->se_proto) != 0) |
457 | if (getpeername(s, (struct sockaddr *)&sn, &size) == 0) | 900 | return (0); |
458 | (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sn.sin_addr)); | 901 | |
459 | else | 902 | /* |
460 | (void) sprintf(buf, "-%s", a); | 903 | * If the new servtab is bound to a specific address, check that the |
461 | strncpy(cp, buf, LastArg - cp); | 904 | * old servtab is bound to the same entry. If the new service is not |
462 | cp += strlen(cp); | 905 | * bound to a specific address then the check of se_hostaddr above |
463 | while (cp < LastArg) | 906 | * is sufficient. |
464 | *cp++ = ' '; | 907 | */ |
908 | |||
909 | if (old->se_family == AF_INET && new->se_family == AF_INET && | ||
910 | memcmp (&old->se_ctrladdr_in.sin_addr, | ||
911 | &new->se_ctrladdr_in.sin_addr, | ||
912 | sizeof (new->se_ctrladdr_in.sin_addr)) != 0) | ||
913 | return (0); | ||
914 | |||
915 | #ifdef CONFIG_FEATURE_IPV6 | ||
916 | if (old->se_family == AF_INET6 && new->se_family == AF_INET6 && | ||
917 | memcmp (&old->se_ctrladdr_in6.sin6_addr, | ||
918 | &new->se_ctrladdr_in6.sin6_addr, | ||
919 | sizeof (new->se_ctrladdr_in6.sin6_addr)) != 0) | ||
920 | return (0); | ||
921 | #endif | ||
922 | return (1); | ||
465 | } | 923 | } |
466 | #endif /* INETD_FEATURE_ENABLED */ | ||
467 | |||
468 | 924 | ||
469 | static void setup(servtab_t *sep) | 925 | static void config (int sig __attribute__((unused))) |
470 | { | 926 | { |
471 | int on = 1; | 927 | servtab_t *sep, *cp, **sepp; |
928 | int omask; | ||
929 | int add; | ||
930 | size_t n; | ||
931 | char protoname[10]; | ||
932 | |||
933 | if (!setconfig ()) { | ||
934 | syslog (LOG_ERR, "%s: %m", CONFIG); | ||
935 | return; | ||
936 | } | ||
937 | for (sep = servtab; sep; sep = sep->se_next) | ||
938 | sep->se_checked = 0; | ||
939 | cp = getconfigent (); | ||
940 | while (cp != NULL) { | ||
941 | for (sep = servtab; sep; sep = sep->se_next) | ||
942 | if (matchconf (sep, cp)) | ||
943 | break; | ||
944 | add = 0; | ||
945 | if (sep != 0) { | ||
946 | int i; | ||
947 | |||
948 | #define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;} | ||
949 | |||
950 | omask = sigblock (SIGBLOCK); | ||
951 | /* | ||
952 | * sep->se_wait may be holding the pid of a daemon | ||
953 | * that we're waiting for. If so, don't overwrite | ||
954 | * it unless the config file explicitly says don't | ||
955 | * wait. | ||
956 | */ | ||
957 | if ( | ||
958 | #ifdef INETD_FEATURE_ENABLED | ||
959 | cp->se_bi == 0 && | ||
960 | #endif | ||
961 | (sep->se_wait == 1 || cp->se_wait == 0)) | ||
962 | sep->se_wait = cp->se_wait; | ||
963 | SWAP (int, cp->se_max, sep->se_max); | ||
964 | SWAP (char *, sep->se_user, cp->se_user); | ||
965 | SWAP (char *, sep->se_group, cp->se_group); | ||
966 | SWAP (char *, sep->se_server, cp->se_server); | ||
967 | for (i = 0; i < MAXARGV; i++) | ||
968 | SWAP (char *, sep->se_argv[i], cp->se_argv[i]); | ||
969 | #undef SWAP | ||
472 | 970 | ||
473 | if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) { | 971 | #ifdef CONFIG_FEATURE_INETD_RPC |
474 | syslog(LOG_ERR, "%s/%s: socket: %m", | 972 | if (isrpcservice (sep)) |
475 | sep->se_service, sep->se_proto); | 973 | unregister_rpc (sep); |
476 | return; | 974 | sep->se_rpcversl = cp->se_rpcversl; |
975 | sep->se_rpcversh = cp->se_rpcversh; | ||
976 | #endif | ||
977 | sigsetmask (omask); | ||
978 | freeconfig (cp); | ||
979 | add = 1; | ||
980 | } else { | ||
981 | sep = enter (cp); | ||
477 | } | 982 | } |
478 | if (setsockopt(sep->se_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, | 983 | sep->se_checked = 1; |
479 | sizeof(on)) < 0) | 984 | |
480 | syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m"); | 985 | switch (sep->se_family) { |
481 | if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) { | 986 | case AF_UNIX: |
482 | syslog(LOG_ERR, "%s/%s: bind: %m", | 987 | if (sep->se_fd != -1) |
483 | sep->se_service, sep->se_proto); | 988 | break; |
484 | (void) close(sep->se_fd); | 989 | (void) unlink (sep->se_service); |
485 | sep->se_fd = -1; | 990 | n = strlen (sep->se_service); |
486 | if (!timingout) { | 991 | if (n > sizeof sep->se_ctrladdr_un.sun_path - 1) |
487 | timingout = 1; | 992 | n = sizeof sep->se_ctrladdr_un.sun_path - 1; |
488 | alarm(RETRYTIME); | 993 | safe_strncpy (sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1); |
994 | sep->se_ctrladdr_un.sun_family = AF_UNIX; | ||
995 | sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family; | ||
996 | setup (sep); | ||
997 | break; | ||
998 | case AF_INET: | ||
999 | sep->se_ctrladdr_in.sin_family = AF_INET; | ||
1000 | /* se_ctrladdr_in was set in getconfigent */ | ||
1001 | sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in; | ||
1002 | |||
1003 | #ifdef CONFIG_FEATURE_INETD_RPC | ||
1004 | if (isrpcservice (sep)) { | ||
1005 | struct rpcent *rp; | ||
1006 | |||
1007 | sep->se_rpcprog = atoi (sep->se_service); | ||
1008 | if (sep->se_rpcprog == 0) { | ||
1009 | rp = getrpcbyname (sep->se_service); | ||
1010 | if (rp == 0) { | ||
1011 | syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service); | ||
1012 | goto serv_unknown; | ||
1013 | } | ||
1014 | sep->se_rpcprog = rp->r_number; | ||
489 | } | 1015 | } |
490 | return; | 1016 | if (sep->se_fd == -1) |
491 | } | 1017 | setup (sep); |
492 | if (sep->se_socktype == SOCK_STREAM) | 1018 | if (sep->se_fd != -1) |
493 | listen(sep->se_fd, global_queuelen); | 1019 | register_rpc (sep); |
494 | 1020 | } else | |
495 | FD_SET(sep->se_fd, &allsock); | 1021 | #endif |
496 | nsock++; | 1022 | { |
497 | if (sep->se_fd > maxsock) { | 1023 | u_short port = htons (atoi (sep->se_service)); |
498 | maxsock = sep->se_fd; | 1024 | |
499 | if (maxsock > rlim_ofile_cur - FD_MARGIN) { | 1025 | if (!port) { |
500 | #ifdef RLIMIT_NOFILE | 1026 | /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname)); |
501 | # define FD_CHUNK 32 | 1027 | if (isdigit (protoname[strlen (protoname) - 1])) |
502 | struct rlimit rl; | 1028 | protoname[strlen (protoname) - 1] = '\0'; |
503 | 1029 | sp = getservbyname (sep->se_service, protoname); | |
504 | if (getrlimit(RLIMIT_NOFILE, &rl) < 0) { | 1030 | if (sp == 0) { |
505 | syslog(LOG_ERR, "getrlimit: %m"); | 1031 | syslog (LOG_ERR, |
506 | return; | 1032 | "%s/%s: unknown service", sep->se_service, sep->se_proto); |
507 | } | 1033 | goto serv_unknown; |
508 | rl.rlim_cur = rl.rlim_max < (rl.rlim_cur + FD_CHUNK) ? rl.rlim_max : (rl.rlim_cur + FD_CHUNK); | 1034 | } |
509 | if (rl.rlim_cur <= rlim_ofile_cur) { | 1035 | port = sp->s_port; |
510 | syslog(LOG_ERR, | ||
511 | # if _FILE_OFFSET_BITS == 64 | ||
512 | "bump_nofile: cannot extend file limit, max = %lld", | ||
513 | # else | ||
514 | "bump_nofile: cannot extend file limit, max = %ld", | ||
515 | # endif | ||
516 | rl.rlim_cur); | ||
517 | return; | ||
518 | } | ||
519 | |||
520 | if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { | ||
521 | syslog(LOG_ERR, "setrlimit: %m"); | ||
522 | return; | ||
523 | } | ||
524 | |||
525 | rlim_ofile_cur = rl.rlim_cur; | ||
526 | return; | ||
527 | #else | ||
528 | syslog(LOG_ERR, "bump_nofile: cannot extend file limit"); | ||
529 | return; | ||
530 | #endif /* RLIMIT_NOFILE */ | ||
531 | } | 1036 | } |
532 | } | 1037 | if (port != sep->se_ctrladdr_in.sin_port) { |
533 | } | 1038 | sep->se_ctrladdr_in.sin_port = port; |
534 | 1039 | if (sep->se_fd != -1) { | |
535 | static void config(int signum) | 1040 | FD_CLR (sep->se_fd, &allsock); |
536 | { | 1041 | nsock--; |
537 | servtab_t *sep, *cp, **sepp; | 1042 | (void) close (sep->se_fd); |
538 | sigset_t oldmask; | 1043 | } |
539 | unsigned n; | 1044 | sep->se_fd = -1; |
540 | |||
541 | (void)signum; | ||
542 | |||
543 | if (fconfig != NULL) { | ||
544 | fseek(fconfig, 0L, L_SET); | ||
545 | } else { | ||
546 | fconfig = fopen(CONFIG, "r"); | ||
547 | if (fconfig == NULL) { | ||
548 | syslog(LOG_ERR, "%s: %m", CONFIG); | ||
549 | return; | ||
550 | } | 1045 | } |
551 | } | 1046 | if (sep->se_fd == -1) |
552 | 1047 | setup (sep); | |
553 | for (sep = servtab; sep; sep = sep->se_next) | 1048 | } |
554 | sep->se_checked = 0; | 1049 | break; |
555 | while ((cp = getconfigent()) != NULL) { | 1050 | #ifdef CONFIG_FEATURE_IPV6 |
556 | for (sep = servtab; sep; sep = sep->se_next) | 1051 | case AF_INET6: |
557 | if (strcmp(sep->se_service, cp->se_service) == 0 && | 1052 | sep->se_ctrladdr_in6.sin6_family = AF_INET6; |
558 | strcmp(sep->se_proto, cp->se_proto) == 0) | 1053 | /* se_ctrladdr_in was set in getconfigent */ |
559 | break; | 1054 | sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6; |
560 | if (sep != 0) { | 1055 | |
561 | int i; | 1056 | #ifdef CONFIG_FEATURE_INETD_RPC |
562 | 1057 | if (isrpcservice (sep)) { | |
563 | #define SWAP(type, a, b) {type c=(type)(a); (a)=(type)(b); (b)=(type)c;} | 1058 | struct rpcent *rp; |
564 | 1059 | ||
565 | sigprocmask(SIG_BLOCK, &emptymask, &oldmask); | 1060 | sep->se_rpcprog = atoi (sep->se_service); |
566 | /* | 1061 | if (sep->se_rpcprog == 0) { |
567 | * sep->se_wait may be holding the pid of a daemon | 1062 | rp = getrpcbyname (sep->se_service); |
568 | * that we're waiting for. If so, don't overwrite | 1063 | if (rp == 0) { |
569 | * it unless the config file explicitly says don't | 1064 | syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service); |
570 | * wait. | 1065 | goto serv_unknown; |
571 | */ | 1066 | } |
572 | if ( | 1067 | sep->se_rpcprog = rp->r_number; |
573 | #ifdef INETD_FEATURE_ENABLED | 1068 | } |
574 | cp->se_bi == 0 && | 1069 | if (sep->se_fd == -1) |
1070 | setup (sep); | ||
1071 | if (sep->se_fd != -1) | ||
1072 | register_rpc (sep); | ||
1073 | } else | ||
575 | #endif | 1074 | #endif |
576 | (sep->se_wait == 1 || cp->se_wait == 0)) | 1075 | { |
577 | sep->se_wait = cp->se_wait; | 1076 | u_short port = htons (atoi (sep->se_service)); |
578 | if (cp->se_max != sep->se_max) | 1077 | |
579 | SWAP(int, cp->se_max, sep->se_max); | 1078 | if (!port) { |
580 | if (cp->se_user) | 1079 | /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname)); |
581 | SWAP(char *, sep->se_user, cp->se_user); | 1080 | if (isdigit (protoname[strlen (protoname) - 1])) |
582 | if (cp->se_group) | 1081 | protoname[strlen (protoname) - 1] = '\0'; |
583 | SWAP(char *, sep->se_group, cp->se_group); | 1082 | sp = getservbyname (sep->se_service, protoname); |
584 | if (cp->se_server) | 1083 | if (sp == 0) { |
585 | SWAP(char *, sep->se_server, cp->se_server); | 1084 | syslog (LOG_ERR, |
586 | for (i = 0; i < MAXARGV; i++) | 1085 | "%s/%s: unknown service", sep->se_service, sep->se_proto); |
587 | SWAP(char *, sep->se_argv[i], cp->se_argv[i]); | 1086 | goto serv_unknown; |
588 | #undef SWAP | 1087 | } |
589 | sigprocmask(SIG_SETMASK, &oldmask, NULL); | 1088 | port = sp->s_port; |
590 | // This freeconfig() is probably a bug, since it will try and free() | ||
591 | // each of the argv[] values, which are really just pointers | ||
592 | // into the middle of a single line buffer for the config file. | ||
593 | //freeconfig(cp); // BUG? | ||
594 | } else { | ||
595 | sep = (servtab_t *)xmalloc(sizeof (*sep)); | ||
596 | *sep = *cp; | ||
597 | sep->se_fd = -1; | ||
598 | sigprocmask(SIG_BLOCK, &blockmask, &oldmask); | ||
599 | sep->se_next = servtab; | ||
600 | servtab = sep; | ||
601 | sigprocmask(SIG_SETMASK, &oldmask, NULL); | ||
602 | } | 1089 | } |
603 | sep->se_checked = 1; | 1090 | if (port != sep->se_ctrladdr_in6.sin6_port) { |
604 | 1091 | sep->se_ctrladdr_in6.sin6_port = port; | |
605 | switch (sep->se_family) { | 1092 | if (sep->se_fd != -1) { |
606 | case AF_UNIX: | 1093 | FD_CLR (sep->se_fd, &allsock); |
607 | if (sep->se_fd != -1) | 1094 | nsock--; |
608 | break; | 1095 | (void) close (sep->se_fd); |
609 | (void)unlink(sep->se_service); | 1096 | } |
610 | n = strlen(sep->se_service); | 1097 | sep->se_fd = -1; |
611 | if (n > sizeof(sep->se_ctrladdr_un.sun_path) - 1) | ||
612 | n = sizeof(sep->se_ctrladdr_un.sun_path) - 1; | ||
613 | strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n); | ||
614 | sep->se_ctrladdr_un.sun_family = AF_UNIX; | ||
615 | sep->se_ctrladdr_size = n + | ||
616 | sizeof sep->se_ctrladdr_un.sun_family; | ||
617 | setup(sep); | ||
618 | break; | ||
619 | case AF_INET: | ||
620 | sep->se_ctrladdr_in.sin_family = AF_INET; | ||
621 | sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in; | ||
622 | { | ||
623 | u_short port = bb_lookup_port(sep->se_service, sep->se_proto, 0); | ||
624 | |||
625 | if (port == 0) { | ||
626 | syslog(LOG_ERR, | ||
627 | "%s/%s: unknown service", | ||
628 | sep->se_service, sep->se_proto); | ||
629 | continue; | ||
630 | } | ||
631 | if (port != sep->se_ctrladdr_in.sin_port) { | ||
632 | sep->se_ctrladdr_in.sin_port = port; | ||
633 | if (sep->se_fd != -1) { | ||
634 | FD_CLR(sep->se_fd, &allsock); | ||
635 | nsock--; | ||
636 | (void) close(sep->se_fd); | ||
637 | } | ||
638 | sep->se_fd = -1; | ||
639 | } | ||
640 | if (sep->se_fd == -1) | ||
641 | setup(sep); | ||
642 | } | ||
643 | } | 1098 | } |
1099 | if (sep->se_fd == -1) | ||
1100 | setup (sep); | ||
1101 | } | ||
1102 | break; | ||
1103 | #endif /* CONFIG_FEATURE_IPV6 */ | ||
644 | } | 1104 | } |
645 | if (fconfig) { | 1105 | serv_unknown: |
646 | (void) fclose(fconfig); | 1106 | if (cp->se_next != NULL) { |
647 | fconfig = NULL; | 1107 | servtab_t *tmp = cp; |
1108 | |||
1109 | cp = cp->se_next; | ||
1110 | free (tmp); | ||
1111 | } else { | ||
1112 | free (cp); | ||
1113 | cp = getconfigent (); | ||
648 | } | 1114 | } |
649 | /* | 1115 | } |
650 | * Purge anything not looked at above. | 1116 | endconfig (); |
651 | */ | 1117 | /* |
652 | sigprocmask(SIG_SETMASK, &blockmask, &oldmask); | 1118 | * Purge anything not looked at above. |
653 | sepp = &servtab; | 1119 | */ |
654 | while ((sep = *sepp) != NULL) { | 1120 | omask = sigblock (SIGBLOCK); |
655 | if (sep->se_checked) { | 1121 | sepp = &servtab; |
656 | sepp = &sep->se_next; | 1122 | while ((sep = *sepp)) { |
657 | continue; | 1123 | if (sep->se_checked) { |
658 | } | 1124 | sepp = &sep->se_next; |
659 | *sepp = sep->se_next; | 1125 | continue; |
660 | if (sep->se_fd != -1) { | 1126 | } |
661 | FD_CLR(sep->se_fd, &allsock); | 1127 | *sepp = sep->se_next; |
662 | nsock--; | 1128 | if (sep->se_fd != -1) { |
663 | (void) close(sep->se_fd); | 1129 | FD_CLR (sep->se_fd, &allsock); |
664 | } | 1130 | nsock--; |
665 | if (sep->se_family == AF_UNIX) | 1131 | (void) close (sep->se_fd); |
666 | (void)unlink(sep->se_service); | ||
667 | freeconfig(sep); | ||
668 | free((char *)sep); | ||
669 | } | 1132 | } |
670 | sigprocmask(SIG_SETMASK, &oldmask, NULL); | 1133 | #ifdef CONFIG_FEATURE_INETD_RPC |
1134 | if (isrpcservice (sep)) | ||
1135 | unregister_rpc (sep); | ||
1136 | #endif | ||
1137 | if (sep->se_family == AF_UNIX) | ||
1138 | (void) unlink (sep->se_service); | ||
1139 | freeconfig (sep); | ||
1140 | free (sep); | ||
1141 | } | ||
1142 | (void) sigsetmask (omask); | ||
671 | } | 1143 | } |
672 | 1144 | ||
673 | 1145 | ||
674 | 1146 | static void reapchild (int sig __attribute__((unused))) | |
675 | static void reapchild(int signum) | ||
676 | { | 1147 | { |
677 | int status; | 1148 | pid_t pid; |
678 | int pid; | 1149 | int save_errno = errno, status; |
679 | servtab_t *sep; | 1150 | servtab_t *sep; |
680 | 1151 | ||
681 | (void)signum; | 1152 | for (;;) { |
682 | for (;;) { | 1153 | pid = wait3 (&status, WNOHANG, NULL); |
683 | pid = wait3(&status, WNOHANG, (struct rusage *)0); | 1154 | if (pid <= 0) |
684 | if (pid <= 0) | 1155 | break; |
685 | break; | 1156 | for (sep = servtab; sep; sep = sep->se_next) |
686 | for (sep = servtab; sep; sep = sep->se_next) | 1157 | if (sep->se_wait == pid) { |
687 | if (sep->se_wait == pid) { | 1158 | if (WIFEXITED (status) && WEXITSTATUS (status)) |
688 | if (WIFEXITED(status) && WEXITSTATUS(status)) | 1159 | syslog (LOG_WARNING, |
689 | syslog(LOG_WARNING, | 1160 | "%s: exit status 0x%x", |
690 | "%s: exit status 0x%x", | 1161 | sep->se_server, WEXITSTATUS (status)); |
691 | sep->se_server, WEXITSTATUS(status)); | 1162 | else if (WIFSIGNALED (status)) |
692 | else if (WIFSIGNALED(status)) | 1163 | syslog (LOG_WARNING, |
693 | syslog(LOG_WARNING, | 1164 | "%s: exit signal 0x%x", sep->se_server, WTERMSIG (status)); |
694 | "%s: exit signal 0x%x", | 1165 | sep->se_wait = 1; |
695 | sep->se_server, WTERMSIG(status)); | 1166 | FD_SET (sep->se_fd, &allsock); |
696 | sep->se_wait = 1; | 1167 | nsock++; |
697 | FD_SET(sep->se_fd, &allsock); | 1168 | } |
698 | nsock++; | 1169 | } |
699 | } | 1170 | errno = save_errno; |
700 | } | ||
701 | } | 1171 | } |
702 | 1172 | ||
703 | static void retry(int signum) | 1173 | static void retry (int sig __attribute__((unused))) |
704 | { | 1174 | { |
705 | servtab_t *sep; | 1175 | servtab_t *sep; |
706 | 1176 | ||
707 | (void)signum; | 1177 | timingout = 0; |
708 | timingout = 0; | 1178 | for (sep = servtab; sep; sep = sep->se_next) { |
709 | for (sep = servtab; sep; sep = sep->se_next) { | 1179 | if (sep->se_fd == -1) { |
710 | if (sep->se_fd == -1) { | 1180 | switch (sep->se_family) { |
711 | switch (sep->se_family) { | 1181 | case AF_UNIX: |
712 | case AF_UNIX: | 1182 | case AF_INET: |
713 | case AF_INET: | 1183 | #ifdef CONFIG_FEATURE_IPV6 |
714 | setup(sep); | 1184 | case AF_INET6: |
715 | break; | 1185 | #endif |
716 | } | 1186 | setup (sep); |
717 | } | 1187 | #ifdef CONFIG_FEATURE_INETD_RPC |
1188 | if (sep->se_fd != -1 && isrpcservice (sep)) | ||
1189 | register_rpc (sep); | ||
1190 | #endif | ||
1191 | break; | ||
1192 | } | ||
718 | } | 1193 | } |
1194 | } | ||
719 | } | 1195 | } |
720 | 1196 | ||
721 | static void goaway(int signum) | 1197 | static void goaway (int sig __attribute__((unused))) |
722 | { | 1198 | { |
723 | servtab_t *sep; | 1199 | servtab_t *sep; |
724 | 1200 | ||
725 | (void)signum; | 1201 | /* XXX signal race walking sep list */ |
726 | for (sep = servtab; sep; sep = sep->se_next) | 1202 | for (sep = servtab; sep; sep = sep->se_next) { |
727 | if (sep->se_fd != -1 && sep->se_family == AF_UNIX) | 1203 | if (sep->se_fd == -1) |
728 | (void)unlink(sep->se_service); | 1204 | continue; |
729 | (void)unlink(_PATH_INETDPID); | 1205 | |
730 | exit(0); | 1206 | switch (sep->se_family) { |
1207 | case AF_UNIX: | ||
1208 | (void) unlink (sep->se_service); | ||
1209 | break; | ||
1210 | case AF_INET: | ||
1211 | #ifdef CONFIG_FEATURE_IPV6 | ||
1212 | case AF_INET6: | ||
1213 | #endif | ||
1214 | #ifdef CONFIG_FEATURE_INETD_RPC | ||
1215 | if (sep->se_wait == 1 && isrpcservice (sep)) | ||
1216 | unregister_rpc (sep); /* XXX signal race */ | ||
1217 | #endif | ||
1218 | break; | ||
1219 | } | ||
1220 | (void) close (sep->se_fd); | ||
1221 | } | ||
1222 | (void) unlink (_PATH_INETDPID); | ||
1223 | exit (0); | ||
731 | } | 1224 | } |
732 | 1225 | ||
733 | 1226 | ||
1227 | #ifdef INETD_SETPROCTITLE | ||
1228 | static char **Argv; | ||
1229 | static char *LastArg; | ||
734 | 1230 | ||
735 | extern int inetd_main(int argc, char *argv[]) | 1231 | static void |
1232 | inetd_setproctitle (char *a, int s) | ||
736 | { | 1233 | { |
737 | servtab_t *sep; | 1234 | int size; |
738 | struct group *grp = NULL; | 1235 | char *cp; |
739 | struct sigaction sa; | 1236 | struct sockaddr_in prt_sin; |
740 | int pid; | 1237 | char buf[80]; |
741 | unsigned long opt; | 1238 | |
742 | char *sq; | 1239 | cp = Argv[0]; |
743 | gid_t gid; | 1240 | size = sizeof (prt_sin); |
744 | 1241 | (void) snprintf (buf, sizeof buf, "-%s", a); | |
745 | #ifdef INETD_FEATURE_ENABLED | 1242 | if (getpeername (s, (struct sockaddr *) &prt_sin, &size) == 0) { |
746 | extern char **environ; | 1243 | char *sa = inet_ntoa (prt_sin.sin_addr); |
1244 | |||
1245 | buf[sizeof (buf) - 1 - strlen (sa) - 3] = '\0'; | ||
1246 | strcat (buf, " ["); | ||
1247 | strcat (buf, sa); | ||
1248 | strcat (buf, "]"); | ||
1249 | } | ||
1250 | strncpy (cp, buf, LastArg - cp); | ||
1251 | cp += strlen (cp); | ||
1252 | while (cp < LastArg) | ||
1253 | *cp++ = ' '; | ||
1254 | } | ||
747 | #endif | 1255 | #endif |
748 | 1256 | ||
749 | gid = getgid(); | ||
750 | setgroups(1, &gid); | ||
751 | 1257 | ||
752 | #ifdef INETD_FEATURE_ENABLED | 1258 | int |
753 | Argv = argv; | 1259 | inetd_main (int argc, char *argv[]) |
754 | if (environ == 0 || *environ == 0) | 1260 | { |
755 | environ = argv; | 1261 | servtab_t *sep; |
756 | while (*environ) | 1262 | struct passwd *pwd; |
757 | environ++; | 1263 | struct group *grp = NULL; |
758 | LastArg = environ[-1] + strlen(environ[-1]); | 1264 | int tmpint; |
1265 | struct sigaction sa, sapipe; | ||
1266 | int opt; | ||
1267 | pid_t pid; | ||
1268 | char buf[50]; | ||
1269 | char *stoomany; | ||
1270 | |||
1271 | #ifdef INETD_SETPROCTITLE | ||
1272 | extern char **environ; | ||
1273 | char **envp = environ; | ||
1274 | |||
1275 | Argv = argv; | ||
1276 | if (envp == 0 || *envp == 0) | ||
1277 | envp = argv; | ||
1278 | while (*envp) | ||
1279 | envp++; | ||
1280 | LastArg = envp[-1] + strlen (envp[-1]); | ||
759 | #endif | 1281 | #endif |
760 | 1282 | ||
761 | opt = bb_getopt_ulflags(argc, argv, "q:f", &sq); | 1283 | openlog (bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON); |
762 | if (!(opt & 2)) { | 1284 | |
763 | daemon(0, 0); | 1285 | opt = bb_getopt_ulflags (argc, argv, "R:f", &stoomany); |
1286 | if(opt & 1) { | ||
1287 | char *e; | ||
1288 | |||
1289 | toomany = strtoul (stoomany, &e, 0); | ||
1290 | if (!(toomany >= 0 && *e == '\0')) { | ||
1291 | toomany = TOOMANY; | ||
1292 | syslog (LOG_ERR, "-R %s: bad value for service invocation rate", stoomany); | ||
1293 | } | ||
1294 | } | ||
1295 | argc -= optind; | ||
1296 | argv += optind; | ||
1297 | |||
1298 | uid = getuid (); | ||
1299 | if (uid != 0) | ||
1300 | CONFIG = NULL; | ||
1301 | if (argc > 0) | ||
1302 | CONFIG = argv[0]; | ||
1303 | if (CONFIG == NULL) | ||
1304 | bb_error_msg_and_die ("non-root must specify a config file"); | ||
1305 | |||
1306 | if (!(opt & 2)) { | ||
764 | #if defined(__uClinux__) | 1307 | #if defined(__uClinux__) |
765 | /* reexec for vfork() do continue parent */ | 1308 | /* reexec for vfork() do continue parent */ |
766 | vfork_daemon_rexec(argc, argv, "-f"); | 1309 | vfork_daemon_rexec (0, 0, argc, argv, "-f"); |
1310 | #else | ||
1311 | daemon (0, 0); | ||
767 | #endif /* uClinux */ | 1312 | #endif /* uClinux */ |
768 | } | 1313 | } else { |
1314 | setsid (); | ||
1315 | } | ||
769 | 1316 | ||
770 | if(opt & 1) { | 1317 | if (uid == 0) { |
771 | global_queuelen = atoi(sq); | 1318 | gid_t gid = getgid (); |
772 | if (global_queuelen < 8) global_queuelen=8; | ||
773 | } | ||
774 | argc -= optind; | ||
775 | argv += optind; | ||
776 | 1319 | ||
777 | if (argc > 0) | 1320 | /* If run by hand, ensure groups vector gets trashed */ |
778 | CONFIG = argv[0]; | 1321 | setgroups (1, &gid); |
1322 | } | ||
779 | 1323 | ||
780 | openlog(bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON); | 1324 | { |
781 | { | 1325 | FILE *fp; |
782 | FILE *fp; | ||
783 | 1326 | ||
784 | if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) { | 1327 | if ((fp = fopen (_PATH_INETDPID, "w")) != NULL) { |
785 | fprintf(fp, "%u\n", getpid()); | 1328 | fprintf (fp, "%u\n", getpid ()); |
786 | (void)fclose(fp); | 1329 | (void) fclose (fp); |
787 | } | ||
788 | } | 1330 | } |
1331 | } | ||
1332 | |||
1333 | if (getrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) { | ||
1334 | syslog (LOG_ERR, "getrlimit: %m"); | ||
1335 | } else { | ||
1336 | rlim_ofile_cur = rlim_ofile.rlim_cur; | ||
1337 | if (rlim_ofile_cur == RLIM_INFINITY) /* ! */ | ||
1338 | rlim_ofile_cur = OPEN_MAX; | ||
1339 | } | ||
1340 | |||
1341 | memset ((char *) &sa, 0, sizeof (sa)); | ||
1342 | sigemptyset (&sa.sa_mask); | ||
1343 | sigaddset (&sa.sa_mask, SIGALRM); | ||
1344 | sigaddset (&sa.sa_mask, SIGCHLD); | ||
1345 | sigaddset (&sa.sa_mask, SIGHUP); | ||
1346 | sa.sa_handler = retry; | ||
1347 | sigaction (SIGALRM, &sa, NULL); | ||
1348 | /* doconfig(); */ | ||
1349 | config (SIGHUP); | ||
1350 | sa.sa_handler = config; | ||
1351 | sigaction (SIGHUP, &sa, NULL); | ||
1352 | sa.sa_handler = reapchild; | ||
1353 | sigaction (SIGCHLD, &sa, NULL); | ||
1354 | sa.sa_handler = goaway; | ||
1355 | sigaction (SIGTERM, &sa, NULL); | ||
1356 | sa.sa_handler = goaway; | ||
1357 | sigaction (SIGINT, &sa, NULL); | ||
1358 | sa.sa_handler = SIG_IGN; | ||
1359 | sigaction (SIGPIPE, &sa, &sapipe); | ||
1360 | |||
1361 | { | ||
1362 | /* space for daemons to overwrite environment for ps */ | ||
1363 | #define DUMMYSIZE 100 | ||
1364 | char dummy[DUMMYSIZE]; | ||
789 | 1365 | ||
790 | #ifdef RLIMIT_NOFILE | 1366 | (void) memset (dummy, 'x', DUMMYSIZE - 1); |
791 | if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) { | 1367 | dummy[DUMMYSIZE - 1] = '\0'; |
792 | syslog(LOG_ERR, "getrlimit: %m"); | ||
793 | } else { | ||
794 | rlim_ofile_cur = rlim_ofile.rlim_cur; | ||
795 | if (rlim_ofile_cur == RLIM_INFINITY) /* ! */ | ||
796 | rlim_ofile_cur = OPEN_MAX; | ||
797 | } | ||
798 | #endif | ||
799 | 1368 | ||
800 | config(0); | 1369 | (void) setenv ("inetd_dummy", dummy, 1); |
801 | 1370 | } | |
802 | sigemptyset(&emptymask); | ||
803 | sigemptyset(&blockmask); | ||
804 | sigaddset(&blockmask, SIGCHLD); | ||
805 | sigaddset(&blockmask, SIGHUP); | ||
806 | sigaddset(&blockmask, SIGALRM); | ||
807 | |||
808 | memset(&sa, 0, sizeof(sa)); | ||
809 | sa.sa_mask = blockmask; | ||
810 | sa.sa_handler = retry; | ||
811 | sigaction(SIGALRM, &sa, NULL); | ||
812 | sa.sa_handler = config; | ||
813 | sigaction(SIGHUP, &sa, NULL); | ||
814 | sa.sa_handler = reapchild; | ||
815 | sigaction(SIGCHLD, &sa, NULL); | ||
816 | sa.sa_handler = goaway; | ||
817 | sigaction(SIGTERM, &sa, NULL); | ||
818 | sa.sa_handler = goaway; | ||
819 | sigaction(SIGINT, &sa, NULL); | ||
820 | sa.sa_handler = SIG_IGN; | ||
821 | sigaction(SIGPIPE, &sa, NULL); | ||
822 | |||
823 | { | ||
824 | /* space for daemons to overwrite environment for ps */ | ||
825 | #define DUMMYSIZE 100 | ||
826 | char dummy[DUMMYSIZE]; | ||
827 | 1371 | ||
828 | (void)memset(dummy, 'x', DUMMYSIZE - 1); | 1372 | for (;;) { |
829 | dummy[DUMMYSIZE - 1] = '\0'; | 1373 | int n, ctrl = -1; |
1374 | fd_set readable; | ||
830 | 1375 | ||
831 | (void)setenv("inetd_dummy", dummy, 1); | 1376 | if (nsock == 0) { |
1377 | (void) sigblock (SIGBLOCK); | ||
1378 | while (nsock == 0) | ||
1379 | sigpause (0L); | ||
1380 | (void) sigsetmask (0L); | ||
832 | } | 1381 | } |
833 | 1382 | ||
834 | for (;;) { | 1383 | readable = allsock; |
835 | fd_set readable; | 1384 | if ((n = select (maxsock + 1, &readable, NULL, NULL, NULL)) <= 0) { |
836 | int ctrl; | 1385 | if (n < 0 && errno != EINTR) { |
837 | int n; | 1386 | syslog (LOG_WARNING, "select: %m"); |
838 | 1387 | sleep (1); | |
839 | if (nsock == 0) { | 1388 | } |
840 | sigprocmask(SIG_BLOCK, &blockmask, NULL); | 1389 | continue; |
841 | while (nsock == 0) { | 1390 | } |
842 | sigsuspend(&emptymask); | 1391 | for (sep = servtab; n && sep; sep = sep->se_next) |
1392 | if (sep->se_fd != -1 && FD_ISSET (sep->se_fd, &readable)) { | ||
1393 | n--; | ||
1394 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { | ||
1395 | ctrl = accept (sep->se_fd, NULL, NULL); | ||
1396 | if (ctrl < 0) { | ||
1397 | if (errno == EINTR) | ||
1398 | continue; | ||
1399 | syslog (LOG_WARNING, "accept (for %s): %m", sep->se_service); | ||
1400 | continue; | ||
1401 | } | ||
1402 | if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) { | ||
1403 | struct sockaddr_in peer; | ||
1404 | int plen = sizeof (peer); | ||
1405 | |||
1406 | if (getpeername (ctrl, (struct sockaddr *) &peer, &plen) < 0) { | ||
1407 | syslog (LOG_WARNING, "could not getpeername"); | ||
1408 | close (ctrl); | ||
1409 | continue; | ||
843 | } | 1410 | } |
844 | sigprocmask(SIG_SETMASK, &emptymask, NULL); | 1411 | if (ntohs (peer.sin_port) == 20) { |
845 | } | 1412 | /* XXX ftp bounce */ |
846 | readable = allsock; | 1413 | close (ctrl); |
847 | n = select(maxsock + 1, &readable, (fd_set *)0, (fd_set *)0, (struct timeval *)0); | 1414 | continue; |
848 | if (n <= 0) { | ||
849 | if (n < 0 && errno != EINTR) { | ||
850 | syslog(LOG_WARNING, "select: %m"); | ||
851 | } | 1415 | } |
852 | sleep(1); | 1416 | } |
853 | continue; | 1417 | } else |
854 | } | 1418 | ctrl = sep->se_fd; |
855 | for (sep = servtab; n && sep; sep = sep->se_next) { | 1419 | (void) sigblock (SIGBLOCK); |
856 | if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) { | 1420 | pid = 0; |
857 | n--; | ||
858 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { | ||
859 | /* Fixed AGC */ | ||
860 | fcntl(sep->se_fd, F_SETFL, O_NDELAY); | ||
861 | /* --------- */ | ||
862 | ctrl = accept(sep->se_fd, NULL, NULL); | ||
863 | fcntl(sep->se_fd, F_SETFL, 0); | ||
864 | if (ctrl < 0) { | ||
865 | if (errno == EINTR || errno == EWOULDBLOCK) { | ||
866 | continue; | ||
867 | } | ||
868 | syslog(LOG_WARNING, "accept (for %s): %m", | ||
869 | sep->se_service); | ||
870 | continue; | ||
871 | } | ||
872 | } else { | ||
873 | ctrl = sep->se_fd; | ||
874 | } | ||
875 | sigprocmask(SIG_BLOCK, &blockmask, NULL); | ||
876 | pid = 0; | ||
877 | #ifdef INETD_FEATURE_ENABLED | 1421 | #ifdef INETD_FEATURE_ENABLED |
878 | if (sep->se_bi == 0 || sep->se_bi->bi_fork) | 1422 | if (sep->se_bi == 0 || sep->se_bi->bi_fork) |
879 | #endif | 1423 | #endif |
880 | { | 1424 | { |
881 | if (sep->se_count++ == 0) { | 1425 | if (sep->se_count++ == 0) |
882 | gettimeofday(&sep->se_time, (struct timezone *)0); | 1426 | (void) gettimeofday (&sep->se_time, NULL); |
883 | } | 1427 | else if (toomany > 0 && sep->se_count >= sep->se_max) { |
884 | else if (sep->se_count >= sep->se_max) { | 1428 | struct timeval now; |
885 | struct timeval now; | 1429 | |
886 | 1430 | (void) gettimeofday (&now, NULL); | |
887 | gettimeofday(&now, (struct timezone *)0); | 1431 | if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) { |
888 | if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) { | 1432 | sep->se_time = now; |
889 | sep->se_time = now; | 1433 | sep->se_count = 1; |
890 | sep->se_count = 1; | 1434 | } else { |
891 | } else { | 1435 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) |
892 | syslog(LOG_ERR, | 1436 | close (ctrl); |
893 | "%s/%s server failing (looping), service terminated", | 1437 | if (sep->se_family == AF_INET && |
894 | sep->se_service, sep->se_proto); | 1438 | ntohs (sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) { |
895 | FD_CLR(sep->se_fd, &allsock); | 1439 | /* |
896 | close(sep->se_fd); | 1440 | * Cannot close it -- there are |
897 | sep->se_fd = -1; | 1441 | * thieves on the system. |
898 | sep->se_count = 0; | 1442 | * Simply ignore the connection. |
899 | nsock--; | 1443 | */ |
900 | sigprocmask(SIG_SETMASK, &emptymask, NULL); | 1444 | --sep->se_count; |
901 | if (!timingout) { | 1445 | continue; |
902 | timingout = 1; | 1446 | } |
903 | alarm(RETRYTIME); | 1447 | syslog (LOG_ERR, |
904 | } | 1448 | "%s/%s server failing (looping), service terminated", |
905 | continue; | 1449 | sep->se_service, sep->se_proto); |
906 | } | 1450 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) |
907 | } | 1451 | close (ctrl); |
908 | pid = fork(); | 1452 | FD_CLR (sep->se_fd, &allsock); |
909 | if (pid < 0) { | 1453 | (void) close (sep->se_fd); |
910 | syslog(LOG_ERR, "fork: %m"); | 1454 | sep->se_fd = -1; |
911 | if (sep->se_socktype == SOCK_STREAM) { | 1455 | sep->se_count = 0; |
912 | close(ctrl); | 1456 | nsock--; |
913 | } | 1457 | sigsetmask (0L); |
914 | sigprocmask(SIG_SETMASK, &emptymask, NULL); | 1458 | if (!timingout) { |
915 | sleep(1); | 1459 | timingout = 1; |
916 | continue; | 1460 | alarm (RETRYTIME); |
917 | } | 1461 | } |
918 | if (pid && sep->se_wait) { | 1462 | continue; |
919 | sep->se_wait = pid; | 1463 | } |
920 | FD_CLR(sep->se_fd, &allsock); | 1464 | } |
921 | nsock--; | 1465 | pid = fork (); |
922 | } | 1466 | } |
923 | } | 1467 | if (pid < 0) { |
924 | sigprocmask(SIG_SETMASK, &emptymask, NULL); | 1468 | syslog (LOG_ERR, "fork: %m"); |
925 | if (pid == 0) { | 1469 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) |
1470 | close (ctrl); | ||
1471 | sigsetmask (0L); | ||
1472 | sleep (1); | ||
1473 | continue; | ||
1474 | } | ||
1475 | if (pid && sep->se_wait) { | ||
1476 | sep->se_wait = pid; | ||
1477 | FD_CLR (sep->se_fd, &allsock); | ||
1478 | nsock--; | ||
1479 | } | ||
1480 | sigsetmask (0L); | ||
1481 | if (pid == 0) { | ||
926 | #ifdef INETD_FEATURE_ENABLED | 1482 | #ifdef INETD_FEATURE_ENABLED |
927 | if (sep->se_bi) { | 1483 | if (sep->se_bi) { |
928 | (*sep->se_bi->bi_fn)(ctrl, sep); | 1484 | (*sep->se_bi->bi_fn) (ctrl, sep); |
929 | } else | 1485 | } else |
930 | #endif | 1486 | #endif |
931 | { | 1487 | { |
932 | struct passwd *pwd = getpwnam(sep->se_user); | 1488 | if ((pwd = getpwnam (sep->se_user)) == NULL) { |
933 | if (pwd == NULL) { | 1489 | syslog (LOG_ERR, "getpwnam: %s: No such user", sep->se_user); |
934 | syslog_err_and_discard_dg( | 1490 | if (sep->se_socktype != SOCK_STREAM) |
935 | sep->se_socktype, | 1491 | recv (0, buf, sizeof (buf), 0); |
936 | "getpwnam: %s: No such user", | 1492 | _exit (1); |
937 | sep->se_user); | 1493 | } |
938 | } | 1494 | if (setsid () < 0) |
939 | if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) { | 1495 | syslog (LOG_ERR, "%s: setsid: %m", sep->se_service); |
940 | syslog_err_and_discard_dg(sep->se_socktype, | 1496 | if (sep->se_group && (grp = getgrnam (sep->se_group)) == NULL) { |
941 | "getgrnam: %s: No such group", sep->se_group); | 1497 | syslog (LOG_ERR, "getgrnam: %s: No such group", sep->se_group); |
942 | } | 1498 | if (sep->se_socktype != SOCK_STREAM) |
943 | /* | 1499 | recv (0, buf, sizeof (buf), 0); |
944 | * Ok. There are four cases here: | 1500 | _exit (1); |
945 | * 1. nonroot user, no group specified | 1501 | } |
946 | * 2. nonroot user, some group specified | 1502 | if (uid != 0) { |
947 | * 3. root user, no group specified | 1503 | /* a user running private inetd */ |
948 | * 4. root user, some group specified | 1504 | if (uid != pwd->pw_uid) |
949 | * In cases 2 and 4 we setgid to the specified | 1505 | _exit (1); |
950 | * group. In cases 1 and 2 we run initgroups | 1506 | } else if (pwd->pw_uid) { |
951 | * to run with the groups of the given user. | 1507 | if (sep->se_group) { |
952 | * In case 4 we do setgroups to run with the | 1508 | pwd->pw_gid = grp->gr_gid; |
953 | * given group. In case 3 we do nothing. | 1509 | } |
954 | */ | 1510 | setgid ((gid_t) pwd->pw_gid); |
955 | if (pwd->pw_uid) { | 1511 | initgroups (pwd->pw_name, pwd->pw_gid); |
956 | if (sep->se_group) { | 1512 | setuid ((uid_t) pwd->pw_uid); |
957 | pwd->pw_gid = grp->gr_gid; | 1513 | } else if (sep->se_group) { |
958 | } | 1514 | setgid (grp->gr_gid); |
959 | setgid((gid_t)pwd->pw_gid); | 1515 | setgroups (1, &grp->gr_gid); |
960 | initgroups(pwd->pw_name, pwd->pw_gid); | ||
961 | setuid((uid_t)pwd->pw_uid); | ||
962 | } else if (sep->se_group) { | ||
963 | setgid((gid_t)grp->gr_gid); | ||
964 | setgroups(1, &grp->gr_gid); | ||
965 | } | ||
966 | dup2(ctrl, 0); | ||
967 | close(ctrl); | ||
968 | dup2(0, 1); | ||
969 | dup2(0, 2); | ||
970 | #ifdef RLIMIT_NOFILE | ||
971 | if (rlim_ofile.rlim_cur != rlim_ofile_cur) { | ||
972 | if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) { | ||
973 | syslog(LOG_ERR,"setrlimit: %m"); | ||
974 | } | ||
975 | } | ||
976 | #endif | ||
977 | for (ctrl = rlim_ofile_cur-1; --ctrl > 2; ) { | ||
978 | (void)close(ctrl); | ||
979 | } | ||
980 | memset(&sa, 0, sizeof(sa)); | ||
981 | sa.sa_handler = SIG_DFL; | ||
982 | sigaction(SIGPIPE, &sa, NULL); | ||
983 | |||
984 | execv(sep->se_server, sep->se_argv); | ||
985 | syslog_err_and_discard_dg(sep->se_socktype, "execv %s: %m", sep->se_server); | ||
986 | } | ||
987 | } | ||
988 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) { | ||
989 | close(ctrl); | ||
990 | } | ||
991 | } | 1516 | } |
1517 | dup2 (ctrl, 0); | ||
1518 | close (ctrl); | ||
1519 | dup2 (0, 1); | ||
1520 | dup2 (0, 2); | ||
1521 | if (rlim_ofile.rlim_cur != rlim_ofile_cur) | ||
1522 | if (setrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) | ||
1523 | syslog (LOG_ERR, "setrlimit: %m"); | ||
1524 | closelog (); | ||
1525 | for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;) | ||
1526 | (void) close (tmpint); | ||
1527 | sigaction (SIGPIPE, &sapipe, NULL); | ||
1528 | execv (sep->se_server, sep->se_argv); | ||
1529 | if (sep->se_socktype != SOCK_STREAM) | ||
1530 | recv (0, buf, sizeof (buf), 0); | ||
1531 | syslog (LOG_ERR, "execv %s: %m", sep->se_server); | ||
1532 | _exit (1); | ||
1533 | } | ||
992 | } | 1534 | } |
993 | } | 1535 | if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) |
1536 | close (ctrl); | ||
1537 | } | ||
1538 | } | ||
994 | } | 1539 | } |
995 | 1540 | ||
996 | |||
997 | /* | 1541 | /* |
998 | * Internet services provided internally by inetd: | 1542 | * Internet services provided internally by inetd: |
999 | */ | 1543 | */ |
1000 | #define BUFSIZE 4096 | 1544 | #define BUFSIZE 4096 |
1001 | 1545 | ||
1002 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO | 1546 | #if defined(CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO) || \ |
1003 | /* Echo service -- echo data back */ | 1547 | defined(CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN) || \ |
1004 | static void echo_stream(int s, servtab_t *sep) | 1548 | defined(CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME) |
1549 | static int dg_badinput (struct sockaddr_in *dg_sin) | ||
1005 | { | 1550 | { |
1006 | char buffer[BUFSIZE]; | 1551 | if (ntohs (dg_sin->sin_port) < IPPORT_RESERVED) |
1007 | int i; | 1552 | return (1); |
1008 | 1553 | if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST)) | |
1009 | setproctitle(sep->se_service, s); | 1554 | return (1); |
1010 | while ((i = read(s, buffer, sizeof(buffer))) > 0 && | 1555 | /* XXX compare against broadcast addresses in SIOCGIFCONF list? */ |
1011 | write(s, buffer, i) > 0) | 1556 | return (0); |
1012 | ; | ||
1013 | exit(0); | ||
1014 | } | 1557 | } |
1558 | #endif | ||
1015 | 1559 | ||
1560 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO | ||
1016 | /* Echo service -- echo data back */ | 1561 | /* Echo service -- echo data back */ |
1017 | static void echo_dg(int s, servtab_t *sep) | 1562 | /* ARGSUSED */ |
1563 | static void | ||
1564 | echo_stream (int s, servtab_t *sep) | ||
1018 | { | 1565 | { |
1019 | char buffer[BUFSIZE]; | 1566 | char buffer[BUFSIZE]; |
1020 | int i; | 1567 | int i; |
1021 | socklen_t size; | ||
1022 | struct sockaddr sa; | ||
1023 | |||
1024 | (void)sep; | ||
1025 | 1568 | ||
1026 | size = sizeof(sa); | 1569 | inetd_setproctitle (sep->se_service, s); |
1027 | if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) | 1570 | while ((i = read (s, buffer, sizeof (buffer))) > 0 && |
1028 | return; | 1571 | write (s, buffer, i) > 0); |
1029 | (void) sendto(s, buffer, i, 0, &sa, sizeof(sa)); | 1572 | exit (0); |
1030 | } | 1573 | } |
1031 | #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO */ | ||
1032 | 1574 | ||
1575 | /* Echo service -- echo data back */ | ||
1576 | /* ARGSUSED */ | ||
1577 | static void | ||
1578 | echo_dg (int s, servtab_t *sep __attribute__((unused))) | ||
1579 | { | ||
1580 | char buffer[BUFSIZE]; | ||
1581 | int i, size; | ||
1582 | /* struct sockaddr_storage ss; */ | ||
1583 | struct sockaddr sa; | ||
1584 | |||
1585 | size = sizeof (sa); | ||
1586 | if ((i = recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size)) < 0) | ||
1587 | return; | ||
1588 | if (dg_badinput ((struct sockaddr_in *) &sa)) | ||
1589 | return; | ||
1590 | (void) sendto (s, buffer, i, 0, &sa, sizeof (sa)); | ||
1591 | } | ||
1592 | #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO */ | ||
1033 | 1593 | ||
1034 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD | 1594 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD |
1035 | /* Discard service -- ignore data */ | 1595 | /* Discard service -- ignore data */ |
1036 | static void discard_stream(int s, servtab_t *sep) | 1596 | /* ARGSUSED */ |
1597 | static void | ||
1598 | discard_stream (int s, servtab_t *sep) | ||
1037 | { | 1599 | { |
1038 | char buffer[BUFSIZE]; | 1600 | char buffer[BUFSIZE]; |
1039 | 1601 | ||
1040 | setproctitle(sep->se_service, s); | 1602 | inetd_setproctitle (sep->se_service, s); |
1041 | while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) || | 1603 | while ((errno = 0, read (s, buffer, sizeof (buffer)) > 0) || |
1042 | errno == EINTR) | 1604 | errno == EINTR); |
1043 | ; | 1605 | exit (0); |
1044 | exit(0); | ||
1045 | } | 1606 | } |
1046 | 1607 | ||
1047 | /* Discard service -- ignore data */ | 1608 | /* Discard service -- ignore data */ |
1048 | static void discard_dg(int s, servtab_t *sep) | 1609 | /* ARGSUSED */ |
1610 | static void | ||
1611 | discard_dg (int s, servtab_t *sep __attribute__((unused))) | ||
1049 | { | 1612 | { |
1050 | char buffer[BUFSIZE]; | 1613 | char buffer[BUFSIZE]; |
1051 | (void)sep; | 1614 | |
1052 | read(s, buffer, sizeof(buffer)); | 1615 | (void) read (s, buffer, sizeof (buffer)); |
1053 | } | 1616 | } |
1054 | #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD */ | 1617 | #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD */ |
1055 | 1618 | ||
1056 | 1619 | ||
1057 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN | 1620 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN |
1058 | #include <ctype.h> | ||
1059 | #define LINESIZ 72 | 1621 | #define LINESIZ 72 |
1060 | static char ring[128]; | 1622 | static char ring[128]; |
1061 | static char *endring; | 1623 | static char *endring; |
1062 | 1624 | ||
1063 | static void initring(void) | 1625 | static void |
1626 | initring (void) | ||
1064 | { | 1627 | { |
1065 | int i; | 1628 | int i; |
1066 | 1629 | ||
1067 | endring = ring; | 1630 | endring = ring; |
1068 | 1631 | ||
1069 | for (i = 0; i <= 128; ++i) | 1632 | for (i = 0; i <= 128; ++i) |
1070 | if (isprint(i)) | 1633 | if (isprint (i)) |
1071 | *endring++ = i; | 1634 | *endring++ = i; |
1072 | } | 1635 | } |
1073 | 1636 | ||
1074 | /* Character generator */ | 1637 | /* Character generator */ |
1075 | static void chargen_stream(int s, servtab_t *sep) | 1638 | /* ARGSUSED */ |
1639 | static void | ||
1640 | chargen_stream (int s, servtab_t *sep) | ||
1076 | { | 1641 | { |
1077 | char *rs; | 1642 | char *rs; |
1078 | int len; | 1643 | int len; |
1079 | char text[LINESIZ+2]; | 1644 | char text[LINESIZ + 2]; |
1080 | 1645 | ||
1081 | setproctitle(sep->se_service, s); | 1646 | inetd_setproctitle (sep->se_service, s); |
1082 | 1647 | ||
1083 | if (!endring) { | 1648 | if (!endring) { |
1084 | initring(); | 1649 | initring (); |
1085 | rs = ring; | 1650 | rs = ring; |
1086 | } | 1651 | } |
1087 | 1652 | ||
1088 | text[LINESIZ] = '\r'; | 1653 | text[LINESIZ] = '\r'; |
1089 | text[LINESIZ + 1] = '\n'; | 1654 | text[LINESIZ + 1] = '\n'; |
1090 | for (rs = ring;;) { | 1655 | for (rs = ring;;) { |
1091 | if ((len = endring - rs) >= LINESIZ) | 1656 | if ((len = endring - rs) >= LINESIZ) |
1092 | memcpy(text, rs, LINESIZ); | 1657 | memmove (text, rs, LINESIZ); |
1093 | else { | 1658 | else { |
1094 | memcpy(text, rs, len); | 1659 | memmove (text, rs, len); |
1095 | memcpy(text + len, ring, LINESIZ - len); | 1660 | memmove (text + len, ring, LINESIZ - len); |
1096 | } | ||
1097 | if (++rs == endring) | ||
1098 | rs = ring; | ||
1099 | if (write(s, text, sizeof(text)) != sizeof(text)) | ||
1100 | break; | ||
1101 | } | 1661 | } |
1102 | exit(0); | 1662 | if (++rs == endring) |
1663 | rs = ring; | ||
1664 | if (write (s, text, sizeof (text)) != sizeof (text)) | ||
1665 | break; | ||
1666 | } | ||
1667 | exit (0); | ||
1103 | } | 1668 | } |
1104 | 1669 | ||
1105 | /* Character generator */ | 1670 | /* Character generator */ |
1106 | static void chargen_dg(int s, servtab_t *sep) | 1671 | /* ARGSUSED */ |
1672 | static void | ||
1673 | chargen_dg (int s, servtab_t *sep __attribute__((unused))) | ||
1107 | { | 1674 | { |
1108 | struct sockaddr sa; | 1675 | /* struct sockaddr_storage ss; */ |
1109 | static char *rs; | 1676 | struct sockaddr sa; |
1110 | size_t len; | 1677 | static char *rs; |
1111 | socklen_t size; | 1678 | int len, size; |
1112 | char text[LINESIZ+2]; | 1679 | char text[LINESIZ + 2]; |
1113 | 1680 | ||
1114 | (void)sep; | 1681 | if (endring == 0) { |
1115 | 1682 | initring (); | |
1116 | if (endring == 0) { | 1683 | rs = ring; |
1117 | initring(); | 1684 | } |
1118 | rs = ring; | 1685 | |
1119 | } | 1686 | size = sizeof (sa); |
1120 | 1687 | if (recvfrom (s, text, sizeof (text), 0, &sa, &size) < 0) | |
1121 | size = sizeof(sa); | 1688 | return; |
1122 | if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0) | 1689 | if (dg_badinput ((struct sockaddr_in *) &sa)) |
1123 | return; | 1690 | return; |
1124 | 1691 | ||
1125 | if ((len = endring - rs) >= LINESIZ) | 1692 | if ((len = endring - rs) >= LINESIZ) |
1126 | memcpy(text, rs, LINESIZ); | 1693 | memmove (text, rs, LINESIZ); |
1127 | else { | 1694 | else { |
1128 | memcpy(text, rs, len); | 1695 | memmove (text, rs, len); |
1129 | memcpy(text + len, ring, LINESIZ - len); | 1696 | memmove (text + len, ring, LINESIZ - len); |
1130 | } | 1697 | } |
1131 | if (++rs == endring) | 1698 | if (++rs == endring) |
1132 | rs = ring; | 1699 | rs = ring; |
1133 | text[LINESIZ] = '\r'; | 1700 | text[LINESIZ] = '\r'; |
1134 | text[LINESIZ + 1] = '\n'; | 1701 | text[LINESIZ + 1] = '\n'; |
1135 | (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa)); | 1702 | (void) sendto (s, text, sizeof (text), 0, &sa, sizeof (sa)); |
1136 | } | 1703 | } |
1137 | #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN */ | 1704 | #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN */ |
1138 | 1705 | ||
@@ -1146,74 +1713,84 @@ static void chargen_dg(int s, servtab_t *sep) | |||
1146 | * some seventy years Bell Labs was asleep. | 1713 | * some seventy years Bell Labs was asleep. |
1147 | */ | 1714 | */ |
1148 | 1715 | ||
1149 | static long machtime(void) | 1716 | static u_int machtime (void) |
1150 | { | 1717 | { |
1151 | struct timeval tv; | 1718 | struct timeval tv; |
1152 | 1719 | ||
1153 | if (gettimeofday(&tv, (struct timezone *)0) < 0) { | 1720 | if (gettimeofday (&tv, NULL) < 0) { |
1154 | fprintf(stderr, "Unable to get time of day\n"); | 1721 | fprintf (stderr, "Unable to get time of day\n"); |
1155 | return (0L); | 1722 | return (0L); |
1156 | } | 1723 | } |
1157 | return (htonl((long)tv.tv_sec + 2208988800UL)); | 1724 | return (htonl ((u_int) tv.tv_sec + 2208988800UL)); |
1158 | } | 1725 | } |
1159 | 1726 | ||
1160 | static void machtime_stream(int s, servtab_t *sep) | 1727 | /* ARGSUSED */ |
1728 | static void | ||
1729 | machtime_stream (int s, servtab_t *sep __attribute__((unused))) | ||
1161 | { | 1730 | { |
1162 | long result; | 1731 | u_int result; |
1163 | (void)sep; | ||
1164 | 1732 | ||
1165 | result = machtime(); | 1733 | result = machtime (); |
1166 | write(s, (char *) &result, sizeof(result)); | 1734 | (void) write (s, (char *) &result, sizeof (result)); |
1167 | } | 1735 | } |
1168 | 1736 | ||
1169 | static void machtime_dg(int s, servtab_t *sep) | 1737 | /* ARGSUSED */ |
1738 | static void | ||
1739 | machtime_dg (int s, servtab_t *sep __attribute__((unused))) | ||
1170 | { | 1740 | { |
1171 | long result; | 1741 | u_int result; |
1172 | struct sockaddr sa; | 1742 | /* struct sockaddr_storage ss; */ |
1173 | socklen_t size; | 1743 | struct sockaddr sa; |
1174 | (void)sep; | 1744 | struct sockaddr_in *dg_sin; |
1175 | 1745 | int size; | |
1176 | size = sizeof(sa); | 1746 | |
1177 | if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) | 1747 | size = sizeof (sa); |
1178 | return; | 1748 | if (recvfrom (s, (char *) &result, sizeof (result), 0, &sa, &size) < 0) |
1179 | result = machtime(); | 1749 | return; |
1180 | (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa)); | 1750 | /* if (dg_badinput((struct sockaddr *)&ss)) */ |
1751 | dg_sin = (struct sockaddr_in *) &sa; | ||
1752 | if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST) || | ||
1753 | ntohs (dg_sin->sin_port) < IPPORT_RESERVED / 2) | ||
1754 | return; | ||
1755 | result = machtime (); | ||
1756 | (void) sendto (s, (char *) &result, sizeof (result), 0, &sa, sizeof (sa)); | ||
1181 | } | 1757 | } |
1182 | #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME */ | 1758 | #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME */ |
1183 | 1759 | ||
1184 | 1760 | ||
1185 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME | 1761 | #ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME |
1186 | /* Return human-readable time of day */ | 1762 | /* Return human-readable time of day */ |
1187 | static int human_readable_time_sprintf(char *buffer) | 1763 | /* ARGSUSED */ |
1188 | { | 1764 | static void daytime_stream (int s, servtab_t *sep __attribute__((unused))) |
1189 | time_t clocc = time(NULL); | ||
1190 | |||
1191 | return sprintf(buffer, "%.24s\r\n", ctime(&clocc)); | ||
1192 | } | ||
1193 | |||
1194 | static void daytime_stream(int s, servtab_t *sep) | ||
1195 | { | 1765 | { |
1196 | char buffer[256]; | 1766 | char buffer[256]; |
1197 | size_t st = human_readable_time_sprintf(buffer); | 1767 | time_t t; |
1198 | 1768 | ||
1199 | (void)sep; | 1769 | t = time (NULL); |
1200 | 1770 | ||
1201 | write(s, buffer, st); | 1771 | (void) sprintf (buffer, "%.24s\r\n", ctime (&t)); |
1772 | (void) write (s, buffer, strlen (buffer)); | ||
1202 | } | 1773 | } |
1203 | 1774 | ||
1204 | /* Return human-readable time of day */ | 1775 | /* Return human-readable time of day */ |
1205 | static void daytime_dg(int s, servtab_t *sep) | 1776 | /* ARGSUSED */ |
1777 | void | ||
1778 | daytime_dg (int s, servtab_t *sep __attribute__((unused))) | ||
1206 | { | 1779 | { |
1207 | char buffer[256]; | 1780 | char buffer[256]; |
1208 | struct sockaddr sa; | 1781 | time_t t; |
1209 | socklen_t size; | 1782 | /* struct sockaddr_storage ss; */ |
1210 | 1783 | struct sockaddr sa; | |
1211 | (void)sep; | 1784 | int size; |
1212 | 1785 | ||
1213 | size = sizeof(sa); | 1786 | t = time ((time_t *) 0); |
1214 | if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0) | 1787 | |
1215 | return; | 1788 | size = sizeof (sa); |
1216 | size = human_readable_time_sprintf(buffer); | 1789 | if (recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size) < 0) |
1217 | sendto(s, buffer, size, 0, &sa, sizeof(sa)); | 1790 | return; |
1791 | if (dg_badinput ((struct sockaddr_in *) &sa)) | ||
1792 | return; | ||
1793 | (void) sprintf (buffer, "%.24s\r\n", ctime (&t)); | ||
1794 | (void) sendto (s, buffer, strlen (buffer), 0, &sa, sizeof (sa)); | ||
1218 | } | 1795 | } |
1219 | #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME */ | 1796 | #endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME */ |