+DWORD
+ScmGetServiceNameFromTag(PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams, 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->hProcess == (HANDLE)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)
+ {
+ MIDL_user_free(OutBuffer);
+ }
+
+ /* Return error/success */
+ return dwError;
+}
+
+
+static
+BOOL
+ScmIsSameServiceAccount(
+ _In_ PCWSTR pszAccountName1,
+ _In_ PCWSTR pszAccountName2)
+{
+ if (pszAccountName1 == NULL &&
+ pszAccountName2 == NULL)
+ return TRUE;
+
+ if (pszAccountName1 == NULL &&
+ pszAccountName2 != NULL &&
+ _wcsicmp(pszAccountName2, L"LocalSystem") == 0)
+ return TRUE;
+
+ if (pszAccountName1 != NULL &&
+ pszAccountName2 == NULL &&
+ _wcsicmp(pszAccountName1, L"LocalSystem") == 0)
+ return TRUE;
+
+ if (pszAccountName1 != NULL &&
+ pszAccountName2 != NULL &&
+ _wcsicmp(pszAccountName1, pszAccountName2) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+static
+BOOL
+ScmIsLocalSystemAccount(
+ _In_ PCWSTR pszAccountName)
+{
+ if (pszAccountName == NULL ||
+ _wcsicmp(pszAccountName, L"LocalSystem") == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+static
+DWORD
+ScmLogonService(
+ IN PSERVICE pService,
+ IN PSERVICE_IMAGE pImage)
+{
+ DWORD dwError = ERROR_SUCCESS;
+ PROFILEINFOW ProfileInfo;
+ PWSTR pszUserName = NULL;
+ PWSTR pszDomainName = NULL;
+ PWSTR pszPassword = NULL;
+ PWSTR ptr;
+
+ DPRINT("ScmLogonService(%p %p)\n", pService, pImage);
+ DPRINT("Service %S\n", pService->lpServiceName);
+
+ if (ScmIsLocalSystemAccount(pImage->pszAccountName))
+ return ERROR_SUCCESS;
+
+ /* 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;
+ }
+
+ /* Build the service 'password' */
+ pszPassword = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (wcslen(pService->lpServiceName) + 5) * sizeof(WCHAR));
+ if (pszPassword == NULL)
+ {
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ wcscpy(pszPassword, L"_SC_");
+ wcscat(pszPassword, pService->lpServiceName);
+
+ DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName, pszUserName, pszPassword);
+
+ /* Do the service logon */
+ if (!LogonUserW(pszUserName,
+ pszDomainName,
+ pszPassword,
+ LOGON32_LOGON_SERVICE,
+ LOGON32_PROVIDER_DEFAULT,
+ &pImage->hToken))
+ {
+ dwError = GetLastError();
+ DPRINT1("LogonUserW() failed (Error %lu)\n", dwError);
+
+ /* Normalize the returned error */
+ dwError = ERROR_SERVICE_LOGON_FAILED;
+ goto done;
+ }
+
+ /* 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;
+ ProfileInfo.lpUserName = pszUserName;
+ // ProfileInfo.lpProfilePath = NULL;
+ // ProfileInfo.lpDefaultPath = NULL;
+ // ProfileInfo.lpServerName = NULL;
+ // ProfileInfo.lpPolicyPath = NULL;
+ // ProfileInfo.hProfile = NULL;
+
+ if (!LoadUserProfileW(pImage->hToken, &ProfileInfo))
+ {
+ dwError = GetLastError();
+ DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError);
+ goto done;
+ }
+
+ pImage->hProfile = ProfileInfo.hProfile;
+
+done:
+ if (pszPassword != NULL)
+ HeapFree(GetProcessHeap(), 0, pszPassword);
+
+ if (ptr != NULL)
+ *ptr = L'\\';
+
+ return dwError;
+}
+
+