[WINLOGON] On logoff, also disconnect from any remote location
[reactos.git] / base / system / winlogon / sas.c
index e9945e9..d914beb 100644 (file)
@@ -43,6 +43,8 @@ typedef struct tagLOGOFF_SHUTDOWN_DATA
 
 static BOOL ExitReactOSInProgress = FALSE;
 
+LUID LuidNone = {0, 0};
+
 /* FUNCTIONS ****************************************************************/
 
 static BOOL
@@ -106,51 +108,69 @@ StartUserShell(
 
 BOOL
 SetDefaultLanguage(
-    IN BOOL UserProfile)
+    IN PWLSESSION Session)
 {
-    HKEY BaseKey;
-    LPCWSTR SubKey;
-    LPCWSTR ValueName;
+    BOOL ret = FALSE;
+    BOOL UserProfile;
     LONG rc;
-    HKEY hKey = NULL;
+    HKEY UserKey, hKey = NULL;
+    LPCWSTR SubKey, ValueName;
     DWORD dwType, dwSize;
     LPWSTR Value = NULL;
     UNICODE_STRING ValueString;
     NTSTATUS Status;
     LCID Lcid;
-    BOOL ret = FALSE;
+
+    UserProfile = (Session && Session->UserToken);
+
+    if (UserProfile && !ImpersonateLoggedOnUser(Session->UserToken))
+    {
+        ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
+        return FALSE;
+        // FIXME: ... or use the default language of the system??
+        // UserProfile = FALSE;
+    }
 
     if (UserProfile)
     {
-        BaseKey = HKEY_CURRENT_USER;
+        rc = RegOpenCurrentUser(MAXIMUM_ALLOWED, &UserKey);
+        if (rc != ERROR_SUCCESS)
+        {
+            TRACE("RegOpenCurrentUser() failed with error %lu\n", rc);
+            goto cleanup;
+        }
+
         SubKey = L"Control Panel\\International";
         ValueName = L"Locale";
     }
     else
     {
-        BaseKey = HKEY_LOCAL_MACHINE;
+        UserKey = NULL;
         SubKey = L"System\\CurrentControlSet\\Control\\Nls\\Language";
         ValueName = L"Default";
     }
 
-    rc = RegOpenKeyExW(
-        BaseKey,
-        SubKey,
-        0,
-        KEY_READ,
-        &hKey);
+    rc = RegOpenKeyExW(UserKey ? UserKey : HKEY_LOCAL_MACHINE,
+                       SubKey,
+                       0,
+                       KEY_READ,
+                       &hKey);
+
+    if (UserKey)
+        RegCloseKey(UserKey);
+
     if (rc != ERROR_SUCCESS)
     {
         TRACE("RegOpenKeyEx() failed with error %lu\n", rc);
         goto cleanup;
     }
-    rc = RegQueryValueExW(
-        hKey,
-        ValueName,
-        NULL,
-        &dwType,
-        NULL,
-        &dwSize);
+
+    rc = RegQueryValueExW(hKey,
+                          ValueName,
+                          NULL,
+                          &dwType,
+                          NULL,
+                          &dwSize);
     if (rc != ERROR_SUCCESS)
     {
         TRACE("RegQueryValueEx() failed with error %lu\n", rc);
@@ -169,13 +189,12 @@ SetDefaultLanguage(
         TRACE("HeapAlloc() failed\n");
         goto cleanup;
     }
-    rc = RegQueryValueExW(
-        hKey,
-        ValueName,
-        NULL,
-        NULL,
-        (LPBYTE)Value,
-        &dwSize);
+    rc = RegQueryValueExW(hKey,
+                          ValueName,
+                          NULL,
+                          NULL,
+                          (LPBYTE)Value,
+                          &dwSize);
     if (rc != ERROR_SUCCESS)
     {
         TRACE("RegQueryValueEx() failed with error %lu\n", rc);
@@ -204,10 +223,15 @@ SetDefaultLanguage(
     ret = TRUE;
 
 cleanup:
-    if (hKey)
-        RegCloseKey(hKey);
     if (Value)
         HeapFree(GetProcessHeap(), 0, Value);
+
+    if (hKey)
+        RegCloseKey(hKey);
+
+    if (UserProfile)
+        RevertToSelf();
+
     return ret;
 }
 
@@ -272,6 +296,11 @@ PlayLogonSoundThread(
     ULONG Index = 0;
     SC_HANDLE hSCManager, hService;
 
+    //
+    // FIXME: Isn't it possible to *JUST* impersonate the current user
+    // *AND* open its HKCU??
+    //
+
     /* Get SID of current user */
     Status = NtQueryInformationToken((HANDLE)lpParameter,
                                      TokenUser,
@@ -336,7 +365,7 @@ PlayLogonSoundThread(
         return 0;
     }
 
-    /* Open service manager */
+    /* Open the service manager */
     hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
     if (!hSCManager)
     {
@@ -344,17 +373,17 @@ PlayLogonSoundThread(
         return 0;
     }
 
-    /* Open wdmaud service */
+    /* Open the wdmaud service */
     hService = OpenServiceW(hSCManager, L"wdmaud", GENERIC_READ);
     if (!hService)
     {
-        /* Sound is not installed */
+        /* The service is not installed */
         TRACE("Failed to open wdmaud service (%x)\n", GetLastError());
         CloseServiceHandle(hSCManager);
         return 0;
     }
 
-    /* Wait for wdmaud start */
+    /* Wait for wdmaud to start */
     do
     {
         if (!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&Info, sizeof(SERVICE_STATUS_PROCESS), &dwSize))
@@ -398,6 +427,87 @@ PlayLogonSound(
         CloseHandle(hThread);
 }
 
+static BOOL
+AllowWinstaAccess(PWLSESSION Session)
+{
+    BOOL bSuccess = FALSE;
+    DWORD dwIndex;
+    DWORD dwLength = 0;
+    PTOKEN_GROUPS ptg = NULL;
+    PSID psid;
+    TOKEN_STATISTICS Stats;
+    DWORD cbStats;
+    DWORD ret;
+
+    // Get required buffer size and allocate the TOKEN_GROUPS buffer.
+
+    if (!GetTokenInformation(Session->UserToken,
+                             TokenGroups,
+                             ptg,
+                             0,
+                             &dwLength))
+    {
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+            return FALSE;
+
+        ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
+        if (ptg == NULL)
+            return FALSE;
+    }
+
+    // Get the token group information from the access token.
+    if (!GetTokenInformation(Session->UserToken,
+                             TokenGroups,
+                             ptg,
+                             dwLength,
+                             &dwLength))
+    {
+        goto Cleanup;
+    }
+
+    // Loop through the groups to find the logon SID.
+
+    for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
+    {
+        if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID)
+            == SE_GROUP_LOGON_ID)
+        {
+            psid = ptg->Groups[dwIndex].Sid;
+            break;
+        }
+    }
+
+    dwLength = GetLengthSid(psid);
+
+    if (!GetTokenInformation(Session->UserToken,
+                             TokenStatistics,
+                             &Stats,
+                             sizeof(TOKEN_STATISTICS),
+                             &cbStats))
+    {
+        WARN("Couldn't get Authentication id from user token!\n");
+        goto Cleanup;
+    }
+
+    AddAceToWindowStation(Session->InteractiveWindowStation, psid);
+
+    ret = SetWindowStationUser(Session->InteractiveWindowStation,
+                               &Stats.AuthenticationId,
+                               psid,
+                               dwLength);
+    TRACE("SetWindowStationUser returned 0x%x\n", ret);
+
+    bSuccess = TRUE;
+
+Cleanup:
+
+    // Free the buffer for the token groups.
+    if (ptg != NULL)
+        HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
+
+    return bSuccess;
+}
+
 static
 BOOL
 HandleLogon(
@@ -451,13 +561,15 @@ HandleLogon(
     DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGYOURPERSONALSETTINGS);
     UpdatePerUserSystemParameters(0, TRUE);
 
-    /* Set default language */
-    if (!SetDefaultLanguage(TRUE))
+    /* Set default user language */
+    if (!SetDefaultLanguage(Session))
     {
         WARN("WL: SetDefaultLanguage() failed\n");
         goto cleanup;
     }
 
+    AllowWinstaAccess(Session);
+
     if (!StartUserShell(Session))
     {
         //WCHAR StatusMsg[256];
@@ -474,7 +586,7 @@ HandleLogon(
 
     Session->hProfileInfo = ProfileInfo.hProfile;
 
-    /* Logon has successed. Play sound. */
+    /* Logon has succeeded. Play sound. */
     PlayLogonSound(Session);
 
     ret = TRUE;
@@ -493,6 +605,8 @@ cleanup:
     RemoveStatusMessage(Session);
     if (!ret)
     {
+        SetWindowStationUser(Session->InteractiveWindowStation,
+                             &LuidNone, NULL, 0);
         CloseHandle(Session->UserToken);
         Session->UserToken = NULL;
     }
@@ -531,7 +645,7 @@ LogoffShutdownThread(
 
     uFlags = EWX_CALLER_WINLOGON | (LSData->Flags & 0x0F);
 
-    ERR("In LogoffShutdownThread with uFlags == 0x%x; exit_in_progress == %s\n",
+    TRACE("In LogoffShutdownThread with uFlags == 0x%x; exit_in_progress == %s\n",
         uFlags, ExitReactOSInProgress ? "true" : "false");
 
     ExitReactOSInProgress = TRUE;
@@ -543,6 +657,9 @@ LogoffShutdownThread(
         ret = 0;
     }
 
+    /* Cancel all the user connections */
+    WNetClearConnections(0);
+
     if (LSData->Session->UserToken)
         RevertToSelf();
 
@@ -558,7 +675,7 @@ KillComProcesses(
     DWORD ret = 1;
     PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA)Parameter;
 
-    ERR("In KillComProcesses\n");
+    TRACE("In KillComProcesses\n");
 
     if (LSData->Session->UserToken != NULL &&
         !ImpersonateLoggedOnUser(LSData->Session->UserToken))
@@ -765,6 +882,11 @@ HandleLogoff(
 
     SwitchDesktop(Session->WinlogonDesktop);
 
+    // TODO: Play logoff sound!
+
+    SetWindowStationUser(Session->InteractiveWindowStation,
+                         &LuidNone, NULL, 0);
+
     // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_LOGGINGOFF);
 
     // FIXME: Closing network connections!
@@ -1018,94 +1140,6 @@ DoGenericAction(
     }
 }
 
-DWORD WINAPI SetWindowStationUser(HWINSTA hWinSta, LUID* pluid, PSID psid, DWORD sidSize);
-
-BOOL
-AddAceToWindowStation(
-    IN HWINSTA WinSta,
-    IN PSID Sid);
-
-static
-BOOL AllowWinstaAccess(PWLSESSION Session)
-{
-    BOOL bSuccess = FALSE;
-    DWORD dwIndex;
-    DWORD dwLength = 0;
-    PTOKEN_GROUPS ptg = NULL;
-    PSID psid;
-    TOKEN_STATISTICS Stats;
-    DWORD cbStats;
-    DWORD ret;
-
-    // Get required buffer size and allocate the TOKEN_GROUPS buffer.
-
-    if (!GetTokenInformation(Session->UserToken,
-                             TokenGroups,
-                             ptg,
-                             0,
-                             &dwLength))
-    {
-        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
-            return FALSE;
-
-        ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
-        if (ptg == NULL)
-            return FALSE;
-    }
-
-    // Get the token group information from the access token.
-    if (!GetTokenInformation(Session->UserToken,
-                             TokenGroups,
-                             ptg,
-                             dwLength,
-                             &dwLength))
-    {
-        goto Cleanup;
-    }
-
-    // Loop through the groups to find the logon SID.
-
-    for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
-    {
-        if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID)
-            == SE_GROUP_LOGON_ID)
-        {
-            psid = ptg->Groups[dwIndex].Sid;
-            break;
-        }
-    }
-
-    dwLength = GetLengthSid(psid);
-
-    if (!GetTokenInformation(Session->UserToken,
-                             TokenStatistics,
-                             &Stats,
-                             sizeof(TOKEN_STATISTICS),
-                             &cbStats))
-    {
-        WARN("Couldn't get Authentication id from user token!\n");
-        goto Cleanup;
-    }
-
-    AddAceToWindowStation(Session->InteractiveWindowStation, psid);
-
-    ret = SetWindowStationUser(Session->InteractiveWindowStation,
-                               &Stats.AuthenticationId,
-                               psid,
-                               dwLength);
-    TRACE("SetWindowStationUser returned 0x%x\n", ret);
-
-    bSuccess = TRUE;
-
-Cleanup:
-
-    // Free the buffer for the token groups.
-    if (ptg != NULL)
-        HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
-
-    return bSuccess;
-}
-
 static
 VOID
 DispatchSAS(
@@ -1113,7 +1147,6 @@ DispatchSAS(
     IN DWORD dwSasType)
 {
     DWORD wlxAction = WLX_SAS_ACTION_NONE;
-    HWND hwnd;
     PSID LogonSid = NULL; /* FIXME */
     BOOL bSecure = TRUE;
 
@@ -1130,9 +1163,7 @@ DispatchSAS(
                 case STATE_LOGGED_OFF:
                     Session->LogonState = STATE_LOGGED_OFF_SAS;
 
-                    hwnd = GetTopDialogWindow();
-                    if (hwnd != NULL)
-                        SendMessage(hwnd, WLX_WM_SAS, 0, 0);
+                    CloseAllDialogWindows();
 
                     Session->Options = 0;
 
@@ -1145,8 +1176,6 @@ DispatchSAS(
                         &Session->UserToken,
                         &Session->MprNotifyInfo,
                         (PVOID*)&Session->Profile);
-
-                    AllowWinstaAccess(Session);
                     break;
 
                 case STATE_LOGGED_OFF_SAS:
@@ -1165,9 +1194,7 @@ DispatchSAS(
                 case STATE_LOCKED:
                     Session->LogonState = STATE_LOCKED_SAS;
 
-                    hwnd = GetTopDialogWindow();
-                    if (hwnd != NULL)
-                        SendMessage(hwnd, WLX_WM_SAS, 0, 0);
+                    CloseAllDialogWindows();
 
                     wlxAction = (DWORD)Session->Gina.Functions.WlxWkstaLockedSAS(Session->Gina.Context, dwSasType);
                     break;
@@ -1306,7 +1333,8 @@ SASWindowProc(
                 case MAKELONG(MOD_CONTROL | MOD_SHIFT, VK_ESCAPE):
                 {
                     TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
-                    DoGenericAction(Session, WLX_SAS_ACTION_TASKLIST);
+                    if (Session->LogonState == STATE_LOGGED_ON)
+                        DoGenericAction(Session, WLX_SAS_ACTION_TASKLIST);
                     return TRUE;
                 }
             }
@@ -1350,7 +1378,9 @@ SASWindowProc(
                 case LN_SHELL_EXITED:
                 {
                     /* lParam is the exit code */
-                    if(lParam != 1)
+                    if (lParam != 1 &&
+                        Session->LogonState != STATE_LOGGED_OFF &&
+                        Session->LogonState != STATE_LOGGED_OFF_SAS)
                     {
                         SetTimer(hwndDlg, 1, 1000, NULL);
                     }
@@ -1419,7 +1449,7 @@ SASWindowProc(
                         }
                     }
 
-                    ERR("In LN_LOGOFF, exit_in_progress == %s\n",
+                    TRACE("In LN_LOGOFF, exit_in_progress == %s\n",
                         ExitReactOSInProgress ? "true" : "false");
 
                     /*
@@ -1530,7 +1560,7 @@ InitializeSAS(
         goto cleanup;
     }
 
-    if (!SetDefaultLanguage(FALSE))
+    if (!SetDefaultLanguage(NULL))
         return FALSE;
 
     ret = TRUE;