1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167#include <syslog.h>
168#include <sys/un.h>
169
170#include "libbb.h"
171
172#if ENABLE_FEATURE_INETD_RPC
173# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
174# error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
175# endif
176# include <rpc/rpc.h>
177# include <rpc/pmap_clnt.h>
178#endif
179
180#if !BB_MMU
181
182
183#undef ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
184#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0
185#endif
186
187#define _PATH_INETDPID "/var/run/inetd.pid"
188
189#define CNT_INTERVAL 60
190#define RETRYTIME 60
191
192
193
194#ifndef RLIMIT_NOFILE
195#define RLIMIT_NOFILE RLIMIT_OFILE
196#endif
197
198#ifndef OPEN_MAX
199#define OPEN_MAX 64
200#endif
201
202
203#define FD_MARGIN 8
204
205#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD \
206 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO \
207 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN \
208 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME \
209 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
210# define INETD_BUILTINS_ENABLED
211#endif
212
213typedef struct servtab_t {
214
215 int se_fd;
216
217
218 char *se_local_hostname;
219 char *se_service;
220
221 char *se_proto;
222#if ENABLE_FEATURE_INETD_RPC
223 int se_rpcprog;
224 int se_rpcver_lo;
225 int se_rpcver_hi;
226#define is_rpc_service(sep) ((sep)->se_rpcver_lo != 0)
227#else
228#define is_rpc_service(sep) 0
229#endif
230 pid_t se_wait;
231
232 socktype_t se_socktype;
233 family_t se_family;
234
235 smallint se_proto_no;
236 smallint se_checked;
237 unsigned se_max;
238 unsigned se_count;
239 unsigned se_time;
240 char *se_user;
241 char *se_group;
242#ifdef INETD_BUILTINS_ENABLED
243 const struct builtin *se_builtin;
244#endif
245 struct servtab_t *se_next;
246 len_and_sockaddr *se_lsa;
247 char *se_program;
248#define MAXARGV 20
249 char *se_argv[MAXARGV + 1];
250} servtab_t;
251
252#ifdef INETD_BUILTINS_ENABLED
253
254#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
255static void FAST_FUNC echo_stream(int, servtab_t *);
256static void FAST_FUNC echo_dg(int, servtab_t *);
257#endif
258
259#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
260static void FAST_FUNC discard_stream(int, servtab_t *);
261static void FAST_FUNC discard_dg(int, servtab_t *);
262#endif
263
264#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
265static void FAST_FUNC machtime_stream(int, servtab_t *);
266static void FAST_FUNC machtime_dg(int, servtab_t *);
267#endif
268
269#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
270static void FAST_FUNC daytime_stream(int, servtab_t *);
271static void FAST_FUNC daytime_dg(int, servtab_t *);
272#endif
273
274#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
275static void FAST_FUNC chargen_stream(int, servtab_t *);
276static void FAST_FUNC chargen_dg(int, servtab_t *);
277#endif
278
279struct builtin {
280
281 char bi_service7[7];
282 uint8_t bi_fork;
283 void (*bi_stream_fn)(int, servtab_t *) FAST_FUNC;
284 void (*bi_dgram_fn)(int, servtab_t *) FAST_FUNC;
285};
286
287static const struct builtin builtins[] = {
288#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
289 { "echo", 1, echo_stream, echo_dg },
290#endif
291#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
292 { "discard", 1, discard_stream, discard_dg },
293#endif
294#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
295 { "chargen", 1, chargen_stream, chargen_dg },
296#endif
297#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
298 { "time", 0, machtime_stream, machtime_dg },
299#endif
300#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
301 { "daytime", 0, daytime_stream, daytime_dg },
302#endif
303};
304#endif
305
306struct globals {
307 rlim_t rlim_ofile_cur;
308 struct rlimit rlim_ofile;
309 servtab_t *serv_list;
310 int global_queuelen;
311 int maxsock;
312
313
314 int prev_maxsock;
315 unsigned max_concurrency;
316 smallint alarm_armed;
317 uid_t real_uid;
318 const char *config_filename;
319 parser_t *parser;
320 char *default_local_hostname;
321#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
322 char *end_ring;
323 char *ring_pos;
324 char ring[128];
325#endif
326 fd_set allsock;
327
328 char line[256];
329} FIX_ALIASING;
330#define G (*(struct globals*)&bb_common_bufsiz1)
331enum { LINE_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line) };
332struct BUG_G_too_big {
333 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
334};
335#define rlim_ofile_cur (G.rlim_ofile_cur )
336#define rlim_ofile (G.rlim_ofile )
337#define serv_list (G.serv_list )
338#define global_queuelen (G.global_queuelen)
339#define maxsock (G.maxsock )
340#define prev_maxsock (G.prev_maxsock )
341#define max_concurrency (G.max_concurrency)
342#define alarm_armed (G.alarm_armed )
343#define real_uid (G.real_uid )
344#define config_filename (G.config_filename)
345#define parser (G.parser )
346#define default_local_hostname (G.default_local_hostname)
347#define first_ps_byte (G.first_ps_byte )
348#define last_ps_byte (G.last_ps_byte )
349#define end_ring (G.end_ring )
350#define ring_pos (G.ring_pos )
351#define ring (G.ring )
352#define allsock (G.allsock )
353#define line (G.line )
354#define INIT_G() do { \
355 rlim_ofile_cur = OPEN_MAX; \
356 global_queuelen = 128; \
357 config_filename = "/etc/inetd.conf"; \
358} while (0)
359
360static void maybe_close(int fd)
361{
362 if (fd >= 0)
363 close(fd);
364}
365
366
367static len_and_sockaddr *xzalloc_lsa(int family)
368{
369 len_and_sockaddr *lsa;
370 int sz;
371
372 sz = sizeof(struct sockaddr_in);
373 if (family == AF_UNIX)
374 sz = sizeof(struct sockaddr_un);
375#if ENABLE_FEATURE_IPV6
376 if (family == AF_INET6)
377 sz = sizeof(struct sockaddr_in6);
378#endif
379 lsa = xzalloc(LSA_LEN_SIZE + sz);
380 lsa->len = sz;
381 lsa->u.sa.sa_family = family;
382 return lsa;
383}
384
385static void rearm_alarm(void)
386{
387 if (!alarm_armed) {
388 alarm_armed = 1;
389 alarm(RETRYTIME);
390 }
391}
392
393static void block_CHLD_HUP_ALRM(sigset_t *m)
394{
395 sigemptyset(m);
396 sigaddset(m, SIGCHLD);
397 sigaddset(m, SIGHUP);
398 sigaddset(m, SIGALRM);
399 sigprocmask(SIG_BLOCK, m, m);
400}
401
402static void restore_sigmask(sigset_t *m)
403{
404 sigprocmask(SIG_SETMASK, m, NULL);
405}
406
407#if ENABLE_FEATURE_INETD_RPC
408static void register_rpc(servtab_t *sep)
409{
410 int n;
411 struct sockaddr_in ir_sin;
412 socklen_t size;
413
414 size = sizeof(ir_sin);
415 if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
416 bb_perror_msg("getsockname");
417 return;
418 }
419
420 for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) {
421 pmap_unset(sep->se_rpcprog, n);
422 if (!pmap_set(sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port)))
423 bb_perror_msg("%s %s: pmap_set(%u,%u,%u,%u)",
424 sep->se_service, sep->se_proto,
425 sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port));
426 }
427}
428
429static void unregister_rpc(servtab_t *sep)
430{
431 int n;
432
433 for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) {
434 if (!pmap_unset(sep->se_rpcprog, n))
435 bb_perror_msg("pmap_unset(%u,%u)", sep->se_rpcprog, n);
436 }
437}
438#endif
439
440static void bump_nofile(void)
441{
442 enum { FD_CHUNK = 32 };
443 struct rlimit rl;
444
445
446 getrlimit(RLIMIT_NOFILE, &rl);
447 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
448 rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
449 if (rl.rlim_cur <= rlim_ofile_cur) {
450 bb_error_msg("can't extend file limit, max = %d",
451 (int) rl.rlim_cur);
452 return;
453 }
454
455 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
456 bb_perror_msg("setrlimit");
457 return;
458 }
459
460 rlim_ofile_cur = rl.rlim_cur;
461}
462
463static void remove_fd_from_set(int fd)
464{
465 if (fd >= 0) {
466 FD_CLR(fd, &allsock);
467 maxsock = -1;
468 }
469}
470
471static void add_fd_to_set(int fd)
472{
473 if (fd >= 0) {
474 FD_SET(fd, &allsock);
475 if (maxsock >= 0 && fd > maxsock) {
476 prev_maxsock = maxsock = fd;
477 if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN)
478 bump_nofile();
479 }
480 }
481}
482
483static void recalculate_maxsock(void)
484{
485 int fd = 0;
486
487
488
489 maxsock = 0;
490 while (fd <= prev_maxsock) {
491 if (FD_ISSET(fd, &allsock))
492 maxsock = fd;
493 fd++;
494 }
495 prev_maxsock = maxsock;
496 if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
497 bump_nofile();
498}
499
500static void prepare_socket_fd(servtab_t *sep)
501{
502 int r, fd;
503
504 fd = socket(sep->se_family, sep->se_socktype, 0);
505 if (fd < 0) {
506 bb_perror_msg("socket");
507 return;
508 }
509 setsockopt_reuseaddr(fd);
510
511#if ENABLE_FEATURE_INETD_RPC
512 if (is_rpc_service(sep)) {
513 struct passwd *pwd;
514
515
516
517 set_nport(&sep->se_lsa->u.sa, 0);
518
519
520
521 if (real_uid == 0 && sep->se_family == AF_INET
522 && (pwd = getpwnam(sep->se_user)) != NULL
523 && pwd->pw_uid == 0
524 ) {
525 r = bindresvport(fd, &sep->se_lsa->u.sin);
526 } else {
527 r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len);
528 }
529 if (r == 0) {
530 int saveerrno = errno;
531
532 getsockname(fd, &sep->se_lsa->u.sa, &sep->se_lsa->len);
533 errno = saveerrno;
534 }
535 } else
536#endif
537 {
538 if (sep->se_family == AF_UNIX) {
539 struct sockaddr_un *sun;
540 sun = (struct sockaddr_un*)&(sep->se_lsa->u.sa);
541 unlink(sun->sun_path);
542 }
543 r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len);
544 }
545 if (r < 0) {
546 bb_perror_msg("%s/%s: bind",
547 sep->se_service, sep->se_proto);
548 close(fd);
549 rearm_alarm();
550 return;
551 }
552 if (sep->se_socktype == SOCK_STREAM)
553 listen(fd, global_queuelen);
554
555 add_fd_to_set(fd);
556 sep->se_fd = fd;
557}
558
559static int reopen_config_file(void)
560{
561 free(default_local_hostname);
562 default_local_hostname = xstrdup("*");
563 if (parser != NULL)
564 config_close(parser);
565 parser = config_open(config_filename);
566 return (parser != NULL);
567}
568
569static void close_config_file(void)
570{
571 if (parser) {
572 config_close(parser);
573 parser = NULL;
574 }
575}
576
577static void free_servtab_strings(servtab_t *cp)
578{
579 int i;
580
581 free(cp->se_local_hostname);
582 free(cp->se_service);
583 free(cp->se_proto);
584 free(cp->se_user);
585 free(cp->se_group);
586 free(cp->se_lsa);
587 free(cp->se_program);
588 for (i = 0; i < MAXARGV; i++)
589 free(cp->se_argv[i]);
590}
591
592static servtab_t *new_servtab(void)
593{
594 servtab_t *newtab = xzalloc(sizeof(servtab_t));
595 newtab->se_fd = -1;
596 return newtab;
597}
598
599static servtab_t *dup_servtab(servtab_t *sep)
600{
601 servtab_t *newtab;
602 int argc;
603
604 newtab = new_servtab();
605 *newtab = *sep;
606
607 newtab->se_service = xstrdup(newtab->se_service);
608 newtab->se_proto = xstrdup(newtab->se_proto);
609 newtab->se_user = xstrdup(newtab->se_user);
610 newtab->se_group = xstrdup(newtab->se_group);
611 newtab->se_program = xstrdup(newtab->se_program);
612 for (argc = 0; argc <= MAXARGV; argc++)
613 newtab->se_argv[argc] = xstrdup(newtab->se_argv[argc]);
614
615
616
617
618 return newtab;
619}
620
621
622static servtab_t *parse_one_line(void)
623{
624 int argc;
625 char *token[6+MAXARGV];
626 char *p, *arg;
627 char *hostdelim;
628 servtab_t *sep;
629 servtab_t *nsep;
630 new:
631 sep = new_servtab();
632 more:
633 argc = config_read(parser, token, 6+MAXARGV, 1, "# \t", PARSE_NORMAL);
634 if (!argc) {
635 free(sep);
636 return NULL;
637 }
638
639
640
641 arg = token[0];
642 hostdelim = strrchr(arg, ':');
643 if (hostdelim) {
644 *hostdelim = '\0';
645 sep->se_local_hostname = xstrdup(arg);
646 arg = hostdelim + 1;
647 if (*arg == '\0' && argc == 1) {
648
649
650 free(default_local_hostname);
651 default_local_hostname = sep->se_local_hostname;
652 goto more;
653 }
654 } else
655 sep->se_local_hostname = xstrdup(default_local_hostname);
656
657
658 sep->se_service = xstrdup(arg);
659
660
661 if (argc < 6) {
662 parse_err:
663 bb_error_msg("parse error on line %u, line is ignored",
664 parser->lineno);
665 free_servtab_strings(sep);
666
667
668
669 free(sep);
670 goto new;
671 }
672
673 {
674 static const int8_t SOCK_xxx[] ALIGN1 = {
675 -1,
676 SOCK_STREAM, SOCK_DGRAM, SOCK_RDM,
677 SOCK_SEQPACKET, SOCK_RAW
678 };
679 sep->se_socktype = SOCK_xxx[1 + index_in_strings(
680 "stream""\0" "dgram""\0" "rdm""\0"
681 "seqpacket""\0" "raw""\0"
682 , token[1])];
683 }
684
685
686 sep->se_proto = arg = xstrdup(token[2]);
687 if (strcmp(arg, "unix") == 0) {
688 sep->se_family = AF_UNIX;
689 } else {
690 char *six;
691 sep->se_family = AF_INET;
692 six = last_char_is(arg, '6');
693 if (six) {
694#if ENABLE_FEATURE_IPV6
695 *six = '\0';
696 sep->se_family = AF_INET6;
697#else
698 bb_error_msg("%s: no support for IPv6", sep->se_proto);
699 goto parse_err;
700#endif
701 }
702 if (strncmp(arg, "rpc/", 4) == 0) {
703#if ENABLE_FEATURE_INETD_RPC
704 unsigned n;
705 arg += 4;
706 p = strchr(sep->se_service, '/');
707 if (p == NULL) {
708 bb_error_msg("no rpc version: '%s'", sep->se_service);
709 goto parse_err;
710 }
711 *p++ = '\0';
712 n = bb_strtou(p, &p, 10);
713 if (n > INT_MAX) {
714 bad_ver_spec:
715 bb_error_msg("bad rpc version");
716 goto parse_err;
717 }
718 sep->se_rpcver_lo = sep->se_rpcver_hi = n;
719 if (*p == '-') {
720 p++;
721 n = bb_strtou(p, &p, 10);
722 if (n > INT_MAX || (int)n < sep->se_rpcver_lo)
723 goto bad_ver_spec;
724 sep->se_rpcver_hi = n;
725 }
726 if (*p != '\0')
727 goto bad_ver_spec;
728#else
729 bb_error_msg("no support for rpc services");
730 goto parse_err;
731#endif
732 }
733
734 if (strcmp(arg, "tcp") == 0)
735 sep->se_proto_no = IPPROTO_TCP;
736 if (strcmp(arg, "udp") == 0)
737 sep->se_proto_no = IPPROTO_UDP;
738 if (six)
739 *six = '6';
740 if (!sep->se_proto_no)
741 goto parse_err;
742 }
743
744
745 arg = token[3];
746 sep->se_max = max_concurrency;
747 p = strchr(arg, '.');
748 if (p) {
749 *p++ = '\0';
750 sep->se_max = bb_strtou(p, NULL, 10);
751 if (errno)
752 goto parse_err;
753 }
754 sep->se_wait = (arg[0] != 'n' || arg[1] != 'o');
755 if (!sep->se_wait)
756 arg += 2;
757 if (strcmp(arg, "wait") != 0)
758 goto parse_err;
759
760
761 sep->se_user = xstrdup(token[4]);
762 arg = strchr(sep->se_user, '.');
763 if (arg == NULL)
764 arg = strchr(sep->se_user, ':');
765 if (arg) {
766 *arg++ = '\0';
767 sep->se_group = xstrdup(arg);
768 }
769
770
771 sep->se_program = xstrdup(token[5]);
772#ifdef INETD_BUILTINS_ENABLED
773 if (strcmp(sep->se_program, "internal") == 0
774 && strlen(sep->se_service) <= 7
775 && (sep->se_socktype == SOCK_STREAM
776 || sep->se_socktype == SOCK_DGRAM)
777 ) {
778 unsigned i;
779 for (i = 0; i < ARRAY_SIZE(builtins); i++)
780 if (strncmp(builtins[i].bi_service7, sep->se_service, 7) == 0)
781 goto found_bi;
782 bb_error_msg("unknown internal service %s", sep->se_service);
783 goto parse_err;
784 found_bi:
785 sep->se_builtin = &builtins[i];
786
787 if (sep->se_wait != (sep->se_socktype == SOCK_DGRAM))
788 goto parse_err;
789 }
790#endif
791 argc = 0;
792 while ((arg = token[6+argc]) != NULL && argc < MAXARGV)
793 sep->se_argv[argc++] = xstrdup(arg);
794
795
796
797
798 if (argc == 0)
799 sep->se_argv[0] = xstrdup(sep->se_program);
800
801
802 if (sep->se_socktype == SOCK_STREAM) {
803 if (sep->se_proto_no == IPPROTO_UDP)
804 goto parse_err;
805 }
806 if (sep->se_socktype == SOCK_DGRAM) {
807 if (sep->se_proto_no == IPPROTO_TCP)
808 goto parse_err;
809 }
810
811
812
813
814
815
816
817
818 while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) {
819 nsep = dup_servtab(sep);
820
821
822 *hostdelim++ = '\0';
823 nsep->se_local_hostname = xstrdup(hostdelim);
824 nsep->se_next = sep->se_next;
825 sep->se_next = nsep;
826 }
827
828
829
830
831
832 return sep;
833}
834
835static servtab_t *insert_in_servlist(servtab_t *cp)
836{
837 servtab_t *sep;
838 sigset_t omask;
839
840 sep = new_servtab();
841 *sep = *cp;
842 sep->se_fd = -1;
843#if ENABLE_FEATURE_INETD_RPC
844 sep->se_rpcprog = -1;
845#endif
846 block_CHLD_HUP_ALRM(&omask);
847 sep->se_next = serv_list;
848 serv_list = sep;
849 restore_sigmask(&omask);
850 return sep;
851}
852
853static int same_serv_addr_proto(servtab_t *old, servtab_t *new)
854{
855 if (strcmp(old->se_local_hostname, new->se_local_hostname) != 0)
856 return 0;
857 if (strcmp(old->se_service, new->se_service) != 0)
858 return 0;
859 if (strcmp(old->se_proto, new->se_proto) != 0)
860 return 0;
861 return 1;
862}
863
864static void reread_config_file(int sig UNUSED_PARAM)
865{
866 servtab_t *sep, *cp, **sepp;
867 len_and_sockaddr *lsa;
868 sigset_t omask;
869 unsigned n;
870 uint16_t port;
871 int save_errno = errno;
872
873 if (!reopen_config_file())
874 goto ret;
875 for (sep = serv_list; sep; sep = sep->se_next)
876 sep->se_checked = 0;
877
878 goto first_line;
879 while (1) {
880 if (cp == NULL) {
881 first_line:
882 cp = parse_one_line();
883 if (cp == NULL)
884 break;
885 }
886 for (sep = serv_list; sep; sep = sep->se_next)
887 if (same_serv_addr_proto(sep, cp))
888 goto equal_servtab;
889
890 sep = insert_in_servlist(cp);
891 goto after_check;
892 equal_servtab:
893 {
894 int i;
895
896 block_CHLD_HUP_ALRM(&omask);
897#if ENABLE_FEATURE_INETD_RPC
898 if (is_rpc_service(sep))
899 unregister_rpc(sep);
900 sep->se_rpcver_lo = cp->se_rpcver_lo;
901 sep->se_rpcver_hi = cp->se_rpcver_hi;
902#endif
903 if (cp->se_wait == 0) {
904
905
906
907
908
909 add_fd_to_set(sep->se_fd);
910 }
911 sep->se_wait = cp->se_wait;
912 sep->se_max = cp->se_max;
913
914#define SWAP(type, a, b) do { type c = (type)a; a = (type)b; b = (type)c; } while (0)
915 SWAP(char*, sep->se_user, cp->se_user);
916 SWAP(char*, sep->se_group, cp->se_group);
917 SWAP(char*, sep->se_program, cp->se_program);
918 for (i = 0; i < MAXARGV; i++)
919 SWAP(char*, sep->se_argv[i], cp->se_argv[i]);
920#undef SWAP
921 restore_sigmask(&omask);
922 free_servtab_strings(cp);
923 }
924 after_check:
925
926
927 sep->se_checked = 1;
928
929
930 switch (sep->se_family) {
931 struct sockaddr_un *sun;
932 case AF_UNIX:
933 lsa = xzalloc_lsa(AF_UNIX);
934 sun = (struct sockaddr_un*)&lsa->u.sa;
935 safe_strncpy(sun->sun_path, sep->se_service, sizeof(sun->sun_path));
936 break;
937
938 default:
939 n = bb_strtou(sep->se_service, NULL, 10);
940#if ENABLE_FEATURE_INETD_RPC
941 if (is_rpc_service(sep)) {
942 sep->se_rpcprog = n;
943 if (errno) {
944 struct rpcent *rp = getrpcbyname(sep->se_service);
945 if (rp == NULL) {
946 bb_error_msg("%s: unknown rpc service", sep->se_service);
947 goto next_cp;
948 }
949 sep->se_rpcprog = rp->r_number;
950 }
951 if (sep->se_fd == -1)
952 prepare_socket_fd(sep);
953 if (sep->se_fd != -1)
954 register_rpc(sep);
955 goto next_cp;
956 }
957#endif
958
959 port = htons(n);
960 if (errno || n > 0xffff) {
961 char protoname[4];
962 struct servent *sp;
963
964 safe_strncpy(protoname, sep->se_proto, 4);
965 sp = getservbyname(sep->se_service, protoname);
966 if (sp == NULL) {
967 bb_error_msg("%s/%s: unknown service",
968 sep->se_service, sep->se_proto);
969 goto next_cp;
970 }
971 port = sp->s_port;
972 }
973 if (LONE_CHAR(sep->se_local_hostname, '*')) {
974 lsa = xzalloc_lsa(sep->se_family);
975 set_nport(&lsa->u.sa, port);
976 } else {
977 lsa = host_and_af2sockaddr(sep->se_local_hostname,
978 ntohs(port), sep->se_family);
979 if (!lsa) {
980 bb_error_msg("%s/%s: unknown host '%s'",
981 sep->se_service, sep->se_proto,
982 sep->se_local_hostname);
983 goto next_cp;
984 }
985 }
986 break;
987 }
988
989
990 if (sep->se_lsa == NULL
991 || lsa->len != sep->se_lsa->len
992 || memcmp(&lsa->u.sa, &sep->se_lsa->u.sa, lsa->len) != 0
993 ) {
994 remove_fd_from_set(sep->se_fd);
995 maybe_close(sep->se_fd);
996 free(sep->se_lsa);
997 sep->se_lsa = lsa;
998 sep->se_fd = -1;
999 } else {
1000 free(lsa);
1001 }
1002 if (sep->se_fd == -1)
1003 prepare_socket_fd(sep);
1004 next_cp:
1005 sep = cp->se_next;
1006 free(cp);
1007 cp = sep;
1008 }
1009 close_config_file();
1010
1011
1012
1013 block_CHLD_HUP_ALRM(&omask);
1014 sepp = &serv_list;
1015 while ((sep = *sepp)) {
1016 if (sep->se_checked) {
1017 sepp = &sep->se_next;
1018 continue;
1019 }
1020 *sepp = sep->se_next;
1021 remove_fd_from_set(sep->se_fd);
1022 maybe_close(sep->se_fd);
1023#if ENABLE_FEATURE_INETD_RPC
1024 if (is_rpc_service(sep))
1025 unregister_rpc(sep);
1026#endif
1027 if (sep->se_family == AF_UNIX)
1028 unlink(sep->se_service);
1029 free_servtab_strings(sep);
1030 free(sep);
1031 }
1032 restore_sigmask(&omask);
1033 ret:
1034 errno = save_errno;
1035}
1036
1037static void reap_child(int sig UNUSED_PARAM)
1038{
1039 pid_t pid;
1040 int status;
1041 servtab_t *sep;
1042 int save_errno = errno;
1043
1044 for (;;) {
1045 pid = wait_any_nohang(&status);
1046 if (pid <= 0)
1047 break;
1048 for (sep = serv_list; sep; sep = sep->se_next) {
1049 if (sep->se_wait != pid)
1050 continue;
1051
1052 if (WIFEXITED(status) && WEXITSTATUS(status))
1053 bb_error_msg("%s: exit status %u",
1054 sep->se_program, WEXITSTATUS(status));
1055 else if (WIFSIGNALED(status))
1056 bb_error_msg("%s: exit signal %u",
1057 sep->se_program, WTERMSIG(status));
1058 sep->se_wait = 1;
1059 add_fd_to_set(sep->se_fd);
1060 break;
1061 }
1062 }
1063 errno = save_errno;
1064}
1065
1066static void retry_network_setup(int sig UNUSED_PARAM)
1067{
1068 int save_errno = errno;
1069 servtab_t *sep;
1070
1071 alarm_armed = 0;
1072 for (sep = serv_list; sep; sep = sep->se_next) {
1073 if (sep->se_fd == -1) {
1074 prepare_socket_fd(sep);
1075#if ENABLE_FEATURE_INETD_RPC
1076 if (sep->se_fd != -1 && is_rpc_service(sep))
1077 register_rpc(sep);
1078#endif
1079 }
1080 }
1081 errno = save_errno;
1082}
1083
1084static void clean_up_and_exit(int sig UNUSED_PARAM)
1085{
1086 servtab_t *sep;
1087
1088
1089 for (sep = serv_list; sep; sep = sep->se_next) {
1090 if (sep->se_fd == -1)
1091 continue;
1092
1093 switch (sep->se_family) {
1094 case AF_UNIX:
1095 unlink(sep->se_service);
1096 break;
1097 default:
1098#if ENABLE_FEATURE_INETD_RPC
1099 if (sep->se_wait == 1 && is_rpc_service(sep))
1100 unregister_rpc(sep);
1101#endif
1102 break;
1103 }
1104 if (ENABLE_FEATURE_CLEAN_UP)
1105 close(sep->se_fd);
1106 }
1107 remove_pidfile(_PATH_INETDPID);
1108 exit(EXIT_SUCCESS);
1109}
1110
1111int inetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1112int inetd_main(int argc UNUSED_PARAM, char **argv)
1113{
1114 struct sigaction sa, saved_pipe_handler;
1115 servtab_t *sep, *sep2;
1116 struct passwd *pwd;
1117 struct group *grp = grp;
1118 int opt;
1119 pid_t pid;
1120 sigset_t omask;
1121
1122 INIT_G();
1123
1124 real_uid = getuid();
1125 if (real_uid != 0)
1126 config_filename = NULL;
1127
1128 opt_complementary = "R+:q+";
1129 opt = getopt32(argv, "R:feq:", &max_concurrency, &global_queuelen);
1130 argv += optind;
1131
1132 if (argv[0])
1133 config_filename = argv[0];
1134 if (config_filename == NULL)
1135 bb_error_msg_and_die("non-root must specify config file");
1136 if (!(opt & 2))
1137 bb_daemonize_or_rexec(0, argv - optind);
1138 else
1139 bb_sanitize_stdio();
1140 if (!(opt & 4)) {
1141
1142
1143
1144
1145
1146 openlog(applet_name, LOG_PID | LOG_NDELAY, LOG_DAEMON);
1147 logmode = LOGMODE_SYSLOG;
1148 }
1149
1150 if (real_uid == 0) {
1151
1152 gid_t gid = getgid();
1153 setgroups(1, &gid);
1154 }
1155
1156 write_pidfile(_PATH_INETDPID);
1157
1158
1159 getrlimit(RLIMIT_NOFILE, &rlim_ofile);
1160 rlim_ofile_cur = rlim_ofile.rlim_cur;
1161 if (rlim_ofile_cur == RLIM_INFINITY)
1162 rlim_ofile_cur = OPEN_MAX;
1163
1164 memset(&sa, 0, sizeof(sa));
1165
1166 sigaddset(&sa.sa_mask, SIGALRM);
1167 sigaddset(&sa.sa_mask, SIGCHLD);
1168 sigaddset(&sa.sa_mask, SIGHUP);
1169
1170
1171 sa.sa_handler = retry_network_setup;
1172 sigaction_set(SIGALRM, &sa);
1173
1174 sa.sa_handler = reread_config_file;
1175 sigaction_set(SIGHUP, &sa);
1176
1177 sa.sa_handler = reap_child;
1178 sigaction_set(SIGCHLD, &sa);
1179
1180 sa.sa_handler = clean_up_and_exit;
1181 sigaction_set(SIGTERM, &sa);
1182 sa.sa_handler = clean_up_and_exit;
1183 sigaction_set(SIGINT, &sa);
1184 sa.sa_handler = SIG_IGN;
1185 sigaction(SIGPIPE, &sa, &saved_pipe_handler);
1186
1187 reread_config_file(SIGHUP);
1188
1189 for (;;) {
1190 int ready_fd_cnt;
1191 int ctrl, accepted_fd, new_udp_fd;
1192 fd_set readable;
1193
1194 if (maxsock < 0)
1195 recalculate_maxsock();
1196
1197 readable = allsock;
1198
1199
1200
1201 ready_fd_cnt = select(maxsock + 1, &readable, NULL, NULL, NULL);
1202 if (ready_fd_cnt < 0) {
1203 if (errno != EINTR) {
1204 bb_perror_msg("select");
1205 sleep(1);
1206 }
1207 continue;
1208 }
1209
1210 for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) {
1211 if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
1212 continue;
1213
1214 ready_fd_cnt--;
1215 ctrl = sep->se_fd;
1216 accepted_fd = -1;
1217 new_udp_fd = -1;
1218 if (!sep->se_wait) {
1219 if (sep->se_socktype == SOCK_STREAM) {
1220 ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
1221 if (ctrl < 0) {
1222 if (errno != EINTR)
1223 bb_perror_msg("accept (for %s)", sep->se_service);
1224 continue;
1225 }
1226 }
1227
1228 if (sep->se_socktype == SOCK_DGRAM
1229 && sep->se_family != AF_UNIX
1230 ) {
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240 new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0);
1241 if (new_udp_fd < 0) {
1242 udp_err:
1243 recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT);
1244 continue;
1245 }
1246 setsockopt_reuseaddr(new_udp_fd);
1247
1248
1249
1250 if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) {
1251 close(new_udp_fd);
1252 goto udp_err;
1253 }
1254 }
1255 }
1256
1257 block_CHLD_HUP_ALRM(&omask);
1258 pid = 0;
1259#ifdef INETD_BUILTINS_ENABLED
1260
1261 if (sep->se_builtin == NULL
1262 || (sep->se_socktype == SOCK_STREAM
1263 && sep->se_builtin->bi_fork))
1264#endif
1265 {
1266 if (sep->se_max != 0) {
1267 if (++sep->se_count == 1)
1268 sep->se_time = monotonic_sec();
1269 else if (sep->se_count >= sep->se_max) {
1270 unsigned now = monotonic_sec();
1271
1272 if (now - sep->se_time <= CNT_INTERVAL) {
1273 bb_error_msg("%s/%s: too many connections, pausing",
1274 sep->se_service, sep->se_proto);
1275 remove_fd_from_set(sep->se_fd);
1276 close(sep->se_fd);
1277 sep->se_fd = -1;
1278 sep->se_count = 0;
1279 rearm_alarm();
1280 restore_sigmask(&omask);
1281 maybe_close(accepted_fd);
1282 continue;
1283 }
1284 sep->se_count = 0;
1285 }
1286 }
1287
1288
1289
1290#ifdef INETD_BUILTINS_ENABLED
1291 if (BB_MMU && sep->se_builtin)
1292 pid = fork();
1293 else
1294#endif
1295 pid = vfork();
1296
1297 if (pid < 0) {
1298 bb_perror_msg("vfork"+1);
1299 sleep(1);
1300 restore_sigmask(&omask);
1301 maybe_close(accepted_fd);
1302 continue;
1303 }
1304 if (pid == 0)
1305 pid--;
1306 }
1307
1308
1309 if (pid > 0) {
1310 if (sep->se_wait) {
1311
1312
1313 sep->se_wait = pid;
1314 remove_fd_from_set(sep->se_fd);
1315 }
1316 if (new_udp_fd >= 0) {
1317
1318
1319 xmove_fd(new_udp_fd, sep->se_fd);
1320 }
1321 restore_sigmask(&omask);
1322 maybe_close(accepted_fd);
1323 continue;
1324 }
1325
1326
1327#ifdef INETD_BUILTINS_ENABLED
1328 if (sep->se_builtin) {
1329 if (pid) {
1330 close(sep->se_fd);
1331 logmode = LOGMODE_NONE;
1332 }
1333 restore_sigmask(&omask);
1334 if (sep->se_socktype == SOCK_STREAM)
1335 sep->se_builtin->bi_stream_fn(ctrl, sep);
1336 else
1337 sep->se_builtin->bi_dgram_fn(ctrl, sep);
1338 if (pid)
1339 _exit(EXIT_FAILURE);
1340 maybe_close(accepted_fd);
1341 continue;
1342 }
1343#endif
1344
1345 setsid();
1346
1347 if (new_udp_fd >= 0) {
1348 len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
1349
1350 int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
1351 &lsa->u.sa, &lsa->len);
1352 if (r < 0)
1353 goto do_exit1;
1354
1355
1356
1357 connect(ctrl, &lsa->u.sa, lsa->len);
1358 free(lsa);
1359 }
1360
1361 pwd = getpwnam(sep->se_user);
1362 if (pwd == NULL) {
1363 bb_error_msg("%s: no such %s", sep->se_user, "user");
1364 goto do_exit1;
1365 }
1366 if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
1367 bb_error_msg("%s: no such %s", sep->se_group, "group");
1368 goto do_exit1;
1369 }
1370 if (real_uid != 0 && real_uid != pwd->pw_uid) {
1371
1372 bb_error_msg("non-root must run services as himself");
1373 goto do_exit1;
1374 }
1375 if (pwd->pw_uid) {
1376 if (sep->se_group)
1377 pwd->pw_gid = grp->gr_gid;
1378
1379 change_identity(pwd);
1380 } else if (sep->se_group) {
1381 xsetgid(grp->gr_gid);
1382 setgroups(1, &grp->gr_gid);
1383 }
1384 if (rlim_ofile.rlim_cur != rlim_ofile_cur)
1385 if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
1386 bb_perror_msg("setrlimit");
1387
1388
1389
1390
1391
1392 xmove_fd(ctrl, STDIN_FILENO);
1393 xdup2(STDIN_FILENO, STDOUT_FILENO);
1394
1395
1396
1397 if (!sep->se_wait)
1398 xdup2(STDIN_FILENO, STDERR_FILENO);
1399
1400
1401 for (sep2 = serv_list; sep2; sep2 = sep2->se_next)
1402 if (sep2->se_fd != ctrl)
1403 maybe_close(sep2->se_fd);
1404 sigaction_set(SIGPIPE, &saved_pipe_handler);
1405 restore_sigmask(&omask);
1406 BB_EXECVP(sep->se_program, sep->se_argv);
1407 bb_perror_msg("can't execute '%s'", sep->se_program);
1408 do_exit1:
1409
1410 if (sep->se_socktype != SOCK_STREAM)
1411 recv(0, line, LINE_SIZE, MSG_DONTWAIT);
1412 _exit(EXIT_FAILURE);
1413 }
1414 }
1415}
1416
1417#if !BB_MMU
1418static const char *const cat_args[] = { "cat", NULL };
1419#endif
1420
1421
1422
1423
1424#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
1425
1426
1427static void FAST_FUNC echo_stream(int s, servtab_t *sep UNUSED_PARAM)
1428{
1429#if BB_MMU
1430 while (1) {
1431 ssize_t sz = safe_read(s, line, LINE_SIZE);
1432 if (sz <= 0)
1433 break;
1434 xwrite(s, line, sz);
1435 }
1436#else
1437
1438
1439 xmove_fd(s, STDIN_FILENO);
1440 xdup2(STDIN_FILENO, STDOUT_FILENO);
1441
1442 close(STDERR_FILENO);
1443 xopen(bb_dev_null, O_WRONLY);
1444 BB_EXECVP("cat", (char**)cat_args);
1445
1446#endif
1447}
1448static void FAST_FUNC echo_dg(int s, servtab_t *sep)
1449{
1450 enum { BUFSIZE = 12*1024 };
1451 char *buf = xmalloc(BUFSIZE);
1452 int sz;
1453 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1454
1455 lsa->len = sep->se_lsa->len;
1456
1457 sz = recvfrom(s, buf, BUFSIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len);
1458 if (sz > 0)
1459 sendto(s, buf, sz, 0, &lsa->u.sa, lsa->len);
1460 free(buf);
1461}
1462#endif
1463
1464
1465#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
1466
1467
1468static void FAST_FUNC discard_stream(int s, servtab_t *sep UNUSED_PARAM)
1469{
1470#if BB_MMU
1471 while (safe_read(s, line, LINE_SIZE) > 0)
1472 continue;
1473#else
1474
1475
1476 xmove_fd(s, STDIN_FILENO);
1477
1478 close(STDOUT_FILENO);
1479 xopen(bb_dev_null, O_WRONLY);
1480
1481 xdup2(STDOUT_FILENO, STDERR_FILENO);
1482 BB_EXECVP("cat", (char**)cat_args);
1483
1484#endif
1485}
1486
1487static void FAST_FUNC discard_dg(int s, servtab_t *sep UNUSED_PARAM)
1488{
1489
1490 recv(s, line, LINE_SIZE, MSG_DONTWAIT);
1491}
1492#endif
1493
1494
1495#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
1496#define LINESIZ 72
1497static void init_ring(void)
1498{
1499 int i;
1500
1501 end_ring = ring;
1502 for (i = ' '; i < 127; i++)
1503 *end_ring++ = i;
1504}
1505
1506
1507static void FAST_FUNC chargen_stream(int s, servtab_t *sep UNUSED_PARAM)
1508{
1509 char *rs;
1510 int len;
1511 char text[LINESIZ + 2];
1512
1513 if (!end_ring) {
1514 init_ring();
1515 rs = ring;
1516 }
1517
1518 text[LINESIZ] = '\r';
1519 text[LINESIZ + 1] = '\n';
1520 rs = ring;
1521 for (;;) {
1522 len = end_ring - rs;
1523 if (len >= LINESIZ)
1524 memmove(text, rs, LINESIZ);
1525 else {
1526 memmove(text, rs, len);
1527 memmove(text + len, ring, LINESIZ - len);
1528 }
1529 if (++rs == end_ring)
1530 rs = ring;
1531 xwrite(s, text, sizeof(text));
1532 }
1533}
1534
1535static void FAST_FUNC chargen_dg(int s, servtab_t *sep)
1536{
1537 int len;
1538 char text[LINESIZ + 2];
1539 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1540
1541
1542
1543 lsa->len = sep->se_lsa->len;
1544 if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1545 return;
1546
1547 if (!end_ring) {
1548 init_ring();
1549 ring_pos = ring;
1550 }
1551
1552 len = end_ring - ring_pos;
1553 if (len >= LINESIZ)
1554 memmove(text, ring_pos, LINESIZ);
1555 else {
1556 memmove(text, ring_pos, len);
1557 memmove(text + len, ring, LINESIZ - len);
1558 }
1559 if (++ring_pos == end_ring)
1560 ring_pos = ring;
1561 text[LINESIZ] = '\r';
1562 text[LINESIZ + 1] = '\n';
1563 sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len);
1564}
1565#endif
1566
1567
1568#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
1569
1570
1571
1572
1573
1574
1575
1576static uint32_t machtime(void)
1577{
1578 struct timeval tv;
1579
1580 gettimeofday(&tv, NULL);
1581 return htonl((uint32_t)(tv.tv_sec + 2208988800));
1582}
1583
1584static void FAST_FUNC machtime_stream(int s, servtab_t *sep UNUSED_PARAM)
1585{
1586 uint32_t result;
1587
1588 result = machtime();
1589 full_write(s, &result, sizeof(result));
1590}
1591static void FAST_FUNC machtime_dg(int s, servtab_t *sep)
1592{
1593 uint32_t result;
1594 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1595
1596 lsa->len = sep->se_lsa->len;
1597 if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1598 return;
1599
1600 result = machtime();
1601 sendto(s, &result, sizeof(result), 0, &lsa->u.sa, lsa->len);
1602}
1603#endif
1604
1605
1606#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
1607
1608
1609static void FAST_FUNC daytime_stream(int s, servtab_t *sep UNUSED_PARAM)
1610{
1611 time_t t;
1612
1613 t = time(NULL);
1614 fdprintf(s, "%.24s\r\n", ctime(&t));
1615}
1616static void FAST_FUNC daytime_dg(int s, servtab_t *sep)
1617{
1618 time_t t;
1619 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1620
1621 lsa->len = sep->se_lsa->len;
1622 if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1623 return;
1624
1625 t = time(NULL);
1626 sprintf(line, "%.24s\r\n", ctime(&t));
1627 sendto(s, line, strlen(line), 0, &lsa->u.sa, lsa->len);
1628}
1629#endif
1630