[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.
This commit is contained in:
Hermès Bélusca-Maïto
2025-06-14 20:56:58 +02:00
parent b0fbeb6801
commit 545f9cebb2

View File

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