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 echo_stream(int, servtab_t *);
243static void echo_dg(int, servtab_t *);
244#endif
245
246#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
247static void discard_stream(int, servtab_t *);
248static void discard_dg(int, servtab_t *);
249#endif
250
251#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
252static void machtime_stream(int, servtab_t *);
253static void machtime_dg(int, servtab_t *);
254#endif
255
256#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
257static void daytime_stream(int, servtab_t *);
258static void daytime_dg(int, servtab_t *);
259#endif
260
261#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
262static void chargen_stream(int, servtab_t *);
263static void 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 *);
271 void (*bi_dgram_fn)(int, servtab_t *);
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 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 0x%x",
1035 sep->se_program, WEXITSTATUS(status));
1036 else if (WIFSIGNALED(status))
1037 bb_error_msg("%s: exit signal 0x%x",
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 openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
1123 logmode = LOGMODE_SYSLOG;
1124 }
1125
1126 if (real_uid == 0) {
1127
1128 gid_t gid = getgid();
1129 setgroups(1, &gid);
1130 }
1131
1132 write_pidfile(_PATH_INETDPID);
1133
1134
1135 getrlimit(RLIMIT_NOFILE, &rlim_ofile);
1136 rlim_ofile_cur = rlim_ofile.rlim_cur;
1137 if (rlim_ofile_cur == RLIM_INFINITY)
1138 rlim_ofile_cur = OPEN_MAX;
1139
1140 memset(&sa, 0, sizeof(sa));
1141
1142 sigaddset(&sa.sa_mask, SIGALRM);
1143 sigaddset(&sa.sa_mask, SIGCHLD);
1144 sigaddset(&sa.sa_mask, SIGHUP);
1145 sa.sa_handler = retry_network_setup;
1146 sigaction_set(SIGALRM, &sa);
1147 sa.sa_handler = reread_config_file;
1148 sigaction_set(SIGHUP, &sa);
1149 sa.sa_handler = reap_child;
1150 sigaction_set(SIGCHLD, &sa);
1151 sa.sa_handler = clean_up_and_exit;
1152 sigaction_set(SIGTERM, &sa);
1153 sa.sa_handler = clean_up_and_exit;
1154 sigaction_set(SIGINT, &sa);
1155 sa.sa_handler = SIG_IGN;
1156 sigaction(SIGPIPE, &sa, &saved_pipe_handler);
1157
1158 reread_config_file(SIGHUP);
1159
1160 for (;;) {
1161 int ready_fd_cnt;
1162 int ctrl, accepted_fd, new_udp_fd;
1163 fd_set readable;
1164
1165 if (maxsock < 0)
1166 recalculate_maxsock();
1167
1168 readable = allsock;
1169
1170
1171
1172 ready_fd_cnt = select(maxsock + 1, &readable, NULL, NULL, NULL);
1173 if (ready_fd_cnt < 0) {
1174 if (errno != EINTR) {
1175 bb_perror_msg("select");
1176 sleep(1);
1177 }
1178 continue;
1179 }
1180
1181 for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) {
1182 if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
1183 continue;
1184
1185 ready_fd_cnt--;
1186 ctrl = sep->se_fd;
1187 accepted_fd = -1;
1188 new_udp_fd = -1;
1189 if (!sep->se_wait) {
1190 if (sep->se_socktype == SOCK_STREAM) {
1191 ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
1192 if (ctrl < 0) {
1193 if (errno != EINTR)
1194 bb_perror_msg("accept (for %s)", sep->se_service);
1195 continue;
1196 }
1197 }
1198
1199 if (sep->se_socktype == SOCK_DGRAM
1200 && sep->se_family != AF_UNIX
1201 ) {
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211 new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0);
1212 if (new_udp_fd < 0) {
1213 udp_err:
1214 recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT);
1215 continue;
1216 }
1217 setsockopt_reuseaddr(new_udp_fd);
1218
1219
1220
1221 if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) {
1222 close(new_udp_fd);
1223 goto udp_err;
1224 }
1225 }
1226 }
1227
1228 block_CHLD_HUP_ALRM(&omask);
1229 pid = 0;
1230#ifdef INETD_BUILTINS_ENABLED
1231
1232 if (sep->se_builtin == NULL
1233 || (sep->se_socktype == SOCK_STREAM
1234 && sep->se_builtin->bi_fork))
1235#endif
1236 {
1237 if (sep->se_max != 0) {
1238 if (++sep->se_count == 1)
1239 sep->se_time = monotonic_sec();
1240 else if (sep->se_count >= sep->se_max) {
1241 unsigned now = monotonic_sec();
1242
1243 if (now - sep->se_time <= CNT_INTERVAL) {
1244 bb_error_msg("%s/%s: too many connections, pausing",
1245 sep->se_service, sep->se_proto);
1246 remove_fd_from_set(sep->se_fd);
1247 close(sep->se_fd);
1248 sep->se_fd = -1;
1249 sep->se_count = 0;
1250 rearm_alarm();
1251 restore_sigmask(&omask);
1252 maybe_close(accepted_fd);
1253 continue;
1254 }
1255 sep->se_count = 0;
1256 }
1257 }
1258
1259
1260
1261#ifdef INETD_BUILTINS_ENABLED
1262 if (BB_MMU && sep->se_builtin)
1263 pid = fork();
1264 else
1265#endif
1266 pid = vfork();
1267
1268 if (pid < 0) {
1269 bb_perror_msg("fork");
1270 sleep(1);
1271 restore_sigmask(&omask);
1272 maybe_close(accepted_fd);
1273 continue;
1274 }
1275 if (pid == 0)
1276 pid--;
1277 }
1278
1279
1280 if (pid > 0) {
1281 if (sep->se_wait) {
1282
1283
1284 sep->se_wait = pid;
1285 remove_fd_from_set(sep->se_fd);
1286 }
1287 if (new_udp_fd >= 0) {
1288
1289
1290 xmove_fd(new_udp_fd, sep->se_fd);
1291 }
1292 restore_sigmask(&omask);
1293 maybe_close(accepted_fd);
1294 continue;
1295 }
1296
1297
1298#ifdef INETD_BUILTINS_ENABLED
1299 if (sep->se_builtin) {
1300 if (pid) {
1301 close(sep->se_fd);
1302 logmode = 0;
1303 }
1304 restore_sigmask(&omask);
1305 if (sep->se_socktype == SOCK_STREAM)
1306 sep->se_builtin->bi_stream_fn(ctrl, sep);
1307 else
1308 sep->se_builtin->bi_dgram_fn(ctrl, sep);
1309 if (pid)
1310 _exit(EXIT_FAILURE);
1311 maybe_close(accepted_fd);
1312 continue;
1313 }
1314#endif
1315
1316 setsid();
1317
1318 if (new_udp_fd >= 0) {
1319 len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
1320
1321 int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
1322 &lsa->u.sa, &lsa->len);
1323 if (r < 0)
1324 goto do_exit1;
1325
1326
1327
1328 connect(ctrl, &lsa->u.sa, lsa->len);
1329 free(lsa);
1330 }
1331
1332 pwd = getpwnam(sep->se_user);
1333 if (pwd == NULL) {
1334 bb_error_msg("%s: no such %s", sep->se_user, "user");
1335 goto do_exit1;
1336 }
1337 if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
1338 bb_error_msg("%s: no such %s", sep->se_group, "group");
1339 goto do_exit1;
1340 }
1341 if (real_uid != 0 && real_uid != pwd->pw_uid) {
1342
1343 bb_error_msg("non-root must run services as himself");
1344 goto do_exit1;
1345 }
1346 if (pwd->pw_uid) {
1347 if (sep->se_group)
1348 pwd->pw_gid = grp->gr_gid;
1349
1350 change_identity(pwd);
1351 } else if (sep->se_group) {
1352 xsetgid(grp->gr_gid);
1353 setgroups(1, &grp->gr_gid);
1354 }
1355 if (rlim_ofile.rlim_cur != rlim_ofile_cur)
1356 if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
1357 bb_perror_msg("setrlimit");
1358 closelog();
1359 xmove_fd(ctrl, 0);
1360 xdup2(0, 1);
1361 xdup2(0, 2);
1362
1363
1364 for (sep2 = serv_list; sep2; sep2 = sep2->se_next)
1365 maybe_close(sep2->se_fd);
1366 sigaction_set(SIGPIPE, &saved_pipe_handler);
1367 restore_sigmask(&omask);
1368 BB_EXECVP(sep->se_program, sep->se_argv);
1369 bb_perror_msg("exec %s", sep->se_program);
1370 do_exit1:
1371
1372 if (sep->se_socktype != SOCK_STREAM)
1373 recv(0, line, LINE_SIZE, MSG_DONTWAIT);
1374 _exit(EXIT_FAILURE);
1375 }
1376 }
1377}
1378
1379#if !BB_MMU
1380static const char *const cat_args[] = { "cat", NULL };
1381#endif
1382
1383
1384
1385
1386#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
1387
1388
1389static void echo_stream(int s, servtab_t *sep UNUSED_PARAM)
1390{
1391#if BB_MMU
1392 while (1) {
1393 ssize_t sz = safe_read(s, line, LINE_SIZE);
1394 if (sz <= 0)
1395 break;
1396 xwrite(s, line, sz);
1397 }
1398#else
1399
1400
1401 xmove_fd(s, STDIN_FILENO);
1402 xdup2(STDIN_FILENO, STDOUT_FILENO);
1403
1404 close(STDERR_FILENO);
1405 xopen(bb_dev_null, O_WRONLY);
1406 BB_EXECVP("cat", (char**)cat_args);
1407
1408#endif
1409}
1410static void echo_dg(int s, servtab_t *sep)
1411{
1412 enum { BUFSIZE = 12*1024 };
1413 char *buf = xmalloc(BUFSIZE);
1414 int sz;
1415 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1416
1417 lsa->len = sep->se_lsa->len;
1418
1419 sz = recvfrom(s, buf, BUFSIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len);
1420 if (sz > 0)
1421 sendto(s, buf, sz, 0, &lsa->u.sa, lsa->len);
1422 free(buf);
1423}
1424#endif
1425
1426
1427#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
1428
1429
1430static void discard_stream(int s, servtab_t *sep UNUSED_PARAM)
1431{
1432#if BB_MMU
1433 while (safe_read(s, line, LINE_SIZE) > 0)
1434 continue;
1435#else
1436
1437
1438 xmove_fd(s, STDIN_FILENO);
1439
1440 close(STDOUT_FILENO);
1441 xopen(bb_dev_null, O_WRONLY);
1442
1443 xdup2(STDOUT_FILENO, STDERR_FILENO);
1444 BB_EXECVP("cat", (char**)cat_args);
1445
1446#endif
1447}
1448
1449static void discard_dg(int s, servtab_t *sep UNUSED_PARAM)
1450{
1451
1452 recv(s, line, LINE_SIZE, MSG_DONTWAIT);
1453}
1454#endif
1455
1456
1457#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
1458#define LINESIZ 72
1459static void init_ring(void)
1460{
1461 int i;
1462
1463 end_ring = ring;
1464 for (i = 0; i <= 128; ++i)
1465 if (isprint(i))
1466 *end_ring++ = i;
1467}
1468
1469
1470static void chargen_stream(int s, servtab_t *sep UNUSED_PARAM)
1471{
1472 char *rs;
1473 int len;
1474 char text[LINESIZ + 2];
1475
1476 if (!end_ring) {
1477 init_ring();
1478 rs = ring;
1479 }
1480
1481 text[LINESIZ] = '\r';
1482 text[LINESIZ + 1] = '\n';
1483 rs = ring;
1484 for (;;) {
1485 len = end_ring - rs;
1486 if (len >= LINESIZ)
1487 memmove(text, rs, LINESIZ);
1488 else {
1489 memmove(text, rs, len);
1490 memmove(text + len, ring, LINESIZ - len);
1491 }
1492 if (++rs == end_ring)
1493 rs = ring;
1494 xwrite(s, text, sizeof(text));
1495 }
1496}
1497
1498static void chargen_dg(int s, servtab_t *sep)
1499{
1500 int len;
1501 char text[LINESIZ + 2];
1502 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1503
1504
1505
1506 lsa->len = sep->se_lsa->len;
1507 if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1508 return;
1509
1510 if (!end_ring) {
1511 init_ring();
1512 ring_pos = ring;
1513 }
1514
1515 len = end_ring - ring_pos;
1516 if (len >= LINESIZ)
1517 memmove(text, ring_pos, LINESIZ);
1518 else {
1519 memmove(text, ring_pos, len);
1520 memmove(text + len, ring, LINESIZ - len);
1521 }
1522 if (++ring_pos == end_ring)
1523 ring_pos = ring;
1524 text[LINESIZ] = '\r';
1525 text[LINESIZ + 1] = '\n';
1526 sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len);
1527}
1528#endif
1529
1530
1531#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
1532
1533
1534
1535
1536
1537
1538
1539static uint32_t machtime(void)
1540{
1541 struct timeval tv;
1542
1543 gettimeofday(&tv, NULL);
1544 return htonl((uint32_t)(tv.tv_sec + 2208988800));
1545}
1546
1547static void machtime_stream(int s, servtab_t *sep UNUSED_PARAM)
1548{
1549 uint32_t result;
1550
1551 result = machtime();
1552 full_write(s, &result, sizeof(result));
1553}
1554static void machtime_dg(int s, servtab_t *sep)
1555{
1556 uint32_t result;
1557 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1558
1559 lsa->len = sep->se_lsa->len;
1560 if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1561 return;
1562
1563 result = machtime();
1564 sendto(s, &result, sizeof(result), 0, &lsa->u.sa, lsa->len);
1565}
1566#endif
1567
1568
1569#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
1570
1571
1572static void daytime_stream(int s, servtab_t *sep UNUSED_PARAM)
1573{
1574 time_t t;
1575
1576 t = time(NULL);
1577 fdprintf(s, "%.24s\r\n", ctime(&t));
1578}
1579static void daytime_dg(int s, servtab_t *sep)
1580{
1581 time_t t;
1582 len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1583
1584 lsa->len = sep->se_lsa->len;
1585 if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1586 return;
1587
1588 t = time(NULL);
1589 sprintf(line, "%.24s\r\n", ctime(&t));
1590 sendto(s, line, strlen(line), 0, &lsa->u.sa, lsa->len);
1591}
1592#endif
1593