From 545f9cebb2ae0d69c26a7962b4db4b584757d4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sat, 14 Jun 2025 20:56:58 +0200 Subject: [PATCH] [WINLOGON] Allow workstation (un)locking only if we are in the correct LogonState (#8132) - Locking (`WLX_SAS_ACTION_LOCK_WKSTA`) is allowed only if `LogonState` is either `STATE_LOGGED_ON` or `STATE_LOGGED_ON_SAS`, i.e., either the user invokes the `user32:LockWorkStation()` API or presses Win-L, or, opens the Logged-On SAS dialog then clicks on the "Lock Workstation" button. - Unlocking (`WLX_SAS_ACTION_UNLOCK_WKSTA`) is allowed only if `LogonState` is either `STATE_LOCKED` or `STATE_LOCKED_SAS`, i.e., the workstation is locked and we are either on the Locked- notice or on the SAS dialog that asks for the user credentials. Additionally: - Fix the invocation order of `LockHandler`/`UnlockHandler` notifications: * the `LockHandler` is invoked on the Winlogon desktop, just before displaying the Locked-notice dialog; * the `UnlockHandler` is invoked on the Winlogon desktop, just before switching back to the user's desktop. - If we are on the Logged-On SAS dialog and the user presses Win-L to lock the workstation (instead of pressing the corresponding dialog button), the `DoGenericAction(WLX_SAS_ACTION_LOCK_WKSTA)` handler is invoked asynchronously while the SAS dialog is still being displayed. We thus need to ensure all the existing dialogs are closed before displaying the Locked-notice dialog, in order to avoid stray dialogs being shown concurrently. --- base/system/winlogon/sas.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/base/system/winlogon/sas.c b/base/system/winlogon/sas.c index 7013c711658..1b30616b4cd 100644 --- a/base/system/winlogon/sas.c +++ b/base/system/winlogon/sas.c @@ -1093,12 +1093,19 @@ DoGenericAction( } break; case WLX_SAS_ACTION_LOCK_WKSTA: /* 0x03 */ - if (Session->Gina.Functions.WlxIsLockOk(Session->Gina.Context)) + if ((Session->LogonState == STATE_LOGGED_ON) || + (Session->LogonState == STATE_LOGGED_ON_SAS)) { - SwitchDesktop(Session->WinlogonDesktop); - Session->LogonState = STATE_LOCKED; - Session->Gina.Functions.WlxDisplayLockedNotice(Session->Gina.Context); - CallNotificationDlls(Session, LockHandler); + if (Session->Gina.Functions.WlxIsLockOk(Session->Gina.Context)) + { + Session->LogonState = STATE_LOCKED; + SwitchDesktop(Session->WinlogonDesktop); + /* We may be on the Logged-On SAS dialog, in which case + * we need to close it if the lock action came via Win-L */ + CloseAllDialogWindows(); + CallNotificationDlls(Session, LockHandler); + Session->Gina.Functions.WlxDisplayLockedNotice(Session->Gina.Context); + } } break; case WLX_SAS_ACTION_LOGOFF: /* 0x04 */ @@ -1145,9 +1152,13 @@ DoGenericAction( } break; case WLX_SAS_ACTION_UNLOCK_WKSTA: /* 0x08 */ - SwitchDesktop(Session->ApplicationDesktop); - Session->LogonState = STATE_LOGGED_ON; - CallNotificationDlls(Session, UnlockHandler); + if ((Session->LogonState == STATE_LOCKED) || + (Session->LogonState == STATE_LOCKED_SAS)) + { + CallNotificationDlls(Session, UnlockHandler); + SwitchDesktop(Session->ApplicationDesktop); + Session->LogonState = STATE_LOGGED_ON; + } break; default: WARN("Unknown SAS action 0x%lx\n", wlxAction);