blob: fd72aa72668bb82940663caae96676860b8717f7 [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00002/* $Slackware: inetd.c 1.79s 2001/02/06 13:18:00 volkerdi Exp $ */
3/* $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $ */
4/* $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $ */
5/* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru> */
Glenn L McGrath06e95652003-02-09 06:51:14 +00006/*
7 * Copyright (c) 1983,1991 The Regents of the University of California.
8 * All rights reserved.
9 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +000010 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
Glenn L McGrath06e95652003-02-09 06:51:14 +000025 *
Denis Vlasenkof8138d12007-01-11 23:26:13 +000026 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +000027 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
Glenn L McGrath06e95652003-02-09 06:51:14 +000037 */
38
Denis Vlasenkof8138d12007-01-11 23:26:13 +000039/* Inetd - Internet super-server
Glenn L McGrath06e95652003-02-09 06:51:14 +000040 *
41 * This program invokes all internet services as needed.
42 * connection-oriented services are invoked each time a
43 * connection is made, by creating a process. This process
44 * is passed the connection as file descriptor 0 and is
45 * expected to do a getpeername to find out the source host
46 * and port.
47 *
48 * Datagram oriented services are invoked when a datagram
49 * arrives; a process is created and passed a pending message
50 * on file descriptor 0. Datagram servers may either connect
51 * to their peer, freeing up the original socket for inetd
Denis Vlasenkof8138d12007-01-11 23:26:13 +000052 * to receive further messages on, or "take over the socket",
Glenn L McGrath06e95652003-02-09 06:51:14 +000053 * processing all arriving datagrams and, eventually, timing
Denis Vlasenkof8138d12007-01-11 23:26:13 +000054 * out. The first type of server is said to be "multi-threaded";
55 * the second type of server "single-threaded".
Glenn L McGrath06e95652003-02-09 06:51:14 +000056 *
57 * Inetd uses a configuration file which is read at startup
58 * and, possibly, at some later time in response to a hangup signal.
Denis Vlasenkof8138d12007-01-11 23:26:13 +000059 * The configuration file is "free format" with fields given in the
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +000060 * order shown below. Continuation lines for an entry must begin with
Glenn L McGrath06e95652003-02-09 06:51:14 +000061 * a space or tab. All fields must be present in each entry.
62 *
63 * service name must be in /etc/services
64 * socket type stream/dgram/raw/rdm/seqpacket
65 * protocol must be in /etc/protocols
66 * wait/nowait[.max] single-threaded/multi-threaded, max #
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +000067 * user[.group] or user[:group] user/group to run daemon as
Glenn L McGrath06e95652003-02-09 06:51:14 +000068 * server program full path name
69 * server program arguments maximum of MAXARGS (20)
70 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +000071 * 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
77 * server program full path name
78 * server program arguments maximum of MAXARGS (20)
79 *
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.
Glenn L McGrath06e95652003-02-09 06:51:14 +0000103 *
104 * Comment lines are indicated by a `#' in column 1.
105 */
106
Denis Vlasenkof8138d12007-01-11 23:26:13 +0000107/* inetd rules for passing file descriptors to children
108 * (http://www.freebsd.org/cgi/man.cgi?query=inetd):
109 *
110 * The wait/nowait entry specifies whether the server that is invoked by
111 * inetd will take over the socket associated with the service access point,
112 * and thus whether inetd should wait for the server to exit before listen-
113 * ing for new service requests. Datagram servers must use "wait", as
114 * they are always invoked with the original datagram socket bound to the
115 * specified service address. These servers must read at least one datagram
116 * from the socket before exiting. If a datagram server connects to its
117 * peer, freeing the socket so inetd can receive further messages on the
118 * socket, it is said to be a "multi-threaded" server; it should read one
119 * datagram from the socket and create a new socket connected to the peer.
120 * It should fork, and the parent should then exit to allow inetd to check
121 * for new service requests to spawn new servers. Datagram servers which
122 * process all incoming datagrams on a socket and eventually time out are
123 * said to be "single-threaded". The comsat(8), (biff(1)) and talkd(8)
124 * utilities are both examples of the latter type of datagram server. The
125 * tftpd(8) utility is an example of a multi-threaded datagram server.
126 *
127 * Servers using stream sockets generally are multi-threaded and use the
128 * "nowait" entry. Connection requests for these services are accepted by
129 * inetd, and the server is given only the newly-accepted socket connected
130 * to a client of the service. Most stream-based services operate in this
131 * manner. Stream-based servers that use "wait" are started with the lis-
132 * tening service socket, and must accept at least one connection request
133 * before exiting. Such a server would normally accept and process incoming
134 * connection requests until a timeout.
135 */
136
137/* Here's the scoop concerning the user[.:]group feature:
Glenn L McGrath06e95652003-02-09 06:51:14 +0000138 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000139 * 1) set-group-option off.
Glenn L McGrath06e95652003-02-09 06:51:14 +0000140 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000141 * a) user = root: NO setuid() or setgid() is done
Glenn L McGrath06e95652003-02-09 06:51:14 +0000142 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000143 * b) other: setgid(primary group as found in passwd)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000144 * initgroups(name, primary group)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000145 * setuid()
Glenn L McGrath06e95652003-02-09 06:51:14 +0000146 *
147 * 2) set-group-option on.
148 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000149 * a) user = root: setgid(specified group)
150 * NO initgroups()
151 * NO setuid()
Glenn L McGrath06e95652003-02-09 06:51:14 +0000152 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000153 * b) other: setgid(specified group)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000154 * initgroups(name, specified group)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000155 * setuid()
Glenn L McGrath06e95652003-02-09 06:51:14 +0000156 */
157
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000158#include "busybox.h"
Rob Landleyd921b2e2006-08-03 15:41:12 +0000159#include <syslog.h>
Rob Landley099ed502006-08-28 09:41:49 +0000160#include <sys/un.h>
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000161
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000162//#define ENABLE_FEATURE_INETD_RPC 1
163//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1
164//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1
165//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 1
166//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1
167//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1
168//#define ENABLE_FEATURE_IPV6 1
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000169
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000170#if ENABLE_FEATURE_INETD_RPC
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000171#include <rpc/rpc.h>
172#include <rpc/pmap_clnt.h>
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000173#endif
174
Glenn L McGrath06e95652003-02-09 06:51:14 +0000175#define _PATH_INETDPID "/var/run/inetd.pid"
176
Glenn L McGrath06e95652003-02-09 06:51:14 +0000177
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000178#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
179#define RETRYTIME (60*10) /* retry after bind or server fail */
180
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000181#ifndef RLIMIT_NOFILE
182#define RLIMIT_NOFILE RLIMIT_OFILE
183#endif
184
185#ifndef OPEN_MAX
186#define OPEN_MAX 64
187#endif
Glenn L McGrath06e95652003-02-09 06:51:14 +0000188
189/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
Denis Vlasenkof8138d12007-01-11 23:26:13 +0000190#define FD_MARGIN 8
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000191static rlim_t rlim_ofile_cur = OPEN_MAX;
192static struct rlimit rlim_ofile;
193
Glenn L McGrath06e95652003-02-09 06:51:14 +0000194
Glenn L McGrathb1207b32003-02-10 22:31:09 +0000195/* Check unsupporting builtin */
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000196#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
197 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
198 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \
199 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \
200 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000201# define INETD_FEATURE_ENABLED
Glenn L McGrathb1207b32003-02-10 22:31:09 +0000202#endif
Glenn L McGrath06e95652003-02-09 06:51:14 +0000203
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000204#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
205 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
206 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000207# define INETD_SETPROCTITLE
Glenn L McGrath06e95652003-02-09 06:51:14 +0000208#endif
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000209
Denis Vlasenkoc1876d72006-09-23 15:58:01 +0000210typedef struct servtab {
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000211 char *se_hostaddr; /* host address to listen on */
212 char *se_service; /* name of service */
213 int se_socktype; /* type of socket to use */
214 int se_family; /* address family */
215 char *se_proto; /* protocol used */
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000216#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000217 int se_rpcprog; /* rpc program number */
218 int se_rpcversl; /* rpc program lowest version */
219 int se_rpcversh; /* rpc program highest version */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000220#define isrpcservice(sep) ((sep)->se_rpcversl != 0)
221#else
222#define isrpcservice(sep) 0
223#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000224 pid_t se_wait; /* single threaded server */
225 short se_checked; /* looked at during merge */
226 char *se_user; /* user name to run as */
227 char *se_group; /* group name to run as */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000228#ifdef INETD_FEATURE_ENABLED
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000229 const struct builtin *se_bi; /* if built-in, description */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000230#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000231 char *se_server; /* server program */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000232#define MAXARGV 20
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000233 char *se_argv[MAXARGV + 1]; /* program arguments */
234 int se_fd; /* open descriptor */
Denis Vlasenkoc1876d72006-09-23 15:58:01 +0000235 union {
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000236 struct sockaddr se_un_ctrladdr;
237 struct sockaddr_in se_un_ctrladdr_in;
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000238#if ENABLE_FEATURE_IPV6
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000239 struct sockaddr_in6 se_un_ctrladdr_in6;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000240#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000241 struct sockaddr_un se_un_ctrladdr_un;
242 } se_un; /* bound address */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000243#define se_ctrladdr se_un.se_un_ctrladdr
244#define se_ctrladdr_in se_un.se_un_ctrladdr_in
245#define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
246#define se_ctrladdr_un se_un.se_un_ctrladdr_un
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000247 int se_ctrladdr_size;
248 int se_max; /* max # of instances of this service */
249 int se_count; /* number started since se_time */
250 struct timeval se_time; /* start of se_count */
251 struct servtab *se_next;
Glenn L McGrath03a06432004-02-18 13:19:58 +0000252} servtab_t;
253
254static servtab_t *servtab;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000255
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000256#ifdef INETD_FEATURE_ENABLED
Denis Vlasenkoc1876d72006-09-23 15:58:01 +0000257struct builtin {
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000258 const char *bi_service; /* internally provided service name */
259 int bi_socktype; /* type of socket supported */
260 short bi_fork; /* 1 if should fork before call */
261 short bi_wait; /* 1 if should wait for child */
262 void (*bi_fn) (int, servtab_t *);
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000263};
Glenn L McGrath06e95652003-02-09 06:51:14 +0000264
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000265 /* Echo received data */
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000266#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000267static void echo_stream(int, servtab_t *);
268static void echo_dg(int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000269#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000270 /* Internet /dev/null */
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000271#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000272static void discard_stream(int, servtab_t *);
273static void discard_dg(int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000274#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000275 /* Return 32 bit time since 1900 */
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000276#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000277static void machtime_stream(int, servtab_t *);
278static void machtime_dg(int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000279#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000280 /* Return human-readable time */
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000281#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000282static void daytime_stream(int, servtab_t *);
283static void daytime_dg(int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000284#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000285 /* Familiar character generator */
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000286#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000287static void chargen_stream(int, servtab_t *);
288static void chargen_dg(int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000289#endif
290
Bernhard Reutner-Fischera4acf662006-04-10 12:26:47 +0000291static const struct builtin builtins[] = {
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000292#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000293 /* Echo received data */
294 {"echo", SOCK_STREAM, 1, 0, echo_stream,},
295 {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
Glenn L McGrath06e95652003-02-09 06:51:14 +0000296#endif
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000297#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000298 /* Internet /dev/null */
299 {"discard", SOCK_STREAM, 1, 0, discard_stream,},
300 {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
Glenn L McGrath06e95652003-02-09 06:51:14 +0000301#endif
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000302#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000303 /* Return 32 bit time since 1900 */
304 {"time", SOCK_STREAM, 0, 0, machtime_stream,},
305 {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
Glenn L McGrath06e95652003-02-09 06:51:14 +0000306#endif
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000307#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000308 /* Return human-readable time */
309 {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
310 {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
Glenn L McGrath06e95652003-02-09 06:51:14 +0000311#endif
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000312#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000313 /* Familiar character generator */
314 {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
315 {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
Glenn L McGrath06e95652003-02-09 06:51:14 +0000316#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000317 {NULL, 0, 0, 0, NULL}
Glenn L McGrath06e95652003-02-09 06:51:14 +0000318};
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000319#endif /* INETD_FEATURE_ENABLED */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000320
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000321static int global_queuelen = 128;
322static int nsock, maxsock;
323static fd_set allsock;
Denis Vlasenko13858992006-10-08 12:49:22 +0000324static int toomany;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000325static int timingout;
326static struct servent *sp;
327static uid_t uid;
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000328
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000329static const char *config_filename = "/etc/inetd.conf";
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000330
331static FILE *fconfig;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000332static char *defhost;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000333
Denis Vlasenko3538b9a2006-09-06 18:36:50 +0000334/* xstrdup(NULL) returns NULL, but this one
335 * will return newly-allocated "" if called with NULL arg
336 * TODO: audit whether this makes any real difference
337 */
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000338static char *xxstrdup(char *cp)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000339{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000340 return xstrdup(cp ? cp : "");
Glenn L McGrath06e95652003-02-09 06:51:14 +0000341}
342
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000343static int setconfig(void)
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000344{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000345 free(defhost);
346 defhost = xstrdup("*");
347 if (fconfig != NULL) {
348 fseek(fconfig, 0L, SEEK_SET);
349 return 1;
350 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000351 fconfig = fopen(config_filename, "r");
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000352 return (fconfig != NULL);
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000353}
354
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000355static void endconfig(void)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000356{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000357 if (fconfig) {
358 (void) fclose(fconfig);
359 fconfig = NULL;
360 }
361 free(defhost);
362 defhost = 0;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000363}
Glenn L McGrath53766c42004-01-18 08:58:06 +0000364
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000365#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000366static void register_rpc(servtab_t *sep)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000367{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000368 int n;
369 struct sockaddr_in ir_sin;
370 struct protoent *pp;
371 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000372
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000373 if ((pp = getprotobyname(sep->se_proto + 4)) == NULL) {
374 bb_perror_msg("%s: getproto", sep->se_proto);
375 return;
376 }
377 size = sizeof ir_sin;
378 if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
379 bb_perror_msg("%s/%s: getsockname",
380 sep->se_service, sep->se_proto);
381 return;
382 }
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000383
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000384 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
385 (void) pmap_unset(sep->se_rpcprog, n);
386 if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port)))
387 bb_perror_msg("%s %s: pmap_set: %u %u %u %u",
388 sep->se_service, sep->se_proto,
389 sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port));
390 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000391}
Glenn L McGrath06e95652003-02-09 06:51:14 +0000392
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000393static void unregister_rpc(servtab_t *sep)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000394{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000395 int n;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000396
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000397 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
398 if (!pmap_unset(sep->se_rpcprog, n))
399 bb_error_msg("pmap_unset(%u, %u)", sep->se_rpcprog, n);
400 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000401}
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000402#endif /* FEATURE_INETD_RPC */
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000403
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000404static void freeconfig(servtab_t *cp)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000405{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000406 int i;
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000407
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000408 free(cp->se_hostaddr);
409 free(cp->se_service);
410 free(cp->se_proto);
411 free(cp->se_user);
412 free(cp->se_group);
413 free(cp->se_server);
414 for (i = 0; i < MAXARGV; i++)
415 free(cp->se_argv[i]);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000416}
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000417
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000418static int bump_nofile(void)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000419{
420#define FD_CHUNK 32
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000421
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000422 struct rlimit rl;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000423
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000424 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000425 bb_perror_msg("getrlimit");
426 return -1;
427 }
428 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
429 rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
430 if (rl.rlim_cur <= rlim_ofile_cur) {
431 bb_error_msg("bump_nofile: cannot extend file limit, max = %d",
432 (int) rl.rlim_cur);
433 return -1;
434 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000435
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000436 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
437 bb_perror_msg("setrlimit");
438 return -1;
439 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000440
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000441 rlim_ofile_cur = rl.rlim_cur;
442 return 0;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000443}
444
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000445static void setup(servtab_t *sep)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000446{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000447 int r;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000448
Denis Vlasenkoc1876d72006-09-23 15:58:01 +0000449 sep->se_fd = socket(sep->se_family, sep->se_socktype, 0);
450 if (sep->se_fd < 0) {
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000451 bb_perror_msg("%s/%s: socket", sep->se_service, sep->se_proto);
452 return;
453 }
Denis Vlasenko48237b02006-11-22 23:22:06 +0000454 if (setsockopt_reuseaddr(sep->se_fd) < 0)
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000455 bb_perror_msg("setsockopt(SO_REUSEADDR)");
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000456
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000457#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000458 if (isrpcservice(sep)) {
459 struct passwd *pwd;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000460
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000461 /*
462 * for RPC services, attempt to use a reserved port
463 * if they are going to be running as root.
464 *
465 * Also, zero out the port for all RPC services; let bind()
466 * find one.
467 */
468 sep->se_ctrladdr_in.sin_port = 0;
469 if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
470 pwd->pw_uid == 0 && uid == 0)
471 r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
472 else {
473 r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
474 if (r == 0) {
475 socklen_t len = sep->se_ctrladdr_size;
476 int saveerrno = errno;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000477
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000478 /* update se_ctrladdr_in.sin_port */
479 r = getsockname(sep->se_fd, &sep->se_ctrladdr, &len);
480 if (r <= 0)
481 errno = saveerrno;
482 }
483 }
484 } else
Glenn L McGrath53766c42004-01-18 08:58:06 +0000485#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000486 r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
487 if (r < 0) {
488 bb_perror_msg("%s/%s (%d): bind",
489 sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family);
490 close(sep->se_fd);
491 sep->se_fd = -1;
492 if (!timingout) {
493 timingout = 1;
494 alarm(RETRYTIME);
495 }
496 return;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000497 }
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000498 if (sep->se_socktype == SOCK_STREAM)
499 listen(sep->se_fd, global_queuelen);
Glenn L McGrath53766c42004-01-18 08:58:06 +0000500
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000501 FD_SET(sep->se_fd, &allsock);
502 nsock++;
503 if (sep->se_fd > maxsock) {
504 maxsock = sep->se_fd;
505 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
506 bump_nofile();
507 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000508}
509
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000510static char *nextline(void)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000511{
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000512#define line bb_common_bufsiz1
513
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000514 char *cp;
515 FILE *fd = fconfig;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000516
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000517 if (fgets(line, sizeof(line), fd) == NULL)
518 return NULL;
519 cp = strchr(line, '\n');
520 if (cp)
521 *cp = '\0';
522 return line;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000523}
524
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000525static char *skip(char **cpp) /* int report; */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000526{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000527 char *cp = *cpp;
528 char *start;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000529
530/* erp: */
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000531 if (*cpp == NULL) {
532 /* if (report) */
533 /* bb_error_msg("syntax error in inetd config file"); */
534 return NULL;
535 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000536
Denis Vlasenkoce074df2007-03-24 12:07:31 +0000537 again:
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000538 while (*cp == ' ' || *cp == '\t')
539 cp++;
540 if (*cp == '\0') {
541 int c;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000542
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000543 c = getc(fconfig);
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000544 ungetc(c, fconfig);
545 if (c == ' ' || c == '\t') {
546 cp = nextline();
547 if (cp)
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000548 goto again;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000549 }
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000550 *cpp = NULL;
551 /* goto erp; */
552 return NULL;
553 }
554 start = cp;
555 while (*cp && *cp != ' ' && *cp != '\t')
556 cp++;
557 if (*cp != '\0')
558 *cp++ = '\0';
559 /* if ((*cpp = cp) == NULL) */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000560 /* goto erp; */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000561
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000562 *cpp = cp;
563 return start;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000564}
565
566static servtab_t *new_servtab(void)
567{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000568 return xmalloc(sizeof(servtab_t));
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000569}
570
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000571static servtab_t *dupconfig(servtab_t *sep)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000572{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000573 servtab_t *newtab;
574 int argc;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000575
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000576 newtab = new_servtab();
577 memset(newtab, 0, sizeof(servtab_t));
578 newtab->se_service = xstrdup(sep->se_service);
579 newtab->se_socktype = sep->se_socktype;
580 newtab->se_family = sep->se_family;
581 newtab->se_proto = xstrdup(sep->se_proto);
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000582#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000583 newtab->se_rpcprog = sep->se_rpcprog;
584 newtab->se_rpcversl = sep->se_rpcversl;
585 newtab->se_rpcversh = sep->se_rpcversh;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000586#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000587 newtab->se_wait = sep->se_wait;
588 newtab->se_user = xstrdup(sep->se_user);
589 newtab->se_group = xstrdup(sep->se_group);
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000590#ifdef INETD_FEATURE_ENABLED
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000591 newtab->se_bi = sep->se_bi;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000592#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000593 newtab->se_server = xstrdup(sep->se_server);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000594
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000595 for (argc = 0; argc <= MAXARGV; argc++)
596 newtab->se_argv[argc] = xstrdup(sep->se_argv[argc]);
597 newtab->se_max = sep->se_max;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000598
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000599 return newtab;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000600}
601
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000602static servtab_t *getconfigent(void)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000603{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000604 servtab_t *sep;
605 int argc;
606 char *cp, *arg;
607 char *hostdelim;
608 servtab_t *nsep;
609 servtab_t *psep;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000610
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000611 sep = new_servtab();
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000612
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000613 /* memset(sep, 0, sizeof *sep); */
Denis Vlasenko13858992006-10-08 12:49:22 +0000614 more:
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000615 /* freeconfig(sep); */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000616
Denis Vlasenko13858992006-10-08 12:49:22 +0000617 while ((cp = nextline()) && *cp == '#') /* skip comment line */;
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000618 if (cp == NULL) {
619 /* free(sep); */
620 return NULL;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000621 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000622
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000623 memset((char *) sep, 0, sizeof *sep);
624 arg = skip(&cp);
625 if (arg == NULL) {
626 /* A blank line. */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000627 goto more;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000628 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000629
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000630 /* Check for a host name. */
631 hostdelim = strrchr(arg, ':');
632 if (hostdelim) {
633 *hostdelim = '\0';
634 sep->se_hostaddr = xstrdup(arg);
635 arg = hostdelim + 1;
636 /*
637 * If the line is of the form `host:', then just change the
638 * default host for the following lines.
639 */
640 if (*arg == '\0') {
641 arg = skip(&cp);
642 if (cp == NULL) {
643 free(defhost);
644 defhost = sep->se_hostaddr;
645 goto more;
646 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000647 }
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000648 } else
649 sep->se_hostaddr = xxstrdup(defhost);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000650
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000651 sep->se_service = xxstrdup(arg);
652 arg = skip(&cp);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000653
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000654 if (strcmp(arg, "stream") == 0)
655 sep->se_socktype = SOCK_STREAM;
656 else if (strcmp(arg, "dgram") == 0)
657 sep->se_socktype = SOCK_DGRAM;
658 else if (strcmp(arg, "rdm") == 0)
659 sep->se_socktype = SOCK_RDM;
660 else if (strcmp(arg, "seqpacket") == 0)
661 sep->se_socktype = SOCK_SEQPACKET;
662 else if (strcmp(arg, "raw") == 0)
663 sep->se_socktype = SOCK_RAW;
664 else
665 sep->se_socktype = -1;
666
667 sep->se_proto = xxstrdup(skip(&cp));
668
669 if (strcmp(sep->se_proto, "unix") == 0) {
670 sep->se_family = AF_UNIX;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000671 } else {
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000672 sep->se_family = AF_INET;
673 if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000674#if ENABLE_FEATURE_IPV6
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000675 sep->se_family = AF_INET6;
676#else
677 bb_error_msg("%s: IPV6 not supported", sep->se_proto);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000678#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000679 if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000680#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000681 char *p, *ccp;
682 long l;
683
684 p = strchr(sep->se_service, '/');
685 if (p == 0) {
686 bb_error_msg("%s: no rpc version", sep->se_service);
687 goto more;
688 }
689 *p++ = '\0';
690 l = strtol(p, &ccp, 0);
691 if (ccp == p || l < 0 || l > INT_MAX) {
Denis Vlasenkoce074df2007-03-24 12:07:31 +0000692 badafterall:
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000693 bb_error_msg("%s/%s: bad rpc version", sep->se_service, p);
694 goto more;
695 }
696 sep->se_rpcversl = sep->se_rpcversh = l;
697 if (*ccp == '-') {
698 p = ccp + 1;
699 l = strtol(p, &ccp, 0);
700 if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp)
701 goto badafterall;
702 sep->se_rpcversh = l;
703 } else if (*ccp != '\0')
704 goto badafterall;
705#else
Denis Vlasenko13858992006-10-08 12:49:22 +0000706 bb_error_msg("%s: rpc services not supported", sep->se_service);
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000707#endif
708 }
709 }
710 arg = skip(&cp);
711 if (arg == NULL)
712 goto more;
713
714 {
715 char *s = strchr(arg, '.');
716 if (s) {
717 *s++ = '\0';
Denis Vlasenko13858992006-10-08 12:49:22 +0000718 sep->se_max = xatoi(s);
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000719 } else
720 sep->se_max = toomany;
721 }
722 sep->se_wait = strcmp(arg, "wait") == 0;
723 /* if ((arg = skip(&cp, 1)) == NULL) */
724 /* goto more; */
725 sep->se_user = xxstrdup(skip(&cp));
726 arg = strchr(sep->se_user, '.');
727 if (arg == NULL)
728 arg = strchr(sep->se_user, ':');
729 if (arg) {
730 *arg++ = '\0';
731 sep->se_group = xstrdup(arg);
732 }
733 /* if ((arg = skip(&cp, 1)) == NULL) */
734 /* goto more; */
735
736 sep->se_server = xxstrdup(skip(&cp));
737 if (strcmp(sep->se_server, "internal") == 0) {
738#ifdef INETD_FEATURE_ENABLED
739 const struct builtin *bi;
740
741 for (bi = builtins; bi->bi_service; bi++)
742 if (bi->bi_socktype == sep->se_socktype &&
743 strcmp(bi->bi_service, sep->se_service) == 0)
744 break;
745 if (bi->bi_service == 0) {
746 bb_error_msg("internal service %s unknown", sep->se_service);
747 goto more;
748 }
749 sep->se_bi = bi;
750 sep->se_wait = bi->bi_wait;
751#else
752 bb_perror_msg("internal service %s unknown", sep->se_service);
753 goto more;
754#endif
755 }
756#ifdef INETD_FEATURE_ENABLED
757 else
758 sep->se_bi = NULL;
759#endif
760 argc = 0;
761 for (arg = skip(&cp); cp; arg = skip(&cp)) {
762 if (argc < MAXARGV)
763 sep->se_argv[argc++] = xxstrdup(arg);
764 }
765 while (argc <= MAXARGV)
766 sep->se_argv[argc++] = NULL;
767
768 /*
769 * Now that we've processed the entire line, check if the hostname
770 * specifier was a comma separated list of hostnames. If so
771 * we'll make new entries for each address.
772 */
773 while ((hostdelim = strrchr(sep->se_hostaddr, ',')) != NULL) {
774 nsep = dupconfig(sep);
775
776 /*
777 * NULL terminate the hostname field of the existing entry,
778 * and make a dup for the new entry.
779 */
780 *hostdelim++ = '\0';
781 nsep->se_hostaddr = xstrdup(hostdelim);
782
783 nsep->se_next = sep->se_next;
784 sep->se_next = nsep;
785 }
786
787 nsep = sep;
788 while (nsep != NULL) {
789 nsep->se_checked = 1;
790 if (nsep->se_family == AF_INET) {
Denis Vlasenkobf66fbc2006-12-21 13:23:14 +0000791 if (LONE_CHAR(nsep->se_hostaddr, '*'))
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000792 nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
793 else if (!inet_aton(nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
794 struct hostent *hp;
795
796 hp = gethostbyname(nsep->se_hostaddr);
797 if (hp == 0) {
798 bb_error_msg("%s: unknown host", nsep->se_hostaddr);
799 nsep->se_checked = 0;
800 goto skip;
801 } else if (hp->h_addrtype != AF_INET) {
802 bb_error_msg("%s: address isn't an Internet "
803 "address", nsep->se_hostaddr);
804 nsep->se_checked = 0;
805 goto skip;
806 } else {
807 int i = 1;
808
809 memmove(&nsep->se_ctrladdr_in.sin_addr,
810 hp->h_addr_list[0], sizeof(struct in_addr));
811 while (hp->h_addr_list[i] != NULL) {
812 psep = dupconfig(nsep);
813 psep->se_hostaddr = xxstrdup(nsep->se_hostaddr);
814 psep->se_checked = 1;
815 memmove(&psep->se_ctrladdr_in.sin_addr,
816 hp->h_addr_list[i], sizeof(struct in_addr));
817 psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in);
818 i++;
819 /* Prepend to list, don't want to look up */
820 /* its hostname again. */
821 psep->se_next = sep;
822 sep = psep;
823 }
824 }
825 }
826 }
827/* XXX BUG?: is this skip: label supposed to remain? */
Denis Vlasenkoce074df2007-03-24 12:07:31 +0000828 skip:
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000829 nsep = nsep->se_next;
830 }
831
832 /*
833 * Finally, free any entries which failed the gethostbyname
834 * check.
835 */
836 psep = NULL;
837 nsep = sep;
838 while (nsep != NULL) {
839 servtab_t *tsep;
840
841 if (nsep->se_checked == 0) {
842 tsep = nsep;
843 if (psep == NULL) {
844 sep = nsep->se_next;
845 nsep = sep;
846 } else {
847 nsep = nsep->se_next;
848 psep->se_next = nsep;
849 }
850 freeconfig(tsep);
851 } else {
852 nsep->se_checked = 0;
853 psep = nsep;
854 nsep = nsep->se_next;
855 }
856 }
857
858 return sep;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000859}
860
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000861#define Block_Using_Signals(m) do { \
862 sigemptyset(&m); \
863 sigaddset(&m, SIGCHLD); \
864 sigaddset(&m, SIGHUP); \
865 sigaddset(&m, SIGALRM); \
866 sigprocmask(SIG_BLOCK, &m, NULL); \
Denis Vlasenkobf0a2012006-12-26 10:42:51 +0000867} while (0)
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000868
869static servtab_t *enter(servtab_t *cp)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000870{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000871 servtab_t *sep;
872 sigset_t omask;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000873
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000874 sep = new_servtab();
875 *sep = *cp;
876 sep->se_fd = -1;
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000877#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000878 sep->se_rpcprog = -1;
879#endif
880 Block_Using_Signals(omask);
881 sep->se_next = servtab;
882 servtab = sep;
883 sigprocmask(SIG_UNBLOCK, &omask, NULL);
884 return sep;
885}
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000886
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000887static int matchconf(servtab_t *old, servtab_t *new)
888{
889 if (strcmp(old->se_service, new->se_service) != 0)
890 return 0;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000891
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000892 if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
893 return 0;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000894
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000895 if (strcmp(old->se_proto, new->se_proto) != 0)
896 return 0;
897
898 /*
899 * If the new servtab is bound to a specific address, check that the
900 * old servtab is bound to the same entry. If the new service is not
901 * bound to a specific address then the check of se_hostaddr above
902 * is sufficient.
903 */
904
905 if (old->se_family == AF_INET && new->se_family == AF_INET &&
906 memcmp(&old->se_ctrladdr_in.sin_addr,
907 &new->se_ctrladdr_in.sin_addr,
908 sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
909 return 0;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000910
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000911#if ENABLE_FEATURE_IPV6
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000912 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
913 memcmp(&old->se_ctrladdr_in6.sin6_addr,
914 &new->se_ctrladdr_in6.sin6_addr,
915 sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
916 return 0;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000917#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000918 return 1;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000919}
920
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000921static void config(int sig ATTRIBUTE_UNUSED)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000922{
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000923 servtab_t *sep, *cp, **sepp;
924 sigset_t omask;
925 size_t n;
926 char protoname[10];
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000927
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000928 if (!setconfig()) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000929 bb_perror_msg("%s", config_filename);
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000930 return;
931 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000932 for (sep = servtab; sep; sep = sep->se_next)
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000933 sep->se_checked = 0;
934 cp = getconfigent();
935 while (cp != NULL) {
936 for (sep = servtab; sep; sep = sep->se_next)
937 if (matchconf(sep, cp))
938 break;
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000939
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000940 if (sep != 0) {
941 int i;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000942
Mike Frysinger23fedb32005-10-05 00:50:03 +0000943#define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000944
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000945 Block_Using_Signals(omask);
946 /*
947 * sep->se_wait may be holding the pid of a daemon
948 * that we're waiting for. If so, don't overwrite
949 * it unless the config file explicitly says don't
950 * wait.
951 */
952 if (
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000953#ifdef INETD_FEATURE_ENABLED
Denis Vlasenko13858992006-10-08 12:49:22 +0000954 cp->se_bi == 0 &&
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000955#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000956 (sep->se_wait == 1 || cp->se_wait == 0))
957 sep->se_wait = cp->se_wait;
958 SWAP(int, cp->se_max, sep->se_max);
959 SWAP(char *, sep->se_user, cp->se_user);
960 SWAP(char *, sep->se_group, cp->se_group);
961 SWAP(char *, sep->se_server, cp->se_server);
962 for (i = 0; i < MAXARGV; i++)
963 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000964#undef SWAP
965
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000966#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000967 if (isrpcservice(sep))
968 unregister_rpc(sep);
969 sep->se_rpcversl = cp->se_rpcversl;
970 sep->se_rpcversh = cp->se_rpcversh;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000971#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000972 sigprocmask(SIG_UNBLOCK, &omask, NULL);
973 freeconfig(cp);
974 } else {
975 sep = enter(cp);
976 }
977 sep->se_checked = 1;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000978
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000979 switch (sep->se_family) {
980 case AF_UNIX:
981 if (sep->se_fd != -1)
982 break;
983 (void) unlink(sep->se_service);
984 n = strlen(sep->se_service);
985 if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
986 n = sizeof sep->se_ctrladdr_un.sun_path - 1;
987 safe_strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
988 sep->se_ctrladdr_un.sun_family = AF_UNIX;
989 sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
990 setup(sep);
991 break;
992 case AF_INET:
993 sep->se_ctrladdr_in.sin_family = AF_INET;
994 /* se_ctrladdr_in was set in getconfigent */
995 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000996
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +0000997#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +0000998 if (isrpcservice(sep)) {
999 struct rpcent *rp;
Denis Vlasenko13858992006-10-08 12:49:22 +00001000 // FIXME: atoi_or_else(str, 0) would be handy here
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001001 sep->se_rpcprog = atoi(sep->se_service);
1002 if (sep->se_rpcprog == 0) {
1003 rp = getrpcbyname(sep->se_service);
1004 if (rp == 0) {
1005 bb_error_msg("%s: unknown rpc service", sep->se_service);
1006 goto serv_unknown;
1007 }
1008 sep->se_rpcprog = rp->r_number;
1009 }
1010 if (sep->se_fd == -1)
1011 setup(sep);
1012 if (sep->se_fd != -1)
1013 register_rpc(sep);
1014 } else
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001015#endif
Denis Vlasenko13858992006-10-08 12:49:22 +00001016 {
Denis Vlasenko28703012006-12-19 20:32:02 +00001017 uint16_t port = htons(atoi(sep->se_service));
Denis Vlasenko13858992006-10-08 12:49:22 +00001018 // FIXME: atoi_or_else(str, 0) would be handy here
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001019 if (!port) {
1020 /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
1021 if (isdigit(protoname[strlen(protoname) - 1]))
1022 protoname[strlen(protoname) - 1] = '\0';
1023 sp = getservbyname(sep->se_service, protoname);
1024 if (sp == 0) {
1025 bb_error_msg("%s/%s: unknown service",
1026 sep->se_service, sep->se_proto);
1027 goto serv_unknown;
1028 }
1029 port = sp->s_port;
1030 }
1031 if (port != sep->se_ctrladdr_in.sin_port) {
1032 sep->se_ctrladdr_in.sin_port = port;
1033 if (sep->se_fd != -1) {
1034 FD_CLR(sep->se_fd, &allsock);
1035 nsock--;
1036 (void) close(sep->se_fd);
1037 }
1038 sep->se_fd = -1;
1039 }
1040 if (sep->se_fd == -1)
1041 setup(sep);
1042 }
1043 break;
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001044#if ENABLE_FEATURE_IPV6
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001045 case AF_INET6:
1046 sep->se_ctrladdr_in6.sin6_family = AF_INET6;
1047 /* se_ctrladdr_in was set in getconfigent */
1048 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001049
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001050#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001051 if (isrpcservice(sep)) {
1052 struct rpcent *rp;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001053
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001054 sep->se_rpcprog = atoi(sep->se_service);
1055 if (sep->se_rpcprog == 0) {
1056 rp = getrpcbyname(sep->se_service);
1057 if (rp == 0) {
1058 bb_error_msg("%s: unknown rpc service", sep->se_service);
1059 goto serv_unknown;
1060 }
1061 sep->se_rpcprog = rp->r_number;
1062 }
1063 if (sep->se_fd == -1)
1064 setup(sep);
1065 if (sep->se_fd != -1)
1066 register_rpc(sep);
1067 } else
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001068#endif
Denis Vlasenko28703012006-12-19 20:32:02 +00001069 {
1070 uint16_t port = htons(atoi(sep->se_service));
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001071
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001072 if (!port) {
1073 /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
1074 if (isdigit(protoname[strlen(protoname) - 1]))
1075 protoname[strlen(protoname) - 1] = '\0';
1076 sp = getservbyname(sep->se_service, protoname);
1077 if (sp == 0) {
1078 bb_error_msg("%s/%s: unknown service",
1079 sep->se_service, sep->se_proto);
1080 goto serv_unknown;
1081 }
1082 port = sp->s_port;
1083 }
1084 if (port != sep->se_ctrladdr_in6.sin6_port) {
1085 sep->se_ctrladdr_in6.sin6_port = port;
1086 if (sep->se_fd != -1) {
1087 FD_CLR(sep->se_fd, &allsock);
1088 nsock--;
1089 (void) close(sep->se_fd);
1090 }
1091 sep->se_fd = -1;
1092 }
1093 if (sep->se_fd == -1)
1094 setup(sep);
1095 }
1096 break;
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001097#endif /* FEATURE_IPV6 */
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001098 }
Denis Vlasenkoce074df2007-03-24 12:07:31 +00001099 serv_unknown:
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001100 if (cp->se_next != NULL) {
1101 servtab_t *tmp = cp;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001102
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001103 cp = cp->se_next;
1104 free(tmp);
1105 } else {
1106 free(cp);
1107 cp = getconfigent();
1108 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001109 }
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001110 endconfig();
1111 /*
1112 * Purge anything not looked at above.
1113 */
1114 Block_Using_Signals(omask);
1115 sepp = &servtab;
1116 while ((sep = *sepp)) {
1117 if (sep->se_checked) {
1118 sepp = &sep->se_next;
1119 continue;
1120 }
1121 *sepp = sep->se_next;
1122 if (sep->se_fd != -1) {
1123 FD_CLR(sep->se_fd, &allsock);
1124 nsock--;
1125 (void) close(sep->se_fd);
1126 }
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001127#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001128 if (isrpcservice(sep))
1129 unregister_rpc(sep);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001130#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001131 if (sep->se_family == AF_UNIX)
1132 (void) unlink(sep->se_service);
1133 freeconfig(sep);
1134 free(sep);
1135 }
1136 sigprocmask(SIG_UNBLOCK, &omask, NULL);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001137}
1138
1139
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001140static void reapchild(int sig ATTRIBUTE_UNUSED)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001141{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001142 pid_t pid;
1143 int save_errno = errno, status;
1144 servtab_t *sep;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001145
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001146 for (;;) {
1147 pid = wait3(&status, WNOHANG, NULL);
1148 if (pid <= 0)
1149 break;
1150 for (sep = servtab; sep; sep = sep->se_next)
1151 if (sep->se_wait == pid) {
1152 if (WIFEXITED(status) && WEXITSTATUS(status))
1153 bb_error_msg("%s: exit status 0x%x",
1154 sep->se_server, WEXITSTATUS(status));
1155 else if (WIFSIGNALED(status))
1156 bb_error_msg("%s: exit signal 0x%x",
1157 sep->se_server, WTERMSIG(status));
1158 sep->se_wait = 1;
1159 FD_SET(sep->se_fd, &allsock);
1160 nsock++;
1161 }
1162 }
1163 errno = save_errno;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001164}
1165
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001166static void retry(int sig ATTRIBUTE_UNUSED)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001167{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001168 servtab_t *sep;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001169
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001170 timingout = 0;
1171 for (sep = servtab; sep; sep = sep->se_next) {
1172 if (sep->se_fd == -1) {
1173 switch (sep->se_family) {
1174 case AF_UNIX:
1175 case AF_INET:
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001176#if ENABLE_FEATURE_IPV6
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001177 case AF_INET6:
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001178#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001179 setup(sep);
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001180#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001181 if (sep->se_fd != -1 && isrpcservice(sep))
1182 register_rpc(sep);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001183#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001184 break;
1185 }
1186 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001187 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001188}
1189
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001190static void goaway(int sig ATTRIBUTE_UNUSED)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001191{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001192 servtab_t *sep;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001193
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001194 /* XXX signal race walking sep list */
1195 for (sep = servtab; sep; sep = sep->se_next) {
1196 if (sep->se_fd == -1)
1197 continue;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001198
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001199 switch (sep->se_family) {
1200 case AF_UNIX:
1201 (void) unlink(sep->se_service);
1202 break;
1203 case AF_INET:
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001204#if ENABLE_FEATURE_IPV6
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001205 case AF_INET6:
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001206#endif
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001207#if ENABLE_FEATURE_INETD_RPC
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001208 if (sep->se_wait == 1 && isrpcservice(sep))
1209 unregister_rpc(sep); /* XXX signal race */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001210#endif
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001211 break;
1212 }
1213 (void) close(sep->se_fd);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001214 }
Denis Vlasenko10457b92007-03-27 22:01:31 +00001215 remove_pidfile(_PATH_INETDPID);
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001216 exit(0);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001217}
1218
1219
1220#ifdef INETD_SETPROCTITLE
Glenn L McGrath06e95652003-02-09 06:51:14 +00001221static char **Argv;
1222static char *LastArg;
1223
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001224static void
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001225inetd_setproctitle(char *a, int s)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001226{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001227 socklen_t size;
1228 char *cp;
1229 struct sockaddr_in prt_sin;
1230 char buf[80];
Glenn L McGrath06e95652003-02-09 06:51:14 +00001231
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001232 cp = Argv[0];
1233 size = sizeof(prt_sin);
1234 (void) snprintf(buf, sizeof buf, "-%s", a);
1235 if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) {
1236 char *sa = inet_ntoa(prt_sin.sin_addr);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001237
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001238 buf[sizeof(buf) - 1 - strlen(sa) - 3] = '\0';
1239 strcat(buf, " [");
1240 strcat(buf, sa);
1241 strcat(buf, "]");
1242 }
1243 strncpy(cp, buf, LastArg - cp);
1244 cp += strlen(cp);
1245 while (cp < LastArg)
1246 *cp++ = ' ';
Glenn L McGrath06e95652003-02-09 06:51:14 +00001247}
Glenn L McGrath06e95652003-02-09 06:51:14 +00001248#endif
1249
Glenn L McGrath06e95652003-02-09 06:51:14 +00001250
Denis Vlasenko06af2162007-02-03 17:28:39 +00001251int inetd_main(int argc, char *argv[]);
1252int inetd_main(int argc, char *argv[])
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001253{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001254 servtab_t *sep;
1255 struct passwd *pwd;
1256 struct group *grp = NULL;
1257 int tmpint;
1258 struct sigaction sa, sapipe;
1259 int opt;
1260 pid_t pid;
1261 char buf[50];
1262 char *stoomany;
1263 sigset_t omask, wait_mask;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001264
1265#ifdef INETD_SETPROCTITLE
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001266 extern char **environ;
1267 char **envp = environ;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001268
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001269 Argv = argv;
1270 if (envp == 0 || *envp == 0)
1271 envp = argv;
1272 while (*envp)
1273 envp++;
1274 LastArg = envp[-1] + strlen(envp[-1]);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001275#endif
1276
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001277 uid = getuid();
1278 if (uid != 0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001279 config_filename = NULL;
Denis Vlasenko5a142022007-03-26 13:20:54 +00001280
1281 opt = getopt32(argc, argv, "R:f", &stoomany);
1282 if (opt & 1)
1283 toomany = xatoi_u(stoomany);
1284 argv += optind;
1285 argc -= optind;
1286 if (argc)
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001287 config_filename = argv[0];
1288 if (config_filename == NULL)
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001289 bb_error_msg_and_die("non-root must specify a config file");
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001290
Denis Vlasenko5a142022007-03-26 13:20:54 +00001291 if (!(opt & 2))
1292 bb_daemonize_or_rexec(0, argv - optind);
1293 else
1294 bb_sanitize_stdio();
Denis Vlasenkoffcef2d2007-01-14 02:03:28 +00001295 openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001296 logmode = LOGMODE_SYSLOG;
Eric Andersen35e643b2003-07-28 07:40:39 +00001297
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001298 if (uid == 0) {
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001299 /* If run by hand, ensure groups vector gets trashed */
Denis Vlasenko7a431b32007-01-14 01:29:06 +00001300 gid_t gid = getgid();
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001301 setgroups(1, &gid);
1302 }
1303
Denis Vlasenko10457b92007-03-27 22:01:31 +00001304 write_pidfile(_PATH_INETDPID);
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001305
1306 if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
1307 bb_perror_msg("getrlimit");
1308 } else {
1309 rlim_ofile_cur = rlim_ofile.rlim_cur;
1310 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */
1311 rlim_ofile_cur = OPEN_MAX;
1312 }
1313
1314 memset((char *) &sa, 0, sizeof(sa));
1315 sigemptyset(&sa.sa_mask);
1316 sigaddset(&sa.sa_mask, SIGALRM);
1317 sigaddset(&sa.sa_mask, SIGCHLD);
1318 sigaddset(&sa.sa_mask, SIGHUP);
1319 sa.sa_handler = retry;
1320 sigaction(SIGALRM, &sa, NULL);
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001321 config(SIGHUP);
1322 sa.sa_handler = config;
1323 sigaction(SIGHUP, &sa, NULL);
1324 sa.sa_handler = reapchild;
1325 sigaction(SIGCHLD, &sa, NULL);
1326 sa.sa_handler = goaway;
1327 sigaction(SIGTERM, &sa, NULL);
1328 sa.sa_handler = goaway;
1329 sigaction(SIGINT, &sa, NULL);
1330 sa.sa_handler = SIG_IGN;
1331 sigaction(SIGPIPE, &sa, &sapipe);
1332 memset(&wait_mask, 0, sizeof(wait_mask));
1333 {
1334 /* space for daemons to overwrite environment for ps */
Glenn L McGrath06e95652003-02-09 06:51:14 +00001335#define DUMMYSIZE 100
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001336 char dummy[DUMMYSIZE];
Glenn L McGrath06e95652003-02-09 06:51:14 +00001337
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001338 (void) memset(dummy, 'x', DUMMYSIZE - 1);
1339 dummy[DUMMYSIZE - 1] = '\0';
Glenn L McGrath06e95652003-02-09 06:51:14 +00001340
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001341 (void) setenv("inetd_dummy", dummy, 1);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001342 }
1343
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001344 for (;;) {
1345 int n, ctrl = -1;
1346 fd_set readable;
1347
1348 if (nsock == 0) {
1349 Block_Using_Signals(omask);
1350 while (nsock == 0)
1351 sigsuspend(&wait_mask);
1352 sigprocmask(SIG_UNBLOCK, &omask, NULL);
1353 }
1354
1355 readable = allsock;
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001356 n = select(maxsock + 1, &readable, NULL, NULL, NULL);
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001357 if (n <= 0) {
1358 if (n < 0 && errno != EINTR) {
1359 bb_perror_msg("select");
1360 sleep(1);
1361 }
Glenn L McGrath82d42db2004-02-18 13:12:53 +00001362 continue;
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001363 }
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001364
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001365 for (sep = servtab; n && sep; sep = sep->se_next) {
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001366 if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
1367 continue;
1368
1369 n--;
1370 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
1371 ctrl = accept(sep->se_fd, NULL, NULL);
1372 if (ctrl < 0) {
1373 if (errno == EINTR)
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001374 continue;
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001375 bb_perror_msg("accept (for %s)", sep->se_service);
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001376 continue;
1377 }
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001378 if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
1379 struct sockaddr_in peer;
1380 socklen_t plen = sizeof(peer);
1381
1382 if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00001383 bb_error_msg("cannot getpeername");
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001384 close(ctrl);
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001385 continue;
1386 }
1387 if (ntohs(peer.sin_port) == 20) {
1388 /* XXX ftp bounce */
1389 close(ctrl);
1390 continue;
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001391 }
1392 }
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001393 } else
1394 ctrl = sep->se_fd;
1395
1396 Block_Using_Signals(omask);
1397 pid = 0;
1398#ifdef INETD_FEATURE_ENABLED
1399 if (sep->se_bi == 0 || sep->se_bi->bi_fork)
1400#endif
1401 {
1402 if (sep->se_count++ == 0)
1403 (void) gettimeofday(&sep->se_time, NULL);
1404 else if (toomany > 0 && sep->se_count >= sep->se_max) {
1405 struct timeval now;
1406
1407 (void) gettimeofday(&now, NULL);
1408 if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
1409 sep->se_time = now;
1410 sep->se_count = 1;
1411 } else {
1412 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1413 close(ctrl);
1414 if (sep->se_family == AF_INET &&
1415 ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
1416 /*
1417 * Cannot close it -- there are
1418 * thieves on the system.
1419 * Simply ignore the connection.
1420 */
1421 --sep->se_count;
1422 continue;
1423 }
1424 bb_error_msg("%s/%s server failing (looping), service terminated",
1425 sep->se_service, sep->se_proto);
1426 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1427 close(ctrl);
1428 FD_CLR(sep->se_fd, &allsock);
1429 (void) close(sep->se_fd);
1430 sep->se_fd = -1;
1431 sep->se_count = 0;
1432 nsock--;
1433 sigprocmask(SIG_UNBLOCK, &omask, NULL);
1434 if (!timingout) {
1435 timingout = 1;
1436 alarm(RETRYTIME);
1437 }
1438 continue;
1439 }
1440 }
1441 pid = fork();
1442 }
1443 if (pid < 0) {
1444 bb_perror_msg("fork");
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001445 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1446 close(ctrl);
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001447 sigprocmask(SIG_UNBLOCK, &omask, NULL);
1448 sleep(1);
1449 continue;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001450 }
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001451 if (pid && sep->se_wait) {
1452 sep->se_wait = pid;
1453 FD_CLR(sep->se_fd, &allsock);
1454 nsock--;
1455 }
1456 sigprocmask(SIG_UNBLOCK, &omask, NULL);
1457 if (pid == 0) {
1458#ifdef INETD_FEATURE_ENABLED
1459 if (sep->se_bi) {
1460 (*sep->se_bi->bi_fn)(ctrl, sep);
1461 } else
1462#endif
Denis Vlasenkob64eed62007-01-14 17:06:11 +00001463 {
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001464 pwd = getpwnam(sep->se_user);
1465 if (pwd == NULL) {
1466 bb_error_msg("getpwnam: %s: no such user", sep->se_user);
1467 goto do_exit1;
1468 }
1469 if (setsid() < 0)
1470 bb_perror_msg("%s: setsid", sep->se_service);
1471 if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
1472 bb_error_msg("getgrnam: %s: no such group", sep->se_group);
1473 goto do_exit1;
1474 }
1475 if (uid != 0) {
1476 /* a user running private inetd */
1477 if (uid != pwd->pw_uid)
1478 _exit(1);
1479 } else if (pwd->pw_uid) {
1480 if (sep->se_group)
1481 pwd->pw_gid = grp->gr_gid;
1482 xsetgid((gid_t) pwd->pw_gid);
1483 initgroups(pwd->pw_name, pwd->pw_gid);
1484 xsetuid((uid_t) pwd->pw_uid);
1485 } else if (sep->se_group) {
1486 xsetgid(grp->gr_gid);
1487 setgroups(1, &grp->gr_gid);
1488 }
1489 dup2(ctrl, 0);
1490 if (ctrl) close(ctrl);
1491 dup2(0, 1);
1492 dup2(0, 2);
1493 if (rlim_ofile.rlim_cur != rlim_ofile_cur)
1494 if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
1495 bb_perror_msg("setrlimit");
1496 closelog();
1497 for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
1498 (void) close(tmpint);
1499 sigaction(SIGPIPE, &sapipe, NULL);
1500 execv(sep->se_server, sep->se_argv);
1501 bb_perror_msg("execv %s", sep->se_server);
Denis Vlasenkoce074df2007-03-24 12:07:31 +00001502 do_exit1:
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001503 if (sep->se_socktype != SOCK_STREAM)
1504 recv(0, buf, sizeof(buf), 0);
1505 _exit(1);
1506 }
1507 }
1508 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1509 close(ctrl);
1510 } /* for (sep = servtab...) */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00001511 } /* for (;;) */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001512}
Glenn L McGrath06e95652003-02-09 06:51:14 +00001513
1514/*
1515 * Internet services provided internally by inetd:
1516 */
1517#define BUFSIZE 4096
1518
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001519#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
1520 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \
1521 ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001522static int dg_badinput(struct sockaddr_in *dg_sin)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001523{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001524 if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED)
1525 return 1;
1526 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST))
1527 return 1;
1528 /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
1529 return 0;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001530}
1531#endif
1532
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001533#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
Glenn L McGrath06e95652003-02-09 06:51:14 +00001534/* Echo service -- echo data back */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001535/* ARGSUSED */
1536static void
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001537echo_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001538{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001539 char buffer[BUFSIZE];
1540 int i;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001541
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001542 inetd_setproctitle(sep->se_service, s);
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001543 while (1) {
1544 i = read(s, buffer, sizeof(buffer));
1545 if (i <= 0) break;
1546 /* FIXME: this isnt correct - safe_write()? */
1547 if (write(s, buffer, i) <= 0) break;
1548 }
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001549 exit(0);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001550}
1551
1552/* Echo service -- echo data back */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001553/* ARGSUSED */
1554static void
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001555echo_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001556{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001557 char buffer[BUFSIZE];
1558 int i;
1559 socklen_t size;
1560 /* struct sockaddr_storage ss; */
1561 struct sockaddr sa;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001562
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001563 size = sizeof(sa);
1564 i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size);
1565 if (i < 0)
1566 return;
1567 if (dg_badinput((struct sockaddr_in *) &sa))
1568 return;
1569 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001570}
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001571#endif /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
Glenn L McGrath06e95652003-02-09 06:51:14 +00001572
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001573#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
Glenn L McGrath06e95652003-02-09 06:51:14 +00001574/* Discard service -- ignore data */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001575/* ARGSUSED */
1576static void
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001577discard_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001578{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001579 char buffer[BUFSIZE];
Glenn L McGrath06e95652003-02-09 06:51:14 +00001580
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001581 inetd_setproctitle(sep->se_service, s);
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001582 while (1) {
1583 errno = 0;
1584 if (read(s, buffer, sizeof(buffer)) <= 0 && errno != EINTR)
1585 exit(0);
1586 }
Glenn L McGrath06e95652003-02-09 06:51:14 +00001587}
1588
1589/* Discard service -- ignore data */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001590/* ARGSUSED */
1591static void
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001592discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001593{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001594 char buffer[BUFSIZE];
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001595
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001596 (void) read(s, buffer, sizeof(buffer));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001597}
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001598#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
Glenn L McGrath06e95652003-02-09 06:51:14 +00001599
1600
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001601#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
Glenn L McGrath06e95652003-02-09 06:51:14 +00001602#define LINESIZ 72
1603static char ring[128];
1604static char *endring;
1605
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001606static void
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001607initring(void)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001608{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001609 int i;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001610
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001611 endring = ring;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001612
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001613 for (i = 0; i <= 128; ++i)
1614 if (isprint(i))
1615 *endring++ = i;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001616}
1617
1618/* Character generator */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001619/* ARGSUSED */
1620static void
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001621chargen_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001622{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001623 char *rs;
1624 int len;
1625 char text[LINESIZ + 2];
Glenn L McGrath06e95652003-02-09 06:51:14 +00001626
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001627 inetd_setproctitle(sep->se_service, s);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001628
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001629 if (!endring) {
1630 initring();
1631 rs = ring;
1632 }
Glenn L McGrath06e95652003-02-09 06:51:14 +00001633
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001634 text[LINESIZ] = '\r';
1635 text[LINESIZ + 1] = '\n';
Denis Vlasenkoc1876d72006-09-23 15:58:01 +00001636 rs = ring;
1637 for (;;) {
1638 len = endring - rs;
1639 if (len >= LINESIZ)
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001640 memmove(text, rs, LINESIZ);
1641 else {
1642 memmove(text, rs, len);
1643 memmove(text + len, ring, LINESIZ - len);
1644 }
1645 if (++rs == endring)
1646 rs = ring;
1647 if (write(s, text, sizeof(text)) != sizeof(text))
1648 break;
1649 }
1650 exit(0);
1651}
1652
1653/* Character generator */
1654/* ARGSUSED */
1655static void
1656chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
1657{
1658 /* struct sockaddr_storage ss; */
1659 struct sockaddr sa;
1660 static char *rs;
1661 int len;
1662 char text[LINESIZ + 2];
1663 socklen_t size;
1664
1665 if (endring == 0) {
1666 initring();
1667 rs = ring;
1668 }
1669
1670 size = sizeof(sa);
1671 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1672 return;
1673 if (dg_badinput((struct sockaddr_in *) &sa))
1674 return;
1675
Glenn L McGrath06e95652003-02-09 06:51:14 +00001676 if ((len = endring - rs) >= LINESIZ)
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001677 memmove(text, rs, LINESIZ);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001678 else {
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001679 memmove(text, rs, len);
1680 memmove(text + len, ring, LINESIZ - len);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001681 }
1682 if (++rs == endring)
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001683 rs = ring;
1684 text[LINESIZ] = '\r';
1685 text[LINESIZ + 1] = '\n';
1686 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001687}
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001688#endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
Glenn L McGrath06e95652003-02-09 06:51:14 +00001689
1690
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001691#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
Glenn L McGrath06e95652003-02-09 06:51:14 +00001692/*
1693 * Return a machine readable date and time, in the form of the
1694 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1695 * returns the number of seconds since midnight, Jan 1, 1970,
1696 * we must add 2208988800 seconds to this figure to make up for
1697 * some seventy years Bell Labs was asleep.
1698 */
1699
Denis Vlasenko35d4da02007-01-22 14:04:27 +00001700static unsigned machtime(void)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001701{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001702 struct timeval tv;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001703
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001704 if (gettimeofday(&tv, NULL) < 0) {
1705 fprintf(stderr, "Unable to get time of day\n");
1706 return 0L;
1707 }
Denis Vlasenko35d4da02007-01-22 14:04:27 +00001708 return htonl((unsigned) tv.tv_sec + 2208988800UL);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001709}
1710
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001711/* ARGSUSED */
1712static void
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001713machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001714{
Denis Vlasenko35d4da02007-01-22 14:04:27 +00001715 unsigned result;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001716
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001717 result = machtime();
1718 (void) write(s, (char *) &result, sizeof(result));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001719}
1720
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001721/* ARGSUSED */
1722static void
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001723machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001724{
Denis Vlasenko35d4da02007-01-22 14:04:27 +00001725 unsigned result;
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001726 /* struct sockaddr_storage ss; */
1727 struct sockaddr sa;
1728 struct sockaddr_in *dg_sin;
1729 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001730
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001731 size = sizeof(sa);
1732 if (recvfrom(s, (char *) &result, sizeof(result), 0, &sa, &size) < 0)
1733 return;
1734 /* if (dg_badinput((struct sockaddr *)&ss)) */
1735 dg_sin = (struct sockaddr_in *) &sa;
1736 if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) ||
1737 ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2)
1738 return;
1739 result = machtime();
1740 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001741}
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001742#endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */
Glenn L McGrath06e95652003-02-09 06:51:14 +00001743
1744
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001745#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
Glenn L McGrath06e95652003-02-09 06:51:14 +00001746/* Return human-readable time of day */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001747/* ARGSUSED */
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001748static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001749{
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001750 char buffer[32];
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001751 time_t t;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001752
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001753 t = time(NULL);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001754
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001755// fdprintf instead?
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001756 (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
1757 (void) write(s, buffer, strlen(buffer));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001758}
1759
1760/* Return human-readable time of day */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001761/* ARGSUSED */
1762void
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001763daytime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001764{
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001765 char buffer[256];
1766 time_t t;
1767 /* struct sockaddr_storage ss; */
1768 struct sockaddr sa;
1769 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001770
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001771 t = time(NULL);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001772
Denis Vlasenkoec17d432006-09-23 15:18:38 +00001773 size = sizeof(sa);
1774 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1775 return;
1776 if (dg_badinput((struct sockaddr_in *) &sa))
1777 return;
1778 (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
1779 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001780}
Denis Vlasenkod1a6e8d2007-01-14 14:46:18 +00001781#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */