blob: 7a6ffae0cec6bd1a12225d4095a82cd5881f8fff [file] [log] [blame]
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001/* $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> */
Glenn L McGrath06e95652003-02-09 06:51:14 +00005/*
6 * Copyright (c) 1983,1991 The Regents of the University of California.
7 * All rights reserved.
8 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00009 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
Glenn L McGrath06e95652003-02-09 06:51:14 +000024 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +000025 * 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.
Glenn L McGrath06e95652003-02-09 06:51:14 +000036 */
37
38/*
39 * Inetd - Internet super-server
40 *
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
52 * to receive further messages on, or ``take over the socket'',
53 * processing all arriving datagrams and, eventually, timing
54 * out. The first type of server is said to be ``multi-threaded'';
55 * the second type of server ``single-threaded''.
56 *
57 * Inetd uses a configuration file which is read at startup
58 * and, possibly, at some later time in response to a hangup signal.
59 * 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
107/*
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000108 * Here's the scoop concerning the user[.:]group feature:
Glenn L McGrath06e95652003-02-09 06:51:14 +0000109 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000110 * 1) set-group-option off.
Glenn L McGrath06e95652003-02-09 06:51:14 +0000111 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000112 * a) user = root: NO setuid() or setgid() is done
Glenn L McGrath06e95652003-02-09 06:51:14 +0000113 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000114 * b) other: setgid(primary group as found in passwd)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000115 * initgroups(name, primary group)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000116 * setuid()
Glenn L McGrath06e95652003-02-09 06:51:14 +0000117 *
118 * 2) set-group-option on.
119 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000120 * a) user = root: setgid(specified group)
121 * NO initgroups()
122 * NO setuid()
Glenn L McGrath06e95652003-02-09 06:51:14 +0000123 *
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000124 * b) other: setgid(specified group)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000125 * initgroups(name, specified group)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000126 * setuid()
Glenn L McGrath06e95652003-02-09 06:51:14 +0000127 *
Glenn L McGrath06e95652003-02-09 06:51:14 +0000128 */
129
Glenn L McGrath34e14692004-02-22 04:58:36 +0000130#include <sys/param.h>
Glenn L McGrath34e14692004-02-22 04:58:36 +0000131#include <sys/stat.h>
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000132#include <sys/ioctl.h>
133#include <sys/socket.h>
Glenn L McGrath34e14692004-02-22 04:58:36 +0000134#include <sys/un.h>
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000135#include <sys/file.h>
Glenn L McGrath34e14692004-02-22 04:58:36 +0000136#include <sys/wait.h>
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000137#include <sys/time.h>
138#include <sys/resource.h>
139
Glenn L McGrath06e95652003-02-09 06:51:14 +0000140
141#include <netinet/in.h>
Glenn L McGrath06e95652003-02-09 06:51:14 +0000142#include <arpa/inet.h>
143
144#include <errno.h>
145#include <signal.h>
146#include <netdb.h>
147#include <syslog.h>
Glenn L McGrath06e95652003-02-09 06:51:14 +0000148#include <stdio.h>
149#include <stdlib.h>
Glenn L McGrath06e95652003-02-09 06:51:14 +0000150#include <unistd.h>
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000151#include <string.h>
152#include <ctype.h>
Manuel Novoa III c2843562003-02-11 07:06:06 +0000153#include <time.h>
Glenn L McGrath06e95652003-02-09 06:51:14 +0000154
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000155#include "busybox.h"
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>
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000168#endif
169
Glenn L McGrath06e95652003-02-09 06:51:14 +0000170#define _PATH_INETDCONF "/etc/inetd.conf"
171#define _PATH_INETDPID "/var/run/inetd.pid"
172
Glenn L McGrath06e95652003-02-09 06:51:14 +0000173
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000174#define TOOMANY 0 /* don't start more than TOOMANY */
175
176#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
177#define RETRYTIME (60*10) /* retry after bind or server fail */
178
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000179#ifndef RLIMIT_NOFILE
180#define RLIMIT_NOFILE RLIMIT_OFILE
181#endif
182
183#ifndef OPEN_MAX
184#define OPEN_MAX 64
185#endif
Glenn L McGrath06e95652003-02-09 06:51:14 +0000186
187/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000188#define FD_MARGIN (8)
189static rlim_t rlim_ofile_cur = OPEN_MAX;
190static struct rlimit rlim_ofile;
191
Glenn L McGrath06e95652003-02-09 06:51:14 +0000192
Glenn L McGrathb1207b32003-02-10 22:31:09 +0000193/* Check unsupporting builtin */
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000194#if defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO || \
195 defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD || \
196 defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME || \
197 defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME || \
198 defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
199# define INETD_FEATURE_ENABLED
Glenn L McGrathb1207b32003-02-10 22:31:09 +0000200#endif
Glenn L McGrath06e95652003-02-09 06:51:14 +0000201
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000202#if defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO || \
203 defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD || \
204 defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
205# define INETD_SETPROCTITLE
Glenn L McGrath06e95652003-02-09 06:51:14 +0000206#endif
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000207
208typedef struct servtab
209{
210 char *se_hostaddr; /* host address to listen on */
211 char *se_service; /* name of service */
212 int se_socktype; /* type of socket to use */
213 int se_family; /* address family */
214 char *se_proto; /* protocol used */
215#ifdef CONFIG_FEATURE_INETD_RPC
216 int se_rpcprog; /* rpc program number */
217 int se_rpcversl; /* rpc program lowest version */
218 int se_rpcversh; /* rpc program highest version */
219#define isrpcservice(sep) ((sep)->se_rpcversl != 0)
220#else
221#define isrpcservice(sep) 0
222#endif
223 pid_t se_wait; /* single threaded server */
224 short se_checked; /* looked at during merge */
225 char *se_user; /* user name to run as */
226 char *se_group; /* group name to run as */
227#ifdef INETD_FEATURE_ENABLED
228 const struct biltin *se_bi; /* if built-in, description */
229#endif
230 char *se_server; /* server program */
231#define MAXARGV 20
232 char *se_argv[MAXARGV + 1]; /* program arguments */
233 int se_fd; /* open descriptor */
234 union
235 {
236 struct sockaddr se_un_ctrladdr;
237 struct sockaddr_in se_un_ctrladdr_in;
238#ifdef CONFIG_FEATURE_IPV6
239 struct sockaddr_in6 se_un_ctrladdr_in6;
240#endif
241 struct sockaddr_un se_un_ctrladdr_un;
242 } se_un; /* bound address */
243#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
247 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
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000257struct biltin
258{
259 const char *bi_service; /* internally provided service name */
260 int bi_socktype; /* type of socket supported */
261 short bi_fork; /* 1 if should fork before call */
262 short bi_wait; /* 1 if should wait for child */
263 void (*bi_fn) (int, servtab_t *);
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000264};
Glenn L McGrath06e95652003-02-09 06:51:14 +0000265
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000266 /* Echo received data */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000267#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000268static void echo_stream (int, servtab_t *);
269static void echo_dg (int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000270#endif
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000271 /* Internet /dev/null */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000272#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000273static void discard_stream (int, servtab_t *);
274static void discard_dg (int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000275#endif
276 /* Return 32 bit time since 1900 */
277#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000278static void machtime_stream (int, servtab_t *);
279static void machtime_dg (int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000280#endif
281 /* Return human-readable time */
282#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000283static void daytime_stream (int, servtab_t *);
284static void daytime_dg (int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000285#endif
286 /* Familiar character generator */
287#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000288static void chargen_stream (int, servtab_t *);
289static void chargen_dg (int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000290#endif
291
Glenn L McGrath06e95652003-02-09 06:51:14 +0000292static const struct biltin biltins[] = {
293#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000294 /* Echo received data */
295 {"echo", SOCK_STREAM, 1, 0, echo_stream,},
296 {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
Glenn L McGrath06e95652003-02-09 06:51:14 +0000297#endif
298#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000299 /* Internet /dev/null */
300 {"discard", SOCK_STREAM, 1, 0, discard_stream,},
301 {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
Glenn L McGrath06e95652003-02-09 06:51:14 +0000302#endif
303#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000304 /* Return 32 bit time since 1900 */
305 {"time", SOCK_STREAM, 0, 0, machtime_stream,},
306 {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
Glenn L McGrath06e95652003-02-09 06:51:14 +0000307#endif
308#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000309 /* Return human-readable time */
310 {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
311 {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
Glenn L McGrath06e95652003-02-09 06:51:14 +0000312#endif
313#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000314 /* Familiar character generator */
315 {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
316 {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
Glenn L McGrath06e95652003-02-09 06:51:14 +0000317#endif
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000318 {NULL, 0, 0, 0, NULL}
Glenn L McGrath06e95652003-02-09 06:51:14 +0000319};
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000320#endif /* INETD_FEATURE_ENABLED */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000321
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000322static int global_queuelen = 128;
323static int nsock, maxsock;
324static fd_set allsock;
325static int toomany = TOOMANY;
326static int timingout;
327static struct servent *sp;
328static uid_t uid;
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000329
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000330static char *CONFIG = _PATH_INETDCONF;
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000331
332static FILE *fconfig;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000333static char line[1024];
334static char *defhost;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000335
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000336static char *newstr (char *cp)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000337{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000338 if ((cp = strdup (cp ? cp : "")))
339 return (cp);
340 syslog (LOG_ERR, "strdup: %m");
341 exit (1);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000342}
343
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000344static int setconfig (void)
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000345{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000346 free (defhost);
347 defhost = newstr ("*");
348 if (fconfig != NULL) {
349 fseek (fconfig, 0L, SEEK_SET);
350 return (1);
351 }
352 fconfig = fopen (CONFIG, "r");
353 return (fconfig != NULL);
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000354}
355
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000356static void endconfig (void)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000357{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000358 if (fconfig) {
359 (void) fclose (fconfig);
360 fconfig = NULL;
361 }
362 free (defhost);
363 defhost = 0;
364}
Glenn L McGrath53766c42004-01-18 08:58:06 +0000365
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000366#ifdef CONFIG_FEATURE_INETD_RPC
367static void register_rpc (servtab_t *sep)
368{
369 int n;
370 struct sockaddr_in ir_sin;
371 struct protoent *pp;
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +0000372 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000373
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000374 if ((pp = getprotobyname (sep->se_proto + 4)) == NULL) {
375 syslog (LOG_ERR, "%s: getproto: %m", sep->se_proto);
376 return;
377 }
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +0000378 size = sizeof ir_sin;
379 if (getsockname (sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000380 syslog (LOG_ERR, "%s/%s: getsockname: %m",
381 sep->se_service, sep->se_proto);
382 return;
383 }
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000384
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000385 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
386 (void) pmap_unset (sep->se_rpcprog, n);
387 if (!pmap_set (sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port)))
388 syslog (LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
389 sep->se_service, sep->se_proto,
390 sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port));
391 }
392}
Glenn L McGrath06e95652003-02-09 06:51:14 +0000393
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000394static void unregister_rpc (servtab_t *sep)
395{
396 int n;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000397
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000398 for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
399 if (!pmap_unset (sep->se_rpcprog, n))
400 syslog (LOG_ERR, "pmap_unset(%u, %u)", sep->se_rpcprog, n);
401 }
402}
403#endif /* CONFIG_FEATURE_INETD_RPC */
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000404
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000405static void freeconfig (servtab_t *cp)
406{
407 int i;
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000408
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000409 free (cp->se_hostaddr);
410 free (cp->se_service);
411 free (cp->se_proto);
412 free (cp->se_user);
413 free (cp->se_group);
414 free (cp->se_server);
415 for (i = 0; i < MAXARGV; i++)
416 if (cp->se_argv[i])
417 free (cp->se_argv[i]);
418}
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000419
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000420static int bump_nofile (void)
421{
422#define FD_CHUNK 32
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000423
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000424 struct rlimit rl;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000425
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000426 if (getrlimit (RLIMIT_NOFILE, &rl) < 0) {
427 syslog (LOG_ERR, "getrlimit: %m");
428 return -1;
429 }
430 rl.rlim_cur = MIN (rl.rlim_max, rl.rlim_cur + FD_CHUNK);
431 rl.rlim_cur = MIN (FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
432 if (rl.rlim_cur <= rlim_ofile_cur) {
433 syslog (LOG_ERR, "bump_nofile: cannot extend file limit, max = %d",
434 (int) rl.rlim_cur);
435 return -1;
436 }
437
438 if (setrlimit (RLIMIT_NOFILE, &rl) < 0) {
439 syslog (LOG_ERR, "setrlimit: %m");
440 return -1;
441 }
442
443 rlim_ofile_cur = rl.rlim_cur;
444 return 0;
445}
446
447static void setup (servtab_t *sep)
448{
449 int on = 1;
450 int r;
451
452 if ((sep->se_fd = socket (sep->se_family, sep->se_socktype, 0)) < 0) {
453 syslog (LOG_ERR, "%s/%s: socket: %m", sep->se_service, sep->se_proto);
454 return;
455 }
456#define turnon(fd, opt) \
457setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
458 if (turnon (sep->se_fd, SO_REUSEADDR) < 0)
459 syslog (LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
460#undef turnon
461
462#ifdef CONFIG_FEATURE_INETD_RPC
463 if (isrpcservice (sep)) {
464 struct passwd *pwd;
465
466 /*
467 * for RPC services, attempt to use a reserved port
468 * if they are going to be running as root.
469 *
470 * Also, zero out the port for all RPC services; let bind()
471 * find one.
472 */
473 sep->se_ctrladdr_in.sin_port = 0;
474 if (sep->se_user && (pwd = getpwnam (sep->se_user)) &&
475 pwd->pw_uid == 0 && uid == 0)
476 r = bindresvport (sep->se_fd, &sep->se_ctrladdr_in);
Glenn L McGrath53766c42004-01-18 08:58:06 +0000477 else {
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000478 r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
479 if (r == 0) {
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +0000480 socklen_t len = sep->se_ctrladdr_size;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000481 int saveerrno = errno;
482
483 /* update se_ctrladdr_in.sin_port */
484 r = getsockname (sep->se_fd, &sep->se_ctrladdr, &len);
485 if (r <= 0)
486 errno = saveerrno;
487 }
Glenn L McGrath53766c42004-01-18 08:58:06 +0000488 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000489 } else
Glenn L McGrath53766c42004-01-18 08:58:06 +0000490#endif
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000491 r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
492 if (r < 0) {
493 syslog (LOG_ERR, "%s/%s (%d): bind: %m",
494 sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family);
495 close (sep->se_fd);
496 sep->se_fd = -1;
497 if (!timingout) {
498 timingout = 1;
499 alarm (RETRYTIME);
Glenn L McGrath53766c42004-01-18 08:58:06 +0000500 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000501 return;
502 }
503 if (sep->se_socktype == SOCK_STREAM)
504 listen (sep->se_fd, global_queuelen);
Glenn L McGrath53766c42004-01-18 08:58:06 +0000505
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000506 FD_SET (sep->se_fd, &allsock);
507 nsock++;
508 if (sep->se_fd > maxsock) {
509 maxsock = sep->se_fd;
510 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
511 bump_nofile ();
512 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000513}
514
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000515static char *nextline (void)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000516{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000517 char *cp;
518 FILE *fd = fconfig;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000519
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000520 if (fgets (line, sizeof (line), fd) == NULL)
521 return (NULL);
522 cp = strchr (line, '\n');
523 if (cp)
524 *cp = '\0';
525 return (line);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000526}
527
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000528static char *skip (char **cpp) /* int report; */
529{
530 char *cp = *cpp;
531 char *start;
532
533/* erp: */
534 if (*cpp == NULL) {
535 /* if (report) */
536 /* syslog(LOG_ERR, "syntax error in inetd config file"); */
537 return (NULL);
538 }
539
540again:
541 while (*cp == ' ' || *cp == '\t')
542 cp++;
543 if (*cp == '\0') {
544 int c;
545
546 c = getc (fconfig);
547 (void) ungetc (c, fconfig);
548 if (c == ' ' || c == '\t')
549 if ((cp = nextline ()))
550 goto again;
551 *cpp = NULL;
552 /* goto erp; */
553 return (NULL);
554 }
555 start = cp;
556 while (*cp && *cp != ' ' && *cp != '\t')
557 cp++;
558 if (*cp != '\0')
559 *cp++ = '\0';
560 /* if ((*cpp = cp) == NULL) */
561 /* goto erp; */
562
563 *cpp = cp;
564 return (start);
565}
566
567static servtab_t *new_servtab(void)
568{
569 servtab_t *sep;
570
571 sep = (servtab_t *) malloc (sizeof (servtab_t));
572 if (sep == NULL) {
573 syslog (LOG_ERR, bb_msg_memory_exhausted);
574 exit (1);
575 }
576 return sep;
577}
578
579static servtab_t *dupconfig (servtab_t *sep)
580{
581 servtab_t *newtab;
582 int argc;
583
584 newtab = new_servtab();
585 memset (newtab, 0, sizeof (servtab_t));
586 newtab->se_service = sep->se_service ? newstr (sep->se_service) : NULL;
587 newtab->se_socktype = sep->se_socktype;
588 newtab->se_family = sep->se_family;
589 newtab->se_proto = sep->se_proto ? newstr (sep->se_proto) : NULL;
590#ifdef CONFIG_FEATURE_INETD_RPC
591 newtab->se_rpcprog = sep->se_rpcprog;
592 newtab->se_rpcversl = sep->se_rpcversl;
593 newtab->se_rpcversh = sep->se_rpcversh;
594#endif
595 newtab->se_wait = sep->se_wait;
596 newtab->se_user = sep->se_user ? newstr (sep->se_user) : NULL;
597 newtab->se_group = sep->se_group ? newstr (sep->se_group) : NULL;
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000598#ifdef INETD_FEATURE_ENABLED
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000599 newtab->se_bi = sep->se_bi;
600#endif
601 newtab->se_server = sep->se_server ? newstr (sep->se_server) : 0;
602
603 for (argc = 0; argc <= MAXARGV; argc++)
604 newtab->se_argv[argc] = sep->se_argv[argc] ?
605 newstr (sep->se_argv[argc]) : NULL;
606 newtab->se_max = sep->se_max;
607
608 return (newtab);
609}
610
611static servtab_t *getconfigent (void)
612{
613 servtab_t *sep;
614 int argc;
615 char *cp, *arg;
616 char *hostdelim;
617 servtab_t *nsep;
618 servtab_t *psep;
619
620 sep = new_servtab();
621
622 /* memset(sep, 0, sizeof *sep); */
623more:
624 /* freeconfig(sep); */
625
626 while ((cp = nextline ()) && *cp == '#');
627 if (cp == NULL) {
628 /* free(sep); */
629 return (NULL);
630 }
631
632 memset ((char *) sep, 0, sizeof *sep);
633 arg = skip (&cp);
634 if (arg == NULL) {
635 /* A blank line. */
636 goto more;
637 }
638
639 /* Check for a host name. */
640 hostdelim = strrchr (arg, ':');
641 if (hostdelim) {
642 *hostdelim = '\0';
643 sep->se_hostaddr = newstr (arg);
644 arg = hostdelim + 1;
645 /*
646 * If the line is of the form `host:', then just change the
647 * default host for the following lines.
648 */
649 if (*arg == '\0') {
650 arg = skip (&cp);
651 if (cp == NULL) {
652 free (defhost);
653 defhost = sep->se_hostaddr;
654 goto more;
655 }
656 }
657 } else
658 sep->se_hostaddr = newstr (defhost);
659
660 sep->se_service = newstr (arg);
661 arg = skip (&cp);
662
663 if (strcmp (arg, "stream") == 0)
664 sep->se_socktype = SOCK_STREAM;
665 else if (strcmp (arg, "dgram") == 0)
666 sep->se_socktype = SOCK_DGRAM;
667 else if (strcmp (arg, "rdm") == 0)
668 sep->se_socktype = SOCK_RDM;
669 else if (strcmp (arg, "seqpacket") == 0)
670 sep->se_socktype = SOCK_SEQPACKET;
671 else if (strcmp (arg, "raw") == 0)
672 sep->se_socktype = SOCK_RAW;
673 else
674 sep->se_socktype = -1;
675
676 sep->se_proto = newstr (skip (&cp));
677
678 if (strcmp (sep->se_proto, "unix") == 0) {
679 sep->se_family = AF_UNIX;
680 } else {
681 sep->se_family = AF_INET;
682 if (sep->se_proto[strlen (sep->se_proto) - 1] == '6')
683#ifdef CONFIG_FEATURE_IPV6
684 sep->se_family = AF_INET6;
685#else
686 syslog (LOG_ERR, "%s: IPV6 not supported", sep->se_proto);
687#endif
688 if (strncmp (sep->se_proto, "rpc/", 4) == 0) {
689#ifdef CONFIG_FEATURE_INETD_RPC
690 char *p, *ccp;
691 long l;
692
693 p = strchr (sep->se_service, '/');
694 if (p == 0) {
695 syslog (LOG_ERR, "%s: no rpc version", sep->se_service);
696 goto more;
697 }
698 *p++ = '\0';
699 l = strtol (p, &ccp, 0);
700 if (ccp == p || l < 0 || l > INT_MAX) {
701 badafterall:
702 syslog (LOG_ERR, "%s/%s: bad rpc version", sep->se_service, p);
703 goto more;
704 }
705 sep->se_rpcversl = sep->se_rpcversh = l;
706 if (*ccp == '-') {
707 p = ccp + 1;
708 l = strtol (p, &ccp, 0);
709 if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp)
710 goto badafterall;
711 sep->se_rpcversh = l;
712 } else if (*ccp != '\0')
713 goto badafterall;
714#else
715 syslog (LOG_ERR, "%s: rpc services not supported", sep->se_service);
716#endif
717 }
718 }
719 arg = skip (&cp);
720 if (arg == NULL)
721 goto more;
722
723 {
724 char *s = strchr (arg, '.');
725 if (s) {
726 *s++ = '\0';
727 sep->se_max = atoi (s);
728 } else
729 sep->se_max = toomany;
730 }
731 sep->se_wait = strcmp (arg, "wait") == 0;
732 /* if ((arg = skip(&cp, 1)) == NULL) */
733 /* goto more; */
734 sep->se_user = newstr (skip (&cp));
735 arg = strchr (sep->se_user, '.');
736 if (arg == NULL)
737 arg = strchr (sep->se_user, ':');
738 if (arg) {
739 *arg++ = '\0';
740 sep->se_group = newstr (arg);
741 }
742 /* if ((arg = skip(&cp, 1)) == NULL) */
743 /* goto more; */
744
745 sep->se_server = newstr (skip (&cp));
746 if (strcmp (sep->se_server, "internal") == 0) {
747#ifdef INETD_FEATURE_ENABLED
748 const struct biltin *bi;
749
750 for (bi = biltins; bi->bi_service; bi++)
751 if (bi->bi_socktype == sep->se_socktype &&
752 strcmp (bi->bi_service, sep->se_service) == 0)
753 break;
754 if (bi->bi_service == 0) {
755 syslog (LOG_ERR, "internal service %s unknown", sep->se_service);
756 goto more;
757 }
758 sep->se_bi = bi;
759 sep->se_wait = bi->bi_wait;
760#else
761 syslog (LOG_ERR, "internal service %s unknown", sep->se_service);
762 goto more;
763#endif
764 }
765#ifdef INETD_FEATURE_ENABLED
766 else
767 sep->se_bi = NULL;
768#endif
769 argc = 0;
770 for (arg = skip (&cp); cp; arg = skip (&cp)) {
771 if (argc < MAXARGV)
772 sep->se_argv[argc++] = newstr (arg);
773 }
774 while (argc <= MAXARGV)
775 sep->se_argv[argc++] = NULL;
776
777 /*
778 * Now that we've processed the entire line, check if the hostname
779 * specifier was a comma separated list of hostnames. If so
780 * we'll make new entries for each address.
781 */
782 while ((hostdelim = strrchr (sep->se_hostaddr, ',')) != NULL) {
783 nsep = dupconfig (sep);
784
785 /*
786 * NULL terminate the hostname field of the existing entry,
787 * and make a dup for the new entry.
788 */
789 *hostdelim++ = '\0';
790 nsep->se_hostaddr = newstr (hostdelim);
791
792 nsep->se_next = sep->se_next;
793 sep->se_next = nsep;
794 }
795
796 nsep = sep;
797 while (nsep != NULL) {
798 nsep->se_checked = 1;
799 if (nsep->se_family == AF_INET) {
800 if (!strcmp (nsep->se_hostaddr, "*"))
801 nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
802 else if (!inet_aton (nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
803 struct hostent *hp;
804
805 hp = gethostbyname (nsep->se_hostaddr);
806 if (hp == 0) {
807 syslog (LOG_ERR, "%s: unknown host", nsep->se_hostaddr);
808 nsep->se_checked = 0;
809 goto skip;
810 } else if (hp->h_addrtype != AF_INET) {
811 syslog (LOG_ERR,
812 "%s: address isn't an Internet "
813 "address", nsep->se_hostaddr);
814 nsep->se_checked = 0;
815 goto skip;
816 } else {
817 int i = 1;
818
819 memmove (&nsep->se_ctrladdr_in.sin_addr,
820 hp->h_addr_list[0], sizeof (struct in_addr));
821 while (hp->h_addr_list[i] != NULL) {
822 psep = dupconfig (nsep);
823 psep->se_hostaddr = newstr (nsep->se_hostaddr);
824 psep->se_checked = 1;
825 memmove (&psep->se_ctrladdr_in.sin_addr,
826 hp->h_addr_list[i], sizeof (struct in_addr));
827 psep->se_ctrladdr_size = sizeof (psep->se_ctrladdr_in);
828 i++;
829 /* Prepend to list, don't want to look up its */
830 /* hostname again. */
831 psep->se_next = sep;
832 sep = psep;
833 }
834 }
835 }
836 }
837/* XXX BUG?: is this skip: label supposed to remain? */
838 skip:
839 nsep = nsep->se_next;
840 }
841
842 /*
843 * Finally, free any entries which failed the gethostbyname
844 * check.
845 */
846 psep = NULL;
847 nsep = sep;
848 while (nsep != NULL) {
849 servtab_t *tsep;
850
851 if (nsep->se_checked == 0) {
852 tsep = nsep;
853 if (psep == NULL) {
854 sep = nsep->se_next;
855 nsep = sep;
856 } else {
857 nsep = nsep->se_next;
858 psep->se_next = nsep;
859 }
860 freeconfig (tsep);
861 } else {
862 nsep->se_checked = 0;
863 psep = nsep;
864 nsep = nsep->se_next;
865 }
866 }
867
868 return (sep);
869}
870
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +0000871#define Block_Using_Signals(m) do { sigemptyset(&m); \
872 sigaddset(&m, SIGCHLD); \
873 sigaddset(&m, SIGHUP); \
874 sigaddset(&m, SIGALRM); \
875 sigprocmask(SIG_BLOCK, &m, NULL); \
876 } while(0)
877
878
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000879static servtab_t *enter (servtab_t *cp)
880{
881 servtab_t *sep;
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +0000882 sigset_t omask;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000883
884 sep = new_servtab();
885 *sep = *cp;
886 sep->se_fd = -1;
887#ifdef CONFIG_FEATURE_INETD_RPC
888 sep->se_rpcprog = -1;
889#endif
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +0000890 Block_Using_Signals(omask);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000891 sep->se_next = servtab;
892 servtab = sep;
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +0000893 sigprocmask(SIG_UNBLOCK, &omask, NULL);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000894 return (sep);
895}
896
897static int matchconf (servtab_t *old, servtab_t *new)
898{
899 if (strcmp (old->se_service, new->se_service) != 0)
900 return (0);
901
902 if (strcmp (old->se_hostaddr, new->se_hostaddr) != 0)
903 return (0);
904
905 if (strcmp (old->se_proto, new->se_proto) != 0)
906 return (0);
907
908 /*
909 * If the new servtab is bound to a specific address, check that the
910 * old servtab is bound to the same entry. If the new service is not
911 * bound to a specific address then the check of se_hostaddr above
912 * is sufficient.
913 */
914
915 if (old->se_family == AF_INET && new->se_family == AF_INET &&
916 memcmp (&old->se_ctrladdr_in.sin_addr,
917 &new->se_ctrladdr_in.sin_addr,
918 sizeof (new->se_ctrladdr_in.sin_addr)) != 0)
919 return (0);
920
921#ifdef CONFIG_FEATURE_IPV6
922 if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
923 memcmp (&old->se_ctrladdr_in6.sin6_addr,
924 &new->se_ctrladdr_in6.sin6_addr,
925 sizeof (new->se_ctrladdr_in6.sin6_addr)) != 0)
926 return (0);
927#endif
928 return (1);
929}
930
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000931static void config (int sig ATTRIBUTE_UNUSED)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000932{
933 servtab_t *sep, *cp, **sepp;
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +0000934 sigset_t omask;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000935 int add;
936 size_t n;
937 char protoname[10];
938
939 if (!setconfig ()) {
940 syslog (LOG_ERR, "%s: %m", CONFIG);
941 return;
942 }
943 for (sep = servtab; sep; sep = sep->se_next)
944 sep->se_checked = 0;
945 cp = getconfigent ();
946 while (cp != NULL) {
947 for (sep = servtab; sep; sep = sep->se_next)
948 if (matchconf (sep, cp))
949 break;
950 add = 0;
951 if (sep != 0) {
952 int i;
953
Mike Frysinger23fedb32005-10-05 00:50:03 +0000954#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 +0000955
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +0000956 Block_Using_Signals(omask);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000957 /*
958 * sep->se_wait may be holding the pid of a daemon
959 * that we're waiting for. If so, don't overwrite
960 * it unless the config file explicitly says don't
961 * wait.
962 */
963 if (
964#ifdef INETD_FEATURE_ENABLED
965 cp->se_bi == 0 &&
966#endif
967 (sep->se_wait == 1 || cp->se_wait == 0))
968 sep->se_wait = cp->se_wait;
969 SWAP (int, cp->se_max, sep->se_max);
970 SWAP (char *, sep->se_user, cp->se_user);
971 SWAP (char *, sep->se_group, cp->se_group);
972 SWAP (char *, sep->se_server, cp->se_server);
973 for (i = 0; i < MAXARGV; i++)
974 SWAP (char *, sep->se_argv[i], cp->se_argv[i]);
975#undef SWAP
976
977#ifdef CONFIG_FEATURE_INETD_RPC
978 if (isrpcservice (sep))
979 unregister_rpc (sep);
980 sep->se_rpcversl = cp->se_rpcversl;
981 sep->se_rpcversh = cp->se_rpcversh;
982#endif
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +0000983 sigprocmask(SIG_UNBLOCK, &omask, NULL);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +0000984 freeconfig (cp);
985 add = 1;
986 } else {
987 sep = enter (cp);
988 }
989 sep->se_checked = 1;
990
991 switch (sep->se_family) {
992 case AF_UNIX:
993 if (sep->se_fd != -1)
994 break;
995 (void) unlink (sep->se_service);
996 n = strlen (sep->se_service);
997 if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
998 n = sizeof sep->se_ctrladdr_un.sun_path - 1;
999 safe_strncpy (sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
1000 sep->se_ctrladdr_un.sun_family = AF_UNIX;
1001 sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
1002 setup (sep);
1003 break;
1004 case AF_INET:
1005 sep->se_ctrladdr_in.sin_family = AF_INET;
1006 /* se_ctrladdr_in was set in getconfigent */
1007 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
1008
1009#ifdef CONFIG_FEATURE_INETD_RPC
1010 if (isrpcservice (sep)) {
1011 struct rpcent *rp;
1012
1013 sep->se_rpcprog = atoi (sep->se_service);
1014 if (sep->se_rpcprog == 0) {
1015 rp = getrpcbyname (sep->se_service);
1016 if (rp == 0) {
1017 syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service);
1018 goto serv_unknown;
1019 }
1020 sep->se_rpcprog = rp->r_number;
1021 }
1022 if (sep->se_fd == -1)
1023 setup (sep);
1024 if (sep->se_fd != -1)
1025 register_rpc (sep);
1026 } else
1027#endif
1028 {
1029 u_short port = htons (atoi (sep->se_service));
1030
1031 if (!port) {
1032 /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname));
1033 if (isdigit (protoname[strlen (protoname) - 1]))
1034 protoname[strlen (protoname) - 1] = '\0';
1035 sp = getservbyname (sep->se_service, protoname);
1036 if (sp == 0) {
1037 syslog (LOG_ERR,
1038 "%s/%s: unknown service", sep->se_service, sep->se_proto);
1039 goto serv_unknown;
1040 }
1041 port = sp->s_port;
1042 }
1043 if (port != sep->se_ctrladdr_in.sin_port) {
1044 sep->se_ctrladdr_in.sin_port = port;
1045 if (sep->se_fd != -1) {
1046 FD_CLR (sep->se_fd, &allsock);
1047 nsock--;
1048 (void) close (sep->se_fd);
1049 }
1050 sep->se_fd = -1;
1051 }
1052 if (sep->se_fd == -1)
1053 setup (sep);
1054 }
1055 break;
1056#ifdef CONFIG_FEATURE_IPV6
1057 case AF_INET6:
1058 sep->se_ctrladdr_in6.sin6_family = AF_INET6;
1059 /* se_ctrladdr_in was set in getconfigent */
1060 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
1061
1062#ifdef CONFIG_FEATURE_INETD_RPC
1063 if (isrpcservice (sep)) {
1064 struct rpcent *rp;
1065
1066 sep->se_rpcprog = atoi (sep->se_service);
1067 if (sep->se_rpcprog == 0) {
1068 rp = getrpcbyname (sep->se_service);
1069 if (rp == 0) {
1070 syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service);
1071 goto serv_unknown;
1072 }
1073 sep->se_rpcprog = rp->r_number;
1074 }
1075 if (sep->se_fd == -1)
1076 setup (sep);
1077 if (sep->se_fd != -1)
1078 register_rpc (sep);
1079 } else
1080#endif
1081 {
1082 u_short port = htons (atoi (sep->se_service));
1083
1084 if (!port) {
1085 /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname));
1086 if (isdigit (protoname[strlen (protoname) - 1]))
1087 protoname[strlen (protoname) - 1] = '\0';
1088 sp = getservbyname (sep->se_service, protoname);
1089 if (sp == 0) {
1090 syslog (LOG_ERR,
1091 "%s/%s: unknown service", sep->se_service, sep->se_proto);
1092 goto serv_unknown;
1093 }
1094 port = sp->s_port;
1095 }
1096 if (port != sep->se_ctrladdr_in6.sin6_port) {
1097 sep->se_ctrladdr_in6.sin6_port = port;
1098 if (sep->se_fd != -1) {
1099 FD_CLR (sep->se_fd, &allsock);
1100 nsock--;
1101 (void) close (sep->se_fd);
1102 }
1103 sep->se_fd = -1;
1104 }
1105 if (sep->se_fd == -1)
1106 setup (sep);
1107 }
1108 break;
1109#endif /* CONFIG_FEATURE_IPV6 */
1110 }
1111 serv_unknown:
1112 if (cp->se_next != NULL) {
1113 servtab_t *tmp = cp;
1114
1115 cp = cp->se_next;
1116 free (tmp);
1117 } else {
1118 free (cp);
1119 cp = getconfigent ();
1120 }
1121 }
1122 endconfig ();
1123 /*
1124 * Purge anything not looked at above.
1125 */
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +00001126 Block_Using_Signals(omask);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001127 sepp = &servtab;
1128 while ((sep = *sepp)) {
1129 if (sep->se_checked) {
1130 sepp = &sep->se_next;
1131 continue;
1132 }
1133 *sepp = sep->se_next;
1134 if (sep->se_fd != -1) {
1135 FD_CLR (sep->se_fd, &allsock);
1136 nsock--;
1137 (void) close (sep->se_fd);
1138 }
1139#ifdef CONFIG_FEATURE_INETD_RPC
1140 if (isrpcservice (sep))
1141 unregister_rpc (sep);
1142#endif
1143 if (sep->se_family == AF_UNIX)
1144 (void) unlink (sep->se_service);
1145 freeconfig (sep);
1146 free (sep);
1147 }
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +00001148 sigprocmask(SIG_UNBLOCK, &omask, NULL);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001149}
1150
1151
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001152static void reapchild (int sig ATTRIBUTE_UNUSED)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001153{
1154 pid_t pid;
1155 int save_errno = errno, status;
1156 servtab_t *sep;
1157
1158 for (;;) {
1159 pid = wait3 (&status, WNOHANG, NULL);
1160 if (pid <= 0)
1161 break;
1162 for (sep = servtab; sep; sep = sep->se_next)
1163 if (sep->se_wait == pid) {
1164 if (WIFEXITED (status) && WEXITSTATUS (status))
1165 syslog (LOG_WARNING,
1166 "%s: exit status 0x%x",
1167 sep->se_server, WEXITSTATUS (status));
1168 else if (WIFSIGNALED (status))
1169 syslog (LOG_WARNING,
1170 "%s: exit signal 0x%x", sep->se_server, WTERMSIG (status));
1171 sep->se_wait = 1;
1172 FD_SET (sep->se_fd, &allsock);
1173 nsock++;
1174 }
1175 }
1176 errno = save_errno;
1177}
1178
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001179static void retry (int sig ATTRIBUTE_UNUSED)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001180{
1181 servtab_t *sep;
1182
1183 timingout = 0;
1184 for (sep = servtab; sep; sep = sep->se_next) {
1185 if (sep->se_fd == -1) {
1186 switch (sep->se_family) {
1187 case AF_UNIX:
1188 case AF_INET:
1189#ifdef CONFIG_FEATURE_IPV6
1190 case AF_INET6:
1191#endif
1192 setup (sep);
1193#ifdef CONFIG_FEATURE_INETD_RPC
1194 if (sep->se_fd != -1 && isrpcservice (sep))
1195 register_rpc (sep);
1196#endif
1197 break;
1198 }
1199 }
1200 }
1201}
1202
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001203static void goaway (int sig ATTRIBUTE_UNUSED)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001204{
1205 servtab_t *sep;
1206
1207 /* XXX signal race walking sep list */
1208 for (sep = servtab; sep; sep = sep->se_next) {
1209 if (sep->se_fd == -1)
1210 continue;
1211
1212 switch (sep->se_family) {
1213 case AF_UNIX:
1214 (void) unlink (sep->se_service);
1215 break;
1216 case AF_INET:
1217#ifdef CONFIG_FEATURE_IPV6
1218 case AF_INET6:
1219#endif
1220#ifdef CONFIG_FEATURE_INETD_RPC
1221 if (sep->se_wait == 1 && isrpcservice (sep))
1222 unregister_rpc (sep); /* XXX signal race */
1223#endif
1224 break;
1225 }
1226 (void) close (sep->se_fd);
1227 }
1228 (void) unlink (_PATH_INETDPID);
1229 exit (0);
1230}
1231
1232
1233#ifdef INETD_SETPROCTITLE
Glenn L McGrath06e95652003-02-09 06:51:14 +00001234static char **Argv;
1235static char *LastArg;
1236
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001237static void
1238inetd_setproctitle (char *a, int s)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001239{
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +00001240 socklen_t size;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001241 char *cp;
1242 struct sockaddr_in prt_sin;
1243 char buf[80];
Glenn L McGrath06e95652003-02-09 06:51:14 +00001244
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001245 cp = Argv[0];
1246 size = sizeof (prt_sin);
1247 (void) snprintf (buf, sizeof buf, "-%s", a);
1248 if (getpeername (s, (struct sockaddr *) &prt_sin, &size) == 0) {
1249 char *sa = inet_ntoa (prt_sin.sin_addr);
1250
1251 buf[sizeof (buf) - 1 - strlen (sa) - 3] = '\0';
1252 strcat (buf, " [");
1253 strcat (buf, sa);
1254 strcat (buf, "]");
1255 }
1256 strncpy (cp, buf, LastArg - cp);
1257 cp += strlen (cp);
1258 while (cp < LastArg)
1259 *cp++ = ' ';
Glenn L McGrath06e95652003-02-09 06:51:14 +00001260}
Glenn L McGrath06e95652003-02-09 06:51:14 +00001261#endif
1262
Glenn L McGrath06e95652003-02-09 06:51:14 +00001263
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001264int
1265inetd_main (int argc, char *argv[])
1266{
1267 servtab_t *sep;
1268 struct passwd *pwd;
1269 struct group *grp = NULL;
1270 int tmpint;
1271 struct sigaction sa, sapipe;
1272 int opt;
1273 pid_t pid;
1274 char buf[50];
1275 char *stoomany;
"Vladimir N. Oleynik"ecfd1f62005-11-09 09:19:29 +00001276 sigset_t omask, wait_mask;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001277
1278#ifdef INETD_SETPROCTITLE
1279 extern char **environ;
1280 char **envp = environ;
1281
1282 Argv = argv;
1283 if (envp == 0 || *envp == 0)
1284 envp = argv;
1285 while (*envp)
1286 envp++;
1287 LastArg = envp[-1] + strlen (envp[-1]);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001288#endif
1289
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001290 openlog (bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
1291
1292 opt = bb_getopt_ulflags (argc, argv, "R:f", &stoomany);
1293 if(opt & 1) {
1294 char *e;
1295
1296 toomany = strtoul (stoomany, &e, 0);
1297 if (!(toomany >= 0 && *e == '\0')) {
1298 toomany = TOOMANY;
1299 syslog (LOG_ERR, "-R %s: bad value for service invocation rate", stoomany);
1300 }
1301 }
1302 argc -= optind;
1303 argv += optind;
1304
1305 uid = getuid ();
1306 if (uid != 0)
1307 CONFIG = NULL;
1308 if (argc > 0)
1309 CONFIG = argv[0];
1310 if (CONFIG == NULL)
1311 bb_error_msg_and_die ("non-root must specify a config file");
1312
1313 if (!(opt & 2)) {
Paul Foxb8317532005-08-01 19:39:47 +00001314#if defined(__uClinux__)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001315 /* reexec for vfork() do continue parent */
1316 vfork_daemon_rexec (0, 0, argc, argv, "-f");
1317#else
1318 daemon (0, 0);
Eric Andersen35e643b2003-07-28 07:40:39 +00001319#endif /* uClinux */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001320 } else {
1321 setsid ();
1322 }
1323
1324 if (uid == 0) {
1325 gid_t gid = getgid ();
1326
1327 /* If run by hand, ensure groups vector gets trashed */
1328 setgroups (1, &gid);
1329 }
1330
1331 {
1332 FILE *fp;
1333
1334 if ((fp = fopen (_PATH_INETDPID, "w")) != NULL) {
1335 fprintf (fp, "%u\n", getpid ());
1336 (void) fclose (fp);
Paul Foxb8317532005-08-01 19:39:47 +00001337 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001338 }
Eric Andersen35e643b2003-07-28 07:40:39 +00001339
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001340 if (getrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) {
1341 syslog (LOG_ERR, "getrlimit: %m");
1342 } else {
1343 rlim_ofile_cur = rlim_ofile.rlim_cur;
1344 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */
1345 rlim_ofile_cur = OPEN_MAX;
1346 }
Glenn L McGrath06e95652003-02-09 06:51:14 +00001347
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001348 memset ((char *) &sa, 0, sizeof (sa));
1349 sigemptyset (&sa.sa_mask);
1350 sigaddset (&sa.sa_mask, SIGALRM);
1351 sigaddset (&sa.sa_mask, SIGCHLD);
1352 sigaddset (&sa.sa_mask, SIGHUP);
1353 sa.sa_handler = retry;
1354 sigaction (SIGALRM, &sa, NULL);
1355 /* doconfig(); */
1356 config (SIGHUP);
1357 sa.sa_handler = config;
1358 sigaction (SIGHUP, &sa, NULL);
1359 sa.sa_handler = reapchild;
1360 sigaction (SIGCHLD, &sa, NULL);
1361 sa.sa_handler = goaway;
1362 sigaction (SIGTERM, &sa, NULL);
1363 sa.sa_handler = goaway;
1364 sigaction (SIGINT, &sa, NULL);
1365 sa.sa_handler = SIG_IGN;
1366 sigaction (SIGPIPE, &sa, &sapipe);
"Vladimir N. Oleynik"ecfd1f62005-11-09 09:19:29 +00001367 memset(&wait_mask, 0, sizeof(wait_mask));
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001368 {
1369 /* space for daemons to overwrite environment for ps */
Glenn L McGrath06e95652003-02-09 06:51:14 +00001370#define DUMMYSIZE 100
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001371 char dummy[DUMMYSIZE];
Glenn L McGrath06e95652003-02-09 06:51:14 +00001372
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001373 (void) memset (dummy, 'x', DUMMYSIZE - 1);
1374 dummy[DUMMYSIZE - 1] = '\0';
Glenn L McGrath06e95652003-02-09 06:51:14 +00001375
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001376 (void) setenv ("inetd_dummy", dummy, 1);
1377 }
1378
1379 for (;;) {
1380 int n, ctrl = -1;
1381 fd_set readable;
1382
1383 if (nsock == 0) {
"Vladimir N. Oleynik"c06e80e2005-10-05 14:14:55 +00001384 Block_Using_Signals(omask);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001385 while (nsock == 0)
"Vladimir N. Oleynik"ecfd1f62005-11-09 09:19:29 +00001386 sigsuspend (&wait_mask);
"Vladimir N. Oleynik"c06e80e2005-10-05 14:14:55 +00001387 sigprocmask(SIG_UNBLOCK, &omask, NULL);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001388 }
1389
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001390 readable = allsock;
1391 if ((n = select (maxsock + 1, &readable, NULL, NULL, NULL)) <= 0) {
1392 if (n < 0 && errno != EINTR) {
1393 syslog (LOG_WARNING, "select: %m");
1394 sleep (1);
1395 }
1396 continue;
1397 }
1398 for (sep = servtab; n && sep; sep = sep->se_next)
1399 if (sep->se_fd != -1 && FD_ISSET (sep->se_fd, &readable)) {
1400 n--;
1401 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
1402 ctrl = accept (sep->se_fd, NULL, NULL);
1403 if (ctrl < 0) {
1404 if (errno == EINTR)
1405 continue;
1406 syslog (LOG_WARNING, "accept (for %s): %m", sep->se_service);
Glenn L McGrath82d42db2004-02-18 13:12:53 +00001407 continue;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001408 }
1409 if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
1410 struct sockaddr_in peer;
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +00001411 socklen_t plen = sizeof (peer);
Glenn L McGrath82d42db2004-02-18 13:12:53 +00001412
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001413 if (getpeername (ctrl, (struct sockaddr *) &peer, &plen) < 0) {
1414 syslog (LOG_WARNING, "could not getpeername");
1415 close (ctrl);
1416 continue;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001417 }
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001418 if (ntohs (peer.sin_port) == 20) {
1419 /* XXX ftp bounce */
1420 close (ctrl);
1421 continue;
1422 }
1423 }
1424 } else
1425 ctrl = sep->se_fd;
"Vladimir N. Oleynik"c06e80e2005-10-05 14:14:55 +00001426 Block_Using_Signals(omask);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001427 pid = 0;
1428#ifdef INETD_FEATURE_ENABLED
1429 if (sep->se_bi == 0 || sep->se_bi->bi_fork)
1430#endif
1431 {
1432 if (sep->se_count++ == 0)
1433 (void) gettimeofday (&sep->se_time, NULL);
1434 else if (toomany > 0 && sep->se_count >= sep->se_max) {
1435 struct timeval now;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001436
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001437 (void) gettimeofday (&now, NULL);
1438 if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
1439 sep->se_time = now;
1440 sep->se_count = 1;
1441 } else {
1442 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1443 close (ctrl);
1444 if (sep->se_family == AF_INET &&
1445 ntohs (sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
1446 /*
1447 * Cannot close it -- there are
1448 * thieves on the system.
1449 * Simply ignore the connection.
1450 */
1451 --sep->se_count;
1452 continue;
1453 }
1454 syslog (LOG_ERR,
1455 "%s/%s server failing (looping), service terminated",
1456 sep->se_service, sep->se_proto);
1457 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1458 close (ctrl);
1459 FD_CLR (sep->se_fd, &allsock);
1460 (void) close (sep->se_fd);
1461 sep->se_fd = -1;
1462 sep->se_count = 0;
1463 nsock--;
"Vladimir N. Oleynik"c06e80e2005-10-05 14:14:55 +00001464 sigprocmask(SIG_UNBLOCK, &omask, NULL);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001465 if (!timingout) {
1466 timingout = 1;
1467 alarm (RETRYTIME);
1468 }
1469 continue;
1470 }
1471 }
1472 pid = fork ();
1473 }
1474 if (pid < 0) {
1475 syslog (LOG_ERR, "fork: %m");
1476 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1477 close (ctrl);
"Vladimir N. Oleynik"c06e80e2005-10-05 14:14:55 +00001478 sigprocmask(SIG_UNBLOCK, &omask, NULL);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001479 sleep (1);
1480 continue;
1481 }
1482 if (pid && sep->se_wait) {
1483 sep->se_wait = pid;
1484 FD_CLR (sep->se_fd, &allsock);
1485 nsock--;
1486 }
"Vladimir N. Oleynik"c06e80e2005-10-05 14:14:55 +00001487 sigprocmask(SIG_UNBLOCK, &omask, NULL);
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001488 if (pid == 0) {
1489#ifdef INETD_FEATURE_ENABLED
1490 if (sep->se_bi) {
1491 (*sep->se_bi->bi_fn) (ctrl, sep);
1492 } else
1493#endif
1494 {
1495 if ((pwd = getpwnam (sep->se_user)) == NULL) {
1496 syslog (LOG_ERR, "getpwnam: %s: No such user", sep->se_user);
1497 if (sep->se_socktype != SOCK_STREAM)
1498 recv (0, buf, sizeof (buf), 0);
1499 _exit (1);
1500 }
1501 if (setsid () < 0)
1502 syslog (LOG_ERR, "%s: setsid: %m", sep->se_service);
1503 if (sep->se_group && (grp = getgrnam (sep->se_group)) == NULL) {
1504 syslog (LOG_ERR, "getgrnam: %s: No such group", sep->se_group);
1505 if (sep->se_socktype != SOCK_STREAM)
1506 recv (0, buf, sizeof (buf), 0);
1507 _exit (1);
1508 }
1509 if (uid != 0) {
1510 /* a user running private inetd */
1511 if (uid != pwd->pw_uid)
1512 _exit (1);
1513 } else if (pwd->pw_uid) {
1514 if (sep->se_group) {
1515 pwd->pw_gid = grp->gr_gid;
1516 }
1517 setgid ((gid_t) pwd->pw_gid);
1518 initgroups (pwd->pw_name, pwd->pw_gid);
1519 setuid ((uid_t) pwd->pw_uid);
1520 } else if (sep->se_group) {
1521 setgid (grp->gr_gid);
1522 setgroups (1, &grp->gr_gid);
1523 }
1524 dup2 (ctrl, 0);
1525 close (ctrl);
1526 dup2 (0, 1);
1527 dup2 (0, 2);
1528 if (rlim_ofile.rlim_cur != rlim_ofile_cur)
1529 if (setrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0)
1530 syslog (LOG_ERR, "setrlimit: %m");
1531 closelog ();
1532 for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
1533 (void) close (tmpint);
1534 sigaction (SIGPIPE, &sapipe, NULL);
1535 execv (sep->se_server, sep->se_argv);
1536 if (sep->se_socktype != SOCK_STREAM)
1537 recv (0, buf, sizeof (buf), 0);
1538 syslog (LOG_ERR, "execv %s: %m", sep->se_server);
1539 _exit (1);
1540 }
1541 }
1542 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1543 close (ctrl);
1544 }
1545 }
1546}
Glenn L McGrath06e95652003-02-09 06:51:14 +00001547
1548/*
1549 * Internet services provided internally by inetd:
1550 */
1551#define BUFSIZE 4096
1552
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001553#if defined(CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO) || \
1554 defined(CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN) || \
1555 defined(CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME)
1556static int dg_badinput (struct sockaddr_in *dg_sin)
1557{
1558 if (ntohs (dg_sin->sin_port) < IPPORT_RESERVED)
1559 return (1);
1560 if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST))
1561 return (1);
1562 /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
1563 return (0);
1564}
1565#endif
1566
Glenn L McGrath06e95652003-02-09 06:51:14 +00001567#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
1568/* Echo service -- echo data back */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001569/* ARGSUSED */
1570static void
1571echo_stream (int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001572{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001573 char buffer[BUFSIZE];
1574 int i;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001575
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001576 inetd_setproctitle (sep->se_service, s);
1577 while ((i = read (s, buffer, sizeof (buffer))) > 0 &&
1578 write (s, buffer, i) > 0);
1579 exit (0);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001580}
1581
1582/* Echo service -- echo data back */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001583/* ARGSUSED */
1584static void
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001585echo_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001586{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001587 char buffer[BUFSIZE];
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +00001588 int i;
1589 socklen_t size;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001590 /* struct sockaddr_storage ss; */
1591 struct sockaddr sa;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001592
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001593 size = sizeof (sa);
1594 if ((i = recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size)) < 0)
1595 return;
1596 if (dg_badinput ((struct sockaddr_in *) &sa))
1597 return;
1598 (void) sendto (s, buffer, i, 0, &sa, sizeof (sa));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001599}
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001600#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO */
Glenn L McGrath06e95652003-02-09 06:51:14 +00001601
1602#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
1603/* Discard service -- ignore data */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001604/* ARGSUSED */
1605static void
1606discard_stream (int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001607{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001608 char buffer[BUFSIZE];
Glenn L McGrath06e95652003-02-09 06:51:14 +00001609
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001610 inetd_setproctitle (sep->se_service, s);
1611 while ((errno = 0, read (s, buffer, sizeof (buffer)) > 0) ||
1612 errno == EINTR);
1613 exit (0);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001614}
1615
1616/* Discard service -- ignore data */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001617/* ARGSUSED */
1618static void
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001619discard_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001620{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001621 char buffer[BUFSIZE];
1622
1623 (void) read (s, buffer, sizeof (buffer));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001624}
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001625#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD */
Glenn L McGrath06e95652003-02-09 06:51:14 +00001626
1627
1628#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
Glenn L McGrath06e95652003-02-09 06:51:14 +00001629#define LINESIZ 72
1630static char ring[128];
1631static char *endring;
1632
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001633static void
1634initring (void)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001635{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001636 int i;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001637
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001638 endring = ring;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001639
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001640 for (i = 0; i <= 128; ++i)
1641 if (isprint (i))
1642 *endring++ = i;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001643}
1644
1645/* Character generator */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001646/* ARGSUSED */
1647static void
1648chargen_stream (int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001649{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001650 char *rs;
1651 int len;
1652 char text[LINESIZ + 2];
Glenn L McGrath06e95652003-02-09 06:51:14 +00001653
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001654 inetd_setproctitle (sep->se_service, s);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001655
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001656 if (!endring) {
1657 initring ();
1658 rs = ring;
1659 }
Glenn L McGrath06e95652003-02-09 06:51:14 +00001660
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001661 text[LINESIZ] = '\r';
1662 text[LINESIZ + 1] = '\n';
1663 for (rs = ring;;) {
Glenn L McGrath06e95652003-02-09 06:51:14 +00001664 if ((len = endring - rs) >= LINESIZ)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001665 memmove (text, rs, LINESIZ);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001666 else {
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001667 memmove (text, rs, len);
1668 memmove (text + len, ring, LINESIZ - len);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001669 }
1670 if (++rs == endring)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001671 rs = ring;
1672 if (write (s, text, sizeof (text)) != sizeof (text))
1673 break;
1674 }
1675 exit (0);
1676}
1677
1678/* Character generator */
1679/* ARGSUSED */
1680static void
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001681chargen_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001682{
1683 /* struct sockaddr_storage ss; */
1684 struct sockaddr sa;
1685 static char *rs;
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +00001686 int len;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001687 char text[LINESIZ + 2];
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +00001688 socklen_t size;
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001689
1690 if (endring == 0) {
1691 initring ();
1692 rs = ring;
1693 }
1694
1695 size = sizeof (sa);
1696 if (recvfrom (s, text, sizeof (text), 0, &sa, &size) < 0)
1697 return;
1698 if (dg_badinput ((struct sockaddr_in *) &sa))
1699 return;
1700
1701 if ((len = endring - rs) >= LINESIZ)
1702 memmove (text, rs, LINESIZ);
1703 else {
1704 memmove (text, rs, len);
1705 memmove (text + len, ring, LINESIZ - len);
1706 }
1707 if (++rs == endring)
1708 rs = ring;
1709 text[LINESIZ] = '\r';
1710 text[LINESIZ + 1] = '\n';
1711 (void) sendto (s, text, sizeof (text), 0, &sa, sizeof (sa));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001712}
1713#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN */
1714
1715
1716#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
1717/*
1718 * Return a machine readable date and time, in the form of the
1719 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1720 * returns the number of seconds since midnight, Jan 1, 1970,
1721 * we must add 2208988800 seconds to this figure to make up for
1722 * some seventy years Bell Labs was asleep.
1723 */
1724
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001725static u_int machtime (void)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001726{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001727 struct timeval tv;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001728
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001729 if (gettimeofday (&tv, NULL) < 0) {
1730 fprintf (stderr, "Unable to get time of day\n");
1731 return (0L);
1732 }
1733 return (htonl ((u_int) tv.tv_sec + 2208988800UL));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001734}
1735
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001736/* ARGSUSED */
1737static void
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001738machtime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001739{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001740 u_int result;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001741
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001742 result = machtime ();
1743 (void) write (s, (char *) &result, sizeof (result));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001744}
1745
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001746/* ARGSUSED */
1747static void
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001748machtime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001749{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001750 u_int result;
1751 /* struct sockaddr_storage ss; */
1752 struct sockaddr sa;
1753 struct sockaddr_in *dg_sin;
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +00001754 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001755
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001756 size = sizeof (sa);
1757 if (recvfrom (s, (char *) &result, sizeof (result), 0, &sa, &size) < 0)
1758 return;
1759 /* if (dg_badinput((struct sockaddr *)&ss)) */
1760 dg_sin = (struct sockaddr_in *) &sa;
1761 if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST) ||
1762 ntohs (dg_sin->sin_port) < IPPORT_RESERVED / 2)
1763 return;
1764 result = machtime ();
1765 (void) sendto (s, (char *) &result, sizeof (result), 0, &sa, sizeof (sa));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001766}
1767#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME */
1768
1769
1770#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
1771/* Return human-readable time of day */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001772/* ARGSUSED */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001773static void daytime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001774{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001775 char buffer[256];
1776 time_t t;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001777
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001778 t = time (NULL);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001779
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001780 (void) sprintf (buffer, "%.24s\r\n", ctime (&t));
1781 (void) write (s, buffer, strlen (buffer));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001782}
1783
1784/* Return human-readable time of day */
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001785/* ARGSUSED */
1786void
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001787daytime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001788{
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001789 char buffer[256];
1790 time_t t;
1791 /* struct sockaddr_storage ss; */
1792 struct sockaddr sa;
"Vladimir N. Oleynik"f382c022005-10-05 14:01:13 +00001793 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001794
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001795 t = time ((time_t *) 0);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001796
"Vladimir N. Oleynik"1a2f4d92005-10-03 08:08:58 +00001797 size = sizeof (sa);
1798 if (recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size) < 0)
1799 return;
1800 if (dg_badinput ((struct sockaddr_in *) &sa))
1801 return;
1802 (void) sprintf (buffer, "%.24s\r\n", ctime (&t));
1803 (void) sendto (s, buffer, strlen (buffer), 0, &sa, sizeof (sa));
Glenn L McGrath06e95652003-02-09 06:51:14 +00001804}
1805#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME */