aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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
commit1a2f4d9af7b8ec08db75f245e1b513a47c5535d8 (patch)
tree861e698298dd34d23def9bbf678d18f642cf3977
parent7f782da048defae66ad8b602a3cca8e7957a3639 (diff)
downloadbusybox-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.in7
-rw-r--r--networking/inetd.c2397
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
308config 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
309config CONFIG_IP 316config 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)
192static rlim_t rlim_ofile_cur = OPEN_MAX;
193static 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
154typedef 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 */ 211typedef 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
181static servtab_t *servtab; 257static servtab_t *servtab;
182 258
183#ifdef INETD_FEATURE_ENABLED 259#ifdef INETD_FEATURE_ENABLED
184struct biltin { 260struct 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
194static void echo_stream(int, servtab_t *); 271static void echo_stream (int, servtab_t *);
195static void echo_dg(int, servtab_t *); 272static 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
199static void discard_stream(int, servtab_t *); 276static void discard_stream (int, servtab_t *);
200static void discard_dg(int, servtab_t *); 277static 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
204static void machtime_stream(int, servtab_t *); 281static void machtime_stream (int, servtab_t *);
205static void machtime_dg(int, servtab_t *); 282static 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
209static void daytime_stream(int, servtab_t *); 286static void daytime_stream (int, servtab_t *);
210static void daytime_dg(int, servtab_t *); 287static 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
214static void chargen_stream(int, servtab_t *); 291static void chargen_stream (int, servtab_t *);
215static void chargen_dg(int, servtab_t *); 292static void chargen_dg (int, servtab_t *);
216#endif 293#endif
217 294
218static const struct biltin biltins[] = { 295static 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 325static int global_queuelen = 128;
249static struct rlimit rlim_ofile; 326static int nsock, maxsock;
250#endif 327static fd_set allsock;
328static int toomany = TOOMANY;
329static int timingout;
330static struct servent *sp;
331static uid_t uid;
251 332
252/* Length of socket listen queue. Should be per-service probably. */ 333static char *CONFIG = _PATH_INETDCONF;
253static int global_queuelen = 128;
254 334
255static FILE *fconfig; 335static FILE *fconfig;
256static sigset_t blockmask; 336static char line[1024];
257static sigset_t emptymask; 337static char *defhost;
258static fd_set allsock;
259static int nsock;
260static int maxsock;
261static int timingout;
262static int rlim_ofile_cur = OPEN_MAX;
263static const char *CONFIG = _PATH_INETDCONF;
264 338
265static void 339static char *newstr (char *cp)
266syslog_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
269static void 347static int setconfig (void)
270syslog_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
282static char * inetd_strdup(const char *s) 359static 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"); 370static 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
396static 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
292static servtab_t *getconfigent(void) 407static 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
301more: 422static 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); 449static 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) \
459setsockopt(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); 517static 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); 530static 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
542again:
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); 569static 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) { 581static 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
613static 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); */
625more:
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
431static void freeconfig(servtab_t *cp) 873static 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 891static int matchconf (servtab_t *old, servtab_t *new)
445static char **Argv;
446static char *LastArg;
447
448static 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
469static void setup(servtab_t *sep) 925static 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) {
535static 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 1146static void reapchild (int sig __attribute__((unused)))
675static 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
703static void retry(int signum) 1173static 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
721static void goaway(int signum) 1197static 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
1228static char **Argv;
1229static char *LastArg;
734 1230
735extern int inetd_main(int argc, char *argv[]) 1231static void
1232inetd_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 1258int
753 Argv = argv; 1259inetd_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) || \
1004static void echo_stream(int s, servtab_t *sep) 1548 defined(CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME)
1549static 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 */
1017static void echo_dg(int s, servtab_t *sep) 1562/* ARGSUSED */
1563static void
1564echo_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 */
1577static void
1578echo_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 */
1036static void discard_stream(int s, servtab_t *sep) 1596/* ARGSUSED */
1597static void
1598discard_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 */
1048static void discard_dg(int s, servtab_t *sep) 1609/* ARGSUSED */
1610static void
1611discard_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
1060static char ring[128]; 1622static char ring[128];
1061static char *endring; 1623static char *endring;
1062 1624
1063static void initring(void) 1625static void
1626initring (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 */
1075static void chargen_stream(int s, servtab_t *sep) 1638/* ARGSUSED */
1639static void
1640chargen_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 */
1106static void chargen_dg(int s, servtab_t *sep) 1671/* ARGSUSED */
1672static void
1673chargen_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
1149static long machtime(void) 1716static 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
1160static void machtime_stream(int s, servtab_t *sep) 1727/* ARGSUSED */
1728static void
1729machtime_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
1169static void machtime_dg(int s, servtab_t *sep) 1737/* ARGSUSED */
1738static void
1739machtime_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 */
1187static int human_readable_time_sprintf(char *buffer) 1763/* ARGSUSED */
1188{ 1764static 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
1194static 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 */
1205static void daytime_dg(int s, servtab_t *sep) 1776/* ARGSUSED */
1777void
1778daytime_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 */