blob: c930a892cf0891e92f0a269c84d17798a95d1cfd [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 *
59 * RPC services unsuported
60 *
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 McGrath03a06432004-02-18 13:19:58 +0000282static servtab_t *getconfigent(void)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000283{
Glenn L McGrath03a06432004-02-18 13:19:58 +0000284 static servtab_t serv;
285 servtab_t *sep = &serv;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000286 int argc;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000287 char *cp = NULL;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000288 char *cp_ptr;
289 char *cp_ptr_ptr = NULL;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000290
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000291more:
292 free(cp);
293 cp = bb_get_chomped_line_from_file(fconfig);
294 if (feof(fconfig)) {
295 free(cp);
296 return (NULL);
297 }
298 if ((cp == NULL) || (*cp == '#')) {
Glenn L McGrath06e95652003-02-09 06:51:14 +0000299 goto more;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000300 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000301
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000302 cp_ptr = strtok_r(cp, " \t", &cp_ptr_ptr);
303 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000304 /* Error */
305 goto more;
306 }
307 sep->se_service = bb_xstrdup(cp_ptr);
308
309 cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr);
310 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000311 /* Error */
312 goto more;
313 }
314 if (strcmp(cp_ptr, "stream") == 0)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000315 sep->se_socktype = SOCK_STREAM;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000316 else if (strcmp(cp_ptr, "dgram") == 0)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000317 sep->se_socktype = SOCK_DGRAM;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000318 else if (strcmp(cp_ptr, "rdm") == 0)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000319 sep->se_socktype = SOCK_RDM;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000320 else if (strcmp(cp_ptr, "seqpacket") == 0)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000321 sep->se_socktype = SOCK_SEQPACKET;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000322 else if (strcmp(cp_ptr, "raw") == 0)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000323 sep->se_socktype = SOCK_RAW;
324 else
325 sep->se_socktype = -1;
326
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000327 cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr);
328 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000329 /* error */
330 goto more;
331 }
332 if (strcmp(cp_ptr, "unix") == 0) {
Glenn L McGrath06e95652003-02-09 06:51:14 +0000333 sep->se_family = AF_UNIX;
334 } else {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000335 if (strncmp(cp_ptr, "rpc/", 4) == 0) {
Glenn L McGrath06e95652003-02-09 06:51:14 +0000336 syslog(LOG_ERR, "%s: rpc services not suported",
337 sep->se_service);
338 goto more;
339 }
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000340 sep->se_family = AF_INET;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000341 }
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000342 sep->se_proto = bb_xstrdup(cp_ptr);
343
344 cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr);
345 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000346 /* error */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000347 goto more;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000348 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000349 {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000350 char *s = strchr(cp_ptr, '.');
Glenn L McGrath06e95652003-02-09 06:51:14 +0000351 if (s) {
352 *s++ = '\0';
353 sep->se_max = atoi(s);
354 } else
355 sep->se_max = TOOMANY;
356 }
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000357 sep->se_wait = strcmp(cp_ptr, "wait") == 0;
358
359 cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr);
360 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000361 /* error */
362 goto more;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000363 }
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000364 {
365 char *cp_ptr2 = strchr(cp_ptr, '.');
366 if (cp_ptr2) {
367 *cp_ptr2++ = '\0';
368 sep->se_group = bb_xstrdup(cp_ptr2);
369 }
370 }
371 sep->se_user = bb_xstrdup(cp_ptr);
372
373 cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr);
374 if (cp_ptr == NULL) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000375 /* error */
376 goto more;
377 }
378 if (strcmp(cp_ptr, "internal") == 0) {
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000379#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000380 const struct biltin *bi;
381
Glenn L McGrath53766c42004-01-18 08:58:06 +0000382 for (bi = biltins; bi->bi_service; bi++) {
383 if ((bi->bi_socktype == sep->se_socktype) &&
384 (strcmp(bi->bi_service, sep->se_service) == 0)) {
Glenn L McGrath06e95652003-02-09 06:51:14 +0000385 break;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000386 }
387 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000388 if (bi->bi_service == 0) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000389 syslog(LOG_ERR, "internal service %s unknown", sep->se_service);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000390 goto more;
391 }
392 sep->se_bi = bi;
393 sep->se_wait = bi->bi_wait;
394#else
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000395 syslog(LOG_ERR, "internal service %s unknown", cp_ptr);
396 goto more;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000397#endif
Glenn L McGrath06e95652003-02-09 06:51:14 +0000398 }
Glenn L McGrath53766c42004-01-18 08:58:06 +0000399#ifdef INETD_FEATURE_ENABLED
400 else {
401 sep->se_bi = NULL;
402 }
403#endif
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000404 sep->se_server = bb_xstrdup(cp_ptr);
405
Glenn L McGrath53766c42004-01-18 08:58:06 +0000406 argc = 0;
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000407 while ((cp_ptr = strtok_r(NULL, " \t", &cp_ptr_ptr)) != NULL) {
Glenn L McGrath53766c42004-01-18 08:58:06 +0000408 if (argc < MAXARGV) {
Glenn L McGratheaf5bc02004-01-20 15:32:39 +0000409 sep->se_argv[argc++] = cp_ptr;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000410 }
411 }
412 while (argc <= MAXARGV) {
Glenn L McGrath06e95652003-02-09 06:51:14 +0000413 sep->se_argv[argc++] = NULL;
Glenn L McGrath53766c42004-01-18 08:58:06 +0000414 }
415
Eric Andersen60bb3f32004-02-17 20:04:34 +0000416 //free(cp); // BUG: cp is the argv[] container; we must not free it here!
Glenn L McGrath06e95652003-02-09 06:51:14 +0000417 return (sep);
418}
419
Glenn L McGrath03a06432004-02-18 13:19:58 +0000420static void freeconfig(servtab_t *cp)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000421{
422 int i;
423
424 free(cp->se_service);
425 free(cp->se_proto);
426 free(cp->se_user);
427 /* Note: se_group is part of the newstr'ed se_user */
428 free(cp->se_server);
429 for (i = 0; i < MAXARGV; i++)
430 free(cp->se_argv[i]);
431}
432
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000433#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000434static char **Argv;
435static char *LastArg;
436
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000437static void setproctitle(char *a, int s)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000438{
439 size_t size;
440 char *cp;
441 struct sockaddr_in sn;
442 char buf[80];
443
444 cp = Argv[0];
445 size = sizeof(sn);
446 if (getpeername(s, (struct sockaddr *)&sn, &size) == 0)
447 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sn.sin_addr));
448 else
449 (void) sprintf(buf, "-%s", a);
450 strncpy(cp, buf, LastArg - cp);
451 cp += strlen(cp);
452 while (cp < LastArg)
453 *cp++ = ' ';
454}
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000455#endif /* INETD_FEATURE_ENABLED */
Glenn L McGrath06e95652003-02-09 06:51:14 +0000456
Glenn L McGrath06e95652003-02-09 06:51:14 +0000457
Glenn L McGrath03a06432004-02-18 13:19:58 +0000458static void setup(servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000459{
460 int on = 1;
461
462 if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
463 syslog(LOG_ERR, "%s/%s: socket: %m",
464 sep->se_service, sep->se_proto);
465 return;
466 }
467 if (setsockopt(sep->se_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
468 sizeof(on)) < 0)
469 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
470 if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
471 syslog(LOG_ERR, "%s/%s: bind: %m",
472 sep->se_service, sep->se_proto);
473 (void) close(sep->se_fd);
474 sep->se_fd = -1;
475 if (!timingout) {
476 timingout = 1;
477 alarm(RETRYTIME);
478 }
479 return;
480 }
481 if (sep->se_socktype == SOCK_STREAM)
482 listen(sep->se_fd, global_queuelen);
483
484 FD_SET(sep->se_fd, &allsock);
485 nsock++;
486 if (sep->se_fd > maxsock) {
487 maxsock = sep->se_fd;
Glenn L McGratha277e022004-01-17 03:20:46 +0000488 if (maxsock > rlim_ofile_cur - FD_MARGIN) {
489#ifdef RLIMIT_NOFILE
490# define FD_CHUNK 32
491 struct rlimit rl;
492
493 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
494 syslog(LOG_ERR, "getrlimit: %m");
495 return;
496 }
497 rl.rlim_cur = rl.rlim_max < (rl.rlim_cur + FD_CHUNK) ? rl.rlim_max : (rl.rlim_cur + FD_CHUNK);
498 if (rl.rlim_cur <= rlim_ofile_cur) {
499 syslog(LOG_ERR,
500# if _FILE_OFFSET_BITS == 64
501 "bump_nofile: cannot extend file limit, max = %lld",
502# else
503 "bump_nofile: cannot extend file limit, max = %ld",
504# endif
505 rl.rlim_cur);
506 return;
507 }
508
509 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
510 syslog(LOG_ERR, "setrlimit: %m");
511 return;
512 }
513
514 rlim_ofile_cur = rl.rlim_cur;
515 return;
516#else
517 syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
518 return;
519#endif /* RLIMIT_NOFILE */
520 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000521 }
522}
523
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000524static void config(int signum)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000525{
Glenn L McGrath03a06432004-02-18 13:19:58 +0000526 servtab_t *sep, *cp, **sepp;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000527 sigset_t oldmask;
528 unsigned n;
529
530 (void)signum;
Glenn L McGratha277e022004-01-17 03:20:46 +0000531
532 if (fconfig != NULL) {
533 fseek(fconfig, 0L, L_SET);
534 } else {
535 fconfig = fopen(CONFIG, "r");
536 if (fconfig == NULL) {
537 syslog(LOG_ERR, "%s: %m", CONFIG);
538 return;
539 }
540 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000541
542 for (sep = servtab; sep; sep = sep->se_next)
543 sep->se_checked = 0;
544 while ((cp = getconfigent()) != NULL) {
545 for (sep = servtab; sep; sep = sep->se_next)
546 if (strcmp(sep->se_service, cp->se_service) == 0 &&
547 strcmp(sep->se_proto, cp->se_proto) == 0)
548 break;
549 if (sep != 0) {
550 int i;
551
552#define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
553
554 sigprocmask(SIG_BLOCK, &emptymask, &oldmask);
555 /*
556 * sep->se_wait may be holding the pid of a daemon
557 * that we're waiting for. If so, don't overwrite
558 * it unless the config file explicitly says don't
559 * wait.
560 */
561 if (
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000562#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000563 cp->se_bi == 0 &&
564#endif
565 (sep->se_wait == 1 || cp->se_wait == 0))
566 sep->se_wait = cp->se_wait;
567 if (cp->se_max != sep->se_max)
568 SWAP(int, cp->se_max, sep->se_max);
569 if (cp->se_user)
570 SWAP(char *, sep->se_user, cp->se_user);
571 if (cp->se_group)
572 SWAP(char *, sep->se_group, cp->se_group);
573 if (cp->se_server)
574 SWAP(char *, sep->se_server, cp->se_server);
575 for (i = 0; i < MAXARGV; i++)
576 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
577#undef SWAP
578 sigprocmask(SIG_SETMASK, &oldmask, NULL);
Eric Andersen60bb3f32004-02-17 20:04:34 +0000579 // This freeconfig() is probably a bug, since it will try and free()
580 // each of the argv[] values, which are really just pointers
581 // into the middle of a single line buffer for the config file.
582 //freeconfig(cp); // BUG?
Glenn L McGrath06e95652003-02-09 06:51:14 +0000583 } else {
Glenn L McGrath03a06432004-02-18 13:19:58 +0000584 sep = (servtab_t *)xmalloc(sizeof (*sep));
Glenn L McGratha277e022004-01-17 03:20:46 +0000585 *sep = *cp;
586 sep->se_fd = -1;
587 sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
588 sep->se_next = servtab;
589 servtab = sep;
590 sigprocmask(SIG_SETMASK, &oldmask, NULL);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000591 }
592 sep->se_checked = 1;
593
594 switch (sep->se_family) {
595 case AF_UNIX:
596 if (sep->se_fd != -1)
597 break;
598 (void)unlink(sep->se_service);
599 n = strlen(sep->se_service);
600 if (n > sizeof(sep->se_ctrladdr_un.sun_path) - 1)
601 n = sizeof(sep->se_ctrladdr_un.sun_path) - 1;
602 strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n);
603 sep->se_ctrladdr_un.sun_family = AF_UNIX;
604 sep->se_ctrladdr_size = n +
605 sizeof sep->se_ctrladdr_un.sun_family;
606 setup(sep);
607 break;
608 case AF_INET:
609 sep->se_ctrladdr_in.sin_family = AF_INET;
610 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
611 {
Glenn L McGrath036dbaa2004-01-17 05:03:31 +0000612 u_short port = bb_lookup_port(sep->se_service, sep->se_proto, 0);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000613
Glenn L McGrath036dbaa2004-01-17 05:03:31 +0000614 if (port == 0) {
615 syslog(LOG_ERR,
616 "%s/%s: unknown service",
617 sep->se_service, sep->se_proto);
618 continue;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000619 }
620 if (port != sep->se_ctrladdr_in.sin_port) {
621 sep->se_ctrladdr_in.sin_port = port;
622 if (sep->se_fd != -1) {
623 FD_CLR(sep->se_fd, &allsock);
624 nsock--;
625 (void) close(sep->se_fd);
626 }
627 sep->se_fd = -1;
628 }
629 if (sep->se_fd == -1)
630 setup(sep);
631 }
632 }
633 }
634 if (fconfig) {
635 (void) fclose(fconfig);
636 fconfig = NULL;
637 }
638 /*
639 * Purge anything not looked at above.
640 */
641 sigprocmask(SIG_SETMASK, &blockmask, &oldmask);
642 sepp = &servtab;
643 while ((sep = *sepp) != NULL) {
644 if (sep->se_checked) {
645 sepp = &sep->se_next;
646 continue;
647 }
648 *sepp = sep->se_next;
649 if (sep->se_fd != -1) {
650 FD_CLR(sep->se_fd, &allsock);
651 nsock--;
652 (void) close(sep->se_fd);
653 }
654 if (sep->se_family == AF_UNIX)
655 (void)unlink(sep->se_service);
656 freeconfig(sep);
657 free((char *)sep);
658 }
659 sigprocmask(SIG_SETMASK, &oldmask, NULL);
660}
661
662
663
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000664static void reapchild(int signum)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000665{
666 int status;
667 int pid;
Glenn L McGrath03a06432004-02-18 13:19:58 +0000668 servtab_t *sep;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000669
670 (void)signum;
671 for (;;) {
672 pid = wait3(&status, WNOHANG, (struct rusage *)0);
673 if (pid <= 0)
674 break;
675 for (sep = servtab; sep; sep = sep->se_next)
676 if (sep->se_wait == pid) {
677 if (WIFEXITED(status) && WEXITSTATUS(status))
678 syslog(LOG_WARNING,
679 "%s: exit status 0x%x",
680 sep->se_server, WEXITSTATUS(status));
681 else if (WIFSIGNALED(status))
682 syslog(LOG_WARNING,
683 "%s: exit signal 0x%x",
684 sep->se_server, WTERMSIG(status));
685 sep->se_wait = 1;
686 FD_SET(sep->se_fd, &allsock);
687 nsock++;
688 }
689 }
690}
691
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000692static void retry(int signum)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000693{
Glenn L McGrath03a06432004-02-18 13:19:58 +0000694 servtab_t *sep;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000695
696 (void)signum;
697 timingout = 0;
698 for (sep = servtab; sep; sep = sep->se_next) {
699 if (sep->se_fd == -1) {
700 switch (sep->se_family) {
701 case AF_UNIX:
702 case AF_INET:
703 setup(sep);
704 break;
705 }
706 }
707 }
708}
709
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000710static void goaway(int signum)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000711{
Glenn L McGrath03a06432004-02-18 13:19:58 +0000712 servtab_t *sep;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000713
714 (void)signum;
715 for (sep = servtab; sep; sep = sep->se_next)
716 if (sep->se_fd != -1 && sep->se_family == AF_UNIX)
717 (void)unlink(sep->se_service);
718 (void)unlink(_PATH_INETDPID);
719 exit(0);
720}
721
722
723
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +0000724extern int inetd_main(int argc, char *argv[])
Glenn L McGrath06e95652003-02-09 06:51:14 +0000725{
Glenn L McGrath03a06432004-02-18 13:19:58 +0000726 servtab_t *sep;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000727 struct group *grp = NULL;
728 struct sigaction sa;
Eric Andersen35e643b2003-07-28 07:40:39 +0000729 int pid;
730 unsigned long opt;
731 char *sq;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000732 gid_t gid;
733
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000734#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000735 extern char **environ;
736#endif
737
738 gid = getgid();
739 setgroups(1, &gid);
740
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000741#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath06e95652003-02-09 06:51:14 +0000742 Argv = argv;
743 if (environ == 0 || *environ == 0)
744 environ = argv;
745 while (*environ)
746 environ++;
747 LastArg = environ[-1] + strlen(environ[-1]);
748#endif
749
Eric Andersen35e643b2003-07-28 07:40:39 +0000750#if defined(__uClinux__)
751 opt = bb_getopt_ulflags(argc, argv, "q:f", &sq);
Eric Andersen68d4a852003-07-28 09:31:28 +0000752 if (!(opt & 2)) {
Eric Andersen35e643b2003-07-28 07:40:39 +0000753 daemon(0, 0);
754 /* reexec for vfork() do continue parent */
755 vfork_daemon_rexec(argc, argv, "-f");
756 }
757#else
Eric Andersen68d4a852003-07-28 09:31:28 +0000758 opt = bb_getopt_ulflags(argc, argv, "q:", &sq);
Eric Andersen35e643b2003-07-28 07:40:39 +0000759 daemon(0, 0);
760#endif /* uClinux */
761
762 if(opt & 1) {
Glenn L McGrath06e95652003-02-09 06:51:14 +0000763 global_queuelen = atoi(optarg);
764 if (global_queuelen < 8) global_queuelen=8;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000765 }
766 argc -= optind;
767 argv += optind;
768
769 if (argc > 0)
770 CONFIG = argv[0];
771
Manuel Novoa III cad53642003-03-19 09:13:01 +0000772 openlog(bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000773 {
774 FILE *fp;
775
776 if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
777 fprintf(fp, "%u\n", getpid());
778 (void)fclose(fp);
779 }
780 }
781
782#ifdef RLIMIT_NOFILE
783 if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
784 syslog(LOG_ERR, "getrlimit: %m");
785 } else {
786 rlim_ofile_cur = rlim_ofile.rlim_cur;
787 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */
788 rlim_ofile_cur = OPEN_MAX;
789 }
790#endif
791
792 config(0);
793
794 sigemptyset(&emptymask);
795 sigemptyset(&blockmask);
796 sigaddset(&blockmask, SIGCHLD);
797 sigaddset(&blockmask, SIGHUP);
798 sigaddset(&blockmask, SIGALRM);
799
800 memset(&sa, 0, sizeof(sa));
801 sa.sa_mask = blockmask;
802 sa.sa_handler = retry;
803 sigaction(SIGALRM, &sa, NULL);
804 sa.sa_handler = config;
805 sigaction(SIGHUP, &sa, NULL);
806 sa.sa_handler = reapchild;
807 sigaction(SIGCHLD, &sa, NULL);
808 sa.sa_handler = goaway;
809 sigaction(SIGTERM, &sa, NULL);
810 sa.sa_handler = goaway;
811 sigaction(SIGINT, &sa, NULL);
812 sa.sa_handler = SIG_IGN;
813 sigaction(SIGPIPE, &sa, NULL);
814
815 {
816 /* space for daemons to overwrite environment for ps */
817#define DUMMYSIZE 100
818 char dummy[DUMMYSIZE];
819
820 (void)memset(dummy, 'x', DUMMYSIZE - 1);
821 dummy[DUMMYSIZE - 1] = '\0';
822
823 (void)setenv("inetd_dummy", dummy, 1);
824 }
825
826 for (;;) {
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000827 fd_set readable;
828 int ctrl;
829 int n;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000830
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000831 if (nsock == 0) {
832 sigprocmask(SIG_BLOCK, &blockmask, NULL);
833 while (nsock == 0) {
834 sigsuspend(&emptymask);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000835 }
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000836 sigprocmask(SIG_SETMASK, &emptymask, NULL);
837 }
838 readable = allsock;
839 n = select(maxsock + 1, &readable, (fd_set *)0, (fd_set *)0, (struct timeval *)0);
840 if (n <= 0) {
841 if (n < 0 && errno != EINTR) {
842 syslog(LOG_WARNING, "select: %m");
843 }
844 sleep(1);
845 continue;
846 }
847 for (sep = servtab; n && sep; sep = sep->se_next) {
848 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
849 n--;
850 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
851 /* Fixed AGC */
852 fcntl(sep->se_fd, F_SETFL, O_NDELAY);
853 /* --------- */
854 ctrl = accept(sep->se_fd, NULL, NULL);
855 fcntl(sep->se_fd, F_SETFL, 0);
856 if (ctrl < 0) {
857 if (errno == EINTR || errno == EWOULDBLOCK) {
858 continue;
859 }
860 syslog(LOG_WARNING, "accept (for %s): %m",
861 sep->se_service);
862 continue;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000863 }
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000864 } else {
865 ctrl = sep->se_fd;
Glenn L McGrath06e95652003-02-09 06:51:14 +0000866 }
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000867 sigprocmask(SIG_BLOCK, &blockmask, NULL);
868 pid = 0;
Glenn L McGrathc3b134f2004-01-17 01:26:53 +0000869#ifdef INETD_FEATURE_ENABLED
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000870 if (sep->se_bi == 0 || sep->se_bi->bi_fork)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000871#endif
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000872 {
873 if (sep->se_count++ == 0) {
874 gettimeofday(&sep->se_time, (struct timezone *)0);
875 }
876 else if (sep->se_count >= sep->se_max) {
877 struct timeval now;
878
879 gettimeofday(&now, (struct timezone *)0);
880 if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
881 sep->se_time = now;
882 sep->se_count = 1;
883 } else {
884 syslog(LOG_ERR,
885 "%s/%s server failing (looping), service terminated",
886 sep->se_service, sep->se_proto);
887 FD_CLR(sep->se_fd, &allsock);
888 close(sep->se_fd);
889 sep->se_fd = -1;
890 sep->se_count = 0;
891 nsock--;
892 sigprocmask(SIG_SETMASK, &emptymask, NULL);
893 if (!timingout) {
894 timingout = 1;
895 alarm(RETRYTIME);
896 }
897 continue;
898 }
899 }
900 pid = fork();
901 if (pid < 0) {
902 syslog(LOG_ERR, "fork: %m");
903 if (sep->se_socktype == SOCK_STREAM) {
904 close(ctrl);
905 }
906 sigprocmask(SIG_SETMASK, &emptymask, NULL);
907 sleep(1);
908 continue;
909 }
910 if (pid && sep->se_wait) {
911 sep->se_wait = pid;
912 FD_CLR(sep->se_fd, &allsock);
913 nsock--;
914 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000915 }
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000916 sigprocmask(SIG_SETMASK, &emptymask, NULL);
917 if (pid == 0) {
918#ifdef INETD_FEATURE_ENABLED
919 if (sep->se_bi) {
920 (*sep->se_bi->bi_fn)(ctrl, sep);
921 } else
922#endif
923 {
924 struct passwd *pwd = getpwnam(sep->se_user);
925 if (pwd == NULL) {
926 syslog_err_and_discard_dg(
927 sep->se_socktype,
928 "getpwnam: %s: No such user",
929 sep->se_user);
930 }
931 if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
932 syslog_err_and_discard_dg(sep->se_socktype,
933 "getgrnam: %s: No such group", sep->se_group);
934 }
935 /*
936 * Ok. There are four cases here:
937 * 1. nonroot user, no group specified
938 * 2. nonroot user, some group specified
939 * 3. root user, no group specified
940 * 4. root user, some group specified
941 * In cases 2 and 4 we setgid to the specified
942 * group. In cases 1 and 2 we run initgroups
943 * to run with the groups of the given user.
944 * In case 4 we do setgroups to run with the
945 * given group. In case 3 we do nothing.
946 */
947 if (pwd->pw_uid) {
948 if (sep->se_group) {
949 pwd->pw_gid = grp->gr_gid;
950 }
951 setgid((gid_t)pwd->pw_gid);
952 initgroups(pwd->pw_name, pwd->pw_gid);
953 setuid((uid_t)pwd->pw_uid);
954 } else if (sep->se_group) {
955 setgid((gid_t)grp->gr_gid);
956 setgroups(1, &grp->gr_gid);
957 }
958 dup2(ctrl, 0);
959 close(ctrl);
960 dup2(0, 1);
961 dup2(0, 2);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000962#ifdef RLIMIT_NOFILE
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000963 if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
964 if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
965 syslog(LOG_ERR,"setrlimit: %m");
966 }
967 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000968#endif
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000969 for (ctrl = rlim_ofile_cur-1; --ctrl > 2; ) {
970 (void)close(ctrl);
971 }
972 memset(&sa, 0, sizeof(sa));
973 sa.sa_handler = SIG_DFL;
974 sigaction(SIGPIPE, &sa, NULL);
Glenn L McGrath06e95652003-02-09 06:51:14 +0000975
Glenn L McGrath82d42db2004-02-18 13:12:53 +0000976 execv(sep->se_server, sep->se_argv);
977 syslog_err_and_discard_dg(sep->se_socktype, "execv %s: %m", sep->se_server);
978 }
979 }
980 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
981 close(ctrl);
982 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000983 }
984 }
Glenn L McGrath06e95652003-02-09 06:51:14 +0000985 }
986}
987
988
989/*
990 * Internet services provided internally by inetd:
991 */
992#define BUFSIZE 4096
993
994#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
995/* Echo service -- echo data back */
Glenn L McGrath03a06432004-02-18 13:19:58 +0000996static void echo_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +0000997{
998 char buffer[BUFSIZE];
999 int i;
1000
1001 setproctitle(sep->se_service, s);
1002 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1003 write(s, buffer, i) > 0)
1004 ;
1005 exit(0);
1006}
1007
1008/* Echo service -- echo data back */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001009static void echo_dg(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001010{
1011 char buffer[BUFSIZE];
1012 int i;
1013 size_t size;
1014 struct sockaddr sa;
1015
1016 (void)sep;
1017
1018 size = sizeof(sa);
1019 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
1020 return;
1021 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
1022}
1023#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO */
1024
1025
1026#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
1027/* Discard service -- ignore data */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001028static void discard_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001029{
1030 char buffer[BUFSIZE];
1031
1032 setproctitle(sep->se_service, s);
1033 while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1034 errno == EINTR)
1035 ;
1036 exit(0);
1037}
1038
1039/* Discard service -- ignore data */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001040static void discard_dg(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001041{
1042 char buffer[BUFSIZE];
1043 (void)sep;
1044 read(s, buffer, sizeof(buffer));
1045}
1046#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD */
1047
1048
1049#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
1050#include <ctype.h>
1051#define LINESIZ 72
1052static char ring[128];
1053static char *endring;
1054
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +00001055static void initring(void)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001056{
1057 int i;
1058
1059 endring = ring;
1060
1061 for (i = 0; i <= 128; ++i)
1062 if (isprint(i))
1063 *endring++ = i;
1064}
1065
1066/* Character generator */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001067static void chargen_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001068{
1069 char *rs;
1070 int len;
1071 char text[LINESIZ+2];
1072
1073 setproctitle(sep->se_service, s);
1074
1075 if (!endring) {
1076 initring();
1077 rs = ring;
1078 }
1079
1080 text[LINESIZ] = '\r';
1081 text[LINESIZ + 1] = '\n';
1082 for (rs = ring;;) {
1083 if ((len = endring - rs) >= LINESIZ)
Glenn L McGrath3e77b4e2004-01-17 01:44:32 +00001084 memcpy(rs, text, LINESIZ);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001085 else {
Glenn L McGrath3e77b4e2004-01-17 01:44:32 +00001086 memcpy(rs, text, len);
1087 memcpy(ring, text + len, LINESIZ - len);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001088 }
1089 if (++rs == endring)
1090 rs = ring;
1091 if (write(s, text, sizeof(text)) != sizeof(text))
1092 break;
1093 }
1094 exit(0);
1095}
1096
1097/* Character generator */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001098static void chargen_dg(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001099{
1100 struct sockaddr sa;
1101 static char *rs;
1102 size_t len, size;
1103 char text[LINESIZ+2];
1104
1105 (void)sep;
1106
1107 if (endring == 0) {
1108 initring();
1109 rs = ring;
1110 }
1111
1112 size = sizeof(sa);
1113 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1114 return;
1115
1116 if ((len = endring - rs) >= LINESIZ)
Glenn L McGrath3e77b4e2004-01-17 01:44:32 +00001117 memcpy(rs, text, LINESIZ);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001118 else {
Glenn L McGrath3e77b4e2004-01-17 01:44:32 +00001119 memcpy(rs, text, len);
1120 memcpy(ring, text + len, LINESIZ - len);
Glenn L McGrath06e95652003-02-09 06:51:14 +00001121 }
1122 if (++rs == endring)
1123 rs = ring;
1124 text[LINESIZ] = '\r';
1125 text[LINESIZ + 1] = '\n';
1126 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1127}
1128#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN */
1129
1130
1131#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
1132/*
1133 * Return a machine readable date and time, in the form of the
1134 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1135 * returns the number of seconds since midnight, Jan 1, 1970,
1136 * we must add 2208988800 seconds to this figure to make up for
1137 * some seventy years Bell Labs was asleep.
1138 */
1139
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +00001140static long machtime(void)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001141{
1142 struct timeval tv;
1143
1144 if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1145 fprintf(stderr, "Unable to get time of day\n");
1146 return (0L);
1147 }
1148 return (htonl((long)tv.tv_sec + 2208988800UL));
1149}
1150
Glenn L McGrath03a06432004-02-18 13:19:58 +00001151static void machtime_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001152{
1153 long result;
1154 (void)sep;
1155
1156 result = machtime();
1157 write(s, (char *) &result, sizeof(result));
1158}
1159
Glenn L McGrath03a06432004-02-18 13:19:58 +00001160static void machtime_dg(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001161{
1162 long result;
1163 struct sockaddr sa;
1164 size_t size;
1165 (void)sep;
1166
1167 size = sizeof(sa);
1168 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1169 return;
1170 result = machtime();
1171 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1172}
1173#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME */
1174
1175
1176#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
1177/* Return human-readable time of day */
Glenn L McGrathff6ec8a2004-01-17 02:47:45 +00001178static int human_readable_time_sprintf(char *buffer)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001179{
1180 time_t clocc = time(NULL);
1181
1182 return sprintf(buffer, "%.24s\r\n", ctime(&clocc));
1183}
1184
Glenn L McGrath03a06432004-02-18 13:19:58 +00001185static void daytime_stream(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001186{
1187 char buffer[256];
1188 size_t st = human_readable_time_sprintf(buffer);
1189
1190 (void)sep;
1191
1192 write(s, buffer, st);
1193}
1194
1195/* Return human-readable time of day */
Glenn L McGrath03a06432004-02-18 13:19:58 +00001196static void daytime_dg(int s, servtab_t *sep)
Glenn L McGrath06e95652003-02-09 06:51:14 +00001197{
1198 char buffer[256];
1199 struct sockaddr sa;
1200 size_t size;
1201
1202 (void)sep;
1203
1204 size = sizeof(sa);
1205 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1206 return;
1207 size = human_readable_time_sprintf(buffer);
1208 sendto(s, buffer, size, 0, &sa, sizeof(sa));
1209}
1210#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME */