[SERVICES] Do not try to start lsass.exe as a service.
[reactos.git] / base / system / services / database.c
index 580dc0f..460b748 100644 (file)
@@ -17,6 +17,8 @@
 #include <userenv.h>
 #include <strsafe.h>
 
+#include <reactos/undocuser.h>
+
 #define NDEBUG
 #include <debug.h>
 
@@ -29,6 +31,7 @@ LIST_ENTRY ServiceListHead;
 static RTL_RESOURCE DatabaseLock;
 static DWORD ResumeCount = 1;
 static DWORD NoInteractiveServices = 0;
+static DWORD ServiceTag = 0;
 
 /* The critical section synchronizes service control requests */
 static CRITICAL_SECTION ControlServiceCriticalSection;
@@ -143,22 +146,115 @@ ScmGetServiceImageByImagePath(LPWSTR lpImagePath)
 }
 
 
+DWORD
+ScmGetServiceNameFromTag(IN PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams,
+                         OUT PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS *OutParams)
+{
+    PLIST_ENTRY ServiceEntry;
+    PSERVICE CurrentService;
+    PSERVICE_IMAGE CurrentImage;
+    PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutBuffer = NULL;
+    DWORD dwError;
+
+    /* Lock the database */
+    ScmLockDatabaseExclusive();
+
+    /* Find the matching service */
+    ServiceEntry = ServiceListHead.Flink;
+    while (ServiceEntry != &ServiceListHead)
+    {
+        CurrentService = CONTAINING_RECORD(ServiceEntry,
+                                           SERVICE,
+                                           ServiceListEntry);
+
+        /* We must match the tag */
+        if (CurrentService->dwTag == InParams->dwTag &&
+            CurrentService->lpImage != NULL)
+        {
+            CurrentImage = CurrentService->lpImage;
+            /* And matching the PID */
+            if (CurrentImage->dwProcessId == InParams->dwPid)
+            {
+                break;
+            }
+        }
+
+        ServiceEntry = ServiceEntry->Flink;
+    }
+
+    /* No match! */
+    if (ServiceEntry == &ServiceListHead)
+    {
+        dwError = ERROR_RETRY;
+        goto Cleanup;
+    }
+
+    /* Allocate the output buffer */
+    OutBuffer = MIDL_user_allocate(sizeof(TAG_INFO_NAME_FROM_TAG_OUT_PARAMS));
+    if (OutBuffer == NULL)
+    {
+        dwError = ERROR_NOT_ENOUGH_MEMORY;
+        goto Cleanup;
+    }
+
+    /* And the buffer for the name */
+    OutBuffer->pszName = MIDL_user_allocate(wcslen(CurrentService->lpServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
+    if (OutBuffer->pszName == NULL)
+    {
+        dwError = ERROR_NOT_ENOUGH_MEMORY;
+        goto Cleanup;
+    }
+
+    /* Fill in output data */
+    wcscpy(OutBuffer->pszName, CurrentService->lpServiceName);
+    OutBuffer->TagType = TagTypeService;
+
+    /* And return */
+    *OutParams = OutBuffer;
+    dwError = ERROR_SUCCESS;
+
+Cleanup:
+
+    /* Unlock database */
+    ScmUnlockDatabase();
+
+    /* If failure, free allocated memory */
+    if (dwError != ERROR_SUCCESS)
+    {
+        if (OutBuffer != NULL)
+        {
+            MIDL_user_free(OutBuffer);
+        }
+    }
+
+    /* Return error/success */
+    return dwError;
+}
+
+
 static
 BOOL
 ScmIsSameServiceAccount(
     _In_ PCWSTR pszAccountName1,
     _In_ PCWSTR pszAccountName2)
 {
-    if (pszAccountName1 == NULL && pszAccountName2 == NULL)
+    if (pszAccountName1 == NULL &&
+        pszAccountName2 == NULL)
         return TRUE;
 
-    if (pszAccountName1 == NULL && pszAccountName2 && wcscmp(pszAccountName2, L"LocalSystem") == 0)
+    if (pszAccountName1 == NULL &&
+        pszAccountName2 != NULL &&
+        _wcsicmp(pszAccountName2, L"LocalSystem") == 0)
         return TRUE;
 
-    if (pszAccountName2 == NULL && pszAccountName1 && wcscmp(pszAccountName1, L"LocalSystem") == 0)
+    if (pszAccountName1 != NULL &&
+        pszAccountName2 == NULL &&
+        _wcsicmp(pszAccountName1, L"LocalSystem") == 0)
         return TRUE;
 
-    if (pszAccountName1 && pszAccountName2 && wcscmp(pszAccountName1, pszAccountName2) == 0)
+    if (pszAccountName1 != NULL &&
+        pszAccountName2 != NULL &&
+        _wcsicmp(pszAccountName1, pszAccountName2) == 0)
         return TRUE;
 
     return FALSE;
@@ -171,7 +267,7 @@ ScmIsLocalSystemAccount(
     _In_ PCWSTR pszAccountName)
 {
     if (pszAccountName == NULL ||
-        wcscmp(pszAccountName, L"LocalSystem") == 0)
+        _wcsicmp(pszAccountName, L"LocalSystem") == 0)
         return TRUE;
 
     return FALSE;
@@ -184,37 +280,30 @@ ScmLogonService(
     IN PSERVICE pService,
     IN PSERVICE_IMAGE pImage)
 {
-#if 0
+    DWORD dwError = ERROR_SUCCESS;
     PROFILEINFOW ProfileInfo;
     PWSTR pszUserName = NULL;
     PWSTR pszDomainName = NULL;
     PWSTR pszPassword = NULL;
     PWSTR ptr;
-    DWORD dwError = ERROR_SUCCESS;
-#endif
 
     DPRINT("ScmLogonService(%p %p)\n", pService, pImage);
-
     DPRINT("Service %S\n", pService->lpServiceName);
 
     if (ScmIsLocalSystemAccount(pImage->pszAccountName))
         return ERROR_SUCCESS;
 
-    // FIXME: Always assume LocalSystem
-    return ERROR_SUCCESS;
-
-#if 0
     /* Get the user and domain names */
     ptr = wcschr(pImage->pszAccountName, L'\\');
     if (ptr != NULL)
     {
         *ptr = L'\0';
-
         pszUserName = ptr + 1;
         pszDomainName = pImage->pszAccountName;
     }
     else
     {
+        // ERROR_INVALID_SERVICE_ACCOUNT
         pszUserName = pImage->pszAccountName;
         pszDomainName = NULL;
     }
@@ -234,7 +323,7 @@ ScmLogonService(
 
     DPRINT("Domain: %S  User: %S  Password: %S\n", pszDomainName, pszUserName, pszPassword);
 
-    /* Service logon */
+    /* Do the service logon */
     if (!LogonUserW(pszUserName,
                     pszDomainName,
                     pszPassword,
@@ -244,14 +333,13 @@ ScmLogonService(
     {
         dwError = GetLastError();
         DPRINT1("LogonUserW() failed (Error %lu)\n", dwError);
+
+        /* Normalize the returned error */
+        dwError = ERROR_SERVICE_LOGON_FAILED;
         goto done;
     }
 
-    // FIXME: Call LoadUserProfileW to be able to initialize a per-user
-    // environment block, with user-specific environment variables as
-    // %USERNAME%, %USERPROFILE%, and %ALLUSERSPROFILE% correctly initialized!!
-
-    /* Load the user profile, so that the per-user environment variables can be initialized */
+    /* Load the user profile; the per-user environment variables are thus correctly initialized */
     ZeroMemory(&ProfileInfo, sizeof(ProfileInfo));
     ProfileInfo.dwSize = sizeof(ProfileInfo);
     ProfileInfo.dwFlags = PI_NOUI;
@@ -279,7 +367,6 @@ done:
         *ptr = L'\\';
 
     return dwError;
-#endif
 }
 
 
@@ -552,6 +639,29 @@ ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
 }
 
 
+DWORD
+ScmGenerateServiceTag(PSERVICE lpServiceRecord)
+{
+    /* Check for an overflow */
+    if (ServiceTag == -1)
+    {
+        return ERROR_INVALID_DATA;
+    }
+
+    /* This is only valid for Win32 services */
+    if (!(lpServiceRecord->Status.dwServiceType & SERVICE_WIN32))
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    /* Increment the tag counter and set it */
+    ServiceTag = ServiceTag % 0xFFFFFFFF + 1;
+    lpServiceRecord->dwTag = ServiceTag;
+
+    return ERROR_SUCCESS;
+}
+
+
 DWORD
 ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
                           PSERVICE *lpServiceRecord,
@@ -765,6 +875,8 @@ CreateServiceListEntry(LPCWSTR lpServiceName,
 
     if (ScmIsDeleteFlagSet(hServiceKey))
         lpService->bDeleted = TRUE;
+    else
+        ScmGenerateServiceTag(lpService);
 
     if (lpService->Status.dwServiceType & SERVICE_WIN32)
     {
@@ -1323,6 +1435,7 @@ ScmSendStartCommand(PSERVICE Service,
                                ? SERVICE_CONTROL_START_OWN
                                : SERVICE_CONTROL_START_SHARE;
     ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
+    ControlPacket->dwServiceTag = Service->dwTag;
 
     /* Copy the start command line */
     ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
@@ -1679,11 +1792,6 @@ ScmStartUserModeService(PSERVICE Service,
     StartupInfo.cb = sizeof(StartupInfo);
     ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
 
-    /* Use the interactive desktop if the service is interactive */
-    if ((NoInteractiveServices == 0) &&
-        (Service->Status.dwServiceType & SERVICE_INTERACTIVE_PROCESS))
-        StartupInfo.lpDesktop = L"WinSta0\\Default";
-
     if (Service->lpImage->hToken)
     {
         /* User token: Run the service under the user account */
@@ -1736,18 +1844,34 @@ ScmStartUserModeService(PSERVICE Service,
             lpEnvironment = NULL;
         }
 
-        Result = CreateProcessW(NULL,
-                                Service->lpImage->pszImagePath,
-                                NULL,
-                                NULL,
-                                FALSE,
-                                CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED,
-                                lpEnvironment,
-                                NULL,
-                                &StartupInfo,
-                                &ProcessInformation);
-        if (!Result)
-            dwError = GetLastError();
+        /* Use the interactive desktop if the service is interactive */
+        if ((NoInteractiveServices == 0) &&
+            (Service->Status.dwServiceType & SERVICE_INTERACTIVE_PROCESS))
+        {
+            StartupInfo.dwFlags |= STARTF_INHERITDESKTOP;
+            StartupInfo.lpDesktop = L"WinSta0\\Default";
+        }
+
+        if (wcsstr(Service->lpImage->pszImagePath, L"\\system32\\lsass.exe") == NULL)
+        {
+            Result = CreateProcessW(NULL,
+                                    Service->lpImage->pszImagePath,
+                                    NULL,
+                                    NULL,
+                                    FALSE,
+                                    CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED,
+                                    lpEnvironment,
+                                    NULL,
+                                    &StartupInfo,
+                                    &ProcessInformation);
+            if (!Result)
+                dwError = GetLastError();
+        }
+        else
+        {
+            Result = TRUE;
+            dwError = ERROR_SUCCESS;
+        }
     }
 
     if (lpEnvironment)