This allows pressing ENTER or ESC on the keyboard and have the correct
action done. The equivalent dialog in shell32.dll was already using that.
Simplify the associated code as well.
Also: remove the unused `", 400, 0, 1"` `FONT` resource specification info.
And add missing keyboard accelerators to the dialog buttons
(except for Hebrew where it's not clear what the preferred way
of specifying accelerators is).
Some partition entries (such as those added by the CreateInsertBlankRegion function) may not have their Volume member allocated. This fixes the USETUP crash when such partitions are handled.
- 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.
- 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.
```
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.
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.
- As mentioned in the previous MSGINA commit aa67222595,
`lpProfilePath` specifies the path to a *roaming* user profile,
for example on a domain server, if any. It is then used to create
a local image (copy) of the profile on the local computer.
HOWEVER (ReactOS HACK):
We currently don't implement this in ReactOS; instead, we use it
directly as *the* user's profile path, without doing any copy...
- Yes, MS Windows allows `lpProfileInfo->lpProfilePath` to be NULL :)
The following members of the returned `WLX_PROFILE_V2_0` structure:
`pszProfile`, `pszPolicy`, `pszNetworkDefaultUserProfile`, and
`pszServerName`, have a specific meaning and are used when logging
to (NT4, Active Directory...) domains.
See the added code comments for details.
In particular, `pszProfile` specifies the path to a *roaming* user
profile[^1] on a domain server, if any. It **DOES NOT** specify the local
`"C:\Documents and Settings"` path (got via `GetProfilesDirectoryW()`).
Since we don't really support user login on domains, set these pointers to NULL.
----
Enabling UserEnv debug logging[^2] on Windows 2003, one can observe such
following traces, for a `TestUser` roaming user profile:
```
USERENV(148.14c) 20:24:59:821 LoadUserProfile: Entering, hToken = <0x8bc>, lpProfileInfo = 0x6e5d8
USERENV(148.14c) 20:24:59:875 LoadUserProfile: lpProfileInfo->dwFlags = <0x0>
USERENV(148.14c) 20:24:59:912 LoadUserProfile: lpProfileInfo->lpUserName = <TestUser>
USERENV(148.14c) 20:24:59:966 LoadUserProfile: lpProfileInfo->lpProfilePath = <C:\Documents and Settings\TestUser_Roaming>
USERENV(148.14c) 20:25:00:021 LoadUserProfile: lpProfileInfo->lpDefaultPath = <\\PC-H\netlogon\Default User>
USERENV(148.14c) 20:25:00:075 LoadUserProfile: NULL server name
...
USERENV(148.14c) 20:25:06:177 CopyProfileDirectoryEx: Found hive file NTUSER.DAT
USERENV(148.14c) 20:25:06:395 ReconcileFile: C:\Documents and Settings\TestUser_Roaming\NTUSER.DAT ==> C:\Documents and Settings\TestUser\NTUSER.DAT [OK]
...
```
The `lpProfilePath` specifies a roaming profile directory (`"TestUser_Roaming"`)
for a user named named `TestUser`, and UserEnv proceeds to image the roaming
profile into the directory (`"TestUser"`) in the local computer.
However, when the user has a local profile, the `lpProfilePath` is set to
NULL in this case, and one observes instead:
```
USERENV(148.14c) 20:21:22:644 LoadUserProfile: NULL central profile path
```
----
[^1]: The following links explain this, also demonstrating UserEnv debug logging:
- https://web.archive.org/web/20130319204738/http://blogs.technet.com/b/askds/archive/2008/11/11/understanding-how-to-read-a-userenv-log-part-2.aspx
- https://web.archive.org/web/20150405040409/http://blogs.technet.com/b/ad/archive/2007/08/20/tracking-user-environment-creation.aspx
[^2]: For more details, see:
https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/221833
(archived from: http://support.microsoft.com/kb/221833)
UserEnv debug logging is achieved by adding a `REG_DWORD` value named
`UserEnvDebugLevel` in the following registry sub-key:
`HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon`
with a non-zero value.
To view the output in a debugger (e.g. WinDbg when kernel-debugging
Windows), set the value to `0x00020002`.
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.)
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.
```
Split Windows Server 2003 and Windows Vista behaviour in two different cases and make them used separately: when ReactOS target version is NT 5.2, use the 1st case, otherwise use the 2nd one instead.
Also, handle NdisPhysicalMediumNative802_11 case only for NT 6.0 and newer, since that's actually supported starting from NDIS 6.0, according to MSDN:
https://learn.microsoft.com/en-us/windows-hardware/drivers/network/oid-gen-physical-medium
while for NDIS 5.1 and newer it's:
https://learn.microsoft.com/en-us/previous-versions/windows/hardware/network/ff560255(v=vs.85)
This fixes:
1. A critical regression with unavailable networking in ReactOS when 3rd-party NT5-compatible Ethernet/Wi-Fi drivers are used (both in VM and on real hardware) caused by commit 3842b59f75 from @EricKohl.
2. Failure to open Network Properties and Network Status from the Network tray icon (caused by the same commit too).
MSDN tells us this is done so for Windows XP and Server 2003 as well, and IF_TYPE_IEEE80211 is returned only in Windows Vista and newer, so the following Microsoft documentation is actually correct in this case:
https://learn.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_adapter_info
(see the information about "IP_ADAPTER_INFO.Type" member below on that page)
!!!Please note that the behaviour of Vista+ case (e. g., when compiling ReactOS targeted as NT 6.0 and newer) remains unchanged after this fix (networking still may not work), so it still requires the proper support of 3rd-party NT6+ compatible network miniport drivers (by handling this case via the Vista/NDIS6-style way) for NT6 target!!!
CORE-20244
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.
Use a KSEMAPHORE instead of a NotificationEvent to signal availability. This is to prevent satisfying the wait for multiple waiters, when only a single entry is on the list.
Fixes crashes on SMP builds.
IpReleaseAddress: Use DhcpReleaseParameters instead of DhcpReleaseIpAddressLease.
IpRenewAddress: Use DhcpAcquireParameters instead of DhcpRenewIpAddressLease.