blob: 0604b14bfd3cca85a87b41d3aa18a5dbdf5c377d [file] [log] [blame]
Glenn L McGrath06e95652003-02-09 06:51:14 +00001/*
2 * Copyright (c) 1983,1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * David A. Holland.
7 *
8 * Busybox port by Vladimir Oleynik (C) 2001-2003 <dzo@simtreas.ru>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26/*
27 * Inetd - Internet super-server
28 *
29 * This program invokes all internet services as needed.
30 * connection-oriented services are invoked each time a
31 * connection is made, by creating a process. This process
32 * is passed the connection as file descriptor 0 and is
33 * expected to do a getpeername to find out the source host
34 * and port.
35 *
36 * Datagram oriented services are invoked when a datagram
37 * arrives; a process is created and passed a pending message
38 * on file descriptor 0. Datagram servers may either connect
39 * to their peer, freeing up the original socket for inetd
40 * to receive further messages on, or ``take over the socket'',
41 * processing all arriving datagrams and, eventually, timing
42 * out. The first type of server is said to be ``multi-threaded'';
43 * the second type of server ``single-threaded''.
44 *
45 * Inetd uses a configuration file which is read at startup
46 * and, possibly, at some later time in response to a hangup signal.
47 * The configuration file is ``free format'' with fields given in the
48 * order shown below. Continuation lines for an entry must being with
49 * a space or tab. All fields must be present in each entry.
50 *
51 * service name must be in /etc/services
52 * socket type stream/dgram/raw/rdm/seqpacket
53 * protocol must be in /etc/protocols
54 * wait/nowait[.max] single-threaded/multi-threaded, max #
55 * user[.group] user/group to run daemon as
56 * server program full path name
57 * server program arguments maximum of MAXARGS (20)
58 *
Eric Andersenaff114c2004-04-14 17:51:38 +000059 * RPC services unsupported
Glenn L McGrath06e95652003-02-09 06:51:14 +000060 *
61 * Comment lines are indicated by a `#' in column 1.
62 */
63
64/*
65 * Here's the scoop concerning the user.group feature:
66 *
67 * 1) No group listed.
68 *
69 * a) for root: NO setuid() or setgid() is done
70 *
71 * b) nonroot: setuid()
72 * setgid(primary group as found in passwd)
73 * initgroups(name, primary group)
74 *
75 * 2) set-group-option on.
76 *
77 * a) for root: NO setuid()
78 * setgid(specified group)
79 * setgroups(1, specified group)
80 *
81 * b) nonroot: setuid()
82 * setgid(specified group)
83 * initgroups(name, specified group)
84 *
85 * All supplementary groups are discarded at startup in case inetd was
86 * run manually.
87 */
88
89#define __USE_BSD_SIGNAL
90
91#include "busybox.h"
92
Glenn L McGrath06e95652003-02-09 06:51:14 +000093
94#ifndef __linux__
95#ifndef RLIMIT_NOFILE
96#define RLIMIT_NOFILE RLIMIT_OFILE
97#endif
98#endif
99
Glenn L McGrath06e95652003-02-09 06:51:14 +0000100#include <sys/file.h>
Glenn L McGrath34e14692004-02-22 04:58:36 +0000101#include <sys/ioctl.h>
102#include <sys/param.h>
Glenn L McGrath06e95652003-02-09 06:51:14 +0000103#include <sys/resource.h>
Glenn L McGrath34e14692004-02-22 04:58:36 +0000104#include <sys/socket.h>
105#include <sys/stat.h>
106#include <sys/time.h>
107#include <sys/un.h>
108#include <sys/wait.h>
Glenn L McGrath06e95652003-02-09 06:51:14 +0000109
110#include <netinet/in.h>
111#include <netinet/ip.h>
112#include <arpa/inet.h>
113
114#include <errno.h>
115#include <signal.h>
116#include <netdb.h>
117#include <syslog.h>
Glenn L McGrath06e95652003-02-09 06:51:14 +0000118#include <stdio.h>
119#include <stdlib.h>
120#include <string.h>
121#include <getopt.h>
122#include <unistd.h>
123#include <stdarg.h>
Manuel Novoa III c2843562003-02-11 07:06:06 +0000124#include <time.h>
Glenn L McGrath06e95652003-02-09 06:51:14 +0000125
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000126#ifndef OPEN_MAX
127#define OPEN_MAX 64
128#endif
129
Glenn L McGrath06e95652003-02-09 06:51:14 +0000130#define _PATH_INETDCONF "/etc/inetd.conf"
131#define _PATH_INETDPID "/var/run/inetd.pid"
132
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000133#define TOOMANY 40 /* don't start more than TOOMANY */
134#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
135#define RETRYTIME (60*10) /* retry after bind or server fail */
136#define MAXARGV 20
Glenn L McGrath06e95652003-02-09 06:51:14 +0000137
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000138#define se_ctrladdr se_un.se_un_ctrladdr
139#define se_ctrladdr_in se_un.se_un_ctrladdr_in
140#define se_ctrladdr_un se_un.se_un_ctrladdr_un
Glenn L McGrath06e95652003-02-09 06:51:14 +0000141
142/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000143#define FD_MARGIN (8)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000144
Glenn L McGrathb1207b32003-02-10 22:31:09 +0000145/* Check unsupporting builtin */
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000146#if defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO || \
147 defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD || \
148 defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME || \
149 defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME || \
150 defined CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
151# define INETD_FEATURE_ENABLED
Glenn L McGrathb1207b32003-02-10 22:31:09 +0000152#endif
Glenn L McGrath06e95652003-02-09 06:51:14 +0000153
Glenn L McGrath03a06432004-02-18 13:19:58 +0000154typedef struct servtab_s {
Glenn L McGrath06e95652003-02-09 06:51:14 +0000155 char *se_service; /* name of service */
156 int se_socktype; /* type of socket to use */
157 int se_family; /* address family */
158 char *se_proto; /* protocol used */
159 short se_wait; /* single threaded server */
160 short se_checked; /* looked at during merge */
161 char *se_user; /* user name to run as */
162 char *se_group; /* group name to run as */
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000163#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000164 const struct biltin *se_bi; /* if built-in, description */
165#endif
166 char *se_server; /* server program */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000167 char *se_argv[MAXARGV+1]; /* program arguments */
168 int se_fd; /* open descriptor */
169 union {
170 struct sockaddr se_un_ctrladdr;
171 struct sockaddr_in se_un_ctrladdr_in;
172 struct sockaddr_un se_un_ctrladdr_un;
173 } se_un; /* bound address */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000174 int se_ctrladdr_size;
175 int se_max; /* max # of instances of this service */
176 int se_count; /* number started since se_time */
177 struct timeval se_time; /* start of se_count */
Glenn L McGrath03a06432004-02-18 13:19:58 +0000178 struct servtab_s *se_next;
179} servtab_t;
180
181static servtab_t *servtab;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000182
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000183#ifdef INETD_FEATURE_ENABLED
184struct biltin {
185 const char *bi_service; /* internally provided service name */
186 int bi_socktype; /* type of socket supported */
187 short bi_fork; /* 1 if should fork before call */
188 short bi_wait; /* 1 if should wait for child */
Glenn L McGrath03a06432004-02-18 13:19:58 +0000189 void (*bi_fn)(int, servtab_t *); /* fn which performs it */
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000190};
Glenn L McGrath06e95652003-02-09 06:51:14 +0000191
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000192 /* Echo received data */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000193#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
Glenn L McGrath03a06432004-02-18 13:19:58 +0000194static void echo_stream(int, servtab_t *);
195static void echo_dg(int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000196#endif
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000197 /* Internet /dev/null */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000198#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
Glenn L McGrath03a06432004-02-18 13:19:58 +0000199static void discard_stream(int, servtab_t *);
200static void discard_dg(int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000201#endif
202 /* Return 32 bit time since 1900 */
203#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
Glenn L McGrath03a06432004-02-18 13:19:58 +0000204static void machtime_stream(int, servtab_t *);
205static void machtime_dg(int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000206#endif
207 /* Return human-readable time */
208#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
Glenn L McGrath03a06432004-02-18 13:19:58 +0000209static void daytime_stream(int, servtab_t *);
210static void daytime_dg(int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000211#endif
212 /* Familiar character generator */
213#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
Glenn L McGrath03a06432004-02-18 13:19:58 +0000214static void chargen_stream(int, servtab_t *);
215static void chargen_dg(int, servtab_t *);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000216#endif
217
Glenn L McGrath06e95652003-02-09 06:51:14 +0000218static const struct biltin biltins[] = {
219#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
220 /* Echo received data */
221 { "echo", SOCK_STREAM, 1, 0, echo_stream, },
222 { "echo", SOCK_DGRAM, 0, 0, echo_dg, },
223#endif
224#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
225 /* Internet /dev/null */
226 { "discard", SOCK_STREAM, 1, 0, discard_stream, },
227 { "discard", SOCK_DGRAM, 0, 0, discard_dg, },
228#endif
229#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
230 /* Return 32 bit time since 1900 */
231 { "time", SOCK_STREAM, 0, 0, machtime_stream, },
232 { "time", SOCK_DGRAM, 0, 0, machtime_dg, },
233#endif
234#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
235 /* Return human-readable time */
236 { "daytime", SOCK_STREAM, 0, 0, daytime_stream, },
237 { "daytime", SOCK_DGRAM, 0, 0, daytime_dg, },
238#endif
239#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
240 /* Familiar character generator */
241 { "chargen", SOCK_STREAM, 1, 0, chargen_stream, },
242 { "chargen", SOCK_DGRAM, 0, 0, chargen_dg, },
243#endif
244 { NULL, 0, 0, 0, NULL }
245};
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000246#endif /* INETD_FEATURE_ENABLED */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000247
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000248#ifdef RLIMIT_NOFILE
249static struct rlimit rlim_ofile;
250#endif
251
252/* Length of socket listen queue. Should be per-service probably. */
253static int global_queuelen = 128;
254
255static FILE *fconfig;
256static sigset_t blockmask;
257static sigset_t emptymask;
258static fd_set allsock;
259static int nsock;
260static int maxsock;
261static int timingout;
262static int rlim_ofile_cur = OPEN_MAX;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000263static const char *CONFIG = _PATH_INETDCONF;
264
Glenn L McGrath06e95652003-02-09 06:51:14 +0000265static void
266syslog_err_and_discard_dg(int se_socktype, const char *msg, ...)
267 __attribute__ ((noreturn, format (printf, 2, 3)));
268
269static void
270syslog_err_and_discard_dg(int se_socktype, const char *msg, ...)
271{
272 char buf[50];
273 va_list p;
274
275 va_start(p, msg);
276 vsyslog(LOG_ERR, msg, p);
277 if (se_socktype != SOCK_STREAM)
278 recv(0, buf, sizeof (buf), 0);
279 _exit(1);
280}
281
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000282static char * inetd_strdup(const char *s)
283{
284 char *ms = strdup(s);
285
286 if(ms == NULL)
287 syslog_err_and_discard_dg(SOCK_STREAM, "strdup: %m");
288 return ms;
289}
290
291
Glenn L McGrath03a06432004-02-18 13:19:58 +0000292static servtab_t *getconfigent(void)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000293{
Glenn L McGrath03a06432004-02-18 13:19:58 +0000294 static servtab_t serv;
295 servtab_t *sep = &serv;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000296 int argc;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000297 char *cp = NULL;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000298 char *cp_ptr;
299 char *cp_ptr_ptr = NULL;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000300
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000301more:
302 free(cp);
303 cp = bb_get_chomped_line_from_file(fconfig);
304 if (feof(fconfig)) {
305 free(cp);
306 return (NULL);
307 }
308 if ((cp == NULL) || (*cp == '#')) {
Glenn L McGrath06e95652003-02-09 06:51:14 +0000309 goto more;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000310 }
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000311 /* make bind 0.0.0.0 and other zero default */
312 memset((char *)sep, 0, sizeof *sep);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000313
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000314 cp_ptr = strtok_r(cp, " \t", &cp_ptr_ptr);
315 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000316 /* Error */
317 goto more;
318 }
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000319 sep->se_service = inetd_strdup(cp_ptr);
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000320
321 cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr);
322 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000323 /* Error */
324 goto more;
325 }
326 if (strcmp(cp_ptr, "stream") == 0)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000327 sep->se_socktype = SOCK_STREAM;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000328 else if (strcmp(cp_ptr, "dgram") == 0)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000329 sep->se_socktype = SOCK_DGRAM;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000330 else if (strcmp(cp_ptr, "rdm") == 0)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000331 sep->se_socktype = SOCK_RDM;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000332 else if (strcmp(cp_ptr, "seqpacket") == 0)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000333 sep->se_socktype = SOCK_SEQPACKET;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000334 else if (strcmp(cp_ptr, "raw") == 0)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000335 sep->se_socktype = SOCK_RAW;
336 else
337 sep->se_socktype = -1;
338
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000339 cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr);
340 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000341 /* error */
342 goto more;
343 }
344 if (strcmp(cp_ptr, "unix") == 0) {
Glenn L McGrath06e95652003-02-09 06:51:14 +0000345 sep->se_family = AF_UNIX;
346 } else {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000347 if (strncmp(cp_ptr, "rpc/", 4) == 0) {
Eric Andersenaff114c2004-04-14 17:51:38 +0000348 syslog(LOG_ERR, "%s: rpc services not supported",
Glenn L McGrath06e95652003-02-09 06:51:14 +0000349 sep->se_service);
350 goto more;
351 }
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000352 sep->se_family = AF_INET;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000353 }
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000354 sep->se_proto = inetd_strdup(cp_ptr);
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000355
356 cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr);
357 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000358 /* error */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000359 goto more;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000360 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000361 {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000362 char *s = strchr(cp_ptr, '.');
Glenn L McGrath06e95652003-02-09 06:51:14 +0000363 if (s) {
364 *s++ = '\0';
365 sep->se_max = atoi(s);
366 } else
367 sep->se_max = TOOMANY;
368 }
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000369 sep->se_wait = strcmp(cp_ptr, "wait") == 0;
370
371 cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr);
372 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000373 /* error */
374 goto more;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000375 }
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000376
377 sep->se_user = inetd_strdup(cp_ptr);
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000378 {
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000379 char *cp_ptr2 = strchr(sep->se_user, '.');
380
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000381 if (cp_ptr2) {
382 *cp_ptr2++ = '\0';
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000383 }
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000384 sep->se_group = cp_ptr2;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000385 }
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000386
387 cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr);
388 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000389 /* error */
390 goto more;
391 }
392 if (strcmp(cp_ptr, "internal") == 0) {
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000393#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000394 const struct biltin *bi;
395
Glenn L McGrath53766c42004-01-18 08:58:06 +0000396 for (bi = biltins; bi->bi_service; bi++) {
397 if ((bi->bi_socktype == sep->se_socktype) &&
398 (strcmp(bi->bi_service, sep->se_service) == 0)) {
Glenn L McGrath06e95652003-02-09 06:51:14 +0000399 break;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000400 }
401 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000402 if (bi->bi_service == 0) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000403 syslog(LOG_ERR, "internal service %s unknown", sep->se_service);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000404 goto more;
405 }
406 sep->se_bi = bi;
407 sep->se_wait = bi->bi_wait;
408#else
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000409 syslog(LOG_ERR, "internal service %s unknown", cp_ptr);
410 goto more;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000411#endif
Glenn L McGrath06e95652003-02-09 06:51:14 +0000412 }
Glenn L McGrath53766c42004-01-18 08:58:06 +0000413#ifdef INETD_FEATURE_ENABLED
414 else {
415 sep->se_bi = NULL;
416 }
417#endif
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000418 sep->se_server = inetd_strdup(cp_ptr);
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000419
Glenn L McGrath53766c42004-01-18 08:58:06 +0000420 argc = 0;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000421 while ((cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr)) != NULL) {
Glenn L McGrath53766c42004-01-18 08:58:06 +0000422 if (argc < MAXARGV) {
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000423 sep->se_argv[argc++] = inetd_strdup(cp_ptr);
Glenn L McGrath53766c42004-01-18 08:58:06 +0000424 }
425 }
Glenn L McGrathdf7d84c2004-02-22 11:25:13 +0000426 free(cp);
Glenn L McGrath53766c42004-01-18 08:58:06 +0000427
Glenn L McGrath06e95652003-02-09 06:51:14 +0000428 return (sep);
429}
430
Glenn L McGrath03a06432004-02-18 13:19:58 +0000431static void freeconfig(servtab_t *cp)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000432{
433 int i;
434
435 free(cp->se_service);
436 free(cp->se_proto);
437 free(cp->se_user);
438 /* Note: se_group is part of the newstr'ed se_user */
439 free(cp->se_server);
440 for (i = 0; i < MAXARGV; i++)
441 free(cp->se_argv[i]);
442}
443
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000444#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000445static char **Argv;
446static char *LastArg;
447
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000448static void setproctitle(char *a, int s)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000449{
Mike Frysinger2e3054f2005-07-31 22:20:02 +0000450 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000451 char *cp;
452 struct sockaddr_in sn;
453 char buf[80];
454
455 cp = Argv[0];
456 size = sizeof(sn);
457 if (getpeername(s, (struct sockaddr *)&sn, &size) == 0)
458 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sn.sin_addr));
459 else
460 (void) sprintf(buf, "-%s", a);
461 strncpy(cp, buf, LastArg - cp);
462 cp += strlen(cp);
463 while (cp < LastArg)
464 *cp++ = ' ';
465}
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000466#endif /* INETD_FEATURE_ENABLED */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000467
Glenn L McGrath06e95652003-02-09 06:51:14 +0000468
Glenn L McGrath03a06432004-02-18 13:19:58 +0000469static void setup(servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000470{
471 int on = 1;
472
473 if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
474 syslog(LOG_ERR, "%s/%s: socket: %m",
475 sep->se_service, sep->se_proto);
476 return;
477 }
478 if (setsockopt(sep->se_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
479 sizeof(on)) < 0)
480 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
481 if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
482 syslog(LOG_ERR, "%s/%s: bind: %m",
483 sep->se_service, sep->se_proto);
484 (void) close(sep->se_fd);
485 sep->se_fd = -1;
486 if (!timingout) {
487 timingout = 1;
488 alarm(RETRYTIME);
489 }
490 return;
491 }
492 if (sep->se_socktype == SOCK_STREAM)
493 listen(sep->se_fd, global_queuelen);
494
495 FD_SET(sep->se_fd, &allsock);
496 nsock++;
497 if (sep->se_fd > maxsock) {
498 maxsock = sep->se_fd;
Glenn L McGratha277e022004-01-17 03:20:46 +0000499 if (maxsock > rlim_ofile_cur - FD_MARGIN) {
500#ifdef RLIMIT_NOFILE
501# define FD_CHUNK 32
502 struct rlimit rl;
503
504 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
505 syslog(LOG_ERR, "getrlimit: %m");
506 return;
507 }
508 rl.rlim_cur = rl.rlim_max < (rl.rlim_cur + FD_CHUNK) ? rl.rlim_max : (rl.rlim_cur + FD_CHUNK);
509 if (rl.rlim_cur <= rlim_ofile_cur) {
510 syslog(LOG_ERR,
511# if _FILE_OFFSET_BITS == 64
512 "bump_nofile: cannot extend file limit, max = %lld",
513# else
514 "bump_nofile: cannot extend file limit, max = %ld",
515# endif
516 rl.rlim_cur);
517 return;
518 }
519
520 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
521 syslog(LOG_ERR, "setrlimit: %m");
522 return;
523 }
524
525 rlim_ofile_cur = rl.rlim_cur;
526 return;
527#else
528 syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
529 return;
530#endif /* RLIMIT_NOFILE */
531 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000532 }
533}
534
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000535static void config(int signum)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000536{
Glenn L McGrath03a06432004-02-18 13:19:58 +0000537 servtab_t *sep, *cp, **sepp;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000538 sigset_t oldmask;
539 unsigned n;
540
541 (void)signum;
Glenn L McGratha277e022004-01-17 03:20:46 +0000542
543 if (fconfig != NULL) {
544 fseek(fconfig, 0L, L_SET);
545 } else {
546 fconfig = fopen(CONFIG, "r");
547 if (fconfig == NULL) {
548 syslog(LOG_ERR, "%s: %m", CONFIG);
549 return;
550 }
551 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000552
553 for (sep = servtab; sep; sep = sep->se_next)
554 sep->se_checked = 0;
555 while ((cp = getconfigent()) != NULL) {
556 for (sep = servtab; sep; sep = sep->se_next)
557 if (strcmp(sep->se_service, cp->se_service) == 0 &&
558 strcmp(sep->se_proto, cp->se_proto) == 0)
559 break;
560 if (sep != 0) {
561 int i;
562
Eric Andersen63e5e7bf2005-04-16 08:04:31 +0000563#define SWAP(type, a, b) {type c=(type)(a); (a)=(type)(b); (b)=(type)c;}
Glenn L McGrath06e95652003-02-09 06:51:14 +0000564
565 sigprocmask(SIG_BLOCK, &emptymask, &oldmask);
566 /*
567 * sep->se_wait may be holding the pid of a daemon
568 * that we're waiting for. If so, don't overwrite
569 * it unless the config file explicitly says don't
570 * wait.
571 */
572 if (
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000573#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000574 cp->se_bi == 0 &&
575#endif
576 (sep->se_wait == 1 || cp->se_wait == 0))
577 sep->se_wait = cp->se_wait;
578 if (cp->se_max != sep->se_max)
579 SWAP(int, cp->se_max, sep->se_max);
580 if (cp->se_user)
581 SWAP(char *, sep->se_user, cp->se_user);
582 if (cp->se_group)
583 SWAP(char *, sep->se_group, cp->se_group);
584 if (cp->se_server)
585 SWAP(char *, sep->se_server, cp->se_server);
586 for (i = 0; i < MAXARGV; i++)
587 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
588#undef SWAP
589 sigprocmask(SIG_SETMASK, &oldmask, NULL);
Eric Andersen60bb3f32004-02-17 20:04:34 +0000590 // This freeconfig() is probably a bug, since it will try and free()
591 // each of the argv[] values, which are really just pointers
592 // into the middle of a single line buffer for the config file.
593 //freeconfig(cp); // BUG?
Glenn L McGrath06e95652003-02-09 06:51:14 +0000594 } else {
Glenn L McGrath03a06432004-02-18 13:19:58 +0000595 sep = (servtab_t *)xmalloc(sizeof (*sep));
Glenn L McGratha277e022004-01-17 03:20:46 +0000596 *sep = *cp;
597 sep->se_fd = -1;
598 sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
599 sep->se_next = servtab;
600 servtab = sep;
601 sigprocmask(SIG_SETMASK, &oldmask, NULL);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000602 }
603 sep->se_checked = 1;
604
605 switch (sep->se_family) {
606 case AF_UNIX:
607 if (sep->se_fd != -1)
608 break;
609 (void)unlink(sep->se_service);
610 n = strlen(sep->se_service);
611 if (n > sizeof(sep->se_ctrladdr_un.sun_path) - 1)
612 n = sizeof(sep->se_ctrladdr_un.sun_path) - 1;
613 strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n);
614 sep->se_ctrladdr_un.sun_family = AF_UNIX;
615 sep->se_ctrladdr_size = n +
616 sizeof sep->se_ctrladdr_un.sun_family;
617 setup(sep);
618 break;
619 case AF_INET:
620 sep->se_ctrladdr_in.sin_family = AF_INET;
621 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
622 {
Glenn L McGrath036dbaa2004-01-17 05:03:31 +0000623 u_short port = bb_lookup_port(sep->se_service, sep->se_proto, 0);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000624
Glenn L McGrath036dbaa2004-01-17 05:03:31 +0000625 if (port == 0) {
626 syslog(LOG_ERR,
627 "%s/%s: unknown service",
628 sep->se_service, sep->se_proto);
629 continue;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000630 }
631 if (port != sep->se_ctrladdr_in.sin_port) {
632 sep->se_ctrladdr_in.sin_port = port;
633 if (sep->se_fd != -1) {
634 FD_CLR(sep->se_fd, &allsock);
635 nsock--;
636 (void) close(sep->se_fd);
637 }
638 sep->se_fd = -1;
639 }
640 if (sep->se_fd == -1)
641 setup(sep);
642 }
643 }
644 }
645 if (fconfig) {
646 (void) fclose(fconfig);
647 fconfig = NULL;
648 }
649 /*
650 * Purge anything not looked at above.
651 */
652 sigprocmask(SIG_SETMASK, &blockmask, &oldmask);
653 sepp = &servtab;
654 while ((sep = *sepp) != NULL) {
655 if (sep->se_checked) {
656 sepp = &sep->se_next;
657 continue;
658 }
659 *sepp = sep->se_next;
660 if (sep->se_fd != -1) {
661 FD_CLR(sep->se_fd, &allsock);
662 nsock--;
663 (void) close(sep->se_fd);
664 }
665 if (sep->se_family == AF_UNIX)
666 (void)unlink(sep->se_service);
667 freeconfig(sep);
668 free((char *)sep);
669 }
670 sigprocmask(SIG_SETMASK, &oldmask, NULL);
671}
672
673
674
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000675static void reapchild(int signum)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000676{
677 int status;
678 int pid;
Glenn L McGrath03a06432004-02-18 13:19:58 +0000679 servtab_t *sep;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000680
681 (void)signum;
682 for (;;) {
683 pid = wait3(&status, WNOHANG, (struct rusage *)0);
684 if (pid <= 0)
685 break;
686 for (sep = servtab; sep; sep = sep->se_next)
687 if (sep->se_wait == pid) {
688 if (WIFEXITED(status) && WEXITSTATUS(status))
689 syslog(LOG_WARNING,
690 "%s: exit status 0x%x",
691 sep->se_server, WEXITSTATUS(status));
692 else if (WIFSIGNALED(status))
693 syslog(LOG_WARNING,
694 "%s: exit signal 0x%x",
695 sep->se_server, WTERMSIG(status));
696 sep->se_wait = 1;
697 FD_SET(sep->se_fd, &allsock);
698 nsock++;
699 }
700 }
701}
702
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000703static void retry(int signum)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000704{
Glenn L McGrath03a06432004-02-18 13:19:58 +0000705 servtab_t *sep;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000706
707 (void)signum;
708 timingout = 0;
709 for (sep = servtab; sep; sep = sep->se_next) {
710 if (sep->se_fd == -1) {
711 switch (sep->se_family) {
712 case AF_UNIX:
713 case AF_INET:
714 setup(sep);
715 break;
716 }
717 }
718 }
719}
720
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000721static void goaway(int signum)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000722{
Glenn L McGrath03a06432004-02-18 13:19:58 +0000723 servtab_t *sep;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000724
725 (void)signum;
726 for (sep = servtab; sep; sep = sep->se_next)
727 if (sep->se_fd != -1 && sep->se_family == AF_UNIX)
728 (void)unlink(sep->se_service);
729 (void)unlink(_PATH_INETDPID);
730 exit(0);
731}
732
733
734
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000735extern int inetd_main(int argc, char *argv[])
Glenn L McGrath06e95652003-02-09 06:51:14 +0000736{
Glenn L McGrath03a06432004-02-18 13:19:58 +0000737 servtab_t *sep;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000738 struct group *grp = NULL;
739 struct sigaction sa;
Eric Andersen35e643b2003-07-28 07:40:39 +0000740 int pid;
741 unsigned long opt;
742 char *sq;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000743 gid_t gid;
744
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000745#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000746 extern char **environ;
747#endif
748
749 gid = getgid();
750 setgroups(1, &gid);
751
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000752#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000753 Argv = argv;
754 if (environ == 0 || *environ == 0)
755 environ = argv;
756 while (*environ)
757 environ++;
758 LastArg = environ[-1] + strlen(environ[-1]);
759#endif
760
Eric Andersen35e643b2003-07-28 07:40:39 +0000761 opt = bb_getopt_ulflags(argc, argv, "q:f", &sq);
Eric Andersen68d4a852003-07-28 09:31:28 +0000762 if (!(opt & 2)) {
Eric Andersen35e643b2003-07-28 07:40:39 +0000763 daemon(0, 0);
Paul Foxb8317532005-08-01 19:39:47 +0000764#if defined(__uClinux__)
Eric Andersen35e643b2003-07-28 07:40:39 +0000765 /* reexec for vfork() do continue parent */
766 vfork_daemon_rexec(argc, argv, "-f");
Eric Andersen35e643b2003-07-28 07:40:39 +0000767#endif /* uClinux */
Paul Foxb8317532005-08-01 19:39:47 +0000768 }
Eric Andersen35e643b2003-07-28 07:40:39 +0000769
770 if(opt & 1) {
Eric Andersen78a5dde2004-06-22 08:40:54 +0000771 global_queuelen = atoi(sq);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000772 if (global_queuelen < 8) global_queuelen=8;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000773 }
774 argc -= optind;
775 argv += optind;
776
777 if (argc > 0)
778 CONFIG = argv[0];
779
Manuel Novoa III cad53642003-03-19 09:13:01 +0000780 openlog(bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000781 {
782 FILE *fp;
783
784 if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
785 fprintf(fp, "%u\n", getpid());
786 (void)fclose(fp);
787 }
788 }
789
790#ifdef RLIMIT_NOFILE
791 if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
792 syslog(LOG_ERR, "getrlimit: %m");
793 } else {
794 rlim_ofile_cur = rlim_ofile.rlim_cur;
795 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */
796 rlim_ofile_cur = OPEN_MAX;
797 }
798#endif
799
800 config(0);
801
802 sigemptyset(&emptymask);
803 sigemptyset(&blockmask);
804 sigaddset(&blockmask, SIGCHLD);
805 sigaddset(&blockmask, SIGHUP);
806 sigaddset(&blockmask, SIGALRM);
807
808 memset(&sa, 0, sizeof(sa));
809 sa.sa_mask = blockmask;
810 sa.sa_handler = retry;
811 sigaction(SIGALRM, &sa, NULL);
812 sa.sa_handler = config;
813 sigaction(SIGHUP, &sa, NULL);
814 sa.sa_handler = reapchild;
815 sigaction(SIGCHLD, &sa, NULL);
816 sa.sa_handler = goaway;
817 sigaction(SIGTERM, &sa, NULL);
818 sa.sa_handler = goaway;
819 sigaction(SIGINT, &sa, NULL);
820 sa.sa_handler = SIG_IGN;
821 sigaction(SIGPIPE, &sa, NULL);
822
823 {
824 /* space for daemons to overwrite environment for ps */
825#define DUMMYSIZE 100
826 char dummy[DUMMYSIZE];
827
828 (void)memset(dummy, 'x', DUMMYSIZE - 1);
829 dummy[DUMMYSIZE - 1] = '\0';
830
831 (void)setenv("inetd_dummy", dummy, 1);
832 }
833
834 for (;;) {
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000835 fd_set readable;
836 int ctrl;
837 int n;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000838
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000839 if (nsock == 0) {
840 sigprocmask(SIG_BLOCK, &blockmask, NULL);
841 while (nsock == 0) {
842 sigsuspend(&emptymask);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000843 }
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000844 sigprocmask(SIG_SETMASK, &emptymask, NULL);
845 }
846 readable = allsock;
847 n = select(maxsock + 1, &readable, (fd_set *)0, (fd_set *)0, (struct timeval *)0);
848 if (n <= 0) {
849 if (n < 0 && errno != EINTR) {
850 syslog(LOG_WARNING, "select: %m");
851 }
852 sleep(1);
853 continue;
854 }
855 for (sep = servtab; n && sep; sep = sep->se_next) {
856 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
857 n--;
858 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
859 /* Fixed AGC */
860 fcntl(sep->se_fd, F_SETFL, O_NDELAY);
861 /* --------- */
862 ctrl = accept(sep->se_fd, NULL, NULL);
863 fcntl(sep->se_fd, F_SETFL, 0);
864 if (ctrl < 0) {
865 if (errno == EINTR || errno == EWOULDBLOCK) {
866 continue;
867 }
868 syslog(LOG_WARNING, "accept (for %s): %m",
869 sep->se_service);
870 continue;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000871 }
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000872 } else {
873 ctrl = sep->se_fd;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000874 }
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000875 sigprocmask(SIG_BLOCK, &blockmask, NULL);
876 pid = 0;
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000877#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000878 if (sep->se_bi == 0 || sep->se_bi->bi_fork)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000879#endif
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000880 {
881 if (sep->se_count++ == 0) {
882 gettimeofday(&sep->se_time, (struct timezone *)0);
883 }
884 else if (sep->se_count >= sep->se_max) {
885 struct timeval now;
886
887 gettimeofday(&now, (struct timezone *)0);
888 if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
889 sep->se_time = now;
890 sep->se_count = 1;
891 } else {
892 syslog(LOG_ERR,
893 "%s/%s server failing (looping), service terminated",
894 sep->se_service, sep->se_proto);
895 FD_CLR(sep->se_fd, &allsock);
896 close(sep->se_fd);
897 sep->se_fd = -1;
898 sep->se_count = 0;
899 nsock--;
900 sigprocmask(SIG_SETMASK, &emptymask, NULL);
901 if (!timingout) {
902 timingout = 1;
903 alarm(RETRYTIME);
904 }
905 continue;
906 }
907 }
908 pid = fork();
909 if (pid < 0) {
910 syslog(LOG_ERR, "fork: %m");
911 if (sep->se_socktype == SOCK_STREAM) {
912 close(ctrl);
913 }
914 sigprocmask(SIG_SETMASK, &emptymask, NULL);
915 sleep(1);
916 continue;
917 }
918 if (pid && sep->se_wait) {
919 sep->se_wait = pid;
920 FD_CLR(sep->se_fd, &allsock);
921 nsock--;
922 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000923 }
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000924 sigprocmask(SIG_SETMASK, &emptymask, NULL);
925 if (pid == 0) {
926#ifdef INETD_FEATURE_ENABLED
927 if (sep->se_bi) {
928 (*sep->se_bi->bi_fn)(ctrl, sep);
929 } else
930#endif
931 {
932 struct passwd *pwd = getpwnam(sep->se_user);
933 if (pwd == NULL) {
934 syslog_err_and_discard_dg(
935 sep->se_socktype,
936 "getpwnam: %s: No such user",
937 sep->se_user);
938 }
939 if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
940 syslog_err_and_discard_dg(sep->se_socktype,
941 "getgrnam: %s: No such group", sep->se_group);
942 }
943 /*
944 * Ok. There are four cases here:
945 * 1. nonroot user, no group specified
946 * 2. nonroot user, some group specified
947 * 3. root user, no group specified
948 * 4. root user, some group specified
949 * In cases 2 and 4 we setgid to the specified
950 * group. In cases 1 and 2 we run initgroups
951 * to run with the groups of the given user.
952 * In case 4 we do setgroups to run with the
953 * given group. In case 3 we do nothing.
954 */
955 if (pwd->pw_uid) {
956 if (sep->se_group) {
957 pwd->pw_gid = grp->gr_gid;
958 }
959 setgid((gid_t)pwd->pw_gid);
960 initgroups(pwd->pw_name, pwd->pw_gid);
961 setuid((uid_t)pwd->pw_uid);
962 } else if (sep->se_group) {
963 setgid((gid_t)grp->gr_gid);
964 setgroups(1, &grp->gr_gid);
965 }
966 dup2(ctrl, 0);
967 close(ctrl);
968 dup2(0, 1);
969 dup2(0, 2);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000970#ifdef RLIMIT_NOFILE
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000971 if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
972 if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
973 syslog(LOG_ERR,"setrlimit: %m");
974 }
975 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000976#endif
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000977 for (ctrl = rlim_ofile_cur-1; --ctrl > 2; ) {
978 (void)close(ctrl);
979 }
980 memset(&sa, 0, sizeof(sa));
981 sa.sa_handler = SIG_DFL;
982 sigaction(SIGPIPE, &sa, NULL);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000983
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000984 execv(sep->se_server, sep->se_argv);
985 syslog_err_and_discard_dg(sep->se_socktype, "execv %s: %m", sep->se_server);
986 }
987 }
988 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
989 close(ctrl);
990 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000991 }
992 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000993 }
994}
995
996
997/*
998 * Internet services provided internally by inetd:
999 */
1000#define BUFSIZE 4096
1001
1002#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
1003/* Echo service -- echo data back */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001004static void echo_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001005{
1006 char buffer[BUFSIZE];
1007 int i;
1008
1009 setproctitle(sep->se_service, s);
1010 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1011 write(s, buffer, i) > 0)
1012 ;
1013 exit(0);
1014}
1015
1016/* Echo service -- echo data back */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001017static void echo_dg(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001018{
1019 char buffer[BUFSIZE];
1020 int i;
Mike Frysinger2e3054f2005-07-31 22:20:02 +00001021 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001022 struct sockaddr sa;
1023
1024 (void)sep;
1025
1026 size = sizeof(sa);
1027 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
1028 return;
1029 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
1030}
1031#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO */
1032
1033
1034#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
1035/* Discard service -- ignore data */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001036static void discard_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001037{
1038 char buffer[BUFSIZE];
1039
1040 setproctitle(sep->se_service, s);
1041 while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1042 errno == EINTR)
1043 ;
1044 exit(0);
1045}
1046
1047/* Discard service -- ignore data */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001048static void discard_dg(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001049{
1050 char buffer[BUFSIZE];
1051 (void)sep;
1052 read(s, buffer, sizeof(buffer));
1053}
1054#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD */
1055
1056
1057#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
1058#include <ctype.h>
1059#define LINESIZ 72
1060static char ring[128];
1061static char *endring;
1062
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +00001063static void initring(void)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001064{
1065 int i;
1066
1067 endring = ring;
1068
1069 for (i = 0; i <= 128; ++i)
1070 if (isprint(i))
1071 *endring++ = i;
1072}
1073
1074/* Character generator */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001075static void chargen_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001076{
1077 char *rs;
1078 int len;
1079 char text[LINESIZ+2];
1080
1081 setproctitle(sep->se_service, s);
1082
1083 if (!endring) {
1084 initring();
1085 rs = ring;
1086 }
1087
1088 text[LINESIZ] = '\r';
1089 text[LINESIZ + 1] = '\n';
1090 for (rs = ring;;) {
1091 if ((len = endring - rs) >= LINESIZ)
Paul Foxdeac3712005-07-19 21:19:20 +00001092 memcpy(text, rs, LINESIZ);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001093 else {
Paul Foxdeac3712005-07-19 21:19:20 +00001094 memcpy(text, rs, len);
1095 memcpy(text + len, ring, LINESIZ - len);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001096 }
1097 if (++rs == endring)
1098 rs = ring;
1099 if (write(s, text, sizeof(text)) != sizeof(text))
1100 break;
1101 }
1102 exit(0);
1103}
1104
1105/* Character generator */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001106static void chargen_dg(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001107{
1108 struct sockaddr sa;
1109 static char *rs;
Mike Frysinger2e3054f2005-07-31 22:20:02 +00001110 size_t len;
1111 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001112 char text[LINESIZ+2];
1113
1114 (void)sep;
1115
1116 if (endring == 0) {
1117 initring();
1118 rs = ring;
1119 }
1120
1121 size = sizeof(sa);
1122 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1123 return;
1124
1125 if ((len = endring - rs) >= LINESIZ)
Paul Foxdeac3712005-07-19 21:19:20 +00001126 memcpy(text, rs, LINESIZ);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001127 else {
Paul Foxdeac3712005-07-19 21:19:20 +00001128 memcpy(text, rs, len);
1129 memcpy(text + len, ring, LINESIZ - len);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001130 }
1131 if (++rs == endring)
1132 rs = ring;
1133 text[LINESIZ] = '\r';
1134 text[LINESIZ + 1] = '\n';
1135 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1136}
1137#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN */
1138
1139
1140#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
1141/*
1142 * Return a machine readable date and time, in the form of the
1143 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1144 * returns the number of seconds since midnight, Jan 1, 1970,
1145 * we must add 2208988800 seconds to this figure to make up for
1146 * some seventy years Bell Labs was asleep.
1147 */
1148
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +00001149static long machtime(void)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001150{
1151 struct timeval tv;
1152
1153 if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1154 fprintf(stderr, "Unable to get time of day\n");
1155 return (0L);
1156 }
1157 return (htonl((long)tv.tv_sec + 2208988800UL));
1158}
1159
Glenn L McGrath03a06432004-02-18 13:19:58 +00001160static void machtime_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001161{
1162 long result;
1163 (void)sep;
1164
1165 result = machtime();
1166 write(s, (char *) &result, sizeof(result));
1167}
1168
Glenn L McGrath03a06432004-02-18 13:19:58 +00001169static void machtime_dg(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001170{
1171 long result;
1172 struct sockaddr sa;
Mike Frysinger2e3054f2005-07-31 22:20:02 +00001173 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001174 (void)sep;
1175
1176 size = sizeof(sa);
1177 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1178 return;
1179 result = machtime();
1180 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1181}
1182#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME */
1183
1184
1185#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
1186/* Return human-readable time of day */
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +00001187static int human_readable_time_sprintf(char *buffer)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001188{
1189 time_t clocc = time(NULL);
1190
1191 return sprintf(buffer, "%.24s\r\n", ctime(&clocc));
1192}
1193
Glenn L McGrath03a06432004-02-18 13:19:58 +00001194static void daytime_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001195{
1196 char buffer[256];
1197 size_t st = human_readable_time_sprintf(buffer);
1198
1199 (void)sep;
1200
1201 write(s, buffer, st);
1202}
1203
1204/* Return human-readable time of day */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001205static void daytime_dg(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001206{
1207 char buffer[256];
1208 struct sockaddr sa;
Mike Frysinger2e3054f2005-07-31 22:20:02 +00001209 socklen_t size;
Glenn L McGrath06e95652003-02-09 06:51:14 +00001210
1211 (void)sep;
1212
1213 size = sizeof(sa);
1214 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1215 return;
1216 size = human_readable_time_sprintf(buffer);
1217 sendto(s, buffer, size, 0, &sa, sizeof(sa));
1218}
1219#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME */