diff options
Diffstat (limited to 'networking')
-rw-r--r-- | networking/telnetd.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/networking/telnetd.c b/networking/telnetd.c index cccf03dfd..108bbf44f 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -279,6 +279,10 @@ make_new_session( | |||
279 | /* make new session and process group */ | 279 | /* make new session and process group */ |
280 | setsid(); | 280 | setsid(); |
281 | 281 | ||
282 | /* Restore default signal handling */ | ||
283 | signal(SIGCHLD, SIG_DFL); | ||
284 | signal(SIGPIPE, SIG_DFL); | ||
285 | |||
282 | /* open the child's side of the tty. */ | 286 | /* open the child's side of the tty. */ |
283 | /* NB: setsid() disconnects from any previous ctty's. Therefore | 287 | /* NB: setsid() disconnects from any previous ctty's. Therefore |
284 | * we must open child's side of the tty AFTER setsid! */ | 288 | * we must open child's side of the tty AFTER setsid! */ |
@@ -302,14 +306,18 @@ make_new_session( | |||
302 | /* Uses FILE-based I/O to stdout, but does fflush(stdout), | 306 | /* Uses FILE-based I/O to stdout, but does fflush(stdout), |
303 | * so should be safe with vfork. | 307 | * so should be safe with vfork. |
304 | * I fear, though, that some users will have ridiculously big | 308 | * I fear, though, that some users will have ridiculously big |
305 | * issue files, and they may block writing to fd 1. */ | 309 | * issue files, and they may block writing to fd 1, |
310 | * (parent is supposed to read it, but parent waits | ||
311 | * for vforked child to exec!) */ | ||
306 | print_login_issue(issuefile, NULL); | 312 | print_login_issue(issuefile, NULL); |
307 | 313 | ||
308 | /* Exec shell / login / whatever */ | 314 | /* Exec shell / login / whatever */ |
309 | login_argv[0] = loginpath; | 315 | login_argv[0] = loginpath; |
310 | login_argv[1] = NULL; | 316 | login_argv[1] = NULL; |
311 | execvp(loginpath, (char **)login_argv); | 317 | /* exec busybox applet (if PREFER_APPLETS=y), if that fails, |
312 | /* Safer with vfork, and we shouldn't send message | 318 | * exec external program */ |
319 | BB_EXECVP(loginpath, (char **)login_argv); | ||
320 | /* _exit is safer with vfork, and we shouldn't send message | ||
313 | * to remote clients anyway */ | 321 | * to remote clients anyway */ |
314 | _exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/ | 322 | _exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/ |
315 | } | 323 | } |
@@ -374,7 +382,7 @@ free_session(struct tsession *ts) | |||
374 | 382 | ||
375 | #else /* !FEATURE_TELNETD_STANDALONE */ | 383 | #else /* !FEATURE_TELNETD_STANDALONE */ |
376 | 384 | ||
377 | /* Used in main() only, thus exits. */ | 385 | /* Used in main() only, thus "return 0" actually is exit(0). */ |
378 | #define free_session(ts) return 0 | 386 | #define free_session(ts) return 0 |
379 | 387 | ||
380 | #endif | 388 | #endif |
@@ -384,20 +392,22 @@ static void handle_sigchld(int sig) | |||
384 | pid_t pid; | 392 | pid_t pid; |
385 | struct tsession *ts; | 393 | struct tsession *ts; |
386 | 394 | ||
387 | pid = waitpid(-1, &sig, WNOHANG); | 395 | /* Looping: more than one child may have exited */ |
388 | if (pid > 0) { | 396 | while (1) { |
397 | pid = waitpid(-1, NULL, WNOHANG); | ||
398 | if (pid <= 0) | ||
399 | break; | ||
389 | ts = sessions; | 400 | ts = sessions; |
390 | while (ts) { | 401 | while (ts) { |
391 | if (ts->shell_pid == pid) { | 402 | if (ts->shell_pid == pid) { |
392 | ts->shell_pid = -1; | 403 | ts->shell_pid = -1; |
393 | return; | 404 | break; |
394 | } | 405 | } |
395 | ts = ts->next; | 406 | ts = ts->next; |
396 | } | 407 | } |
397 | } | 408 | } |
398 | } | 409 | } |
399 | 410 | ||
400 | |||
401 | int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 411 | int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
402 | int telnetd_main(int argc, char **argv) | 412 | int telnetd_main(int argc, char **argv) |
403 | { | 413 | { |
@@ -430,7 +440,7 @@ int telnetd_main(int argc, char **argv) | |||
430 | if (!(opt & OPT_FOREGROUND)) { | 440 | if (!(opt & OPT_FOREGROUND)) { |
431 | /* DAEMON_CHDIR_ROOT was giving inconsistent | 441 | /* DAEMON_CHDIR_ROOT was giving inconsistent |
432 | * behavior with/without -F, -i */ | 442 | * behavior with/without -F, -i */ |
433 | bb_daemonize_or_rexec(0 /*DAEMON_CHDIR_ROOT*/, argv); | 443 | bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv); |
434 | } | 444 | } |
435 | } | 445 | } |
436 | /* Redirect log to syslog early, if needed */ | 446 | /* Redirect log to syslog early, if needed */ |
@@ -466,6 +476,8 @@ int telnetd_main(int argc, char **argv) | |||
466 | 476 | ||
467 | if (opt & OPT_WATCHCHILD) | 477 | if (opt & OPT_WATCHCHILD) |
468 | signal(SIGCHLD, handle_sigchld); | 478 | signal(SIGCHLD, handle_sigchld); |
479 | else /* prevent dead children from becoming zombies */ | ||
480 | signal(SIGCHLD, SIG_IGN); | ||
469 | 481 | ||
470 | /* | 482 | /* |
471 | This is how the buffers are used. The arrows indicate the movement | 483 | This is how the buffers are used. The arrows indicate the movement |
@@ -497,7 +509,7 @@ int telnetd_main(int argc, char **argv) | |||
497 | while (ts) { | 509 | while (ts) { |
498 | struct tsession *next = ts->next; /* in case we free ts. */ | 510 | struct tsession *next = ts->next; /* in case we free ts. */ |
499 | if (ts->shell_pid == -1) { | 511 | if (ts->shell_pid == -1) { |
500 | /* Child died ad we detected that */ | 512 | /* Child died and we detected that */ |
501 | free_session(ts); | 513 | free_session(ts); |
502 | } else { | 514 | } else { |
503 | if (ts->size1 > 0) /* can write to pty */ | 515 | if (ts->size1 > 0) /* can write to pty */ |
@@ -514,7 +526,7 @@ int telnetd_main(int argc, char **argv) | |||
514 | if (!IS_INETD) { | 526 | if (!IS_INETD) { |
515 | FD_SET(master_fd, &rdfdset); | 527 | FD_SET(master_fd, &rdfdset); |
516 | /* This is needed because free_session() does not | 528 | /* This is needed because free_session() does not |
517 | * take into account master_fd when it finds new | 529 | * take master_fd into account when it finds new |
518 | * maxfd among remaining fd's */ | 530 | * maxfd among remaining fd's */ |
519 | if (master_fd > maxfd) | 531 | if (master_fd > maxfd) |
520 | maxfd = master_fd; | 532 | maxfd = master_fd; |