telnetd: add -w ("inetd wait") option. Can be configured off.
No binary (build failed)
—
(log yok)
| @@ -1468,11 +1468,11 @@ | |
| "\n -m Get baud rate from modem's CONNECT status message" \ | |
| "\n -w Wait for a CR or LF before sending /etc/issue" \ | |
| "\n -n Do not prompt the user for a login name" \ | |
| - | "\n -f issue_file Display issue_file instead of /etc/issue" \ |
| - | "\n -l login_app Invoke login_app instead of /bin/login" \ |
| - | "\n -t timeout Terminate after timeout if no username is read" \ |
| - | "\n -I initstring Init string to send before anything else" \ |
| - | "\n -H login_host Log login_host into the utmp file as the hostname" \ |
| + | "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" \ |
| + | "\n -l LOGIN Invoke LOGIN instead of /bin/login" \ |
| + | "\n -t SEC Terminate after SEC if no username is read" \ |
| + | "\n -I INITSTR Send INITSTR before anything else" \ |
| + | "\n -H HOST Log HOST into the utmp file as the hostname" \ |
| #define grep_trivial_usage \ | |
| "[-HhrilLnqvso" \ | |
| @@ -4415,14 +4415,18 @@ | |
| IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" \ | |
| "\nOptions:" \ | |
| "\n -l LOGIN Exec LOGIN on connect" \ | |
| - | "\n -f issue_file Display issue_file instead of /etc/issue" \ |
| + | "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" \ |
| "\n -K Close connection as soon as login exits" \ | |
| "\n (normally wait until all programs close slave pty)" \ | |
| IF_FEATURE_TELNETD_STANDALONE( \ | |
| "\n -p PORT Port to listen on" \ | |
| - | "\n -b ADDR Address to bind to" \ |
| + | "\n -b ADDR[:PORT] Address to bind to" \ |
| "\n -F Run in foreground" \ | |
| - | "\n -i Run as inetd subservice" \ |
| + | "\n -i Run as inetd service" \ |
| + | IF_FEATURE_TELNETD_INETD_WAIT( \ |
| + | "\n -w SEC Run as inetd service in wait mode, linger time SEC" \ |
| + | "\n -S Log to syslog (implied by -i or without -F and -w)" \ |
| + | ) \ |
| ) | |
| /* "test --help" does not print help (POSIX compat), only "[ --help" does. | |
| @@ -788,6 +788,27 @@ config FEATURE_TELNETD_STANDALONE | |
| help | |
| Selecting this will make telnetd able to run standalone. | |
| + | config FEATURE_TELNETD_INETD_WAIT |
| + | bool "Support -w SEC option (inetd wait mode)" |
| + | default n |
| + | depends on FEATURE_TELNETD_STANDALONE |
| + | help |
| + | This option allows you to run telnetd in "inet wait" mode. |
| + | Example inetd.conf line (note "wait", not usual "nowait"): |
| + | |
| + | telnet stream tcp wait root /bin/telnetd telnetd -w10 |
| + | |
| + | In this example, inetd passes _listening_ socket_ as fd 0 |
| + | to telnetd when connection appears. |
| + | telnetd will wait for connections until all existing |
| + | connections are closed, and no new connections |
| + | appear during 10 seconds. Then it exits, and inetd continues |
| + | to listen for new connections. |
| + | |
| + | This option is rarely used. "tcp nowait" is much more usual |
| + | way of running tcp services, including telnetd. |
| + | You most probably want to say N here. |
| + | |
| config TFTP | |
| bool "tftp" | |
| default n | |
| @@ -211,8 +211,10 @@ static size_t iac_safe_write(int fd, const char *buf, size_t count) | |
| enum { | |
| OPT_WATCHCHILD = (1 << 2), /* -K */ | |
| OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */ | |
| - | OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */ |
| + | OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p PORT */ |
| OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */ | |
| + | OPT_SYSLOG = (1 << 7) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -S */ |
| + | OPT_WAIT = (1 << 8) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -w SEC */ |
| }; | |
| static struct tsession * | |
| @@ -438,24 +440,29 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) | |
| struct tsession *ts; | |
| #if ENABLE_FEATURE_TELNETD_STANDALONE | |
| #define IS_INETD (opt & OPT_INETD) | |
| - | int master_fd = master_fd; /* be happy, gcc */ |
| - | unsigned portnbr = 23; |
| + | int master_fd = master_fd; /* for compiler */ |
| + | int sec_linger = sec_linger; |
| char *opt_bindaddr = NULL; | |
| char *opt_portnbr; | |
| #else | |
| enum { | |
| IS_INETD = 1, | |
| master_fd = -1, | |
| - | portnbr = 23, |
| }; | |
| #endif | |
| INIT_G(); | |
| + | /* -w NUM, and implies -F. -w and -i don't mix */ |
| + | IF_FEATURE_TELNETD_INETD_WAIT(opt_complementary = "wF:w+:i--w:w--i";) |
| /* Even if !STANDALONE, we accept (and ignore) -i, thus people | |
| * don't need to guess whether it's ok to pass -i to us */ | |
| - | opt = getopt32(argv, "f:l:Ki" IF_FEATURE_TELNETD_STANDALONE("p:b:F"), |
| + | opt = getopt32(argv, "f:l:Ki" |
| + | IF_FEATURE_TELNETD_STANDALONE("p:b:F") |
| + | IF_FEATURE_TELNETD_INETD_WAIT("Sw:"), |
| &G.issuefile, &G.loginpath | |
| - | IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)); |
| + | IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr) |
| + | IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger) |
| + | ); |
| if (!IS_INETD /*&& !re_execed*/) { | |
| /* inform that we start in standalone mode? | |
| * May be useful when people forget to give -i */ | |
| @@ -467,32 +474,30 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) | |
| } | |
| } | |
| /* Redirect log to syslog early, if needed */ | |
| - | if (IS_INETD || !(opt & OPT_FOREGROUND)) { |
| + | if (IS_INETD || (opt & OPT_SYSLOG) || !(opt & OPT_FOREGROUND)) { |
| openlog(applet_name, LOG_PID, LOG_DAEMON); | |
| logmode = LOGMODE_SYSLOG; | |
| } | |
| - | IF_FEATURE_TELNETD_STANDALONE( |
| - | if (opt & OPT_PORT) |
| - | portnbr = xatou16(opt_portnbr); |
| - | ); |
| - | |
| - | /* Used to check access(G.loginpath, X_OK) here. Pointless. |
| - | * exec will do this for us for free later. */ |
| - | |
| #if ENABLE_FEATURE_TELNETD_STANDALONE | |
| if (IS_INETD) { | |
| G.sessions = make_new_session(0); | |
| if (!G.sessions) /* pty opening or vfork problem, exit */ | |
| - | return 1; /* make_new_session prints error message */ |
| + | return 1; /* make_new_session printed error message */ |
| } else { | |
| - | master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr); |
| - | xlisten(master_fd, 1); |
| + | master_fd = 0; |
| + | if (!(opt & OPT_WAIT)) { |
| + | unsigned portnbr = 23; |
| + | if (opt & OPT_PORT) |
| + | portnbr = xatou16(opt_portnbr); |
| + | master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr); |
| + | xlisten(master_fd, 1); |
| + | } |
| close_on_exec_on(master_fd); | |
| } | |
| #else | |
| G.sessions = make_new_session(); | |
| if (!G.sessions) /* pty opening or vfork problem, exit */ | |
| - | return 1; /* make_new_session prints error message */ |
| + | return 1; /* make_new_session printed error message */ |
| #endif | |
| /* We don't want to die if just one session is broken */ | |
| @@ -556,7 +561,18 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) | |
| G.maxfd = master_fd; | |
| } | |
| - | count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, NULL); |
| + | { |
| + | struct timeval tv; |
| + | struct timeval *tv_ptr = NULL; |
| + | if ((opt & OPT_WAIT) && !G.sessions) { |
| + | tv.tv_sec = sec_linger; |
| + | tv.tv_usec = 0; |
| + | tv_ptr = &tv; |
| + | } |
| + | count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, tv_ptr); |
| + | } |
| + | if (count == 0) /* "telnetd -w SEC" timed out */ |
| + | return 0; |
| if (count < 0) | |
| goto again; /* EINTR or ENOMEM */ | |