[WINLOGON] Add WLSESSION logon timestamp (#7590)
authorThamatip Chitpong <thamatip.chitpong@reactos.org>
Wed, 8 Jan 2025 01:28:24 +0000 (08:28 +0700)
committerGitHub <noreply@github.com>
Wed, 8 Jan 2025 01:28:24 +0000 (08:28 +0700)
Remove startup sound hack.
CORE-13951

base/system/winlogon/sas.c
base/system/winlogon/winlogon.h

index 8b169f7..17c7778 100644 (file)
@@ -46,6 +46,12 @@ static BOOL ExitReactOSInProgress = FALSE;
 
 LUID LuidNone = {0, 0};
 
+typedef struct tagLOGON_SOUND_DATA
+{
+    HANDLE UserToken;
+    BOOL IsStartup;
+} LOGON_SOUND_DATA, *PLOGON_SOUND_DATA;
+
 /* FUNCTIONS ****************************************************************/
 
 static BOOL
@@ -286,26 +292,12 @@ PlaySoundRoutine(
 }
 
 static
-BOOL
-IsFirstLogon(VOID)
-{
-    /* FIXME: All of this is a HACK, designed specifically for PlayLogonSoundThread.
-     * Don't call IsFirstLogon multiple times inside the same function. And please
-     * note that this function is not thread-safe. */
-    static BOOL bFirstLogon = TRUE;
-    if (bFirstLogon)
-    {
-        bFirstLogon = FALSE;
-        return TRUE;
-    }
-    return FALSE;
-}
-
 DWORD
 WINAPI
 PlayLogonSoundThread(
-    IN LPVOID lpParameter)
+    _In_ LPVOID lpParameter)
 {
+    PLOGON_SOUND_DATA SoundData = (PLOGON_SOUND_DATA)lpParameter;
     SERVICE_STATUS_PROCESS Info;
     DWORD dwSize;
     ULONG Index = 0;
@@ -316,7 +308,7 @@ PlayLogonSoundThread(
     if (!hSCManager)
     {
         ERR("OpenSCManager failed (%x)\n", GetLastError());
-        return 0;
+        goto Cleanup;
     }
 
     /* Open the wdmaud service */
@@ -326,7 +318,7 @@ PlayLogonSoundThread(
         /* The service is not installed */
         TRACE("Failed to open wdmaud service (%x)\n", GetLastError());
         CloseServiceHandle(hSCManager);
-        return 0;
+        goto Cleanup;
     }
 
     /* Wait for wdmaud to start */
@@ -352,35 +344,50 @@ PlayLogonSoundThread(
     if (Info.dwCurrentState != SERVICE_RUNNING)
     {
         WARN("wdmaud has not started!\n");
-        return 0;
+        goto Cleanup;
     }
 
     /* Sound subsystem is running. Play logon sound. */
-    TRACE("Playing logon sound\n");
-    if (!ImpersonateLoggedOnUser((HANDLE)lpParameter))
+    TRACE("Playing %s sound\n", SoundData->IsStartup ? "startup" : "logon");
+    if (!ImpersonateLoggedOnUser(SoundData->UserToken))
     {
         ERR("ImpersonateLoggedOnUser failed (%x)\n", GetLastError());
     }
     else
     {
-        PlaySoundRoutine(IsFirstLogon() ? L"SystemStart" : L"WindowsLogon",
+        PlaySoundRoutine(SoundData->IsStartup ? L"SystemStart" : L"WindowsLogon",
                          TRUE,
                          SND_ALIAS | SND_NODEFAULT);
         RevertToSelf();
     }
+
+Cleanup:
+    HeapFree(GetProcessHeap(), 0, SoundData);
     return 0;
 }
 
 static
 VOID
 PlayLogonSound(
-    IN OUT PWLSESSION Session)
+    _In_ PWLSESSION Session)
 {
+    PLOGON_SOUND_DATA SoundData;
     HANDLE hThread;
 
-    hThread = CreateThread(NULL, 0, PlayLogonSoundThread, (PVOID)Session->UserToken, 0, NULL);
-    if (hThread)
-        CloseHandle(hThread);
+    SoundData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGON_SOUND_DATA));
+    if (!SoundData)
+        return;
+
+    SoundData->UserToken = Session->UserToken;
+    SoundData->IsStartup = IsFirstLogon(Session);
+
+    hThread = CreateThread(NULL, 0, PlayLogonSoundThread, SoundData, 0, NULL);
+    if (!hThread)
+    {
+        HeapFree(GetProcessHeap(), 0, SoundData);
+        return;
+    }
+    CloseHandle(hThread);
 }
 
 static
@@ -571,6 +578,9 @@ HandleLogon(
     /* Logon has succeeded. Play sound. */
     PlayLogonSound(Session);
 
+    /* NOTE: The logon timestamp has to be set after calling PlayLogonSound
+     * to correctly detect the startup event (first logon) */
+    SetLogonTimestamp(Session);
     ret = TRUE;
 
 cleanup:
index 3dcf6fd..4df8e00 100644 (file)
@@ -41,6 +41,7 @@
 #include <winwlx.h>
 #include <ndk/rtlfuncs.h>
 #include <ndk/exfuncs.h>
+#include <ndk/kefuncs.h>
 #include <strsafe.h>
 
 /* PSEH for SEH Support */
@@ -233,6 +234,7 @@ typedef struct _WLSESSION
     HANDLE hProfileInfo;
     LOGON_STATE LogonState;
     DWORD DialogTimeout; /* Timeout for dialog boxes, in seconds */
+    LARGE_INTEGER LastLogon;
 
     /* Screen-saver informations */
 #ifndef USE_GETLASTINPUTINFO
@@ -285,6 +287,23 @@ extern PWLSESSION WLSession;
    ((Status) == WLX_SAS_ACTION_SHUTDOWN_HIBERNATE) \
   )
 
+FORCEINLINE
+VOID
+SetLogonTimestamp(
+    _Inout_ PWLSESSION Session)
+{
+    NtQuerySystemTime(&Session->LastLogon);
+}
+
+FORCEINLINE
+BOOL
+IsFirstLogon(
+    _In_ PWLSESSION Session)
+{
+    /* The WLSESSION::LastLogon is initialized to 0 so this is OK */
+    return (Session->LastLogon.QuadPart == 0);
+}
+
 /* environment.c */
 BOOL
 CreateUserEnvironment(IN PWLSESSION Session);