135 Commits
Author SHA1 Message Date
Jose Carlos Jesus 9a9f312f88 [WINLOGON] Update Portuguese (pt-PT) translation (#8976) 2026-05-20 18:26:18 +03:00
Katayama Hirofumi MZ 4e2cca167d [WINLOGON] Optimize StartLsass and StartServicesManager (#9016)
Optimize for speed.
JIRA issue: N/A
Do not initialize the STARTUPINFO member, which is already
filled with zeros, with zeros, in StartLsass and
StartServicesManager functions.
Co-authored-by: Hermès BÉLUSCA - MAÏTO <[email protected]>
2026-05-17 08:42:32 +09:00
Timo Kreuzer 1cf31524d5 [REACTOS] Stop using non-conforming swprintf / vswprintf
Use the underscored versions instead.
2026-05-07 06:27:58 +00:00
Hermès Bélusca-Maïto 8c9039bbd4 [WINLOGON] Workaround buggy 3rd-party DLLs that use a wrong notification handler calling convention (#8640)
CORE-20279

PRELIMINARY REMARK: The described bug and code workaround only applies
for x86 32-bit builds.

----

While the Winlogon notification handlers[^1] actually use a `STDCALL`
calling convention, which can be trivially verified by debugging the
official Windows <= 2003 winlogon.exe and its notification extensions,
there exist 3rd-party Winlogon notification DLLs, like the `Ati2evxx.dll`
one from AMD/ATI XP video drivers, that use a `CDECL` calling convention,
or an invalid number (zero) of parameters.

I think the reason why this happens is as follows.
The official documentation[^1] indicates that the handlers have the
following prototype:
```c
void Event_Handler_Function_Name(
  _In_ PWLX_NOTIFICATION_INFO pInfo
);
```
The documentation (and possibly the internal header Windows is using for
Winlogon) is sloppy, because it doesn't tell whether the convention is
`STDCALL` or `CDECL`. When compiling routines with such a signature, the
compiler will employ whatever default convention it is set to use.

Windows code is typically compiled with `STDCALL` convention as the default
(see e.g. how the Windows Development Kit is set up), thus, such a
function signature would default to `STDCALL`. Observation (with debugger)
shows that it is what Windows' winlogon.exe is indeed expecting.

However, 3rd-party code using a different development environment, could
set the compiler to use `CDECL` as the default calling convention. As a
result, the function signature from above would use `CDECL` instead.

The difference between the `STDCALL` and `CDECL` conventions is how the
function parameters are passed on the stack and how the stack is cleaned
at the end (`STDCALL`: the function unwinds the stack; `CDECL`: the caller
does it). A calling convention mismatch would therefore corrupt the stack,
and this is exactly what happens with the `Ati2evxx.dll` from the AMD/ATI
drivers, see CORE-20279.

The ReactOS Winlogon crashes from the `_RTC_Failure()` handler just after
the 3rd-party handler returns, since we compile our code with runtime checks
enabled. Windows' winlogon.exe doesn't apparently crash, because neither
in Release nor in Checked/Debug mode did they compile winlogon.exe with
RTC enabled. However, its stack would become more corrupt with time.

In order to alleviate this in ReactOS' winlogon.exe, I decided to use
a "generic" workaround, manually calling the handler with inline ASM
(which is OK since the problem and solution is x86-specific only).
It does something similar to what the RTC support does: it checks the
stack pointer after the call and restores it if needed.
An informative message is then emitted in the debugger telling which DLL
is buggy and needs to be fixed.

[^1]: https://learn.microsoft.com/en-us/windows/win32/secauthn/event-handler-function-prototype
2026-01-29 21:04:44 +01:00
Copilot d6f68397cf [WINLOGON] Fix memory and handle leaks (#8514)
JIRA issue: CORE-13213
2025-12-27 22:10:44 +09:00
Hermès Bélusca-Maïto 8f3ac7ef58 [ADVAPI32][RPCRT4][UMPNPMGR][WINLOGON] Fix buffer size retrieval for MakeSelfRelativeSD() (#8395)
Based on Timo's observation in PR #8387.

And improve debug ERR strings for last-error values.
2025-10-08 15:45:36 +02:00
Hermès Bélusca-Maïto c1921754aa Revert "[WINLOGON] Temporarily hack around a bug in PSEH for GCC"
This reverts commit ddbe9719c9, now that PSEH has been fixed
in commit d50b8c93fb (PR #8350).

CORE-20307 CORE-20309 CORE-20316
2025-08-30 17:10:07 +02:00
Hermès Bélusca-Maïto ddbe9719c9 [WINLOGON] Temporarily hack around a bug in PSEH for GCC
Commit 51ee32f5f8 moved the `WNetClearConnections()` in the main
Winlogon thread, where it now runs.

`WNetClearConnections()` calls a 3rd-party module (nfs41_np.dll)
that invokes `kernel32!OutputDebugStringA()`.
The SEH usage pattern in `OutputDebugStringA()`, when compiled with
GCC and PSEH, generates an erroneous chain of exception handlers, that,
when running in an execution environment like that of winlogon.exe,
triggers a crash. See CORE-20316 for more details and testing.

As a temporary measure, hackfix away the problem by surrounding the
`WNetClearConnections()` call in a `_SEH2_TRY/_SEH2_EXCEPT` block
(the net effect is to "add" the missing exception handler entry).

Hack for commit 51ee32f5f8
CORE-20307 CORE-20309 CORE-20316
2025-08-26 22:40:42 +02:00
Hermès Bélusca-Maïto bded90874e [WINLOGON] Let the dialog manager manage the default focus (#8337)
- The single default button in the "Shutdown Computer" and "GINA failed
  to load" dialogs will be automatically focused by the dialog manager,
  so there is no need to invoke `SetFocus()` in their `WM_INITDIALOG`
  handler -- which also erroneously returned `TRUE`, thus ignoring any
  focus set by the caller :D

- Use `DeleteMenu()` instead of `RemoveMenu()` so that it'll free any
  memory resources.
2025-08-14 23:28:08 +02:00
Hermès Bélusca-Maïto 35ecbde693 [WINLOGON] *.rc: Fix dialog controls IDs; adjust few translations (#8337)
- "1" == `IDOK`; "-1" == `IDC_STATIC`
- Use the same translation for "Restart" between the two
  "GINA failed to load" and "Shutdown Computer" dialogs.
2025-08-14 23:28:08 +02:00
Hermès Bélusca-Maïto 20b3673aab [MSGINA] Fix default focus to dialog controls (#8337)
Fix some erroneous `SetFocus()` invocations in dialog procedures:

- In `WM_INITDIALOG`, don't return `TRUE` if focus is changed to a
  control, otherwise any focus set by the caller would be ignored;

- In other handlers, `SetFocus()` would generate an inconsistent
  behaviour with the dialog push-buttons, as mentioned in:
  https://devblogs.microsoft.com/oldnewthing/20040802-00/?p=38283
2025-08-14 23:28:02 +02:00
Hermès Bélusca-Maïto c29e4eb944 [WINLOGON] Move WlxShutdown() GINA notification in HandleShutdown() (#8329)
- Both 3rd-party modules and GINA shutdown notifications should be
  called just when shutdown is being started.

  Addendum to commit d3b9c68d22 (r66252)
  CORE-8322

- Factor the two `DisplayStatusMessage()` calls for shutdown vs. reboot.
2025-08-13 16:31:45 +02:00
Hermès Bélusca-Maïto 27e147a8ce [WINLOGON] Fixes for logon/logoff steps and notifications (#8325)
- The `LogonHandler` notification should be invoked only once for a
  given logon operation. It is invoked in `HandleLogon()` after access
  to the window station (and desktop) is allowed for the user logging in.
  And so, it must not be invoked elsewhere, when no user is logged in
  (or a logon failure happened), like after a call to `WlxDisplaySASNotice()`...

- Invoke the `StartShellHandler` notification **before** starting the
  shell, and the `PostShellHandler` notification **after** the shell
  started.

- Invoke the `LogoffHandler` notification on the application desktop,
  just after having terminated all the user's programs, and before
  switching back to Winlogon's desktop.

- Add and show the 'Logging off' status message.

- When performing the following actions:
  `WLX_SAS_ACTION_LOGOFF`, `WLX_SAS_ACTION_FORCE_LOGOFF`,
  as well as:
  `WLX_SAS_ACTION_SHUTDOWN`, `WLX_SAS_ACTION_SHUTDOWN_POWER_OFF`,
  `WLX_SAS_ACTION_SHUTDOWN_REBOOT`,
  ensure that Winlogon is in a correct LogonState for doing the logoff
  sequence.

----

Test results for Winlogon notifications, after fix:

- `Asynchronous: FALSE, Impersonation: FALSE`

  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventStartShell: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventPostShell: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLock: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventUnlock: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventStartScreenSaver: 32 tests executed (0 marked as todo, 6 failures), 0 skipped.
  WLEventStopScreenSaver: 32 tests executed (0 marked as todo, 5 failures), 0 skipped.
  WLEventLogoff: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
  ```

- `Asynchronous: FALSE, Impersonation: TRUE`

  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
  WLEventStartShell: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
  WLEventPostShell: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
  WLEventLock: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
  WLEventUnlock: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
  WLEventStartScreenSaver: 34 tests executed (0 marked as todo, 3 failures), 0 skipped.
  WLEventStopScreenSaver: 34 tests executed (0 marked as todo, 2 failures), 0 skipped.
  WLEventLogoff: 34 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
  ```
2025-08-13 16:26:59 +02:00
Hermès Bélusca-Maïto 51ee32f5f8 [WINLOGON] Close all the user network connections only at logoff (#8324)
Per-user network connections (to shared drives...) are restored at user
logon: `HandleLogon() -> RestoreAllConnections()`.
These connections should be closed only at user logoff, in `HandleLogoff()`,
instead of inside the common logoff/shutdown thread, which is also invoked
at... shutdown!

- Isolate the network connections closing inside a `CloseAllConnections()`
  helper (which also performs the necessary user thread impersonation).

- Invoke this helper directly inside `HandleLogoff()`, and also re-enable
  the `IDS_CLOSINGNETWORKCONNECTIONS` message display.
2025-08-12 23:01:47 +02:00
Hermès Bélusca-Maïto 78ce856564 [WINLOGON] Duplicate the logged-in user/domain names and give them to the notifications (#8322)
Test results:

- Test 1a: `Asynchronous: FALSE, Impersonation: FALSE`
  BEFORE the fix:

  OK, the thread isn't impersonated:
  ```
  Thread Token   : 0x00000000 - User: '(null)\(null)'
  ```
  BUT these two WLX notify info fields aren't set when the user is logged in:
  ```
  Info.UserName       : '(null)'
  Info.Domain         : '(null)'
  ```

  Results:
  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
  WLEventStartShell: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
  (NOTE: WLEventPostShell isn't yet implemented in ReactOS)
  WLEventLock: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventUnlock: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
  WLEventStartScreenSaver: 30 tests executed (0 marked as todo, 9 failures), 2 skipped.
  WLEventStopScreenSaver: 30 tests executed (0 marked as todo, 7 failures), 2 skipped.
  WLEventLogoff: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
  ```

- Test 1b: `Asynchronous: FALSE, Impersonation: FALSE`
  AFTER the fix:

  OK, the thread isn't impersonated:
  ```
  Thread Token   : 0x00000000 - User: '(null)\(null)'
  ```
  OK, these two WLX notify info fields are now set when the user is logged in:
  ```
  Info.UserName       : 'Administrator'
  Info.Domain         : 'MYCOMPUTERNAME'
  ```

  Results:
  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventStartShell: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
  (NOTE: WLEventPostShell isn't yet implemented in ReactOS)
  WLEventLock: 32 tests executed (0 marked as todo, 2 failures), 0 skipped.
  WLEventUnlock: 32 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventStartScreenSaver: 32 tests executed (0 marked as todo, 7 failures), 0 skipped.
  WLEventStopScreenSaver: 32 tests executed (0 marked as todo, 5 failures), 0 skipped.
  WLEventLogoff: 32 tests executed (0 marked as todo, 2 failures), 0 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
  ```
  Less failed tests and none skipped anymore.

- Test 2a: `Asynchronous: FALSE, Impersonation: TRUE`
  BEFORE the fix:

  OK, the thread impersonates the user when (s)he is logged in:
  ```
  Thread Token   : 0x00000360 - User: 'MYCOMPUTERNAME\Administrator'
  ```
  BUT these two WLX notify info fields aren't set when the user is logged in:
  ```
  Info.UserName       : '(null)'
  Info.Domain         : '(null)'
  ```

  Results:
  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 31 tests executed (0 marked as todo, 5 failures), 2 skipped.
  WLEventStartShell: 31 tests executed (0 marked as todo, 5 failures), 2 skipped.
  (NOTE: WLEventPostShell isn't yet implemented in ReactOS)
  WLEventLock: 31 tests executed (0 marked as todo, 6 failures), 2 skipped.
  WLEventUnlock: 31 tests executed (0 marked as todo, 5 failures), 2 skipped.
  WLEventStartScreenSaver: 32 tests executed (0 marked as todo, 6 failures), 2 skipped.
  WLEventStopScreenSaver: 32 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventLogoff: 32 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
  ```

- Test 2b: `Asynchronous: FALSE, Impersonation: TRUE`
  AFTER the fix:

  OK, the thread impersonates the user when (s)he is logged in:
  ```
  Thread Token   : 0x00000360 - User: 'MYCOMPUTERNAME\Administrator'
  ```
  OK, these two WLX notify info fields are now set when the user is logged in:
  ```
  Info.UserName       : 'Administrator'
  Info.Domain         : 'MYCOMPUTERNAME'
  ```

  Results:
  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
  WLEventStartShell: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
  (NOTE: WLEventPostShell isn't yet implemented in ReactOS)
  WLEventLock: 33 tests executed (0 marked as todo, 4 failures), 0 skipped.
  WLEventUnlock: 33 tests executed (0 marked as todo, 3 failures), 0 skipped.
  WLEventStartScreenSaver: 34 tests executed (0 marked as todo, 4 failures), 0 skipped.
  WLEventStopScreenSaver: 34 tests executed (0 marked as todo, 2 failures), 0 skipped.
  WLEventLogoff: 34 tests executed (0 marked as todo, 2 failures), 0 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
  ```
  As well, less failed tests and none skipped anymore.
2025-08-11 22:00:23 +02:00
Hermès Bélusca-Maïto 96249c12d9 [WINLOGON] Implement support for user impersonation when calling notification handlers (#8320)
Also, capture in `CallNotificationDll()` the notify info structure template
before invoking each DLL handler: a malicious caller might modify its contents,
and so we need to re-initialize its contents for each call.

Test results:

- Test 1: `Asynchronous: FALSE, Impersonation: FALSE`
  Before & After the fix, give the same results:
  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
  WLEventStartShell: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
  (NOTE: WLEventPostShell isn't yet implemented in ReactOS)
  WLEventLock: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventUnlock: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
  WLEventStartScreenSaver: 30 tests executed (0 marked as todo, 9 failures), 2 skipped.
  WLEventStopScreenSaver: 30 tests executed (0 marked as todo, 7 failures), 2 skipped.
  WLEventLogoff: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
  ```

  * The current notification thread doesn't impersonate any user, the
    dumped thread token shows:
    `Thread Token   : 0x00000000 - User: '(null)\(null)'`
    (except for `WLEventStartScreenSaver` and `WLEventStopScreenSaver`
    which currently in ReactOS, impersonate the logged user and shows e.g.,
    `Thread Token   : 0x00000250 - User: 'MYCOMPUTERNAME\Administrator' ).

- Test 2: `Asynchronous: FALSE, Impersonation: TRUE`
  Before the fix:
  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 29 tests executed (0 marked as todo, 8 failures), 4 skipped.
  WLEventStartShell: 29 tests executed (0 marked as todo, 8 failures), 4 skipped.
  (NOTE: WLEventPostShell isn't yet implemented in ReactOS)
  WLEventLock: 29 tests executed (0 marked as todo, 9 failures), 4 skipped.
  WLEventUnlock: 29 tests executed (0 marked as todo, 8 failures), 4 skipped.
  WLEventStartScreenSaver: 32 tests executed (0 marked as todo, 6 failures), 2 skipped.
  WLEventStopScreenSaver: 32 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventLogoff: 30 tests executed (0 marked as todo, 7 failures), 4 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
  ```

  * There are more failures (and skipped tests), because in impersonation
    mode, the tests expect that the current thread is impersonating the
    logged-on user, and validate whether this impersonated user matches
    what the WLX notification `Domain` and `UserName` information structure
    members are. However, these two fields aren't set yet, and the thread
    isn't impersonating any user yet.

  * The dumped thread token shows the same information as in Test 1.

- Test 3: `Asynchronous: FALSE, Impersonation: TRUE`
  After the fix:
  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 31 tests executed (0 marked as todo, 5 failures), 2 skipped.
  WLEventStartShell: 31 tests executed (0 marked as todo, 5 failures), 2 skipped.
  (NOTE: WLEventPostShell isn't yet implemented in ReactOS)
  WLEventLock: 31 tests executed (0 marked as todo, 6 failures), 2 skipped.
  WLEventUnlock: 31 tests executed (0 marked as todo, 5 failures), 2 skipped.
  WLEventStartScreenSaver: 32 tests executed (0 marked as todo, 6 failures), 2 skipped.
  WLEventStopScreenSaver: 32 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventLogoff: 32 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
  ```

  * There are now less skipped tests than in Test 2, as much as in Test 1.

  * There are also less failed tests than in Test 2; however, there are
    few more failed tests than in Test 1, but this is balanced by new
    tests being executed.

  The reason is that now, compared to Test 2 in impersonation mode, the
  current thread is correctly impersonating the logged-on user, if any.
  However, the WLX notification `Domain` and `UserName` information
  structure members still aren't set yet, thus some of the tests fail.

  * The dumped thread token for all notifications now show e.g.,
    `Thread Token   : 0x00000360 - User: 'MYCOMPUTERNAME\Administrator'`
    (`WLEventStartup`, `WLEventShutdown` don't show any, since no user
    is logged-in at these stages.)
2025-08-11 18:43:58 +02:00
Hermès Bélusca-Maïto 2cf3f14c50 [WINLOGON] Delay notification DLL loading until the very first notification (#8285)
And retrieve all its exported notification handlers.
This reverts parts of commit 5d4f69bf35.

Because notification DLLs can keep internal state between successive
notifications, they are kept loaded until Winlogon termination.

The SFC notification DLL is also loaded. Because sfc.dll redirects to
sfc_os.dll, the latter is then automatically loaded. This allows doing
what commit 88ee639b06 (r68615) was aiming at, in a less hackish manner.

CORE-9598

Test results:

- Before:

  We observe the repeated loading/unloading of the DLL at each
  notification call:
  ```
  WLNOTIFY(ac.b0):  Entering `DllMain`(hInst: 0x10000000, dwReason: 0x1, pReserved: 0x00000000)
  ...
  WLNOTIFY(ac.b0):  Entering `DllMain`(hInst: 0x10000000, dwReason: 0x0, pReserved: 0x00000000)
  ```

  The global state of the notification DLL is lost between each
  notification, and such testing errors happen:
  ```
  modules\rostests\win32\winlogon\wlntfytests\wlntfytests.c:786: Test failed: **** WLEventLogon: ERROR: Wrong state NON-INITIALIZED, expected Startup or Logoff
  err:(modules\rostests\win32\winlogon\wlntfytests\wlntfytests.c:1034) **** WLEventLogon: Changing state NON-INITIALIZED to Logon
  ```
  The previous notification state is always reset to `NON-INITIALIZED` (its initial value).

  Test results for all the notifications:
  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventStartShell: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
  (NOTE: WLEventPostShell isn't yet implemented in ReactOS)
  WLEventLock: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventUnlock: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventStartScreenSaver: 30 tests executed (0 marked as todo, 10 failures), 0 skipped.
  WLEventStopScreenSaver: 30 tests executed (0 marked as todo, 9 failures), 0 skipped.
  WLEventLogoff: 30 tests executed (0 marked as todo, 5 failures), 2 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 5 failures), 0 skipped.
  ```

- After:

  The DLL is loaded only once, at the first notification, then stays
  loaded for the whole life of winlogon.exe:
  ```
  WLNOTIFY(ac.b0):  Entering `DllMain`(hInst: 0x10000000, dwReason: 0x1, pReserved: 0x00000000)
  ```
  and the global state of the notification DLL is now kept between each
  notification, there are no `ERROR: Wrong state NON-INITIALIZED, expected ...`
  errors anymore.

  Test results for all the notifications:
  ```
  WLEventStartup: 30 tests executed (0 marked as todo, 1 failure), 0 skipped.
  WLEventLogon: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
  WLEventStartShell: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
  (NOTE: WLEventPostShell isn't yet implemented in ReactOS)
  WLEventLock: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventUnlock: 30 tests executed (0 marked as todo, 3 failures), 2 skipped.
  WLEventStartScreenSaver: 30 tests executed (0 marked as todo, 9 failures), 2 skipped.
  WLEventStopScreenSaver: 30 tests executed (0 marked as todo, 7 failures), 2 skipped.
  WLEventLogoff: 30 tests executed (0 marked as todo, 4 failures), 2 skipped.
  WLEventShutdown: 31 tests executed (0 marked as todo, 3 failures), 0 skipped.
  ```
2025-08-08 16:37:44 +02:00
Hermès Bélusca-Maïto 7b1c15f182 [WINLOGON] AddNotificationDll(): Expand the "DllName" path if needed (#8283)
Expand the "DllName" notification DLL path string, independently of
whether it is REG_SZ or REG_EXPAND_SZ, before loading it, similarly
to Windows' winlogon.exe.

Validate also the type/size of the retrieved registry value.
2025-08-08 13:53:18 +02:00
Hermès Bélusca-Maïto ba36b907ad [WINLOGON][WLNTFYTESTS] Implement loading notification DLLs in safe-boot mode (#8278)
Historical note:
Investigation shows that this functionality, introduced between builds
1902 and 1906 of Windows NT 5.0 (future 2000) Beta 3, has always been
"nop-ed" and has remained this way till Windows Server 2003.
The value read from the "SafeMode" registry value is unconditionally
overridden afterwards, causing the notification DLLs to always be loaded.

In ReactOS, this functionality is restored, and only the notifications
tagged as such are loaded in SafeMode.

Furthermore:
Analysis of strings in Win2000 and WinXP/2003 winlogon.exe, show that
the "Safe" registry value doesn't exist for notifications; instead,
it is named "SafeMode".
The "Safe" value appears only for the SensLogn (SENS Winlogon Event) handler
registry entry. My hypothesis is that the value name is a typo for the
"SafeMode" value. It has been introduced in the `\Winlogon\Notify\SensLogn`
registry entry for SensLogn around Windows NT 5.0 build 1946.
2025-07-30 17:46:54 +02:00
Hermès Bélusca-Maïto 96711c6c59 [WINLOGON] AddNotificationDll(): Validate the registry retrieved DWORDs (#8277)
Validate the DWORDs, instead of accepting any sort of value.

+ Add SAL2 annotations and improve a TRACE.
2025-07-30 12:42:31 +02:00
Hermès Bélusca-Maïto b74e243579 [WINLOGON][WLNTFYTESTS] The "Enabled" registry value doesn't exist for notifications (#8276)
Analysis of strings in Win2000 and WinXP/2003 winlogon.exe, show that
the "Enabled" registry value doesn't exist for notifications.

This value is actually only used by the ScCertProp (Smart Card Certificate
Propagation) notifications, in wlnotify.dll, to enable or disable certificate
progagation.[^1]

Note that whatever the "Enabled" registry value is, the notification DLL
is still loaded within winlogon.exe.

We however keep the `bEnabled` internal flag, so as to be able to disable
at runtime notifications that could not be delay-loaded, or that behave
erratically, etc.

[WLNOTIFY] Add a comment about the "Enabled" value in scard.c!SCardStartCertProp()

[^1]: For more information, see:
https://www.microfocus.com/documentation/securelogin/9.0/administration_guide/blm54qb.html?view=print
https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/925884
2025-07-30 12:37:23 +02:00
Hermès Bélusca-Maïto 46e0fffb54 [WINLOGON] Cleanup code in InitNotifications() and CallNotificationDlls()
- `KEY_ENUMERATE_SUB_KEYS` is redundant with `KEY_READ`;
- Simplify the `dwIndex` loop in `InitNotifications()`.
2025-07-28 22:04:04 +02:00
Hermès Bélusca-Maïto 1f7d34ec5b [WINLOGON] Simplify notification structure cleanup code
- Add DeleteNotification() helper;
- Invoke it in failure path in AddNotificationDll(), and in
  CleanupNotifications().
- Simplify iteration loops in CallNotificationDlls() and in
  CleanupNotifications().

Side-note: When doing `Notification = CONTAINING_RECORD(ListEntry, ...);`
where `ListEntry` iterates over a well-formed linked-list, the `Notification`
pointer can **NEVER** be NULL!
2025-07-28 22:04:03 +02:00
Hermès Bélusca-Maïto 627f8da3cd [WINLOGON] SASWindowProc(): Call PostQuitMessage(0) on WM_DESTROY
Now the WinMain() message loop correctly exits and we get to perform
last-time cleanup. However, the main thread must not exit (except under
certain conditions, not yet implemented), so we Sleep for an infinite
amount of time.
2025-07-28 22:04:02 +02:00
Hermès Bélusca-Maïto bb881021ce [WINLOGON] Move logoff/shutdown thread handling code into a helper function (#8222)
This code was in common between HandleLogoff() and HandleShutdown().
2025-07-04 17:07:03 +02:00
Hermès Bélusca-Maïto 2e4cdd4c23 [WINLOGON] Improve EWX_* flags to WLX_* actions mapping in WM_LOGONNOTIFY:LN_LOGOFF
CORE-8322 CORE-11550
2025-07-02 22:44:28 +02:00
Hermès Bélusca-Maïto 3f73319068 [WINLOGON] Cleanup user login information when logon fails and at logoff (#8182) 2025-06-30 14:02:34 +02:00
Hermès Bélusca-Maïto af96e9f353 [TRANSLATIONS] Fix some typos in French translations (#8164) 2025-06-29 16:31:39 +02:00
Hermès Bélusca-Maïto f60be66d1f [MSGINA][WINLOGON] Carefully zero password memory buffers before freeing them (#8172)
Including variables containing pointers to a password buffer and its lengths.
2025-06-27 16:45:12 +02:00
Hermès Bélusca-Maïto b254ea8274 [MSGINA][WINLOGON] Perform thorough memory cleanup after user logging (#8155)
- MSGINA: The `pMprNotifyInfo` and `pProfile` structures returned by
  `WlxLoggedOutSAS()`, as well as all of their pointer fields, are
  allocated by `LocalAlloc()`[^1][^2]. This is what Windows' Winlogon
  expects (and ours too, for interoperability with GINA dlls written
  for Windows), as it then frees them using `LocalFree()`.

- WINLOGON: In `HandleLogon()`, free the cached `MprNotifyInfo` and
  `Profile` buffers (and all their members) obtained from a previous
  call to `WlxLoggedOutSAS()`.

[^1]: https://learn.microsoft.com/en-us/windows/win32/api/winwlx/nf-winwlx-wlxloggedoutsas
[^2]: 3rd-party GINAs rely on this as well. One example can be found at:
      https://www.codeproject.com/Articles/20656/Winlogon-using-Mobile-Disk
2025-06-24 20:30:34 +02:00
Hermès Bélusca-Maïto b8c5e9c209 [WINLOGON] Check whether error popups should be shown if loading user profile fails (#8139)
Respect the `"NoPopupsOnBoot"` REG_DWORD value in `HKLM\System\CurrentControlSet\Control\Windows`
https://www.visualautomation.com/comprod/secure6/nopopups.htm
2025-06-19 16:09:31 +02:00
Hermès Bélusca-Maïto 82a57e41e1 [WINLOGON] Correctly reset LogonState in case logon or shutdown fails (#8133)
CORE-18351 CORE-18237 CORE-17137 CORE-16567
CORE-15360 CORE-5071 CORE-3804

Reset `LogonState` back to `STATE_LOGGED_OFF` before invoking
`WlxDisplaySASNotice()` when:
- in `STATE_LOGGED_OFF_SAS` state, `HandleLogon()` failed;
- or when an attempted shutdown operation failed.

This fixes the resulting inconsistent `LogonState` that happened if
any of these operations failed due to legitimate reasons. For example,
a corrupted user profile that caused the login attempt to abort, or,
an ongoing shutdown attempt being aborted as well.

One of the user-visible effects of this inconsistency, was the inability
to access the familiar Logged-Out SAS dialog by pressing Ctrl-Alt-Del at
the invite (SAS notice) dialog, because the `LogonState` was incorrectly
left into the `STATE_LOGGED_OFF_SAS` state, instead of being reset to
`STATE_LOGGED_OFF`.

----

Typical scenario:
The "Administrator" user, who is auto-logged-in by default after the
installation, gets a corrupted ntuser.dat profile registry hive if the
2nd-stage installation is aborted at the end by force-restarting ReactOS.
After reboot, ReactOS tries to log into the account, but fails, and goes
back to the Ctrl-Alt-Del invite dialog.
Before this fix, the user couldn't go into the Logged-Out SAS dialog to
enter new login credentials and attempt login to another account.
This is now fixed.
2025-06-16 14:16:47 +02:00
Hermès Bélusca-Maïto 545f9cebb2 [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.
2025-06-16 14:11:42 +02:00
Hermès Bélusca-Maïto b0fbeb6801 [WINLOGON][MSGINA] Improve WLX_SAS_ACTION_TASKLIST handling in logged-on/logged-on SAS states (#8131)
CORE-13478
Addendum to commit 46dcab7ab.

The `WLX_SAS_ACTION_TASKLIST` action can be invoked in three scenarii to
open the Task-Manager:

1. from the logged-on state (`LogonState == STATE_LOGGED_ON`), when the
   user presses Ctrl-Shift-Esc while being on its own desktop (usual case);

2. from the Logged-On SAS dialog (`LogonState == STATE_LOGGED_ON_SAS`),
   when the user presses the "Task-Manager" button: here Winlogon should
   switch back to the user's desktop, restoring `STATE_LOGGED_ON` and
   start the TaskMgr;

3. or when the user presses Ctrl-Shift-Esc **while being on the Logged-On
   SAS dialog**: in this case, the Task-Manager is started on the
   currently-hidden user's desktop (and so, will be hidden), but the SAS
   dialog stays open. The user will see the opened TaskMgr once (s)he
   closes the SAS dialog and Winlogon switches back to the user's desktop.

In order to support these scenarii, the `WLX_SAS_ACTION_TASKLIST` action
handling is reworked:

- `SASWindowProc(WM_HOTKEY, IDHK_CTRL_SHIFT_ESC)` always invokes the
  `DoGenericAction(WLX_SAS_ACTION_TASKLIST)`: this allows centralizing
  inside `DoGenericAction()` the condition checks for starting TaskMgr.

- `DoGenericAction(WLX_SAS_ACTION_TASKLIST)` just starts the Task-Manager
  only if the Winlogon's `LogonState` is either `STATE_LOGGED_ON` or
  `STATE_LOGGED_ON_SAS`. It doesn't attempt there to switch desktops nor
  change the `LogonState` value, in order to support scenarii 2 and 3.

- The switch from/to Winlogon/user's desktops when going to the
  `LogonState: STATE_LOGGED_ON -> STATE_LOGGED_ON_SAS` change is done
  in `DispatchSAS()`, just before invoking the GINA's `WlxLoggedOnSAS()`
  (see below for more details) and just after it returns, only in the
  necessary cases.

----

[MSGINA] The WlxLoggedOnSAS() dialog shouldn't switch the desktops itself.

This behaviour can be observed on Windows with Winlogon debugging + tracing
enabled. It is Winlogon instead that does the desktop switch itself, as for
all the other SAS dialogs, in addition to changing its internal `LogonState`.

Fix for commit 7aecedf79 (r58785).
2025-06-16 14:04:33 +02:00
Hermès Bélusca-Maïto a8c5f55315 [WINLOGON] Invoke NtShutdownSystem() with an adequate shutdown action (#8130)
Specify a shutdown action value corresponding to the
`WLX_SAS_ACTION_SHUTDOWN_*` ones.
2025-06-16 14:02:55 +02:00
Hermès Bélusca-Maïto b3e56c95ef [WINLOGON] WlxSwitchDesktopToUser/Winlogon(): ensure the calling thread is assigned the specified desktop (#8130)
Invoke SetThreadDesktop() after a successful SwitchDesktop() call.
2025-06-16 14:02:55 +02:00
Hermès Bélusca-Maïto 14894f2e27 [WINLOGON] DefaultWlxWindowProc(WLX_WM_SAS): return an adequate WLX_DLG_* value (#8130)
For more details, see:
https://learn.microsoft.com/en-us/windows/win32/api/winwlx/nc-winwlx-pwlx_dialog_box_indirect_param#return-value
2025-06-16 14:02:49 +02:00
Hermès Bélusca-Maïto fbd676f4c9 [WINLOGON] Register hotkeys for 'Lock Workstation' and 'Accessibility' (UtilMan) (#8083)
- The hotkeys are respectively: Win+L and Win+U .
- Use instead the hotkey IDs in the WM_HOTKEY handler.
2025-06-04 16:44:44 +02:00
Hermès Bélusca-Maïto 6696d40cfc [SDK] Introduce winbase_undoc.h for undocumented exported kernel32 definitions (#8019)
This header is based on the following files from the official
Windows 10.0.10240.0 PSDK, a copy of which can be found at:
- https://github.com/tpn/winsdk-10/blob/master/Include/10.0.10240.0/um/minwin/winbasep.h
- https://github.com/tpn/winsdk-10/blob/master/Include/10.0.10240.0/um/minwin/wbasek.h
2025-05-27 20:52:17 +02:00
Katayama Hirofumi MZ fe11f7a2e5 [REACTOS] Refresh old URLs (#7632)
URLs are getting old. We have to
update URLs for documentation
purpose.
JIRA issue: CORE-19963
- Refresh old URLs.
- Add " (DEAD_LINK)" labels
  to dead links.
- Use MS Learn links rather
  than MSDN ones.
- Some dead links revived by
  Web Archive.
- Don't change Wine Tests
  and Wine Sync.
- Don't change 3rd party libraries.
- Don't append "redirected" labels.
2025-01-28 13:36:45 +09:00
Thamatip Chitpong 1dfba2a699 [WINLOGON] Add WLSESSION logon timestamp (#7590)
Remove startup sound hack.
CORE-13951
2025-01-08 08:28:24 +07:00
Thamatip Chitpong 2557948179 [WINLOGON] Implement startup sound support (HACK)
CORE-13951
2024-12-09 09:52:57 +07:00
Thamatip Chitpong 37375fcc4d [WINLOGON] Implement shutdown sound support
CORE-13951
2024-12-09 09:52:57 +07:00
Thamatip Chitpong 77bfc12e0f [WINLOGON] Move logoff flags handling code to HandleLogoff 2024-12-09 09:52:57 +07:00
Gabriele Lo Re fbcbbd8768 [TRANSLATION] Improve Italian (it-IT) translation part 2 (#7248) 2024-08-21 01:29:34 +02:00
Stanislav Motylkov 9cf6b253e7 [REACTOS] Fix Kamil Horníček's last name where possible 2024-07-29 17:58:02 +03:00
Václav Zouzalík 6fff27d3f5 [WINLOGON] Update Slovak (sk-SK) translation (#7050) 2024-07-18 18:08:25 +02:00
Václav Zouzalík 7b7c378188 [WINLOGON] Update Czech (cs-CZ) translation (#7036) 2024-06-21 12:42:13 +03:00
Andrei Miloiu 2c96a6b614 [WINLOGON] Update Romanian (ro-RO) translation (#6773) 2024-05-10 21:46:46 +02:00
Andrei Miloiu 12056e88eb [WINLOGON] Update Romanian (ro-RO) translation (#6261) 2024-01-15 21:54:11 +01:00