X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=networking%2Finetd.c;h=584c5e5e40dd3643a9e231e7c9290de7035bdd35;hb=a14f319805c288db25cc9feac3048d89f3d7b41a;hp=6018665ef3420add1c10e34ef8e76ecc578b49a2;hpb=ca18311d0ae16a96e988df15a9009095f93df85e;p=oweals%2Fbusybox.git diff --git a/networking/inetd.c b/networking/inetd.c index 6018665ef..584c5e5e4 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -154,14 +154,29 @@ * setuid() */ +//usage:#define inetd_trivial_usage +//usage: "[-fe] [-q N] [-R N] [CONFFILE]" +//usage:#define inetd_full_usage "\n\n" +//usage: "Listen for network connections and launch programs\n" +//usage: "\n -f Run in foreground" +//usage: "\n -e Log to stderr" +//usage: "\n -q N Socket listen queue (default: 128)" +//usage: "\n -R N Pause services after N connects/min" +//usage: "\n (default: 0 - disabled)" + #include +#include /* setrlimit */ +#include /* un.h may need this */ #include #include "libbb.h" #if ENABLE_FEATURE_INETD_RPC -#include -#include +# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) +# error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support" +# endif +# include +# include #endif #if !BB_MMU @@ -171,8 +186,6 @@ #define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0 #endif -#define _PATH_INETDPID "/var/run/inetd.pid" - #define CNT_INTERVAL 60 /* servers in CNT_INTERVAL sec. */ #define RETRYTIME 60 /* retry after bind or server fail */ @@ -344,10 +357,26 @@ struct BUG_G_too_big { config_filename = "/etc/inetd.conf"; \ } while (0) +#if 1 +# define dbg(...) ((void)0) +#else +# define dbg(...) \ +do { \ + int dbg_fd = open("inetd_debug.log", O_WRONLY | O_CREAT | O_APPEND, 0666); \ + if (dbg_fd >= 0) { \ + fdprintf(dbg_fd, "%d: ", getpid()); \ + fdprintf(dbg_fd, __VA_ARGS__); \ + close(dbg_fd); \ + } \ +} while (0) +#endif + static void maybe_close(int fd) { - if (fd >= 0) + if (fd >= 0) { close(fd); + dbg("closed fd:%d\n", fd); + } } // TODO: move to libbb? @@ -451,7 +480,9 @@ static void remove_fd_from_set(int fd) { if (fd >= 0) { FD_CLR(fd, &allsock); + dbg("stopped listening on fd:%d\n", fd); maxsock = -1; + dbg("maxsock:%d\n", maxsock); } } @@ -459,8 +490,10 @@ static void add_fd_to_set(int fd) { if (fd >= 0) { FD_SET(fd, &allsock); + dbg("started listening on fd:%d\n", fd); if (maxsock >= 0 && fd > maxsock) { prev_maxsock = maxsock = fd; + dbg("maxsock:%d\n", maxsock); if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN) bump_nofile(); } @@ -479,6 +512,7 @@ static void recalculate_maxsock(void) maxsock = fd; fd++; } + dbg("recalculated maxsock:%d\n", maxsock); prev_maxsock = maxsock; if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) bump_nofile(); @@ -536,8 +570,13 @@ static void prepare_socket_fd(servtab_t *sep) rearm_alarm(); return; } - if (sep->se_socktype == SOCK_STREAM) + + if (sep->se_socktype == SOCK_STREAM) { listen(fd, global_queuelen); + dbg("new sep->se_fd:%d (stream)\n", fd); + } else { + dbg("new sep->se_fd:%d (!stream)\n", fd); + } add_fd_to_set(fd); sep->se_fd = fd; @@ -999,7 +1038,7 @@ static void reread_config_file(int sig UNUSED_PARAM) * new config file doesnt have them. */ block_CHLD_HUP_ALRM(&omask); sepp = &serv_list; - while ((sep = *sepp)) { + while ((sep = *sepp) != NULL) { if (sep->se_checked) { sepp = &sep->se_next; continue; @@ -1091,7 +1130,7 @@ static void clean_up_and_exit(int sig UNUSED_PARAM) if (ENABLE_FEATURE_CLEAN_UP) close(sep->se_fd); } - remove_pidfile(_PATH_INETDPID); + remove_pidfile(CONFIG_PID_FILE_PATH "/inetd.pid"); exit(EXIT_SUCCESS); } @@ -1140,7 +1179,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) setgroups(1, &gid); } - write_pidfile(_PATH_INETDPID); + write_pidfile(CONFIG_PID_FILE_PATH "/inetd.pid"); /* never fails under Linux (except if you pass it bad arguments) */ getrlimit(RLIMIT_NOFILE, &rlim_ofile); @@ -1153,12 +1192,17 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sigaddset(&sa.sa_mask, SIGALRM); sigaddset(&sa.sa_mask, SIGCHLD); sigaddset(&sa.sa_mask, SIGHUP); +//FIXME: explain why no SA_RESTART +//FIXME: retry_network_setup is unsafe to run in signal handler (many reasons)! sa.sa_handler = retry_network_setup; sigaction_set(SIGALRM, &sa); +//FIXME: reread_config_file is unsafe to run in signal handler(many reasons)! sa.sa_handler = reread_config_file; sigaction_set(SIGHUP, &sa); +//FIXME: reap_child is unsafe to run in signal handler (uses stdio)! sa.sa_handler = reap_child; sigaction_set(SIGCHLD, &sa); +//FIXME: clean_up_and_exit is unsafe to run in signal handler (uses stdio)! sa.sa_handler = clean_up_and_exit; sigaction_set(SIGTERM, &sa); sa.sa_handler = clean_up_and_exit; @@ -1188,11 +1232,13 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) } continue; } + dbg("ready_fd_cnt:%d\n", ready_fd_cnt); for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) { if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) continue; + dbg("ready fd:%d\n", sep->se_fd); ready_fd_cnt--; ctrl = sep->se_fd; accepted_fd = -1; @@ -1200,6 +1246,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) if (!sep->se_wait) { if (sep->se_socktype == SOCK_STREAM) { ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL); + dbg("accepted_fd:%d\n", accepted_fd); if (ctrl < 0) { if (errno != EINTR) bb_perror_msg("accept (for %s)", sep->se_service); @@ -1220,19 +1267,22 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) * (can create many copies of same child, etc). * Parent must create and use new socket instead. */ new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0); + dbg("new_udp_fd:%d\n", new_udp_fd); if (new_udp_fd < 0) { /* error: eat packet, forget about it */ udp_err: recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT); continue; } setsockopt_reuseaddr(new_udp_fd); - /* TODO: better do bind after vfork in parent, + /* TODO: better do bind after fork in parent, * so that we don't have two wildcard bound sockets * even for a brief moment? */ if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) { + dbg("bind(new_udp_fd) failed\n"); close(new_udp_fd); goto udp_err; } + dbg("bind(new_udp_fd) succeeded\n"); } } @@ -1260,6 +1310,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sep->se_count = 0; rearm_alarm(); /* will revive it in RETRYTIME sec */ restore_sigmask(&omask); + maybe_close(new_udp_fd); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ } @@ -1280,17 +1331,18 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) bb_perror_msg("vfork"+1); sleep(1); restore_sigmask(&omask); + maybe_close(new_udp_fd); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ } if (pid == 0) pid--; /* -1: "we did fork and we are child" */ } - /* if pid == 0 here, we never forked */ + /* if pid == 0 here, we didn't fork */ if (pid > 0) { /* parent */ if (sep->se_wait) { - /* tcp wait: we passed listening socket to child, + /* wait: we passed socket to child, * will wait for child to terminate */ sep->se_wait = pid; remove_fd_from_set(sep->se_fd); @@ -1299,17 +1351,19 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) /* udp nowait: child connected the socket, * we created and will use new, unconnected one */ xmove_fd(new_udp_fd, sep->se_fd); + dbg("moved new_udp_fd:%d to sep->se_fd:%d\n", new_udp_fd, sep->se_fd); } restore_sigmask(&omask); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ } - /* we are either child or didn't vfork at all */ + /* we are either child or didn't fork at all */ #ifdef INETD_BUILTINS_ENABLED if (sep->se_builtin) { - if (pid) { /* "pid" is -1: we did vfork */ + if (pid) { /* "pid" is -1: we did fork */ close(sep->se_fd); /* listening socket */ + dbg("closed sep->se_fd:%d\n", sep->se_fd); logmode = LOGMODE_NONE; /* make xwrite etc silent */ } restore_sigmask(&omask); @@ -1317,7 +1371,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sep->se_builtin->bi_stream_fn(ctrl, sep); else sep->se_builtin->bi_dgram_fn(ctrl, sep); - if (pid) /* we did vfork */ + if (pid) /* we did fork */ _exit(EXIT_FAILURE); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ @@ -1327,9 +1381,14 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) setsid(); /* "nowait" udp */ if (new_udp_fd >= 0) { - len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family); + len_and_sockaddr *lsa; + int r; + + close(new_udp_fd); + dbg("closed new_udp_fd:%d\n", new_udp_fd); + lsa = xzalloc_lsa(sep->se_family); /* peek at the packet and remember peer addr */ - int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, + r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, &lsa->u.sa, &lsa->len); if (r < 0) goto do_exit1; @@ -1337,6 +1396,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) * only packets from this peer will be recv'ed, * and bare write()/send() will work on it */ connect(ctrl, &lsa->u.sa, lsa->len); + dbg("connected ctrl:%d to remote peer\n", ctrl); free(lsa); } /* prepare env and exec program */ @@ -1354,7 +1414,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) bb_error_msg("non-root must run services as himself"); goto do_exit1; } - if (pwd->pw_uid) { + if (pwd->pw_uid != 0) { if (sep->se_group) pwd->pw_gid = grp->gr_gid; /* initgroups, setgid, setuid: */ @@ -1373,6 +1433,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) */ xmove_fd(ctrl, STDIN_FILENO); xdup2(STDIN_FILENO, STDOUT_FILENO); + dbg("moved ctrl:%d to fd 0,1[,2]\n", ctrl); /* manpages of inetd I managed to find either say * that stderr is also redirected to the network, * or do not talk about redirection at all (!) */ @@ -1385,6 +1446,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) maybe_close(sep2->se_fd); sigaction_set(SIGPIPE, &saved_pipe_handler); restore_sigmask(&omask); + dbg("execing:'%s'\n", sep->se_program); BB_EXECVP(sep->se_program, sep->se_argv); bb_perror_msg("can't execute '%s'", sep->se_program); do_exit1: