X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=base%2Fsystem%2Fservices%2Fdatabase.c;h=be6290bef64b8b922a2d4bc86e127203906dcf27;hp=476c627800fe946d73b21275405993165ba68a0b;hb=519a2c9f6f763713b57a29c0fa311eca0c2fa250;hpb=87f326521707b050e5a974d58625927850b21210 diff --git a/base/system/services/database.c b/base/system/services/database.c index 476c627800f..be6290bef64 100644 --- a/base/system/services/database.c +++ b/base/system/services/database.c @@ -14,23 +14,14 @@ #include "services.h" -#include +#include +#include + +#include #define NDEBUG #include -/* - * Uncomment the line below to start services - * using the SERVICE_START_PENDING state. - */ -#define USE_SERVICE_START_PENDING - -/* - * Uncomment the line below to use asynchronous IO operations - * on the service control pipes. - */ -#define USE_ASYNCHRONOUS_IO - /* GLOBALS *******************************************************************/ @@ -39,6 +30,7 @@ LIST_ENTRY ServiceListHead; static RTL_RESOURCE DatabaseLock; static DWORD ResumeCount = 1; +static DWORD NoInteractiveServices = 0; /* The critical section synchronizes service control requests */ static CRITICAL_SECTION ControlServiceCriticalSection; @@ -99,16 +91,13 @@ ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage) } /* Create '\\.\pipe\net\NtControlPipeXXX' instance */ - swprintf(szControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent); + StringCchPrintfW(szControlPipeName, ARRAYSIZE(szControlPipeName), + L"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent); DPRINT("PipeName: %S\n", szControlPipeName); pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName, -#ifdef USE_ASYNCHRONOUS_IO PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, -#else - PIPE_ACCESS_DUPLEX, -#endif PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 100, 8000, @@ -140,9 +129,9 @@ ScmGetServiceImageByImagePath(LPWSTR lpImagePath) CurrentImage = CONTAINING_RECORD(ImageEntry, SERVICE_IMAGE, ImageListEntry); - if (_wcsicmp(CurrentImage->szImagePath, lpImagePath) == 0) + if (_wcsicmp(CurrentImage->pszImagePath, lpImagePath) == 0) { - DPRINT("Found image: '%S'\n", CurrentImage->szImagePath); + DPRINT("Found image: '%S'\n", CurrentImage->pszImagePath); return CurrentImage; } @@ -156,18 +145,242 @@ ScmGetServiceImageByImagePath(LPWSTR lpImagePath) } +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; +} + + static DWORD ScmCreateOrReferenceServiceImage(PSERVICE pService) { - RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + RTL_QUERY_REGISTRY_TABLE QueryTable[3]; UNICODE_STRING ImagePath; + UNICODE_STRING ObjectName; PSERVICE_IMAGE pServiceImage = NULL; NTSTATUS Status; DWORD dwError = ERROR_SUCCESS; + DWORD dwRecordSize; + LPWSTR pString; DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService); RtlInitUnicodeString(&ImagePath, NULL); + RtlInitUnicodeString(&ObjectName, NULL); /* Get service data */ RtlZeroMemory(&QueryTable, @@ -176,6 +389,9 @@ ScmCreateOrReferenceServiceImage(PSERVICE pService) QueryTable[0].Name = L"ImagePath"; QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].EntryContext = &ImagePath; + QueryTable[1].Name = L"ObjectName"; + QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + QueryTable[1].EntryContext = &ObjectName; Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, pService->lpServiceName, @@ -189,14 +405,19 @@ ScmCreateOrReferenceServiceImage(PSERVICE pService) } DPRINT("ImagePath: '%wZ'\n", &ImagePath); + DPRINT("ObjectName: '%wZ'\n", &ObjectName); pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer); if (pServiceImage == NULL) { + dwRecordSize = sizeof(SERVICE_IMAGE) + + ImagePath.Length + sizeof(WCHAR) + + ((ObjectName.Length != 0) ? (ObjectName.Length + sizeof(WCHAR)) : 0); + /* Create a new service image */ pServiceImage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - FIELD_OFFSET(SERVICE_IMAGE, szImagePath[ImagePath.Length / sizeof(WCHAR) + 1])); + dwRecordSize); if (pServiceImage == NULL) { dwError = ERROR_NOT_ENOUGH_MEMORY; @@ -205,18 +426,54 @@ ScmCreateOrReferenceServiceImage(PSERVICE pService) pServiceImage->dwImageRunCount = 1; pServiceImage->hControlPipe = INVALID_HANDLE_VALUE; + pServiceImage->hProcess = INVALID_HANDLE_VALUE; + + pString = (PWSTR)((INT_PTR)pServiceImage + sizeof(SERVICE_IMAGE)); /* Set the image path */ - wcscpy(pServiceImage->szImagePath, + pServiceImage->pszImagePath = pString; + wcscpy(pServiceImage->pszImagePath, ImagePath.Buffer); - RtlFreeUnicodeString(&ImagePath); + /* Set the account name */ + if (ObjectName.Length > 0) + { + pString = pString + wcslen(pString) + 1; + + pServiceImage->pszAccountName = pString; + wcscpy(pServiceImage->pszAccountName, + ObjectName.Buffer); + } + + /* Service logon */ + dwError = ScmLogonService(pService, pServiceImage); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError); + + /* Release the service image */ + HeapFree(GetProcessHeap(), 0, pServiceImage); + + goto done; + } /* Create the control pipe */ dwError = ScmCreateNewControlPipe(pServiceImage); if (dwError != ERROR_SUCCESS) { + DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError); + + /* Unload the user profile */ + if (pServiceImage->hProfile != NULL) + UnloadUserProfile(pServiceImage->hToken, pServiceImage->hProfile); + + /* Close the logon token */ + if (pServiceImage->hToken != NULL) + CloseHandle(pServiceImage->hToken); + + /* Release the service image */ HeapFree(GetProcessHeap(), 0, pServiceImage); + goto done; } @@ -229,16 +486,28 @@ ScmCreateOrReferenceServiceImage(PSERVICE pService) } else { +// if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0) + + /* Fail if services in an image use different accounts */ + if (!ScmIsSameServiceAccount(pServiceImage->pszAccountName, ObjectName.Buffer)) + { + dwError = ERROR_DIFFERENT_SERVICE_ACCOUNT; + goto done; + } + /* Increment the run counter */ pServiceImage->dwImageRunCount++; } + DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage->pszImagePath); + DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage->pszAccountName); DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount); /* Link the service image to the service */ pService->lpImage = pServiceImage; -done:; +done: + RtlFreeUnicodeString(&ObjectName); RtlFreeUnicodeString(&ImagePath); DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError); @@ -247,29 +516,34 @@ done:; } -static VOID -ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage) +VOID +ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage) { - DPRINT1("ScmDereferenceServiceImage() called\n"); + DPRINT1("ScmRemoveServiceImage() called\n"); - pServiceImage->dwImageRunCount--; + /* FIXME: Terminate the process */ - if (pServiceImage->dwImageRunCount == 0) - { - DPRINT1("dwImageRunCount == 0\n"); + /* Remove the service image from the list */ + RemoveEntryList(&pServiceImage->ImageListEntry); - /* FIXME: Terminate the process */ + /* Close the process handle */ + if (pServiceImage->hProcess != INVALID_HANDLE_VALUE) + CloseHandle(pServiceImage->hProcess); - /* Remove the service image from the list */ - RemoveEntryList(&pServiceImage->ImageListEntry); + /* Close the control pipe */ + if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE) + CloseHandle(pServiceImage->hControlPipe); - /* Close the control pipe */ - if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE) - CloseHandle(pServiceImage->hControlPipe); + /* Unload the user profile */ + if (pServiceImage->hProfile != NULL) + UnloadUserProfile(pServiceImage->hToken, pServiceImage->hProfile); - /* Release the service image */ - HeapFree(GetProcessHeap(), 0, pServiceImage); - } + /* Close the logon token */ + if (pServiceImage->hToken != NULL) + CloseHandle(pServiceImage->hToken); + + /* Release the service image */ + HeapFree(GetProcessHeap(), 0, pServiceImage); } @@ -362,7 +636,9 @@ ScmGetServiceEntryByResumeCount(DWORD dwResumeCount) DWORD ScmCreateNewServiceRecord(LPCWSTR lpServiceName, - PSERVICE* lpServiceRecord) + PSERVICE *lpServiceRecord, + DWORD dwServiceType, + DWORD dwStartType) { PSERVICE lpService = NULL; @@ -382,6 +658,9 @@ ScmCreateNewServiceRecord(LPCWSTR lpServiceName, lpService->lpServiceName = lpService->szServiceName; lpService->lpDisplayName = lpService->lpServiceName; + /* Set the start type */ + lpService->dwStartType = dwStartType; + /* Set the resume count */ lpService->dwResumeCount = ResumeCount++; @@ -390,12 +669,15 @@ ScmCreateNewServiceRecord(LPCWSTR lpServiceName, &lpService->ServiceListEntry); /* Initialize the service status */ + lpService->Status.dwServiceType = dwServiceType; lpService->Status.dwCurrentState = SERVICE_STOPPED; lpService->Status.dwControlsAccepted = 0; - lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED; + lpService->Status.dwWin32ExitCode = + (dwStartType == SERVICE_DISABLED) ? ERROR_SERVICE_DISABLED : ERROR_SERVICE_NEVER_STARTED; lpService->Status.dwServiceSpecificExitCode = 0; lpService->Status.dwCheckPoint = 0; - lpService->Status.dwWaitHint = 2000; /* 2 seconds */ + lpService->Status.dwWaitHint = + (dwServiceType & SERVICE_DRIVER) ? 0 : 2000; /* 2 seconds */ return ERROR_SUCCESS; } @@ -413,14 +695,22 @@ ScmDeleteServiceRecord(PSERVICE lpService) /* Dereference the service image */ if (lpService->lpImage) - ScmDereferenceServiceImage(lpService->lpImage); + { + lpService->lpImage->dwImageRunCount--; - /* Decrement the group reference counter */ - if (lpService->lpGroup) - lpService->lpGroup->dwRefCount--; + if (lpService->lpImage->dwImageRunCount == 0) + { + ScmRemoveServiceImage(lpService->lpImage); + lpService->lpImage = NULL; + } + } - /* FIXME: SecurityDescriptor */ + /* Decrement the group reference counter */ + ScmSetServiceGroup(lpService, NULL); + /* Release the SecurityDescriptor */ + if (lpService->pSecurityDescriptor != NULL) + HeapFree(GetProcessHeap(), 0, lpService->pSecurityDescriptor); /* Remove the Service from the List */ RemoveEntryList(&lpService->ServiceListEntry); @@ -522,12 +812,12 @@ CreateServiceListEntry(LPCWSTR lpServiceName, DPRINT("Display name: %S\n", lpDisplayName); dwError = ScmCreateNewServiceRecord(lpServiceName, - &lpService); + &lpService, + dwServiceType, + dwStartType); if (dwError != ERROR_SUCCESS) goto done; - lpService->Status.dwServiceType = dwServiceType; - lpService->dwStartType = dwStartType; lpService->dwErrorControl = dwErrorControl; lpService->dwTag = dwTagId; @@ -558,7 +848,29 @@ CreateServiceListEntry(LPCWSTR lpServiceName, if (ScmIsDeleteFlagSet(hServiceKey)) lpService->bDeleted = TRUE; -done:; + if (lpService->Status.dwServiceType & SERVICE_WIN32) + { + dwError = ScmReadSecurityDescriptor(hServiceKey, + &lpService->pSecurityDescriptor); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Assing the default security descriptor if the security descriptor cannot be read */ + if (lpService->pSecurityDescriptor == NULL) + { + DPRINT("No security descriptor found! Assign default security descriptor!\n"); + dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor); + if (dwError != ERROR_SUCCESS) + goto done; + + dwError = ScmWriteSecurityDescriptor(hServiceKey, + lpService->pSecurityDescriptor); + if (dwError != ERROR_SUCCESS) + goto done; + } + } + +done: if (lpGroup != NULL) HeapFree(GetProcessHeap(), 0, lpGroup); @@ -567,63 +879,13 @@ done:; if (lpService != NULL) { - if (lpService->lpImage != NULL) - ScmDereferenceServiceImage(lpService->lpImage); + ASSERT(lpService->lpImage == NULL); } return dwError; } -DWORD -ScmDeleteRegKey(HKEY hKey, LPCWSTR lpszSubKey) -{ - DWORD dwRet, dwMaxSubkeyLen = 0, dwSize; - WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; - HKEY hSubKey = 0; - - dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); - if (!dwRet) - { - /* Find the maximum subkey length so that we can allocate a buffer */ - dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, - &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL); - if (!dwRet) - { - dwMaxSubkeyLen++; - if (dwMaxSubkeyLen > sizeof(szNameBuf) / sizeof(WCHAR)) - { - /* Name too big: alloc a buffer for it */ - lpszName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwMaxSubkeyLen * sizeof(WCHAR)); - } - - if (!lpszName) - dwRet = ERROR_NOT_ENOUGH_MEMORY; - else - { - while (dwRet == ERROR_SUCCESS) - { - dwSize = dwMaxSubkeyLen; - dwRet = RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL); - if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA) - dwRet = ScmDeleteRegKey(hSubKey, lpszName); - } - if (dwRet == ERROR_NO_MORE_ITEMS) - dwRet = ERROR_SUCCESS; - - if (lpszName != szNameBuf) - HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */ - } - } - - RegCloseKey(hSubKey); - if (!dwRet) - dwRet = RegDeleteKeyW(hKey, lpszSubKey); - } - return dwRet; -} - - VOID ScmDeleteMarkedServices(VOID) { @@ -639,7 +901,7 @@ ScmDeleteMarkedServices(VOID) ServiceEntry = ServiceEntry->Flink; - if (CurrentService->bDeleted == TRUE) + if (CurrentService->bDeleted != FALSE) { dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services", @@ -664,6 +926,33 @@ ScmDeleteMarkedServices(VOID) } +static +VOID +ScmGetNoInteractiveServicesValue(VOID) +{ + HKEY hKey; + DWORD dwKeySize; + LONG lError; + + lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Control\\Windows", + 0, + KEY_READ, + &hKey); + if (lError == ERROR_SUCCESS) + { + dwKeySize = sizeof(NoInteractiveServices); + lError = RegQueryValueExW(hKey, + L"NoInteractiveServices", + 0, + NULL, + (LPBYTE)&NoInteractiveServices, + &dwKeySize); + RegCloseKey(hKey); + } +} + + DWORD ScmCreateServiceDatabase(VOID) { @@ -677,11 +966,15 @@ ScmCreateServiceDatabase(VOID) DPRINT("ScmCreateServiceDatabase() called\n"); + /* Retrieve the NoInteractiveServies value */ + ScmGetNoInteractiveServicesValue(); + + /* Create the service group list */ dwError = ScmCreateGroupList(); if (dwError != ERROR_SUCCESS) return dwError; - /* Initialize basic variables */ + /* Initialize image and service lists */ InitializeListHead(&ImageListHead); InitializeListHead(&ServiceListHead); @@ -832,6 +1125,11 @@ ScmCheckDriver(PSERVICE Service) /* Mark service as 'running' */ Service->Status.dwCurrentState = SERVICE_RUNNING; + Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + Service->Status.dwWin32ExitCode = ERROR_SUCCESS; + Service->Status.dwServiceSpecificExitCode = 0; + Service->Status.dwCheckPoint = 0; + Service->Status.dwWaitHint = 0; /* Mark the service group as 'running' */ if (Service->lpGroup != NULL) @@ -882,7 +1180,9 @@ ScmGetBootAndSystemDriverState(VOID) DWORD -ScmControlService(PSERVICE Service, +ScmControlService(HANDLE hControlPipe, + PWSTR pServiceName, + SERVICE_STATUS_HANDLE hServiceStatus, DWORD dwControl) { PSCM_CONTROL_PACKET ControlPacket; @@ -894,9 +1194,7 @@ ScmControlService(PSERVICE Service, PWSTR Ptr; DWORD dwError = ERROR_SUCCESS; BOOL bResult; -#ifdef USE_ASYNCHRONOUS_IO OVERLAPPED Overlapped = {0}; -#endif DPRINT("ScmControlService() called\n"); @@ -905,7 +1203,7 @@ ScmControlService(PSERVICE Service, /* Calculate the total length of the start command line */ PacketSize = sizeof(SCM_CONTROL_PACKET); - PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR)); + PacketSize += (DWORD)((wcslen(pServiceName) + 1) * sizeof(WCHAR)); ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, @@ -918,18 +1216,17 @@ ScmControlService(PSERVICE Service, ControlPacket->dwSize = PacketSize; ControlPacket->dwControl = dwControl; - ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service; + ControlPacket->hServiceStatus = hServiceStatus; ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); - wcscpy(Ptr, Service->lpServiceName); + wcscpy(Ptr, pServiceName); ControlPacket->dwArgumentsCount = 0; ControlPacket->dwArgumentsOffset = 0; -#ifdef USE_ASYNCHRONOUS_IO - bResult = WriteFile(Service->lpImage->hControlPipe, + bResult = WriteFile(hControlPipe, ControlPacket, PacketSize, &dwWriteCount, @@ -943,13 +1240,13 @@ ScmControlService(PSERVICE Service, { DPRINT("dwError: ERROR_IO_PENDING\n"); - dwError = WaitForSingleObject(Service->lpImage->hControlPipe, + dwError = WaitForSingleObject(hControlPipe, PipeTimeout); DPRINT("WaitForSingleObject() returned %lu\n", dwError); if (dwError == WAIT_TIMEOUT) { - bResult = CancelIo(Service->lpImage->hControlPipe); + bResult = CancelIo(hControlPipe); if (bResult == FALSE) { DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); @@ -960,7 +1257,7 @@ ScmControlService(PSERVICE Service, } else if (dwError == WAIT_OBJECT_0) { - bResult = GetOverlappedResult(Service->lpImage->hControlPipe, + bResult = GetOverlappedResult(hControlPipe, &Overlapped, &dwWriteCount, TRUE); @@ -983,7 +1280,7 @@ ScmControlService(PSERVICE Service, /* Read the reply */ Overlapped.hEvent = (HANDLE) NULL; - bResult = ReadFile(Service->lpImage->hControlPipe, + bResult = ReadFile(hControlPipe, &ReplyPacket, sizeof(SCM_REPLY_PACKET), &dwReadCount, @@ -997,13 +1294,13 @@ ScmControlService(PSERVICE Service, { DPRINT("dwError: ERROR_IO_PENDING\n"); - dwError = WaitForSingleObject(Service->lpImage->hControlPipe, + dwError = WaitForSingleObject(hControlPipe, PipeTimeout); DPRINT("WaitForSingleObject() returned %lu\n", dwError); if (dwError == WAIT_TIMEOUT) { - bResult = CancelIo(Service->lpImage->hControlPipe); + bResult = CancelIo(hControlPipe); if (bResult == FALSE) { DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); @@ -1014,7 +1311,7 @@ ScmControlService(PSERVICE Service, } else if (dwError == WAIT_OBJECT_0) { - bResult = GetOverlappedResult(Service->lpImage->hControlPipe, + bResult = GetOverlappedResult(hControlPipe, &Overlapped, &dwReadCount, TRUE); @@ -1034,45 +1331,8 @@ ScmControlService(PSERVICE Service, } } -#else - /* Send the control packet */ - bResult = WriteFile(Service->lpImage->hControlPipe, - ControlPacket, - PacketSize, - &dwWriteCount, - NULL); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT("WriteFile() failed (Error %lu)\n", dwError); - - if ((dwError == ERROR_GEN_FAILURE) && - (dwControl == SERVICE_CONTROL_STOP)) - { - /* Service is already terminated */ - Service->Status.dwCurrentState = SERVICE_STOPPED; - Service->Status.dwControlsAccepted = 0; - Service->Status.dwWin32ExitCode = ERROR_SERVICE_NOT_ACTIVE; - dwError = ERROR_SUCCESS; - } - goto Done; - } - - /* Read the reply */ - bResult = ReadFile(Service->lpImage->hControlPipe, - &ReplyPacket, - sizeof(SCM_REPLY_PACKET), - &dwReadCount, - NULL); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT("ReadFile() failed (Error %lu)\n", dwError); - } -#endif - Done: - /* Release the contol packet */ + /* Release the control packet */ HeapFree(GetProcessHeap(), 0, ControlPacket); @@ -1082,12 +1342,6 @@ Done: dwError = ReplyPacket.dwError; } - if (dwError == ERROR_SUCCESS && - dwControl == SERVICE_CONTROL_STOP) - { - ScmDereferenceServiceImage(Service->lpImage); - } - LeaveCriticalSection(&ControlServiceCriticalSection); DPRINT("ScmControlService() done\n"); @@ -1101,44 +1355,48 @@ ScmSendStartCommand(PSERVICE Service, DWORD argc, LPWSTR* argv) { + DWORD dwError = ERROR_SUCCESS; PSCM_CONTROL_PACKET ControlPacket; SCM_REPLY_PACKET ReplyPacket; DWORD PacketSize; - PWSTR Ptr; - DWORD dwWriteCount = 0; - DWORD dwReadCount = 0; - DWORD dwError = ERROR_SUCCESS; DWORD i; + PWSTR Ptr; PWSTR *pOffPtr; PWSTR pArgPtr; BOOL bResult; -#ifdef USE_ASYNCHRONOUS_IO + DWORD dwWriteCount = 0; + DWORD dwReadCount = 0; OVERLAPPED Overlapped = {0}; -#endif DPRINT("ScmSendStartCommand() called\n"); /* Calculate the total length of the start command line */ - PacketSize = sizeof(SCM_CONTROL_PACKET) + - (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR)); + PacketSize = sizeof(SCM_CONTROL_PACKET); + PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR)); - /* Calculate the required packet size for the start arguments */ + /* + * Calculate the required packet size for the start argument vector 'argv', + * composed of the list of pointer offsets, followed by UNICODE strings. + * The strings are stored continuously after the vector of offsets, with + * the offsets being relative to the beginning of the vector, as in the + * following layout (with N == argc): + * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] . + */ if (argc > 0 && argv != NULL) { - PacketSize = ALIGN_UP(PacketSize, LPWSTR); + PacketSize = ALIGN_UP(PacketSize, PWSTR); + PacketSize += (argc * sizeof(PWSTR)); DPRINT("Argc: %lu\n", argc); for (i = 0; i < argc; i++) { DPRINT("Argv[%lu]: %S\n", i, argv[i]); - PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR)); + PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR)); } } /* Allocate a control packet */ - ControlPacket = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - PacketSize); + ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PacketSize); if (ControlPacket == NULL) return ERROR_NOT_ENOUGH_MEMORY; @@ -1147,22 +1405,23 @@ ScmSendStartCommand(PSERVICE Service, ? SERVICE_CONTROL_START_OWN : SERVICE_CONTROL_START_SHARE; ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service; - ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); - Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); + /* Copy the start command line */ + ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); + Ptr = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset); wcscpy(Ptr, Service->lpServiceName); - ControlPacket->dwArgumentsCount = 0; + ControlPacket->dwArgumentsCount = 0; ControlPacket->dwArgumentsOffset = 0; - /* Copy argument list */ + /* Copy the argument vector */ if (argc > 0 && argv != NULL) { Ptr += wcslen(Service->lpServiceName) + 1; pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR); pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR)); - ControlPacket->dwArgumentsCount = argc; + ControlPacket->dwArgumentsCount = argc; ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket); DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount); @@ -1170,16 +1429,13 @@ ScmSendStartCommand(PSERVICE Service, for (i = 0; i < argc; i++) { - wcscpy(pArgPtr, argv[i]); - *pOffPtr = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr); - DPRINT("offset: %p\n", *pOffPtr); - - pArgPtr += wcslen(argv[i]) + 1; - pOffPtr++; + wcscpy(pArgPtr, argv[i]); + pOffPtr[i] = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr); + DPRINT("offset[%lu]: %p\n", i, pOffPtr[i]); + pArgPtr += wcslen(argv[i]) + 1; } } -#ifdef USE_ASYNCHRONOUS_IO bResult = WriteFile(Service->lpImage->hControlPipe, ControlPacket, PacketSize, @@ -1285,35 +1541,8 @@ ScmSendStartCommand(PSERVICE Service, } } -#else - /* Send the start command */ - bResult = WriteFile(Service->lpImage->hControlPipe, - ControlPacket, - PacketSize, - &dwWriteCount, - NULL); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT("WriteFile() failed (Error %lu)\n", dwError); - goto Done; - } - - /* Read the reply */ - bResult = ReadFile(Service->lpImage->hControlPipe, - &ReplyPacket, - sizeof(SCM_REPLY_PACKET), - &dwReadCount, - NULL); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT("ReadFile() failed (Error %lu)\n", dwError); - } -#endif - Done: - /* Release the contol packet */ + /* Release the control packet */ HeapFree(GetProcessHeap(), 0, ControlPacket); @@ -1336,18 +1565,15 @@ ScmWaitForServiceConnect(PSERVICE Service) DWORD dwProcessId = 0; DWORD dwError = ERROR_SUCCESS; BOOL bResult; -#ifdef USE_ASYNCHRONOUS_IO OVERLAPPED Overlapped = {0}; -#endif #if 0 - LPCWSTR lpErrorStrings[3]; + LPCWSTR lpLogStrings[3]; WCHAR szBuffer1[20]; WCHAR szBuffer2[20]; #endif DPRINT("ScmWaitForServiceConnect()\n"); -#ifdef USE_ASYNCHRONOUS_IO Overlapped.hEvent = (HANDLE)NULL; bResult = ConnectNamedPipe(Service->lpImage->hControlPipe, @@ -1377,13 +1603,13 @@ ScmWaitForServiceConnect(PSERVICE Service) #if 0 _ultow(PipeTimeout, szBuffer1, 10); - lpErrorStrings[0] = Service->lpDisplayName; - lpErrorStrings[1] = szBuffer1; + lpLogStrings[0] = Service->lpDisplayName; + lpLogStrings[1] = szBuffer1; ScmLogEvent(EVENT_CONNECTION_TIMEOUT, EVENTLOG_ERROR_TYPE, 2, - lpErrorStrings); + lpLogStrings); #endif DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service->lpDisplayName); @@ -1444,12 +1670,12 @@ ScmWaitForServiceConnect(PSERVICE Service) #if 0 _ultow(PipeTimeout, szBuffer1, 10); - lpErrorStrings[0] = szBuffer1; + lpLogStrings[0] = szBuffer1; ScmLogEvent(EVENT_READFILE_TIMEOUT, EVENTLOG_ERROR_TYPE, 1, - lpErrorStrings); + lpLogStrings); #endif DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service->lpDisplayName); @@ -1491,14 +1717,14 @@ ScmWaitForServiceConnect(PSERVICE Service) _ultow(Service->lpImage->dwProcessId, szBuffer1, 10); _ultow(dwProcessId, szBuffer2, 10); - lpErrorStrings[0] = Service->lpDisplayName; - lpErrorStrings[1] = szBuffer1; - lpErrorStrings[2] = szBuffer2; + lpLogStrings[0] = Service->lpDisplayName; + lpLogStrings[1] = szBuffer1; + lpLogStrings[2] = szBuffer2; ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED, EVENTLOG_WARNING_TYPE, 3, - lpErrorStrings); + lpLogStrings); #endif DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service->lpDisplayName); @@ -1507,39 +1733,6 @@ ScmWaitForServiceConnect(PSERVICE Service) DPRINT("ScmWaitForServiceConnect() done\n"); return ERROR_SUCCESS; -#else - - /* Connect control pipe */ - if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ? - TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED) - { - DPRINT("Control pipe connected!\n"); - - /* Read SERVICE_STATUS_HANDLE from pipe */ - bResult = ReadFile(Service->lpImage->hControlPipe, - (LPVOID)&dwProcessId, - sizeof(DWORD), - &dwRead, - NULL); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT1("Reading the service control pipe failed (Error %lu)\n", - dwError); - } - else - { - dwError = ERROR_SUCCESS; - DPRINT("Read control pipe successfully\n"); - } - } - else - { - DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); - } - - return dwError; -#endif } @@ -1550,6 +1743,7 @@ ScmStartUserModeService(PSERVICE Service, { PROCESS_INFORMATION ProcessInformation; STARTUPINFOW StartupInfo; + LPVOID lpEnvironment; BOOL Result; DWORD dwError = ERROR_SUCCESS; @@ -1567,20 +1761,87 @@ ScmStartUserModeService(PSERVICE Service, StartupInfo.cb = sizeof(StartupInfo); ZeroMemory(&ProcessInformation, sizeof(ProcessInformation)); - Result = CreateProcessW(NULL, - Service->lpImage->szImagePath, - NULL, - NULL, - FALSE, - DETACHED_PROCESS | CREATE_SUSPENDED, - NULL, - NULL, - &StartupInfo, - &ProcessInformation); + if (Service->lpImage->hToken) + { + /* User token: Run the service under the user account */ + + if (!CreateEnvironmentBlock(&lpEnvironment, Service->lpImage->hToken, FALSE)) + { + /* We failed, run the service with the current environment */ + DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n", + GetLastError(), Service->lpServiceName); + lpEnvironment = NULL; + } + + /* Impersonate the new user */ + Result = ImpersonateLoggedOnUser(Service->lpImage->hToken); + if (Result) + { + /* Launch the process in the user's logon session */ + Result = CreateProcessAsUserW(Service->lpImage->hToken, + NULL, + Service->lpImage->pszImagePath, + NULL, + NULL, + FALSE, + CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, + lpEnvironment, + NULL, + &StartupInfo, + &ProcessInformation); + if (!Result) + dwError = GetLastError(); + + /* Revert the impersonation */ + RevertToSelf(); + } + else + { + dwError = GetLastError(); + DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError); + } + } + else + { + /* No user token: Run the service under the LocalSystem account */ + + if (!CreateEnvironmentBlock(&lpEnvironment, NULL, TRUE)) + { + /* We failed, run the service with the current environment */ + DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n", + GetLastError(), Service->lpServiceName); + lpEnvironment = NULL; + } + + /* 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"; + } + + Result = CreateProcessW(NULL, + Service->lpImage->pszImagePath, + NULL, + NULL, + FALSE, + CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, + lpEnvironment, + NULL, + &StartupInfo, + &ProcessInformation); + if (!Result) + dwError = GetLastError(); + } + + if (lpEnvironment) + DestroyEnvironmentBlock(lpEnvironment); + if (!Result) { - dwError = GetLastError(); - DPRINT1("Starting '%S' failed!\n", Service->lpServiceName); + DPRINT1("Starting '%S' failed with error %d\n", + Service->lpServiceName, dwError); return dwError; } @@ -1591,30 +1852,25 @@ ScmStartUserModeService(PSERVICE Service, ProcessInformation.dwThreadId, ProcessInformation.hThread); - /* Get process handle and id */ + /* Get the process handle and ID */ + Service->lpImage->hProcess = ProcessInformation.hProcess; Service->lpImage->dwProcessId = ProcessInformation.dwProcessId; - /* Resume Thread */ + /* Resume the main thread and close its handle */ ResumeThread(ProcessInformation.hThread); + CloseHandle(ProcessInformation.hThread); /* Connect control pipe */ dwError = ScmWaitForServiceConnect(Service); - if (dwError == ERROR_SUCCESS) - { - /* Send start command */ - dwError = ScmSendStartCommand(Service, argc, argv); - } - else + if (dwError != ERROR_SUCCESS) { DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); Service->lpImage->dwProcessId = 0; + return dwError; } - /* Close thread and process handle */ - CloseHandle(ProcessInformation.hThread); - CloseHandle(ProcessInformation.hProcess); - - return dwError; + /* Send the start command */ + return ScmSendStartCommand(Service, argc, argv); } @@ -1625,8 +1881,8 @@ ScmLoadService(PSERVICE Service, { PSERVICE_GROUP Group = Service->lpGroup; DWORD dwError = ERROR_SUCCESS; - LPCWSTR lpErrorStrings[2]; - WCHAR szErrorBuffer[32]; + LPCWSTR lpLogStrings[2]; + WCHAR szLogBuffer[80]; DPRINT("ScmLoadService() called\n"); DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName); @@ -1641,13 +1897,8 @@ ScmLoadService(PSERVICE Service, if (Service->Status.dwServiceType & SERVICE_DRIVER) { - /* Load driver */ - dwError = ScmLoadDriver(Service); - if (dwError == ERROR_SUCCESS) - { - Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; - Service->Status.dwCurrentState = SERVICE_RUNNING; - } + /* Start the driver */ + dwError = ScmStartDriver(Service); } else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS)) { @@ -1658,16 +1909,17 @@ ScmLoadService(PSERVICE Service, dwError = ScmStartUserModeService(Service, argc, argv); if (dwError == ERROR_SUCCESS) { -#ifdef USE_SERVICE_START_PENDING Service->Status.dwCurrentState = SERVICE_START_PENDING; -#else - Service->Status.dwCurrentState = SERVICE_RUNNING; -#endif + Service->Status.dwControlsAccepted = 0; } else { - ScmDereferenceServiceImage(Service->lpImage); - Service->lpImage = NULL; + Service->lpImage->dwImageRunCount--; + if (Service->lpImage->dwImageRunCount == 0) + { + ScmRemoveServiceImage(Service->lpImage); + Service->lpImage = NULL; + } } } } @@ -1682,25 +1934,28 @@ ScmLoadService(PSERVICE Service, } /* Log a successful service start */ - lpErrorStrings[0] = Service->lpDisplayName; - lpErrorStrings[1] = L"start"; + LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_START, szLogBuffer, 80); + lpLogStrings[0] = Service->lpDisplayName; + lpLogStrings[1] = szLogBuffer; + ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS, EVENTLOG_INFORMATION_TYPE, 2, - lpErrorStrings); + lpLogStrings); } else { if (Service->dwErrorControl != SERVICE_ERROR_IGNORE) { /* Log a failed service start */ - swprintf(szErrorBuffer, L"%lu", dwError); - lpErrorStrings[0] = Service->lpServiceName; - lpErrorStrings[1] = szErrorBuffer; + StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer), + L"%lu", dwError); + lpLogStrings[0] = Service->lpServiceName; + lpLogStrings[1] = szLogBuffer; ScmLogEvent(EVENT_SERVICE_START_FAILED, EVENTLOG_ERROR_TYPE, 2, - lpErrorStrings); + lpLogStrings); } #if 0 @@ -1774,13 +2029,15 @@ done: VOID ScmAutoStartServices(VOID) { - DWORD dwError = ERROR_SUCCESS; + DWORD dwError; PLIST_ENTRY GroupEntry; PLIST_ENTRY ServiceEntry; PSERVICE_GROUP CurrentGroup; PSERVICE CurrentService; WCHAR szSafeBootServicePath[MAX_PATH]; + DWORD SafeBootEnabled; HKEY hKey; + DWORD dwKeySize; ULONG i; /* @@ -1789,6 +2046,28 @@ ScmAutoStartServices(VOID) */ ASSERT(ScmInitialize); + /* Retrieve the SafeBoot parameter */ + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option", + 0, + KEY_READ, + &hKey); + if (dwError == ERROR_SUCCESS) + { + dwKeySize = sizeof(SafeBootEnabled); + dwError = RegQueryValueExW(hKey, + L"OptionValue", + 0, + NULL, + (LPBYTE)&SafeBootEnabled, + &dwKeySize); + RegCloseKey(hKey); + } + + /* Default to Normal boot if the value doesn't exist */ + if (dwError != ERROR_SUCCESS) + SafeBootEnabled = 0; + /* Acquire the service control critical section, to synchronize starts */ EnterCriticalSection(&ControlServiceCriticalSection); @@ -1799,23 +2078,25 @@ ScmAutoStartServices(VOID) CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); /* Build the safe boot path */ - wcscpy(szSafeBootServicePath, - L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot"); + StringCchCopyW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), + L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot"); - switch (GetSystemMetrics(SM_CLEANBOOT)) + switch (SafeBootEnabled) { /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */ case 1: case 3: - wcscat(szSafeBootServicePath, L"\\Minimal\\"); + StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), + L"\\Minimal\\"); break; case 2: - wcscat(szSafeBootServicePath, L"\\Network\\"); + StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), + L"\\Network\\"); break; } - if (GetSystemMetrics(SM_CLEANBOOT)) + if (SafeBootEnabled != 0) { /* If key does not exist then do not assume safe mode */ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, @@ -1828,9 +2109,8 @@ ScmAutoStartServices(VOID) RegCloseKey(hKey); /* Finish Safe Boot path off */ - wcsncat(szSafeBootServicePath, - CurrentService->lpServiceName, - MAX_PATH - wcslen(szSafeBootServicePath)); + StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), + CurrentService->lpServiceName); /* Check that the key is in the Safe Boot path */ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, @@ -1973,12 +2253,16 @@ ScmAutoShutdownServices(VOID) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); - if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING || - CurrentService->Status.dwCurrentState == SERVICE_START_PENDING) + if ((CurrentService->Status.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) && + (CurrentService->Status.dwCurrentState == SERVICE_RUNNING || + CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)) { - /* shutdown service */ - DPRINT("Shutdown service: %S\n", CurrentService->szServiceName); - ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN); + /* Send the shutdown notification */ + DPRINT("Shutdown service: %S\n", CurrentService->lpServiceName); + ScmControlService(CurrentService->lpImage->hControlPipe, + CurrentService->lpServiceName, + (SERVICE_STATUS_HANDLE)CurrentService, + SERVICE_CONTROL_SHUTDOWN); } ServiceEntry = ServiceEntry->Flink; @@ -2028,14 +2312,13 @@ ScmInitNamedPipeCriticalSection(VOID) &hKey); if (dwError == ERROR_SUCCESS) { - dwKeySize = sizeof(DWORD); + dwKeySize = sizeof(PipeTimeout); RegQueryValueExW(hKey, L"ServicesPipeTimeout", 0, NULL, (LPBYTE)&PipeTimeout, &dwKeySize); - RegCloseKey(hKey); } }