[SERVICES][ADVAPI32] Support the security process aka lsass.exe
authorEric Kohl <eric.kohl@reactos.org>
Sat, 31 Aug 2019 15:24:47 +0000 (17:24 +0200)
committerEric Kohl <eric.kohl@reactos.org>
Sat, 31 Aug 2019 15:24:47 +0000 (17:24 +0200)
- Reserve the pipe NtControlPipe0 for the security process.
- Count regular service control pipes from 1.
- Use I_ScIsSecurityProcess to identify the security process.
- Services.exe uses the SECURITY_SERVICES_STARTED event to notify the security process that NtControlPipe0 is ready for use.

base/system/services/database.c
base/system/services/services.c
base/system/services/services.h
dll/win32/advapi32/service/sctrl.c

index 622bdf0..fc3d673 100644 (file)
@@ -40,61 +40,89 @@ static DWORD PipeTimeout = 30000; /* 30 Seconds */
 
 /* FUNCTIONS *****************************************************************/
 
+static
+BOOL
+ScmIsSecurityService(
+    _In_ PSERVICE_IMAGE pServiceImage)
+{
+    return (wcsstr(pServiceImage->pszImagePath, L"\\system32\\lsass.exe") != NULL);
+}
+
+
 static DWORD
-ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage)
+ScmCreateNewControlPipe(
+    _In_ PSERVICE_IMAGE pServiceImage,
+    _In_ BOOL bSecurityServiceProcess)
 {
     WCHAR szControlPipeName[MAX_PATH + 1];
     SECURITY_ATTRIBUTES SecurityAttributes;
     HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE;
-    DWORD ServiceCurrent = 0;
-    DWORD KeyDisposition;
+    DWORD dwServiceCurrent = 1;
+    DWORD dwKeyDisposition;
     DWORD dwKeySize;
     DWORD dwError;
 
     /* Get the service number */
-    /* TODO: Create registry entry with correct write access */
-    dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
-                              L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL,
-                              REG_OPTION_VOLATILE,
-                              KEY_WRITE | KEY_READ,
-                              NULL,
-                              &hServiceCurrentKey,
-                              &KeyDisposition);
-    if (dwError != ERROR_SUCCESS)
+    if (bSecurityServiceProcess == FALSE)
     {
-        DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError);
-        return dwError;
-    }
-
-    if (KeyDisposition == REG_OPENED_EXISTING_KEY)
-    {
-        dwKeySize = sizeof(DWORD);
-        dwError = RegQueryValueExW(hServiceCurrentKey,
-                                   L"", 0, NULL, (BYTE*)&ServiceCurrent, &dwKeySize);
-
+        /* TODO: Create registry entry with correct write access */
+        dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                                  L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent",
+                                  0,
+                                  NULL,
+                                  REG_OPTION_VOLATILE,
+                                  KEY_WRITE | KEY_READ,
+                                  NULL,
+                                  &hServiceCurrentKey,
+                                  &dwKeyDisposition);
         if (dwError != ERROR_SUCCESS)
         {
-            RegCloseKey(hServiceCurrentKey);
-            DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError);
+            DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError);
             return dwError;
         }
 
-        ServiceCurrent++;
-    }
+        if (dwKeyDisposition == REG_OPENED_EXISTING_KEY)
+        {
+            dwKeySize = sizeof(DWORD);
+            dwError = RegQueryValueExW(hServiceCurrentKey,
+                                       L"",
+                                       0,
+                                       NULL,
+                                       (BYTE*)&dwServiceCurrent,
+                                       &dwKeySize);
+            if (dwError != ERROR_SUCCESS)
+            {
+                RegCloseKey(hServiceCurrentKey);
+                DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError);
+                return dwError;
+            }
 
-    dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent));
+            dwServiceCurrent++;
+        }
 
-    RegCloseKey(hServiceCurrentKey);
+        dwError = RegSetValueExW(hServiceCurrentKey,
+                                 L"",
+                                 0,
+                                 REG_DWORD,
+                                 (BYTE*)&dwServiceCurrent,
+                                 sizeof(dwServiceCurrent));
 
-    if (dwError != ERROR_SUCCESS)
+        RegCloseKey(hServiceCurrentKey);
+
+        if (dwError != ERROR_SUCCESS)
+        {
+            DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError);
+            return dwError;
+        }
+    }
+    else
     {
-        DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError);
-        return dwError;
+        dwServiceCurrent = 0;
     }
 
     /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
     StringCchPrintfW(szControlPipeName, ARRAYSIZE(szControlPipeName),
-                     L"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent);
+                     L"\\\\.\\pipe\\net\\NtControlPipe%lu", dwServiceCurrent);
 
     DPRINT("PipeName: %S\n", szControlPipeName);
 
@@ -437,6 +465,7 @@ ScmCreateOrReferenceServiceImage(PSERVICE pService)
     DWORD dwError = ERROR_SUCCESS;
     DWORD dwRecordSize;
     LPWSTR pString;
+    BOOL bSecurityService;
 
     DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService);
 
@@ -518,8 +547,11 @@ ScmCreateOrReferenceServiceImage(PSERVICE pService)
             goto done;
         }
 
+        bSecurityService = ScmIsSecurityService(pServiceImage);
+
         /* Create the control pipe */
-        dwError = ScmCreateNewControlPipe(pServiceImage);
+        dwError = ScmCreateNewControlPipe(pServiceImage,
+                                          bSecurityService);
         if (dwError != ERROR_SUCCESS)
         {
             DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError);
@@ -542,6 +574,11 @@ ScmCreateOrReferenceServiceImage(PSERVICE pService)
             goto done;
         }
 
+        if (bSecurityService)
+        {
+            SetSecurityServicesEvent();
+        }
+
         /* FIXME: Add more initialization code here */
 
 
@@ -1806,7 +1843,8 @@ ScmWaitForServiceConnect(PSERVICE Service)
         }
     }
 
-    if (dwProcessId != Service->lpImage->dwProcessId)
+    if ((ScmIsSecurityService(Service->lpImage) == FALSE)&&
+        (dwProcessId != Service->lpImage->dwProcessId))
     {
 #if 0
         _ultow(Service->lpImage->dwProcessId, szBuffer1, 10);
@@ -1916,7 +1954,7 @@ ScmStartUserModeService(PSERVICE Service,
             StartupInfo.lpDesktop = L"WinSta0\\Default";
         }
 
-        if (wcsstr(Service->lpImage->pszImagePath, L"\\system32\\lsass.exe") == NULL)
+        if (!ScmIsSecurityService(Service->lpImage))
         {
             Result = CreateProcessW(NULL,
                                     Service->lpImage->pszImagePath,
index 75bfeeb..8172526 100644 (file)
@@ -28,6 +28,7 @@ int WINAPI RegisterServicesProcess(DWORD ServicesProcessId);
 BOOL ScmInitialize = FALSE;
 BOOL ScmShutdown = FALSE;
 static HANDLE hScmShutdownEvent = NULL;
+static HANDLE hScmSecurityServicesEvent = NULL;
 
 
 /* FUNCTIONS *****************************************************************/
@@ -48,6 +49,38 @@ PrintString(LPCSTR fmt, ...)
 }
 
 
+DWORD
+SetSecurityServicesEvent(VOID)
+{
+    DWORD dwError;
+
+    if (hScmSecurityServicesEvent != NULL)
+        return ERROR_SUCCESS;
+
+    /* Create or open the SECURITY_SERVICES_STARTED event */
+    hScmSecurityServicesEvent = CreateEventW(NULL,
+                                             TRUE,
+                                             FALSE,
+                                             L"SECURITY_SERVICES_STARTED");
+    if (hScmSecurityServicesEvent == NULL)
+    {
+        dwError = GetLastError();
+        if (dwError != ERROR_ALREADY_EXISTS)
+            return dwError;
+
+        hScmSecurityServicesEvent = OpenEventW(EVENT_MODIFY_STATE,
+                                               FALSE,
+                                               L"SECURITY_SERVICES_STARTED");
+        if (hScmSecurityServicesEvent == NULL)
+            return GetLastError();
+    }
+
+    SetEvent(hScmSecurityServicesEvent);
+
+    return ERROR_SUCCESS;
+}
+
+
 VOID
 ScmLogEvent(DWORD dwEventId,
             WORD wType,
@@ -258,6 +291,9 @@ done:
     if (bCanDeleteNamedPipeCriticalSection != FALSE)
         ScmDeleteNamedPipeCriticalSection();
 
+    if (hScmSecurityServicesEvent != NULL)
+        CloseHandle(hScmSecurityServicesEvent);
+
     /* Close the shutdown event */
     if (hScmShutdownEvent != NULL)
         CloseHandle(hScmShutdownEvent);
index 6e3ca20..845ea02 100644 (file)
@@ -256,6 +256,7 @@ ScmCreateDefaultServiceSD(
 /* services.c */
 
 VOID PrintString(LPCSTR fmt, ...);
+DWORD SetSecurityServicesEvent(VOID);
 VOID ScmLogEvent(DWORD dwEventId,
                  WORD wType,
                  WORD wStrings,
index 68ec2a6..c0cf0f4 100644 (file)
@@ -58,6 +58,7 @@ typedef struct _ACTIVE_SERVICE
 static DWORD dwActiveServiceCount = 0;
 static PACTIVE_SERVICE lpActiveServices = NULL;
 static handle_t hStatusBinding = NULL;
+static BOOL bSecurityServiceProcess = FALSE;
 
 
 /* FUNCTIONS *****************************************************************/
@@ -227,7 +228,7 @@ ScConnectControlPipe(HANDLE *hPipe)
 {
     DWORD dwBytesWritten;
     DWORD dwState;
-    DWORD dwServiceCurrent = 0;
+    DWORD dwServiceCurrent = 1;
     NTSTATUS Status;
     WCHAR NtControlPipeName[MAX_PATH + 1];
     RTL_QUERY_REGISTRY_TABLE QueryTable[2];
@@ -237,25 +238,32 @@ ScConnectControlPipe(HANDLE *hPipe)
           hPipe);
 
     /* Get the service number and create the named pipe */
-    RtlZeroMemory(&QueryTable,
-                  sizeof(QueryTable));
-
-    QueryTable[0].Name = L"";
-    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
-    QueryTable[0].EntryContext = &dwServiceCurrent;
-
-    Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
-                                    L"ServiceCurrent",
-                                    QueryTable,
-                                    NULL,
-                                    NULL);
-    if (!NT_SUCCESS(Status))
+    if (bSecurityServiceProcess == FALSE)
     {
-        ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
-        return RtlNtStatusToDosError(Status);
+        RtlZeroMemory(&QueryTable, sizeof(QueryTable));
+
+        QueryTable[0].Name = L"";
+        QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+        QueryTable[0].EntryContext = &dwServiceCurrent;
+
+        Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                        L"ServiceCurrent",
+                                        QueryTable,
+                                        NULL,
+                                        NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+            return RtlNtStatusToDosError(Status);
+        }
+    }
+    else
+    {
+        dwServiceCurrent = 0;
     }
 
     swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent);
+    TRACE("PipeName: %S\n", NtControlPipeName);
 
     if (!WaitNamedPipeW(NtControlPipeName, 30000))
     {
@@ -836,13 +844,14 @@ RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
  *
  * Undocumented
  *
- * @unimplemented
+ * @implemented
  */
 VOID
 WINAPI
 I_ScIsSecurityProcess(VOID)
 {
-    FIXME("I_ScIsSecurityProcess()\n");
+    TRACE("I_ScIsSecurityProcess()\n");
+    bSecurityServiceProcess = TRUE;
 }