diff options
-rw-r--r-- | include/usage.h | 20 | ||||
-rw-r--r-- | networking/Config.in | 21 | ||||
-rw-r--r-- | networking/telnetd.c | 56 |
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 | ||
791 | config 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 | |||
791 | config TFTP | 812 | config 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) | |||
211 | enum { | 211 | enum { |
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 | ||
218 | static struct tsession * | 220 | static 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 | ||