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