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; |
