aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/usage.h20
-rw-r--r--networking/Config.in21
-rw-r--r--networking/telnetd.c56
3 files changed, 69 insertions, 28 deletions
diff --git a/include/usage.h b/include/usage.h
index ba77490cb..9fa1b9ef8 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -1468,11 +1468,11 @@
1468 "\n -m Get baud rate from modem's CONNECT status message" \ 1468 "\n -m Get baud rate from modem's CONNECT status message" \
1469 "\n -w Wait for a CR or LF before sending /etc/issue" \ 1469 "\n -w Wait for a CR or LF before sending /etc/issue" \
1470 "\n -n Do not prompt the user for a login name" \ 1470 "\n -n Do not prompt the user for a login name" \
1471 "\n -f issue_file Display issue_file instead of /etc/issue" \ 1471 "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" \
1472 "\n -l login_app Invoke login_app instead of /bin/login" \ 1472 "\n -l LOGIN Invoke LOGIN instead of /bin/login" \
1473 "\n -t timeout Terminate after timeout if no username is read" \ 1473 "\n -t SEC Terminate after SEC if no username is read" \
1474 "\n -I initstring Init string to send before anything else" \ 1474 "\n -I INITSTR Send INITSTR before anything else" \
1475 "\n -H login_host Log login_host into the utmp file as the hostname" \ 1475 "\n -H HOST Log HOST into the utmp file as the hostname" \
1476 1476
1477#define grep_trivial_usage \ 1477#define grep_trivial_usage \
1478 "[-HhrilLnqvso" \ 1478 "[-HhrilLnqvso" \
@@ -4415,14 +4415,18 @@
4415 IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" \ 4415 IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" \
4416 "\nOptions:" \ 4416 "\nOptions:" \
4417 "\n -l LOGIN Exec LOGIN on connect" \ 4417 "\n -l LOGIN Exec LOGIN on connect" \
4418 "\n -f issue_file Display issue_file instead of /etc/issue" \ 4418 "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" \
4419 "\n -K Close connection as soon as login exits" \ 4419 "\n -K Close connection as soon as login exits" \
4420 "\n (normally wait until all programs close slave pty)" \ 4420 "\n (normally wait until all programs close slave pty)" \
4421 IF_FEATURE_TELNETD_STANDALONE( \ 4421 IF_FEATURE_TELNETD_STANDALONE( \
4422 "\n -p PORT Port to listen on" \ 4422 "\n -p PORT Port to listen on" \
4423 "\n -b ADDR Address to bind to" \ 4423 "\n -b ADDR[:PORT] Address to bind to" \
4424 "\n -F Run in foreground" \ 4424 "\n -F Run in foreground" \
4425 "\n -i Run as inetd subservice" \ 4425 "\n -i Run as inetd service" \
4426 IF_FEATURE_TELNETD_INETD_WAIT( \
4427 "\n -w SEC Run as inetd service in wait mode, linger time SEC" \
4428 "\n -S Log to syslog (implied by -i or without -F and -w)" \
4429 ) \
4426 ) 4430 )
4427 4431
4428/* "test --help" does not print help (POSIX compat), only "[ --help" does. 4432/* "test --help" does not print help (POSIX compat), only "[ --help" does.
diff --git a/networking/Config.in b/networking/Config.in
index 83522ffb1..59e88e016 100644
--- a/networking/Config.in
+++ b/networking/Config.in
@@ -788,6 +788,27 @@ config FEATURE_TELNETD_STANDALONE
788 help 788 help
789 Selecting this will make telnetd able to run standalone. 789 Selecting this will make telnetd able to run standalone.
790 790
791config FEATURE_TELNETD_INETD_WAIT
792 bool "Support -w SEC option (inetd wait mode)"
793 default n
794 depends on FEATURE_TELNETD_STANDALONE
795 help
796 This option allows you to run telnetd in "inet wait" mode.
797 Example inetd.conf line (note "wait", not usual "nowait"):
798
799 telnet stream tcp wait root /bin/telnetd telnetd -w10
800
801 In this example, inetd passes _listening_ socket_ as fd 0
802 to telnetd when connection appears.
803 telnetd will wait for connections until all existing
804 connections are closed, and no new connections
805 appear during 10 seconds. Then it exits, and inetd continues
806 to listen for new connections.
807
808 This option is rarely used. "tcp nowait" is much more usual
809 way of running tcp services, including telnetd.
810 You most probably want to say N here.
811
791config TFTP 812config TFTP
792 bool "tftp" 813 bool "tftp"
793 default n 814 default n
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 540387f1a..2a0ace5cb 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -211,8 +211,10 @@ static size_t iac_safe_write(int fd, const char *buf, size_t count)
211enum { 211enum {
212 OPT_WATCHCHILD = (1 << 2), /* -K */ 212 OPT_WATCHCHILD = (1 << 2), /* -K */
213 OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */ 213 OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
214 OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */ 214 OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p PORT */
215 OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */ 215 OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
216 OPT_SYSLOG = (1 << 7) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -S */
217 OPT_WAIT = (1 << 8) * ENABLE_FEATURE_TELNETD_INETD_WAIT, /* -w SEC */
216}; 218};
217 219
218static struct tsession * 220static struct tsession *
@@ -438,24 +440,29 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
438 struct tsession *ts; 440 struct tsession *ts;
439#if ENABLE_FEATURE_TELNETD_STANDALONE 441#if ENABLE_FEATURE_TELNETD_STANDALONE
440#define IS_INETD (opt & OPT_INETD) 442#define IS_INETD (opt & OPT_INETD)
441 int master_fd = master_fd; /* be happy, gcc */ 443 int master_fd = master_fd; /* for compiler */
442 unsigned portnbr = 23; 444 int sec_linger = sec_linger;
443 char *opt_bindaddr = NULL; 445 char *opt_bindaddr = NULL;
444 char *opt_portnbr; 446 char *opt_portnbr;
445#else 447#else
446 enum { 448 enum {
447 IS_INETD = 1, 449 IS_INETD = 1,
448 master_fd = -1, 450 master_fd = -1,
449 portnbr = 23,
450 }; 451 };
451#endif 452#endif
452 INIT_G(); 453 INIT_G();
453 454
455 /* -w NUM, and implies -F. -w and -i don't mix */
456 IF_FEATURE_TELNETD_INETD_WAIT(opt_complementary = "wF:w+:i--w:w--i";)
454 /* Even if !STANDALONE, we accept (and ignore) -i, thus people 457 /* Even if !STANDALONE, we accept (and ignore) -i, thus people
455 * don't need to guess whether it's ok to pass -i to us */ 458 * don't need to guess whether it's ok to pass -i to us */
456 opt = getopt32(argv, "f:l:Ki" IF_FEATURE_TELNETD_STANDALONE("p:b:F"), 459 opt = getopt32(argv, "f:l:Ki"
460 IF_FEATURE_TELNETD_STANDALONE("p:b:F")
461 IF_FEATURE_TELNETD_INETD_WAIT("Sw:"),
457 &G.issuefile, &G.loginpath 462 &G.issuefile, &G.loginpath
458 IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)); 463 IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)
464 IF_FEATURE_TELNETD_INETD_WAIT(, &sec_linger)
465 );
459 if (!IS_INETD /*&& !re_execed*/) { 466 if (!IS_INETD /*&& !re_execed*/) {
460 /* inform that we start in standalone mode? 467 /* inform that we start in standalone mode?
461 * May be useful when people forget to give -i */ 468 * May be useful when people forget to give -i */
@@ -467,32 +474,30 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
467 } 474 }
468 } 475 }
469 /* Redirect log to syslog early, if needed */ 476 /* Redirect log to syslog early, if needed */
470 if (IS_INETD || !(opt & OPT_FOREGROUND)) { 477 if (IS_INETD || (opt & OPT_SYSLOG) || !(opt & OPT_FOREGROUND)) {
471 openlog(applet_name, LOG_PID, LOG_DAEMON); 478 openlog(applet_name, LOG_PID, LOG_DAEMON);
472 logmode = LOGMODE_SYSLOG; 479 logmode = LOGMODE_SYSLOG;
473 } 480 }
474 IF_FEATURE_TELNETD_STANDALONE(
475 if (opt & OPT_PORT)
476 portnbr = xatou16(opt_portnbr);
477 );
478
479 /* Used to check access(G.loginpath, X_OK) here. Pointless.
480 * exec will do this for us for free later. */
481
482#if ENABLE_FEATURE_TELNETD_STANDALONE 481#if ENABLE_FEATURE_TELNETD_STANDALONE
483 if (IS_INETD) { 482 if (IS_INETD) {
484 G.sessions = make_new_session(0); 483 G.sessions = make_new_session(0);
485 if (!G.sessions) /* pty opening or vfork problem, exit */ 484 if (!G.sessions) /* pty opening or vfork problem, exit */
486 return 1; /* make_new_session prints error message */ 485 return 1; /* make_new_session printed error message */
487 } else { 486 } else {
488 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr); 487 master_fd = 0;
489 xlisten(master_fd, 1); 488 if (!(opt & OPT_WAIT)) {
489 unsigned portnbr = 23;
490 if (opt & OPT_PORT)
491 portnbr = xatou16(opt_portnbr);
492 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
493 xlisten(master_fd, 1);
494 }
490 close_on_exec_on(master_fd); 495 close_on_exec_on(master_fd);
491 } 496 }
492#else 497#else
493 G.sessions = make_new_session(); 498 G.sessions = make_new_session();
494 if (!G.sessions) /* pty opening or vfork problem, exit */ 499 if (!G.sessions) /* pty opening or vfork problem, exit */
495 return 1; /* make_new_session prints error message */ 500 return 1; /* make_new_session printed error message */
496#endif 501#endif
497 502
498 /* We don't want to die if just one session is broken */ 503 /* 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)
556 G.maxfd = master_fd; 561 G.maxfd = master_fd;
557 } 562 }
558 563
559 count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, NULL); 564 {
565 struct timeval tv;
566 struct timeval *tv_ptr = NULL;
567 if ((opt & OPT_WAIT) && !G.sessions) {
568 tv.tv_sec = sec_linger;
569 tv.tv_usec = 0;
570 tv_ptr = &tv;
571 }
572 count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, tv_ptr);
573 }
574 if (count == 0) /* "telnetd -w SEC" timed out */
575 return 0;
560 if (count < 0) 576 if (count < 0)
561 goto again; /* EINTR or ENOMEM */ 577 goto again; /* EINTR or ENOMEM */
562 578