diff --git a/contrib/win32/win32compat/signal.c b/contrib/win32/win32compat/signal.c index f61cdd882d8..facc74bcdd8 100644 --- a/contrib/win32/win32compat/signal.c +++ b/contrib/win32/win32compat/signal.c @@ -310,11 +310,11 @@ wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) return 0; } - int sw_initialize() { memset(&children, 0, sizeof(children)); + atexit(terminate_all_child_processes); sw_init_signal_handler_table(); if (sw_init_timer() != 0) return -1; diff --git a/contrib/win32/win32compat/signal_internal.h b/contrib/win32/win32compat/signal_internal.h index 44dcfd73826..a143681c1fd 100644 --- a/contrib/win32/win32compat/signal_internal.h +++ b/contrib/win32/win32compat/signal_internal.h @@ -26,6 +26,7 @@ int register_child(HANDLE child, DWORD pid); int sw_remove_child_at_index(DWORD index); int sw_child_to_zombie(DWORD index); void sw_cleanup_child_zombies(); +void terminate_all_child_processes(); struct _timer_info { HANDLE timer; diff --git a/contrib/win32/win32compat/signal_sigchld.c b/contrib/win32/win32compat/signal_sigchld.c index f533677c43a..8728edcc733 100644 --- a/contrib/win32/win32compat/signal_sigchld.c +++ b/contrib/win32/win32compat/signal_sigchld.c @@ -248,4 +248,22 @@ sw_cleanup_child_zombies() int pid = 1; while (pid > 0) pid = waitpid(-1, NULL, WNOHANG); -} \ No newline at end of file +} + +void +terminate_all_child_processes() +{ + if (children.num_children > 0 && children.num_children <= MAX_CHILDREN) { + if (children.num_zombies >= 0 && children.num_children > children.num_zombies) { + DWORD live_children = children.num_children - children.num_zombies; + while (live_children--) { + DWORD pid = children.process_id[live_children]; + HANDLE handle = children.handles[live_children]; + TerminateProcess(handle, 0); + CloseHandle(handle); + debug4("Terminate child process %p pid %d", handle, pid); + ++children.num_zombies; + } + } + } +} diff --git a/regress/pesterTests/SSHD.Tests.ps1 b/regress/pesterTests/SSHD.Tests.ps1 index a21a841855b..f2e64fdc412 100644 --- a/regress/pesterTests/SSHD.Tests.ps1 +++ b/regress/pesterTests/SSHD.Tests.ps1 @@ -55,8 +55,8 @@ Describe "E2E scenarios for sshd" -Tags "CI" { # with a connection, there should be two additional session processes $sshdPidsCountWithConn | Should Be (2 + $sshdPidCountBefore) - # after LoginGraceTime expires, one of the session processes should exit - $sshdPidsCountAfter | Should Be (1 + $sshdPidCountBefore) + # after LoginGraceTime expires, all session processes should exit + $sshdPidsCountAfter | Should Be $sshdPidCountBefore } It "sshd pre-auth process is spawned under runtime generated virtual account" { diff --git a/sshd-session.c b/sshd-session.c index bba1eaffa39..2d62c6d4893 100644 --- a/sshd-session.c +++ b/sshd-session.c @@ -542,7 +542,10 @@ privsep_child_cmdline() static void grace_alarm_handler(int sig) { -#ifndef WINDOWS +#ifdef WINDOWS + /* We don't have to be signal-safe on Windows. Different native event mechanisms (APC). */ + exit(EXIT_LOGIN_GRACE); /* Perform full C library cleanup and call atexit() registered functions. */ +#else /* * Try to kill any processes that we have spawned, E.g. authorized * keys command helpers or privsep children. @@ -560,8 +563,8 @@ grace_alarm_handler(int sig) (void)sigaction(SIGTERM, &sa, NULL); kill(0, SIGTERM); } + _exit(EXIT_LOGIN_GRACE); /* We have to be signal-safe. */ #endif /* WINDOWS */ - _exit(EXIT_LOGIN_GRACE); } /* Destroy the host and server keys. They will no longer be needed. */