Index: base/system/services/CMakeLists.txt =================================================================== --- base/system/services/CMakeLists.txt (révision 56659) +++ base/system/services/CMakeLists.txt (copie de travail) @@ -12,8 +12,14 @@ database.c driver.c groupdb.c + handles.c + lock.c rpcserver.c + service.c services.c + svcobject.c + unimplemented.c + utils.c services.rc ${CMAKE_CURRENT_BINARY_DIR}/svcctl_s.c) @@ -23,7 +29,7 @@ target_link_libraries(services pseh) endif() -set_module_type(services win32cui UNICODE) +set_module_type(services win32gui UNICODE) add_importlibs(services user32 advapi32 rpcrt4 msvcrt kernel32 ntdll) add_pch(services services.h ${CMAKE_CURRENT_BINARY_DIR}/svcctl_s.h) add_cd_file(TARGET services DESTINATION reactos/system32 FOR all) Index: base/system/services/config.c =================================================================== --- base/system/services/config.c (révision 56659) +++ base/system/services/config.c (copie de travail) @@ -7,18 +7,18 @@ * */ -/* INCLUDES *****************************************************************/ +/* INCLUDES ******************************************************************/ #include "services.h" #define NDEBUG #include + /* FUNCTIONS *****************************************************************/ - DWORD -ScmOpenServiceKey(LPWSTR lpServiceName, +ScmOpenServiceKey(PSERVICE_RECORD pServiceRecord, REGSAM samDesired, PHKEY phKey) { @@ -28,7 +28,7 @@ *phKey = NULL; dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"System\\CurrentControlSet\\Services", + pServiceRecord->Database->RegistryKeyNames.Services, 0, KEY_READ, &hServicesKey); @@ -36,7 +36,7 @@ return dwError; dwError = RegOpenKeyExW(hServicesKey, - lpServiceName, + pServiceRecord->ServiceName, 0, samDesired, phKey); @@ -48,7 +48,7 @@ DWORD -ScmCreateServiceKey(LPCWSTR lpServiceName, +ScmCreateServiceKey(PSERVICE_RECORD pServiceRecord, REGSAM samDesired, PHKEY phKey) { @@ -59,7 +59,7 @@ *phKey = NULL; dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"System\\CurrentControlSet\\Services", + pServiceRecord->Database->RegistryKeyNames.Services, 0, KEY_READ | KEY_CREATE_SUB_KEY, &hServicesKey); @@ -67,7 +67,7 @@ return dwError; dwError = RegCreateKeyExW(hServicesKey, - lpServiceName, + pServiceRecord->ServiceName, 0, NULL, REG_OPTION_NON_VOLATILE, @@ -198,7 +198,7 @@ DWORD -ScmMarkServiceForDelete(PSERVICE pService) +ScmMarkServiceForDelete(PSERVICE_RECORD pService) { HKEY hServiceKey = NULL; DWORD dwValue = 1; @@ -206,7 +206,7 @@ DPRINT("ScmMarkServiceForDelete() called\n"); - dwError = ScmOpenServiceKey(pService->lpServiceName, + dwError = ScmOpenServiceKey(pService, KEY_WRITE, &hServiceKey); if (dwError != ERROR_SUCCESS) @@ -436,4 +436,5 @@ return ERROR_SUCCESS; } + /* EOF */ Index: base/system/services/database.c =================================================================== --- base/system/services/database.c (révision 56659) +++ base/system/services/database.c (copie de travail) @@ -7,286 +7,47 @@ * Copyright 2006 Hervé Poussineau * Copyright 2007 Ged Murphy * Gregor Brunmar + * Copyright 2012 Hermès Bélusca - Maïto * */ -/* INCLUDES *****************************************************************/ +/* INCLUDES ******************************************************************/ #include "services.h" #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 *******************************************************************/ +LIST_ENTRY DatabaseListHead; // List of SC databases on this computer. -/* GLOBALS *******************************************************************/ +/* static */ RTL_RESOURCE DatabaseLock; // HACK: !!!!!!!!!!!!!!!!!! see ApiLockListHead ?? -LIST_ENTRY ImageListHead; -LIST_ENTRY ServiceListHead; - -static RTL_RESOURCE DatabaseLock; static DWORD dwResumeCount = 1; -static CRITICAL_SECTION ControlServiceCriticalSection; -static DWORD dwPipeTimeout = 30000; /* 30 Seconds */ +/* PRIVATE HELPER FUNCTIONS **************************************************/ - -/* FUNCTIONS *****************************************************************/ - -static DWORD -ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage) +/******** there are used only in svcobject.c ************/ +PSERVICE_RECORD +ScmGetServiceEntryByName(IN PSCMGR_DATABASE pScDatabase, + IN LPCWSTR lpServiceName) { - WCHAR szControlPipeName[MAX_PATH + 1]; - HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE; - DWORD ServiceCurrent = 0; - DWORD KeyDisposition; - DWORD dwKeySize; - DWORD dwError; + PLIST_ENTRY ServiceEntry; + PSERVICE_RECORD CurrentService; - /* 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) - { - 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); - - if (dwError != ERROR_SUCCESS) - { - RegCloseKey(hServiceCurrentKey); - DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError); - return dwError; - } - - ServiceCurrent++; - } - - dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent)); - - RegCloseKey(hServiceCurrentKey); - - if (dwError != ERROR_SUCCESS) - { - DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError); - return dwError; - } - - /* Create '\\.\pipe\net\NtControlPipeXXX' instance */ - swprintf(szControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", 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, - 4, - dwPipeTimeout, - NULL); - DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName); - if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE) - { - DPRINT1("Failed to create control pipe!\n"); - return GetLastError(); - } - - return ERROR_SUCCESS; -} - - -static PSERVICE_IMAGE -ScmGetServiceImageByImagePath(LPWSTR lpImagePath) -{ - PLIST_ENTRY ImageEntry; - PSERVICE_IMAGE CurrentImage; - - DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath); - - ImageEntry = ImageListHead.Flink; - while (ImageEntry != &ImageListHead) - { - CurrentImage = CONTAINING_RECORD(ImageEntry, - SERVICE_IMAGE, - ImageListEntry); - if (_wcsicmp(CurrentImage->szImagePath, lpImagePath) == 0) - { - DPRINT("Found image: '%S'\n", CurrentImage->szImagePath); - return CurrentImage; - } - - ImageEntry = ImageEntry->Flink; - } - - DPRINT("Couldn't find a matching image\n"); - - return NULL; - -} - - -static DWORD -ScmCreateOrReferenceServiceImage(PSERVICE pService) -{ - RTL_QUERY_REGISTRY_TABLE QueryTable[2]; - UNICODE_STRING ImagePath; - PSERVICE_IMAGE pServiceImage = NULL; - NTSTATUS Status; - DWORD dwError = ERROR_SUCCESS; - - DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService); - - RtlInitUnicodeString(&ImagePath, NULL); - - /* Get service data */ - RtlZeroMemory(&QueryTable, - sizeof(QueryTable)); - - QueryTable[0].Name = L"ImagePath"; - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].EntryContext = &ImagePath; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, - pService->lpServiceName, - QueryTable, - NULL, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); - return RtlNtStatusToDosError(Status); - } - - DPRINT("ImagePath: '%wZ'\n", &ImagePath); - - pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer); - if (pServiceImage == NULL) - { - /* Create a new service image */ - pServiceImage = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - FIELD_OFFSET(SERVICE_IMAGE, szImagePath[ImagePath.Length / sizeof(WCHAR) + 1])); - if (pServiceImage == NULL) - { - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto done; - } - - pServiceImage->dwImageRunCount = 1; - pServiceImage->hControlPipe = INVALID_HANDLE_VALUE; - - /* Set the image path */ - wcscpy(pServiceImage->szImagePath, - ImagePath.Buffer); - - RtlFreeUnicodeString(&ImagePath); - - /* Create the control pipe */ - dwError = ScmCreateNewControlPipe(pServiceImage); - if (dwError != ERROR_SUCCESS) - { - HeapFree(GetProcessHeap(), 0, pServiceImage); - goto done; - } - - /* FIXME: Add more initialization code here */ - - - /* Append service record */ - InsertTailList(&ImageListHead, - &pServiceImage->ImageListEntry); - } - else - { - /* Increment the run counter */ - pServiceImage->dwImageRunCount++; - } - - DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount); - - /* Link the service image to the service */ - pService->lpImage = pServiceImage; - -done:; - RtlFreeUnicodeString(&ImagePath); - - DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError); - - return dwError; -} - - -static VOID -ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage) -{ - DPRINT1("ScmDereferenceServiceImage() called\n"); - - pServiceImage->dwImageRunCount--; - - if (pServiceImage->dwImageRunCount == 0) - { - DPRINT1("dwImageRunCount == 0\n"); - - /* FIXME: Terminate the process */ - - /* Remove the service image from the list */ - RemoveEntryList(&pServiceImage->ImageListEntry); - - /* Close the control pipe */ - if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE) - CloseHandle(pServiceImage->hControlPipe); - - /* Release the service image */ - HeapFree(GetProcessHeap(), 0, pServiceImage); - } -} - - -PSERVICE -ScmGetServiceEntryByName(LPCWSTR lpServiceName) -{ - PLIST_ENTRY ServiceEntry; - PSERVICE CurrentService; - DPRINT("ScmGetServiceEntryByName() called\n"); - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScDatabase->ServiceListHead)) { CurrentService = CONTAINING_RECORD(ServiceEntry, - SERVICE, + SERVICE_RECORD, ServiceListEntry); - if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0) + if (_wcsicmp(CurrentService->ServiceName, lpServiceName) == 0) { - DPRINT("Found service: '%S'\n", CurrentService->lpServiceName); + DPRINT("Found service: '%S'\n", CurrentService->ServiceName); return CurrentService; } @@ -299,23 +60,24 @@ } -PSERVICE -ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName) +PSERVICE_RECORD +ScmGetServiceEntryByDisplayName(IN PSCMGR_DATABASE pScDatabase, + IN LPCWSTR lpDisplayName) { - PLIST_ENTRY ServiceEntry; - PSERVICE CurrentService; + PLIST_ENTRY ServiceEntry; + PSERVICE_RECORD CurrentService; DPRINT("ScmGetServiceEntryByDisplayName() called\n"); - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScDatabase->ServiceListHead)) { CurrentService = CONTAINING_RECORD(ServiceEntry, - SERVICE, + SERVICE_RECORD, ServiceListEntry); - if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0) + if (_wcsicmp(CurrentService->DisplayName, lpDisplayName) == 0) { - DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName); + DPRINT("Found service: '%S'\n", CurrentService->DisplayName); return CurrentService; } @@ -328,23 +90,24 @@ } -PSERVICE -ScmGetServiceEntryByResumeCount(DWORD dwResumeCount) +PSERVICE_RECORD +ScmGetServiceEntryByResumeCount(IN PSCMGR_DATABASE pScDatabase, + IN DWORD dwResumeCount) { - PLIST_ENTRY ServiceEntry; - PSERVICE CurrentService; + PLIST_ENTRY ServiceEntry; + PSERVICE_RECORD CurrentService; DPRINT("ScmGetServiceEntryByResumeCount() called\n"); - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScDatabase->ServiceListHead)) { CurrentService = CONTAINING_RECORD(ServiceEntry, - SERVICE, + SERVICE_RECORD, ServiceListEntry); if (CurrentService->dwResumeCount > dwResumeCount) { - DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName); + DPRINT("Found service: '%S'\n", CurrentService->DisplayName); return CurrentService; } @@ -355,87 +118,110 @@ return NULL; } +/********************************************************/ DWORD -ScmCreateNewServiceRecord(LPCWSTR lpServiceName, - PSERVICE *lpServiceRecord) +ScmCreateNewServiceRecord(IN PSCMGR_DATABASE pScDatabase, + IN LPCWSTR lpServiceName, + OUT PSERVICE_RECORD* ppServiceRecord) { - PSERVICE lpService = NULL; + PSERVICE_RECORD pServiceRecord = NULL; DPRINT("Service: '%S'\n", lpServiceName); /* Allocate service entry */ - lpService = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - FIELD_OFFSET(SERVICE, szServiceName[wcslen(lpServiceName) + 1])); - if (lpService == NULL) + /* + pServiceRecord = (PSERVICE_RECORD)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + FIELD_OFFSET(SERVICE_RECORD, szServiceName[wcslen(lpServiceName) + 1])); + */ + pServiceRecord = (PSERVICE_RECORD)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(SERVICE_RECORD) + wcssize(lpServiceName)); + + if (pServiceRecord == NULL) return ERROR_NOT_ENOUGH_MEMORY; - *lpServiceRecord = lpService; + *ppServiceRecord = pServiceRecord; + /* Attach the newly created service record to its database */ + pServiceRecord->Database = pScDatabase; + /* Copy service name */ - wcscpy(lpService->szServiceName, lpServiceName); - lpService->lpServiceName = lpService->szServiceName; - lpService->lpDisplayName = lpService->lpServiceName; + if (lpServiceName) + { + pServiceRecord->ServiceName = (LPWSTR)((LPBYTE)(pServiceRecord) + sizeof(SERVICE_RECORD)); + wcscpy(pServiceRecord->ServiceName, lpServiceName); + } + else + { + pServiceRecord->ServiceName = NULL; + } + pServiceRecord->DisplayName = pServiceRecord->ServiceName; /* Set the resume count */ - lpService->dwResumeCount = dwResumeCount++; + pServiceRecord->dwResumeCount = dwResumeCount++; + /* Initialize the service status */ + pServiceRecord->Status.dwCurrentState = SERVICE_STOPPED; + pServiceRecord->Status.dwControlsAccepted = 0; + pServiceRecord->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED; + pServiceRecord->Status.dwServiceSpecificExitCode = 0; + pServiceRecord->Status.dwCheckPoint = 0; + pServiceRecord->Status.dwWaitHint = 2000; /* 2 seconds */ + /* Append service record */ - InsertTailList(&ServiceListHead, - &lpService->ServiceListEntry); + InsertTailList(&(pScDatabase->ServiceListHead), + &(pServiceRecord->ServiceListEntry)); - /* Initialize the service status */ - lpService->Status.dwCurrentState = SERVICE_STOPPED; - lpService->Status.dwControlsAccepted = 0; - lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED; - lpService->Status.dwServiceSpecificExitCode = 0; - lpService->Status.dwCheckPoint = 0; - lpService->Status.dwWaitHint = 2000; /* 2 seconds */ - return ERROR_SUCCESS; } VOID -ScmDeleteServiceRecord(PSERVICE lpService) +ScmDeleteServiceRecord(IN PSERVICE_RECORD pServiceRecord) { - DPRINT("Deleting Service %S\n", lpService->lpServiceName); + DPRINT("Deleting Service %S\n", pServiceRecord->ServiceName); /* Delete the display name */ - if (lpService->lpDisplayName != NULL && - lpService->lpDisplayName != lpService->lpServiceName) - HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName); + if (pServiceRecord->DisplayName != NULL && + pServiceRecord->DisplayName != pServiceRecord->ServiceName) + { + HeapFree(GetProcessHeap(), 0, pServiceRecord->DisplayName); + } /* Dereference the service image */ - if (lpService->lpImage) - ScmDereferenceServiceImage(lpService->lpImage); + if (pServiceRecord->lpImage) + ScmDereferenceServiceImage(pServiceRecord->lpImage); /* Decrement the group reference counter */ - if (lpService->lpGroup) - lpService->lpGroup->dwRefCount--; + if (pServiceRecord->lpGroup) + pServiceRecord->lpGroup->dwRefCount--; /* FIXME: SecurityDescriptor */ /* Remove the Service from the List */ - RemoveEntryList(&lpService->ServiceListEntry); + RemoveEntryList(&pServiceRecord->ServiceListEntry); - DPRINT("Deleted Service %S\n", lpService->lpServiceName); + DPRINT("Deleted Service %S\n", pServiceRecord->ServiceName); /* Delete the service record */ - HeapFree(GetProcessHeap(), 0, lpService); + HeapFree(GetProcessHeap(), 0, pServiceRecord); DPRINT("Done\n"); + + return; } static DWORD -CreateServiceListEntry(LPCWSTR lpServiceName, - HKEY hServiceKey) +CreateServiceListEntry(IN PSCMGR_DATABASE pScDatabase, + IN LPCWSTR lpServiceName, + IN HKEY hServiceKey) { - PSERVICE lpService = NULL; + PSERVICE_RECORD lpService = NULL; LPWSTR lpDisplayName = NULL; LPWSTR lpGroup = NULL; DWORD dwSize; @@ -518,7 +304,8 @@ DPRINT("Display name: %S\n", lpDisplayName); - dwError = ScmCreateNewServiceRecord(lpServiceName, + dwError = ScmCreateNewServiceRecord(pScDatabase, + lpServiceName, &lpService); if (dwError != ERROR_SUCCESS) goto done; @@ -537,11 +324,11 @@ if (lpDisplayName != NULL) { - lpService->lpDisplayName = lpDisplayName; + lpService->DisplayName = lpDisplayName; lpDisplayName = NULL; } - DPRINT("ServiceName: '%S'\n", lpService->lpServiceName); + DPRINT("ServiceName: '%S'\n", lpService->ServiceName); if (lpService->lpGroup != NULL) { DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName); @@ -555,7 +342,7 @@ if (ScmIsDeleteFlagSet(hServiceKey)) lpService->bDeleted = TRUE; -done:; +done: if (lpGroup != NULL) HeapFree(GetProcessHeap(), 0, lpGroup); @@ -572,7 +359,7 @@ } -DWORD +static DWORD ScmDeleteRegKey(HKEY hKey, LPCWSTR lpszSubKey) { DWORD dwRet, dwMaxSubkeyLen = 0, dwSize; @@ -621,31 +408,31 @@ } -VOID -ScmDeleteMarkedServices(VOID) +static VOID +ScmDeleteMarkedServices(IN PSCMGR_DATABASE pScDatabase) { PLIST_ENTRY ServiceEntry; - PSERVICE CurrentService; + PSERVICE_RECORD CurrentService; HKEY hServicesKey; DWORD dwError; - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScDatabase->ServiceListHead)) { - CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE_RECORD, ServiceListEntry); ServiceEntry = ServiceEntry->Flink; if (CurrentService->bDeleted == TRUE) { dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"System\\CurrentControlSet\\Services", + pScDatabase->RegistryKeyNames.Services, 0, DELETE, &hServicesKey); if (dwError == ERROR_SUCCESS) { - dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName); + dwError = ScmDeleteRegKey(hServicesKey, CurrentService->ServiceName); RegCloseKey(hServicesKey); if (dwError == ERROR_SUCCESS) { @@ -655,1091 +442,38 @@ } if (dwError != ERROR_SUCCESS) - DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName); + DPRINT1("Delete service failed: %S\n", CurrentService->ServiceName); } } } VOID -WaitForLSA(VOID) -{ - HANDLE hEvent; - DWORD dwError; - - DPRINT("WaitForLSA() called\n"); - - hEvent = CreateEventW(NULL, - TRUE, - FALSE, - L"LSA_RPC_SERVER_ACTIVE"); - if (hEvent == NULL) - { - dwError = GetLastError(); - DPRINT1("Failed to create the notication event (Error %lu)\n", dwError); - - if (dwError == ERROR_ALREADY_EXISTS) - { - hEvent = OpenEventW(SYNCHRONIZE, - FALSE, - L"LSA_RPC_SERVER_ACTIVE"); - if (hEvent != NULL) - { - DPRINT1("Could not open the notification event!\n"); - return; - } - } - } - - DPRINT("Wait for LSA!\n"); - WaitForSingleObject(hEvent, INFINITE); - DPRINT("LSA is available!\n"); - - CloseHandle(hEvent); - - DPRINT("WaitForLSA() done\n"); -} - - -DWORD -ScmCreateServiceDatabase(VOID) -{ - WCHAR szSubKey[MAX_PATH]; - HKEY hServicesKey; - HKEY hServiceKey; - DWORD dwSubKey; - DWORD dwSubKeyLength; - FILETIME ftLastChanged; - DWORD dwError; - - DPRINT("ScmCreateServiceDatabase() called\n"); - - dwError = ScmCreateGroupList(); - if (dwError != ERROR_SUCCESS) - return dwError; - - /* Initialize basic variables */ - InitializeListHead(&ImageListHead); - InitializeListHead(&ServiceListHead); - - /* Initialize the database lock */ - RtlInitializeResource(&DatabaseLock); - - dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"System\\CurrentControlSet\\Services", - 0, - KEY_READ, - &hServicesKey); - if (dwError != ERROR_SUCCESS) - return dwError; - - dwSubKey = 0; - for (;;) - { - dwSubKeyLength = MAX_PATH; - dwError = RegEnumKeyExW(hServicesKey, - dwSubKey, - szSubKey, - &dwSubKeyLength, - NULL, - NULL, - NULL, - &ftLastChanged); - if (dwError == ERROR_SUCCESS && - szSubKey[0] != L'{') - { - DPRINT("SubKeyName: '%S'\n", szSubKey); - - dwError = RegOpenKeyExW(hServicesKey, - szSubKey, - 0, - KEY_READ, - &hServiceKey); - if (dwError == ERROR_SUCCESS) - { - dwError = CreateServiceListEntry(szSubKey, - hServiceKey); - - RegCloseKey(hServiceKey); - } - } - - if (dwError != ERROR_SUCCESS) - break; - - dwSubKey++; - } - - RegCloseKey(hServicesKey); - - /* Wait for LSA */ - WaitForLSA(); - - /* Delete services that are marked for delete */ - ScmDeleteMarkedServices(); - - DPRINT("ScmCreateServiceDatabase() done\n"); - - return ERROR_SUCCESS; -} - - -VOID -ScmShutdownServiceDatabase(VOID) -{ - DPRINT("ScmShutdownServiceDatabase() called\n"); - - ScmDeleteMarkedServices(); - RtlDeleteResource(&DatabaseLock); - - DPRINT("ScmShutdownServiceDatabase() done\n"); -} - - -static NTSTATUS -ScmCheckDriver(PSERVICE Service) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING DirName; - HANDLE DirHandle; - NTSTATUS Status; - POBJECT_DIRECTORY_INFORMATION DirInfo; - ULONG BufferLength; - ULONG DataLength; - ULONG Index; - - DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName); - - if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER) - { - RtlInitUnicodeString(&DirName, - L"\\Driver"); - } - else - { - RtlInitUnicodeString(&DirName, - L"\\FileSystem"); - } - - InitializeObjectAttributes(&ObjectAttributes, - &DirName, - 0, - NULL, - NULL); - - Status = NtOpenDirectoryObject(&DirHandle, - DIRECTORY_QUERY | DIRECTORY_TRAVERSE, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) + - 2 * MAX_PATH * sizeof(WCHAR); - DirInfo = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - BufferLength); - - Index = 0; - while (TRUE) - { - Status = NtQueryDirectoryObject(DirHandle, - DirInfo, - BufferLength, - TRUE, - FALSE, - &Index, - &DataLength); - if (Status == STATUS_NO_MORE_ENTRIES) - { - /* FIXME: Add current service to 'failed service' list */ - DPRINT("Service '%S' failed\n", Service->lpServiceName); - break; - } - - if (!NT_SUCCESS(Status)) - break; - - DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name); - - if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0) - { - DPRINT("Found: '%S' '%wZ'\n", - Service->lpServiceName, &DirInfo->Name); - - /* Mark service as 'running' */ - Service->Status.dwCurrentState = SERVICE_RUNNING; - - /* Mark the service group as 'running' */ - if (Service->lpGroup != NULL) - { - Service->lpGroup->ServicesRunning = TRUE; - } - - break; - } - } - - HeapFree(GetProcessHeap(), - 0, - DirInfo); - NtClose(DirHandle); - - return STATUS_SUCCESS; -} - - -VOID -ScmGetBootAndSystemDriverState(VOID) -{ - PLIST_ENTRY ServiceEntry; - PSERVICE CurrentService; - - DPRINT("ScmGetBootAndSystemDriverState() called\n"); - - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) - { - CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); - - if (CurrentService->dwStartType == SERVICE_BOOT_START || - CurrentService->dwStartType == SERVICE_SYSTEM_START) - { - /* Check driver */ - DPRINT(" Checking service: %S\n", CurrentService->lpServiceName); - - ScmCheckDriver(CurrentService); - } - - ServiceEntry = ServiceEntry->Flink; - } - - DPRINT("ScmGetBootAndSystemDriverState() done\n"); -} - - -DWORD -ScmControlService(PSERVICE Service, - DWORD dwControl) -{ - PSCM_CONTROL_PACKET ControlPacket; - SCM_REPLY_PACKET ReplyPacket; - - DWORD dwWriteCount = 0; - DWORD dwReadCount = 0; - DWORD PacketSize; - PWSTR Ptr; - DWORD dwError = ERROR_SUCCESS; - BOOL bResult; -#ifdef USE_ASYNCHRONOUS_IO - OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; -#endif - - DPRINT("ScmControlService() called\n"); - - EnterCriticalSection(&ControlServiceCriticalSection); - - /* Calculate the total length of the start command line */ - PacketSize = sizeof(SCM_CONTROL_PACKET); - PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR); - - ControlPacket = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - PacketSize); - if (ControlPacket == NULL) - { - LeaveCriticalSection(&ControlServiceCriticalSection); - return ERROR_NOT_ENOUGH_MEMORY; - } - - ControlPacket->dwSize = PacketSize; - ControlPacket->dwControl = dwControl; - ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service; - - ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); - - Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); - wcscpy(Ptr, Service->lpServiceName); - - ControlPacket->dwArgumentsCount = 0; - ControlPacket->dwArgumentsOffset = 0; - -#ifdef USE_ASYNCHRONOUS_IO - bResult = WriteFile(Service->lpImage->hControlPipe, - ControlPacket, - PacketSize, - &dwWriteCount, - &Overlapped); - if (bResult == FALSE) - { - DPRINT1("WriteFile() returned FALSE\n"); - - dwError = GetLastError(); - if (dwError == ERROR_IO_PENDING) - { - DPRINT1("dwError: ERROR_IO_PENDING\n"); - - dwError = WaitForSingleObject(Service->lpImage->hControlPipe, - dwPipeTimeout); - DPRINT1("WaitForSingleObject() returned %lu\n", dwError); - - if (dwError == WAIT_TIMEOUT) - { - bResult = CancelIo(Service->lpImage->hControlPipe); - if (bResult == FALSE) - { - DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); - } - - dwError = ERROR_SERVICE_REQUEST_TIMEOUT; - goto Done; - } - else if (dwError == ERROR_SUCCESS) - { - bResult = GetOverlappedResult(Service->lpImage->hControlPipe, - &Overlapped, - &dwWriteCount, - TRUE); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); - - goto Done; - } - } - } - else - { - DPRINT1("WriteFile() failed (Error %lu)\n", dwError); - goto Done; - } - } - - /* Read the reply */ - Overlapped.hEvent = (HANDLE) NULL; - - bResult = ReadFile(Service->lpImage->hControlPipe, - &ReplyPacket, - sizeof(SCM_REPLY_PACKET), - &dwReadCount, - &Overlapped); - if (bResult == FALSE) - { - DPRINT1("ReadFile() returned FALSE\n"); - - dwError = GetLastError(); - if (dwError == ERROR_IO_PENDING) - { - DPRINT1("dwError: ERROR_IO_PENDING\n"); - - dwError = WaitForSingleObject(Service->lpImage->hControlPipe, - dwPipeTimeout); - DPRINT1("WaitForSingleObject() returned %lu\n", dwError); - - if (dwError == WAIT_TIMEOUT) - { - bResult = CancelIo(Service->lpImage->hControlPipe); - if (bResult == FALSE) - { - DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); - } - - dwError = ERROR_SERVICE_REQUEST_TIMEOUT; - goto Done; - } - else if (dwError == ERROR_SUCCESS) - { - bResult = GetOverlappedResult(Service->lpImage->hControlPipe, - &Overlapped, - &dwReadCount, - TRUE); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); - - goto Done; - } - } - } - else - { - DPRINT1("ReadFile() failed (Error %lu)\n", dwError); - goto Done; - } - } - -#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 */ - HeapFree(GetProcessHeap(), - 0, - ControlPacket); - - if (dwReadCount == sizeof(SCM_REPLY_PACKET)) - { - dwError = ReplyPacket.dwError; - } - - if (dwError == ERROR_SUCCESS && - dwControl == SERVICE_CONTROL_STOP) - { - ScmDereferenceServiceImage(Service->lpImage); - } - - LeaveCriticalSection(&ControlServiceCriticalSection); - - DPRINT("ScmControlService() done\n"); - - return dwError; -} - - -static DWORD -ScmSendStartCommand(PSERVICE Service, - DWORD argc, - LPWSTR *argv) -{ - 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 *pOffPtr; - PWSTR pArgPtr; - BOOL bResult; -#ifdef USE_ASYNCHRONOUS_IO - OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; -#endif - - DPRINT("ScmSendStartCommand() called\n"); - - /* Calculate the total length of the start command line */ - PacketSize = sizeof(SCM_CONTROL_PACKET); - PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR); - - /* Calculate the required packet size for the start arguments */ - if (argc > 0 && argv != NULL) - { - PacketSize = ALIGN_UP(PacketSize, LPWSTR); - - DPRINT("Argc: %lu\n", argc); - for (i = 0; i < argc; i++) - { - DPRINT("Argv[%lu]: %S\n", i, argv[i]); - PacketSize += (wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR); - } - } - - /* Allocate a control packet */ - ControlPacket = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - PacketSize); - if (ControlPacket == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - ControlPacket->dwSize = PacketSize; - ControlPacket->dwControl = SERVICE_CONTROL_START; - ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service; - ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); - - Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); - wcscpy(Ptr, Service->lpServiceName); - - ControlPacket->dwArgumentsCount = 0; - ControlPacket->dwArgumentsOffset = 0; - - /* Copy argument list */ - 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->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket); - - DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount); - DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset); - - 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++; - } - } - -#ifdef USE_ASYNCHRONOUS_IO - bResult = WriteFile(Service->lpImage->hControlPipe, - ControlPacket, - PacketSize, - &dwWriteCount, - &Overlapped); - if (bResult == FALSE) - { - DPRINT1("WriteFile() returned FALSE\n"); - - dwError = GetLastError(); - if (dwError == ERROR_IO_PENDING) - { - DPRINT1("dwError: ERROR_IO_PENDING\n"); - - dwError = WaitForSingleObject(Service->lpImage->hControlPipe, - dwPipeTimeout); - DPRINT1("WaitForSingleObject() returned %lu\n", dwError); - - if (dwError == WAIT_TIMEOUT) - { - bResult = CancelIo(Service->lpImage->hControlPipe); - if (bResult == FALSE) - { - DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); - } - - dwError = ERROR_SERVICE_REQUEST_TIMEOUT; - goto Done; - } - else if (dwError == ERROR_SUCCESS) - { - bResult = GetOverlappedResult(Service->lpImage->hControlPipe, - &Overlapped, - &dwWriteCount, - TRUE); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); - - goto Done; - } - } - } - else - { - DPRINT1("WriteFile() failed (Error %lu)\n", dwError); - goto Done; - } - } - - /* Read the reply */ - Overlapped.hEvent = (HANDLE) NULL; - - bResult = ReadFile(Service->lpImage->hControlPipe, - &ReplyPacket, - sizeof(SCM_REPLY_PACKET), - &dwReadCount, - &Overlapped); - if (bResult == FALSE) - { - DPRINT1("ReadFile() returned FALSE\n"); - - dwError = GetLastError(); - if (dwError == ERROR_IO_PENDING) - { - DPRINT1("dwError: ERROR_IO_PENDING\n"); - - dwError = WaitForSingleObject(Service->lpImage->hControlPipe, - dwPipeTimeout); - DPRINT1("WaitForSingleObject() returned %lu\n", dwError); - - if (dwError == WAIT_TIMEOUT) - { - bResult = CancelIo(Service->lpImage->hControlPipe); - if (bResult == FALSE) - { - DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); - } - - dwError = ERROR_SERVICE_REQUEST_TIMEOUT; - goto Done; - } - else if (dwError == ERROR_SUCCESS) - { - bResult = GetOverlappedResult(Service->lpImage->hControlPipe, - &Overlapped, - &dwReadCount, - TRUE); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); - - goto Done; - } - } - } - else - { - DPRINT1("ReadFile() failed (Error %lu)\n", dwError); - goto Done; - } - } - -#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 */ - HeapFree(GetProcessHeap(), - 0, - ControlPacket); - - if (dwReadCount == sizeof(SCM_REPLY_PACKET)) - { - dwError = ReplyPacket.dwError; - } - - DPRINT("ScmSendStartCommand() done\n"); - - return dwError; -} - - -static DWORD -ScmWaitForServiceConnect(PSERVICE Service) -{ - DWORD dwRead = 0; - DWORD dwProcessId = 0; - DWORD dwError = ERROR_SUCCESS; - BOOL bResult; -#ifdef USE_ASYNCHRONOUS_IO - OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; -#endif - - DPRINT("ScmWaitForServiceConnect()\n"); - -#ifdef USE_ASYNCHRONOUS_IO - Overlapped.hEvent = (HANDLE)NULL; - - bResult = ConnectNamedPipe(Service->lpImage->hControlPipe, - &Overlapped); - if (bResult == FALSE) - { - DPRINT("ConnectNamedPipe() returned FALSE\n"); - - dwError = GetLastError(); - if (dwError == ERROR_IO_PENDING) - { - DPRINT("dwError: ERROR_IO_PENDING\n"); - - dwError = WaitForSingleObject(Service->lpImage->hControlPipe, - dwPipeTimeout); - DPRINT("WaitForSingleObject() returned %lu\n", dwError); - - if (dwError == WAIT_TIMEOUT) - { - DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n"); - - bResult = CancelIo(Service->lpImage->hControlPipe); - if (bResult == FALSE) - { - DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); - } - - return ERROR_SERVICE_REQUEST_TIMEOUT; - } - else if (dwError == WAIT_OBJECT_0) - { - bResult = GetOverlappedResult(Service->lpImage->hControlPipe, - &Overlapped, - &dwRead, - TRUE); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError); - - return dwError; - } - } - } - else if (dwError != ERROR_PIPE_CONNECTED) - { - DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError); - return dwError; - } - } - - DPRINT("Control pipe connected!\n"); - - Overlapped.hEvent = (HANDLE) NULL; - - /* Read the process id from pipe */ - bResult = ReadFile(Service->lpImage->hControlPipe, - (LPVOID)&dwProcessId, - sizeof(DWORD), - &dwRead, - &Overlapped); - if (bResult == FALSE) - { - DPRINT("ReadFile() returned FALSE\n"); - - dwError = GetLastError(); - if (dwError == ERROR_IO_PENDING) - { - DPRINT("dwError: ERROR_IO_PENDING\n"); - - dwError = WaitForSingleObject(Service->lpImage->hControlPipe, - dwPipeTimeout); - if (dwError == WAIT_TIMEOUT) - { - DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n"); - - bResult = CancelIo(Service->lpImage->hControlPipe); - if (bResult == FALSE) - { - DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); - } - - return ERROR_SERVICE_REQUEST_TIMEOUT; - } - else if (dwError == ERROR_SUCCESS) - { - DPRINT("WaitForSingleObject() returned ERROR_SUCCESS\n"); - - DPRINT("Process Id: %lu\n", dwProcessId); - - bResult = GetOverlappedResult(Service->lpImage->hControlPipe, - &Overlapped, - &dwRead, - TRUE); - if (bResult == FALSE) - { - dwError = GetLastError(); - DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); - - return dwError; - } - } - else - { - DPRINT1("WaitForSingleObject() returned %lu\n", dwError); - } - } - else - { - DPRINT1("ReadFile() failed (Error %lu)\n", dwError); - return dwError; - } - } - - DPRINT1("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 -} - - -static DWORD -ScmStartUserModeService(PSERVICE Service, - DWORD argc, - LPWSTR *argv) -{ - PROCESS_INFORMATION ProcessInformation; - STARTUPINFOW StartupInfo; - BOOL Result; - DWORD dwError = ERROR_SUCCESS; - - DPRINT("ScmStartUserModeService(%p)\n", Service); - - /* If the image is already running ... */ - if (Service->lpImage->dwImageRunCount > 1) - { - /* ... just send a start command */ - return ScmSendStartCommand(Service, argc, argv); - } - - StartupInfo.cb = sizeof(StartupInfo); - StartupInfo.lpReserved = NULL; - StartupInfo.lpDesktop = NULL; - StartupInfo.lpTitle = NULL; - StartupInfo.dwFlags = 0; - StartupInfo.cbReserved2 = 0; - StartupInfo.lpReserved2 = 0; - - Result = CreateProcessW(NULL, - Service->lpImage->szImagePath, - NULL, - NULL, - FALSE, - DETACHED_PROCESS | CREATE_SUSPENDED, - NULL, - NULL, - &StartupInfo, - &ProcessInformation); - if (!Result) - { - dwError = GetLastError(); - DPRINT1("Starting '%S' failed!\n", Service->lpServiceName); - return dwError; - } - - DPRINT("Process Id: %lu Handle %p\n", - ProcessInformation.dwProcessId, - ProcessInformation.hProcess); - DPRINT("Thread Id: %lu Handle %p\n", - ProcessInformation.dwThreadId, - ProcessInformation.hThread); - - /* Get process handle and id */ - Service->lpImage->dwProcessId = ProcessInformation.dwProcessId; - - /* Resume Thread */ - ResumeThread(ProcessInformation.hThread); - - /* Connect control pipe */ - dwError = ScmWaitForServiceConnect(Service); - if (dwError == ERROR_SUCCESS) - { - /* Send start command */ - dwError = ScmSendStartCommand(Service, - argc, - argv); - } - else - { - DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); - Service->lpImage->dwProcessId = 0; - } - - /* Close thread and process handle */ - CloseHandle(ProcessInformation.hThread); - CloseHandle(ProcessInformation.hProcess); - - return dwError; -} - - -DWORD -ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv) -{ - PSERVICE_GROUP Group = Service->lpGroup; - DWORD dwError = ERROR_SUCCESS; - LPCWSTR ErrorLogStrings[2]; - WCHAR szErrorBuffer[32]; - - DPRINT("ScmStartService() called\n"); - - DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName); - - EnterCriticalSection(&ControlServiceCriticalSection); - - if (Service->Status.dwCurrentState != SERVICE_STOPPED) - { - DPRINT("Service %S is already running!\n", Service->lpServiceName); - LeaveCriticalSection(&ControlServiceCriticalSection); - return ERROR_SERVICE_ALREADY_RUNNING; - } - - DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType); - - 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; - } - } - else - { - /* Start user-mode service */ - dwError = ScmCreateOrReferenceServiceImage(Service); - if (dwError == ERROR_SUCCESS) - { - 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 - } - else - { - ScmDereferenceServiceImage(Service->lpImage); - Service->lpImage = NULL; - } - } - } - - LeaveCriticalSection(&ControlServiceCriticalSection); - - DPRINT("ScmStartService() done (Error %lu)\n", dwError); - - if (dwError == ERROR_SUCCESS) - { - if (Group != NULL) - { - Group->ServicesRunning = TRUE; - } - } - else - { - if (Service->dwErrorControl != SERVICE_ERROR_IGNORE) - { - /* Log a failed service start */ - swprintf(szErrorBuffer, L"%lu", dwError); - ErrorLogStrings[0] = Service->lpServiceName; - ErrorLogStrings[1] = szErrorBuffer; - ScmLogError(EVENT_SERVICE_START_FAILED, - 2, - ErrorLogStrings); - } - -#if 0 - switch (Service->dwErrorControl) - { - case SERVICE_ERROR_SEVERE: - if (IsLastKnownGood == FALSE) - { - /* FIXME: Boot last known good configuration */ - } - break; - - case SERVICE_ERROR_CRITICAL: - if (IsLastKnownGood == FALSE) - { - /* FIXME: Boot last known good configuration */ - } - else - { - /* FIXME: BSOD! */ - } - break; - } -#endif - } - - return dwError; -} - - -VOID ScmAutoStartServices(VOID) { + PSCMGR_DATABASE pScActiveDatabase; PLIST_ENTRY GroupEntry; PLIST_ENTRY ServiceEntry; PSERVICE_GROUP CurrentGroup; - PSERVICE CurrentService; + PSERVICE_RECORD CurrentService; WCHAR szSafeBootServicePath[MAX_PATH]; DWORD dwError; HKEY hKey; ULONG i; + /* Find the active database */ + pScActiveDatabase = FindDatabase(SERVICES_ACTIVE_DATABASEW); + if (!pScActiveDatabase) + return; + /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */ - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScActiveDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScActiveDatabase->ServiceListHead)) { - CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE_RECORD, ServiceListEntry); /* Build the safe boot path */ - wcscpy(szSafeBootServicePath, - L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot"); + wcscpy(szSafeBootServicePath, pScActiveDatabase->RegistryKeyNames.Control_SafeBoot); switch (GetSystemMetrics(SM_CLEANBOOT)) { @@ -1768,7 +502,7 @@ /* Finish Safe Boot path off */ wcsncat(szSafeBootServicePath, - CurrentService->lpServiceName, + CurrentService->ServiceName, MAX_PATH - wcslen(szSafeBootServicePath)); /* Check that the key is in the Safe Boot path */ @@ -1800,8 +534,8 @@ } /* Start all services which are members of an existing group */ - GroupEntry = GroupListHead.Flink; - while (GroupEntry != &GroupListHead) + GroupEntry = pScActiveDatabase->GroupListHead.Flink; + while (GroupEntry != &(pScActiveDatabase->GroupListHead)) { CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry); @@ -1810,10 +544,10 @@ /* Start all services witch have a valid tag */ for (i = 0; i < CurrentGroup->TagCount; i++) { - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScActiveDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScActiveDatabase->ServiceListHead)) { - CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE_RECORD, ServiceListEntry); if ((CurrentService->lpGroup == CurrentGroup) && (CurrentService->dwStartType == SERVICE_AUTO_START) && @@ -1829,10 +563,10 @@ } /* Start all services which have an invalid tag or which do not have a tag */ - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScActiveDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScActiveDatabase->ServiceListHead)) { - CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE_RECORD, ServiceListEntry); if ((CurrentService->lpGroup == CurrentGroup) && (CurrentService->dwStartType == SERVICE_AUTO_START) && @@ -1849,10 +583,10 @@ } /* Start all services which are members of any non-existing group */ - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScActiveDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScActiveDatabase->ServiceListHead)) { - CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE_RECORD, ServiceListEntry); if ((CurrentService->lpGroup != NULL) && (CurrentService->dwStartType == SERVICE_AUTO_START) && @@ -1866,10 +600,10 @@ } /* Start all services which are not a member of any group */ - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScActiveDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScActiveDatabase->ServiceListHead)) { - CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE_RECORD, ServiceListEntry); if ((CurrentService->lpGroup == NULL) && (CurrentService->dwStartType == SERVICE_AUTO_START) && @@ -1883,37 +617,45 @@ } /* Clear 'ServiceVisited' flag again */ - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScActiveDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScActiveDatabase->ServiceListHead)) { - CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE_RECORD, ServiceListEntry); CurrentService->ServiceVisited = FALSE; ServiceEntry = ServiceEntry->Flink; } + + return; } VOID ScmAutoShutdownServices(VOID) { + PSCMGR_DATABASE pScActiveDatabase; PLIST_ENTRY ServiceEntry; - PSERVICE CurrentService; + PSERVICE_RECORD CurrentService; DPRINT("ScmAutoShutdownServices() called\n"); + /* Find the active database */ + pScActiveDatabase = FindDatabase(SERVICES_ACTIVE_DATABASEW); + if (!pScActiveDatabase) + return; + /* Lock the service database exclusively */ ScmLockDatabaseExclusive(); - ServiceEntry = ServiceListHead.Flink; - while (ServiceEntry != &ServiceListHead) + ServiceEntry = pScActiveDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScActiveDatabase->ServiceListHead)) { - CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE_RECORD, ServiceListEntry); if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING || CurrentService->Status.dwCurrentState == SERVICE_START_PENDING) { /* shutdown service */ - DPRINT("Shutdown service: %S\n", CurrentService->szServiceName); + DPRINT("Shutdown service: %S\n", CurrentService->ServiceName); ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN); } @@ -1927,60 +669,440 @@ } -BOOL -ScmLockDatabaseExclusive(VOID) +static LONG +ScmGetRegistryDatabase(IN LPCTSTR lpValue OPTIONAL, + OUT LPDWORD lpData OPTIONAL) { - return RtlAcquireResourceExclusive(&DatabaseLock, TRUE); + LONG lRet = ERROR_SUCCESS; + HKEY hKey = INVALID_HANDLE_VALUE; + + lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\Select", 0, KEY_QUERY_VALUE, &hKey); + if (lRet == ERROR_SUCCESS) + { + DWORD dwType = 0, + dwRegData = 0, + dwBufSize = sizeof(dwRegData /* DWORD */); + + lRet = RegQueryValueExW(hKey, lpValue, NULL, &dwType, (LPBYTE)&dwRegData, &dwBufSize); + if (lRet == ERROR_SUCCESS) + { + if ( (dwType == REG_DWORD) && (dwBufSize == sizeof(DWORD)) ) + { + if (lpData) + *lpData = dwRegData; + } + else + { + lRet = ERROR_UNSUPPORTED_TYPE; + } + } + + RegCloseKey(hKey); + } + + return lRet; } -BOOL -ScmLockDatabaseShared(VOID) +static DWORD +ScmCreateServiceDatabase(IN LPCWSTR DatabaseName, + IN LPCWSTR ControlSet) { - return RtlAcquireResourceShared(&DatabaseLock, TRUE); + WCHAR szSubKey[MAX_PATH]; + HKEY hServicesKey; + HKEY hServiceKey; + DWORD dwSubKey; + DWORD dwSubKeyLength; + // FILETIME ftLastChanged; + DWORD dwError; + + size_t size_Control; + size_t size_Control_GroupOrderList; + size_t size_Control_SafeBoot; + size_t size_Control_ServiceCurrent; + size_t size_Services; + size_t partial_size; + + PSCMGR_DATABASE pScDatabase = NULL; // The newly created database. + + DPRINT1("ScmCreateServiceDatabase('%S') called\n", DatabaseName); + + if (!DatabaseName || !ControlSet) + return -1; + + /* + * Estimate the total sizes of the strings + */ + size_Control = (wcslen(L"SYSTEM\\") + wcslen(ControlSet) + wcslen(L"\\Control") + 1) * sizeof(WCHAR); + size_Control_GroupOrderList = size_Control + wcslen(L"\\GroupOrderList") * sizeof(WCHAR); + size_Control_SafeBoot = size_Control + wcslen(L"\\SafeBoot") * sizeof(WCHAR); + size_Control_ServiceCurrent = size_Control + wcslen(L"\\ServiceCurrent") * sizeof(WCHAR); + size_Services = (wcslen(L"SYSTEM\\") + wcslen(ControlSet) + wcslen(L"\\Services") + 1) * sizeof(WCHAR); + + partial_size = sizeof(SCMGR_DATABASE) + wcssize(DatabaseName); + + pScDatabase = (PSCMGR_DATABASE)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + partial_size + size_Control + size_Control_GroupOrderList + size_Control_SafeBoot + size_Control_ServiceCurrent + size_Services); + if (!pScDatabase) + return -1; + + /* Copy the name of the database */ + pScDatabase->DatabaseName = (LPWSTR)((LPBYTE)(pScDatabase) + sizeof(SCMGR_DATABASE)); + wcscpy(pScDatabase->DatabaseName, DatabaseName); + + /* + * Build the registry key names + */ + pScDatabase->RegistryKeyNames.Control = (LPWSTR)((LPBYTE)(pScDatabase) + partial_size); + wcscpy(pScDatabase->RegistryKeyNames.Control, L"SYSTEM\\" ); + wcscat(pScDatabase->RegistryKeyNames.Control, ControlSet ); + wcscat(pScDatabase->RegistryKeyNames.Control, L"\\Control"); + + pScDatabase->RegistryKeyNames.Control_GroupOrderList = (LPWSTR)((LPBYTE)(pScDatabase) + partial_size + size_Control); + wcscpy(pScDatabase->RegistryKeyNames.Control_GroupOrderList, pScDatabase->RegistryKeyNames.Control); + wcscat(pScDatabase->RegistryKeyNames.Control_GroupOrderList, L"\\GroupOrderList"); + + pScDatabase->RegistryKeyNames.Control_SafeBoot = (LPWSTR)((LPBYTE)(pScDatabase) + partial_size + size_Control + size_Control_GroupOrderList); + wcscpy(pScDatabase->RegistryKeyNames.Control_SafeBoot, pScDatabase->RegistryKeyNames.Control); + wcscat(pScDatabase->RegistryKeyNames.Control_SafeBoot, L"\\SafeBoot"); + + pScDatabase->RegistryKeyNames.Control_ServiceCurrent = (LPWSTR)((LPBYTE)(pScDatabase) + partial_size + size_Control + size_Control_GroupOrderList + size_Control_SafeBoot); + wcscpy(pScDatabase->RegistryKeyNames.Control_ServiceCurrent, pScDatabase->RegistryKeyNames.Control); + wcscat(pScDatabase->RegistryKeyNames.Control_ServiceCurrent, L"\\ServiceCurrent"); + + pScDatabase->RegistryKeyNames.Services = (LPWSTR)((LPBYTE)(pScDatabase) + partial_size + size_Control + size_Control_GroupOrderList + size_Control_SafeBoot + size_Control_ServiceCurrent); + wcscpy(pScDatabase->RegistryKeyNames.Services, L"SYSTEM\\" ); + wcscat(pScDatabase->RegistryKeyNames.Services, ControlSet ); + wcscat(pScDatabase->RegistryKeyNames.Services, L"\\Services"); + + + DPRINT1("Creation of database '%S' at 0x%p\n", (pScDatabase->DatabaseName ? pScDatabase->DatabaseName : L"n/a --> bug..."), pScDatabase); + + + /* Initialize the images and services lists */ + InitializeListHead(&(pScDatabase->ImageListHead)); + InitializeListHead(&(pScDatabase->ServiceListHead)); + + /* Initialize the database lock. For the moment it's a big HACK!! */ + /// InitializeListHead(&ApiLockListHead); + /// RtlInitializeResource(&(pScDatabase->DatabaseLock)); + RtlInitializeResource(&DatabaseLock); // HACK: !!!!!!!!!!!!!!!!!!!!! + + /* Initialize the service groups */ + dwError = ScmCreateGroupList(pScDatabase); + if (dwError != ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(), 0, pScDatabase); + return dwError; + } + + /* Initialize the services */ + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + pScDatabase->RegistryKeyNames.Services, + 0, + KEY_READ, + &hServicesKey); + if (dwError != ERROR_SUCCESS) + return dwError; + + dwSubKey = 0; + for (;;) + { + dwSubKeyLength = MAX_PATH; + szSubKey[0] = L'\0'; + dwError = RegEnumKeyExW(hServicesKey, + dwSubKey, + szSubKey, + &dwSubKeyLength, + NULL, + NULL, + NULL, + NULL /* &ftLastChanged */); + + if (dwError == ERROR_NO_MORE_ITEMS) + break; + + if ( (dwError == ERROR_SUCCESS) && + (szSubKey[0] != L'{') ) + { + DPRINT("SubKeyName: '%S'\n", szSubKey); + + dwError = RegOpenKeyExW(hServicesKey, + szSubKey, + 0, + KEY_READ, + &hServiceKey); + if (dwError == ERROR_SUCCESS) + { + dwError = CreateServiceListEntry(pScDatabase, szSubKey, hServiceKey); + RegCloseKey(hServiceKey); + } + } + + dwSubKey++; + } + RegCloseKey(hServicesKey); + + /* Wait for LSA */ + ScmWaitForLsa(); + + /* Delete services that are marked for delete */ + ScmDeleteMarkedServices(pScDatabase); + + /* Update service database */ + ScmGetBootAndSystemDriverState(pScDatabase); // TODO: Is it OK for any database, other than "ServicesActive" ?? + + //// INSERT THE NEWLY CREATED DATABASE INTO THE LIST /// + InsertTailList(&DatabaseListHead, &(pScDatabase->DatabaseListEntry)); + + DPRINT1("Successfully created the database '%S' at 0x%p\n", (pScDatabase->DatabaseName ? pScDatabase->DatabaseName : L"n/a --> bug..."), pScDatabase); + DPRINT1("ScmCreateServiceDatabase() done\n"); + + return ERROR_SUCCESS; } -VOID -ScmUnlockDatabase(VOID) +DWORD +ScmCreateServiceDatabases(VOID) { - RtlReleaseResource(&DatabaseLock); + DWORD dwError = ERROR_SUCCESS; + LPWSTR lpRegKeyName = NULL; + WCHAR idFailedDB[3] = L""; + + DWORD dwCurrentDB = 0, + dwFailedDB = 0; + + DPRINT1("In ScmCreateServiceDatabases()\n"); + + // + // Initialize the list of databases. + // + InitializeListHead(&DatabaseListHead); + + // + // Use an undocumented feature: + // + // - The SERVICES_ACTIVE_DATABASE ("ServicesActive") database corresponds to + // the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet key, which points to + // the HKEY_LOCAL_MACHINE\SYSTEM\ControlSet<00n> given in the 'Current' value + // under the HKEY_LOCAL_MACHINE\SYSTEM\Select key (value >= 1). + // + // - The SERVICES_FAILED_DATABASE ("ServicesFailed") database corresponds to + // the HKEY_LOCAL_MACHINE\SYSTEM\ControlSet<00n> given in the 'Failed' value + // under the HKEY_LOCAL_MACHINE\SYSTEM\Select key. A value = 0 means that + // there is not any failed control set. + // + // For record we remember here the values under the + // HKEY_LOCAL_MACHINE\SYSTEM\Select key: 'Current' 'Default' 'Failed' 'LastKnownGood' + // + + ScmGetRegistryDatabase(L"Current", &dwCurrentDB); + ScmGetRegistryDatabase(L"Failed" , &dwFailedDB ); + + if (dwCurrentDB >= 1) // && dwCurrentDB <= 4) // or <= 5 ?? + { + dwError = ScmCreateServiceDatabase(SERVICES_ACTIVE_DATABASEW, L"CurrentControlSet"); + } + + if (dwFailedDB >= 1 && dwFailedDB <= 4) // or <= 5 ?? + { + _itow(dwFailedDB, idFailedDB, 10); + lpRegKeyName = (LPWSTR)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + wcssize(L"ControlSet00") + wcssize(idFailedDB)); + wcscpy(lpRegKeyName, L"ControlSet00"); + wcscat(lpRegKeyName, idFailedDB); + + dwError = ScmCreateServiceDatabase(SERVICES_FAILED_DATABASEW, lpRegKeyName); + + HeapFree(GetProcessHeap(), 0, lpRegKeyName); + } + + DPRINT1("Exit ScmCreateServiceDatabases() with error code %d\n", dwError); + + return dwError; } +static VOID +ScmShutdownServiceDatabase(IN PSCMGR_DATABASE pScDatabase) +{ + DPRINT("ScmShutdownServiceDatabase() called\n"); + + ScmDeleteMarkedServices(pScDatabase); + // RtlDeleteResource(&DatabaseLock); + + DPRINT("ScmShutdownServiceDatabase() done\n"); +} + + VOID -ScmInitNamedPipeCriticalSection(VOID) +ScmShutdownServiceDatabases(VOID) { - HKEY hKey; - DWORD dwKeySize; - DWORD dwError; + // Start from the beginning of the list. + PLIST_ENTRY EntryList = DatabaseListHead.Flink; + PSCMGR_DATABASE entry = NULL; - InitializeCriticalSection(&ControlServiceCriticalSection); + DPRINT("ScmShutdownServiceDatabases() called\n"); - dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"SYSTEM\\CurrentControlSet\\Control", - 0, - KEY_READ, - &hKey); - if (dwError == ERROR_SUCCESS) - { - dwKeySize = sizeof(DWORD); - RegQueryValueExW(hKey, - L"ServicesPipeTimeout", - 0, - NULL, - (LPBYTE)&dwPipeTimeout, - &dwKeySize); + // ScmAutoShutdownServices(); // No... see ShutdownHandlerRoutine() in services.c - RegCloseKey(hKey); - } + // Loop through the list. + while (EntryList != &DatabaseListHead) + { + entry = CONTAINING_RECORD(EntryList, SCMGR_DATABASE, DatabaseListEntry); + + ScmShutdownServiceDatabase(entry); + + EntryList = EntryList->Flink; + } + + // HACK: added... + RtlDeleteResource(&DatabaseLock); + + DPRINT("ScmShutdownServiceDatabases() done\n"); + + return; } -VOID -ScmDeleteNamedPipeCriticalSection(VOID) +PSCMGR_DATABASE +FindDatabase(IN LPCWSTR DatabaseName) { - DeleteCriticalSection(&ControlServiceCriticalSection); + // Start from the beginning of the list. + PLIST_ENTRY EntryList = DatabaseListHead.Flink; + PSCMGR_DATABASE entry = NULL; + + // Loop through the list. + while (EntryList != &DatabaseListHead) + { + entry = CONTAINING_RECORD(EntryList, SCMGR_DATABASE, DatabaseListEntry); + DPRINT("Found entry 0x%p, name '%S' against DatabaseName '%S'...\n", entry, (entry->DatabaseName ? entry->DatabaseName : L"n/a --> BUG!!"), (DatabaseName ? DatabaseName : L"n/a --> BUG!!")); + if (ScDatabaseNamesMatch(DatabaseName, entry->DatabaseName)) + { + return entry; + } + else + { + // entry = NULL; + EntryList = EntryList->Flink; + } + } + + return NULL; } + +BOOL +IsActiveDatabase(IN PSCMGR_DATABASE pScDatabase) +{ + return ( pScDatabase && (wcsicmp(pScDatabase->DatabaseName, SERVICES_ACTIVE_DATABASEW) == 0) ); +} + + +/* RPC SERVER FUNCTIONS ******************************************************/ + +/* Function 9 */ +DWORD +RNotifyBootConfigStatus(IN SVCCTL_HANDLEW lpMachineName, + IN DWORD BootAcceptable) +{ + DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable); + return ERROR_SUCCESS; + +// UNIMPLEMENTED; +// return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 15 */ +DWORD +ROpenSCManagerW(IN SVCCTL_HANDLEW lpMachineName, + IN LPWSTR lpDatabaseName, + IN DWORD dwDesiredAccess, + OUT LPSC_RPC_HANDLE lpScHandle) +{ + DWORD dwError; + PSC_HANDLE_STRUCT Handle; + + DPRINT("ROpenSCManagerW() called\n"); + DPRINT("lpMachineName = '%p', '%S'\n", lpMachineName , lpMachineName ); + DPRINT("lpDataBaseName = '%p', '%S'\n", lpDatabaseName, lpDatabaseName); + DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess); + + // + // The parameter is only used on the client-side, + // for the RPC system to call this function on + // the right machine. + // + UNREFERENCED_PARAMETER(lpMachineName); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + if (!lpScHandle) + return ERROR_INVALID_PARAMETER; + + dwError = ScmCreateManagerHandle(lpDatabaseName, &Handle); + if (dwError != ERROR_SUCCESS) + { + DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError); + return dwError; + } + + /* Check the desired access */ + dwDesiredAccess |= SC_MANAGER_CONNECT; + dwError = ScmCheckAccess(Handle, dwDesiredAccess); + if (dwError != ERROR_SUCCESS) + { + DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError); + HeapFree(GetProcessHeap(), 0, Handle); + return dwError; + } + + *lpScHandle = (SC_RPC_HANDLE)Handle; + DPRINT("*hScm = %p\n", *lpScHandle); + + DPRINT("ROpenSCManagerW() done\n"); + + return ERROR_SUCCESS; +} + + +/* Function 27 */ +DWORD +ROpenSCManagerA(IN SVCCTL_HANDLEA lpMachineName, + IN LPSTR lpDatabaseName, + IN DWORD dwDesiredAccess, + OUT LPSC_RPC_HANDLE lpScHandle) +{ + UNICODE_STRING DatabaseName; + DWORD dwError; + + DPRINT("ROpenSCManagerA() called\n"); + + // + // The parameter is only used on the client-side, + // for the RPC system to call this function on + // the right machine. + // + UNREFERENCED_PARAMETER(lpMachineName); + + if (lpDatabaseName) + RtlCreateUnicodeStringFromAsciiz(&DatabaseName, + lpDatabaseName); + + dwError = ROpenSCManagerW(NULL, + lpDatabaseName ? DatabaseName.Buffer : NULL, + dwDesiredAccess, + lpScHandle); + + if (lpDatabaseName) + RtlFreeUnicodeString(&DatabaseName); + + return dwError; +} + + /* EOF */ Index: base/system/services/driver.c =================================================================== --- base/system/services/driver.c (révision 56659) +++ base/system/services/driver.c (copie de travail) @@ -7,17 +7,141 @@ * */ -/* INCLUDES *****************************************************************/ +/* INCLUDES ******************************************************************/ #include "services.h" #define NDEBUG #include -/* FUNCTIONS ****************************************************************/ +/* FUNCTIONS *****************************************************************/ + +static NTSTATUS +ScmCheckDriver(PSERVICE_RECORD Service) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING DirName; + HANDLE DirHandle; + NTSTATUS Status; + POBJECT_DIRECTORY_INFORMATION DirInfo; + ULONG BufferLength; + ULONG DataLength; + ULONG Index; + + DPRINT("ScmCheckDriver(%S) called\n", Service->ServiceName); + + if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER) + { + RtlInitUnicodeString(&DirName, + L"\\Driver"); + } + else + { + RtlInitUnicodeString(&DirName, + L"\\FileSystem"); + } + + InitializeObjectAttributes(&ObjectAttributes, + &DirName, + 0, + NULL, + NULL); + + Status = NtOpenDirectoryObject(&DirHandle, + DIRECTORY_QUERY | DIRECTORY_TRAVERSE, + &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) + + 2 * MAX_PATH * sizeof(WCHAR); + DirInfo = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + BufferLength); + + Index = 0; + while (TRUE) + { + Status = NtQueryDirectoryObject(DirHandle, + DirInfo, + BufferLength, + TRUE, + FALSE, + &Index, + &DataLength); + if (Status == STATUS_NO_MORE_ENTRIES) + { + /* FIXME: Add current service to 'failed service' list */ + DPRINT("Service '%S' failed\n", Service->ServiceName); + break; + } + + if (!NT_SUCCESS(Status)) + break; + + DPRINT("Comparing: '%S' '%wZ'\n", Service->ServiceName, &DirInfo->Name); + + if (_wcsicmp(Service->ServiceName, DirInfo->Name.Buffer) == 0) + { + DPRINT("Found: '%S' '%wZ'\n", + Service->ServiceName, &DirInfo->Name); + + /* Mark service as 'running' */ + Service->Status.dwCurrentState = SERVICE_RUNNING; + + /* Mark the service group as 'running' */ + if (Service->lpGroup != NULL) + { + Service->lpGroup->ServicesRunning = TRUE; + } + + break; + } + } + + HeapFree(GetProcessHeap(), + 0, + DirInfo); + NtClose(DirHandle); + + return STATUS_SUCCESS; +} + + +VOID +ScmGetBootAndSystemDriverState(IN PSCMGR_DATABASE pScDatabase) +{ + PLIST_ENTRY ServiceEntry; + PSERVICE_RECORD CurrentService; + + DPRINT("ScmGetBootAndSystemDriverState() called\n"); + + ServiceEntry = pScDatabase->ServiceListHead.Flink; + while (ServiceEntry != &(pScDatabase->ServiceListHead)) + { + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE_RECORD, ServiceListEntry); + + if (CurrentService->dwStartType == SERVICE_BOOT_START || + CurrentService->dwStartType == SERVICE_SYSTEM_START) + { + /* Check driver */ + DPRINT(" Checking service: %S\n", CurrentService->ServiceName); + + ScmCheckDriver(CurrentService); + } + + ServiceEntry = ServiceEntry->Flink; + } + + DPRINT("ScmGetBootAndSystemDriverState() done\n"); +} + + DWORD -ScmLoadDriver(PSERVICE lpService) +ScmLoadDriver(PSERVICE_RECORD lpService) { WCHAR szDriverPath[MAX_PATH]; UNICODE_STRING DriverPath; @@ -25,10 +149,10 @@ DWORD dwError = ERROR_SUCCESS; /* Build the driver path */ - wcscpy(szDriverPath, - L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); - wcscat(szDriverPath, - lpService->lpServiceName); + wcscpy(szDriverPath, L"\\Registry\\Machine\\"); + wcscat(szDriverPath, lpService->Database->RegistryKeyNames.Services); + wcscat(szDriverPath, L"\\"); + wcscat(szDriverPath, lpService->ServiceName); RtlInitUnicodeString(&DriverPath, szDriverPath); @@ -49,8 +173,8 @@ } -DWORD -ScmUnloadDriver(PSERVICE lpService) +static DWORD +ScmUnloadDriver(PSERVICE_RECORD lpService) { WCHAR szDriverPath[MAX_PATH]; UNICODE_STRING DriverPath; @@ -58,10 +182,10 @@ DWORD dwError = ERROR_SUCCESS; /* Build the driver path */ - wcscpy(szDriverPath, - L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); - wcscat(szDriverPath, - lpService->lpServiceName); + wcscpy(szDriverPath, L"\\Registry\\Machine\\"); + wcscat(szDriverPath, lpService->Database->RegistryKeyNames.Services); + wcscat(szDriverPath, L"\\"); + wcscat(szDriverPath, lpService->ServiceName); RtlInitUnicodeString(&DriverPath, szDriverPath); @@ -81,8 +205,8 @@ } -DWORD -ScmGetDriverStatus(PSERVICE lpService, +static DWORD +ScmGetDriverStatus(PSERVICE_RECORD lpService, LPSERVICE_STATUS lpServiceStatus) { OBJECT_ATTRIBUTES ObjectAttributes; @@ -151,12 +275,12 @@ if (!NT_SUCCESS(Status)) break; - DPRINT("Comparing: '%S' '%wZ'\n", lpService->lpServiceName, &DirInfo->Name); + DPRINT("Comparing: '%S' '%wZ'\n", lpService->ServiceName, &DirInfo->Name); - if (_wcsicmp(lpService->lpServiceName, DirInfo->Name.Buffer) == 0) + if (_wcsicmp(lpService->ServiceName, DirInfo->Name.Buffer) == 0) { DPRINT1("Found: '%S' '%wZ'\n", - lpService->lpServiceName, &DirInfo->Name); + lpService->ServiceName, &DirInfo->Name); bFound = TRUE; break; @@ -221,7 +345,7 @@ DWORD -ScmControlDriver(PSERVICE lpService, +ScmControlDriver(PSERVICE_RECORD lpService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus) { @@ -232,33 +356,34 @@ switch (dwControl) { case SERVICE_CONTROL_STOP: - if (lpService->Status.dwCurrentState != SERVICE_RUNNING) + if (lpService->Status.dwCurrentState == SERVICE_RUNNING) { - dwError = ERROR_INVALID_SERVICE_CONTROL; - goto done; + dwError = ScmUnloadDriver(lpService); + if (dwError == ERROR_SUCCESS) + { + lpService->Status.dwControlsAccepted = 0; + lpService->Status.dwCurrentState = SERVICE_STOPPED; + } } - - dwError = ScmUnloadDriver(lpService); - if (dwError == ERROR_SUCCESS) + else { - lpService->Status.dwControlsAccepted = 0; - lpService->Status.dwCurrentState = SERVICE_STOPPED; + dwError = ERROR_INVALID_SERVICE_CONTROL; } break; case SERVICE_CONTROL_INTERROGATE: - dwError = ScmGetDriverStatus(lpService, - lpServiceStatus); + dwError = ScmGetDriverStatus(lpService, lpServiceStatus); break; default: dwError = ERROR_INVALID_SERVICE_CONTROL; + break; } -done:; DPRINT("ScmControlDriver() done (Erorr: %lu)\n", dwError); return dwError; } + /* EOF */ Index: base/system/services/groupdb.c =================================================================== --- base/system/services/groupdb.c (révision 56659) +++ base/system/services/groupdb.c (copie de travail) @@ -7,7 +7,7 @@ * */ -/* INCLUDES *****************************************************************/ +/* INCLUDES ******************************************************************/ #include "services.h" @@ -15,53 +15,47 @@ #include -/* GLOBALS *******************************************************************/ - -LIST_ENTRY GroupListHead; -LIST_ENTRY UnknownGroupListHead; - - /* FUNCTIONS *****************************************************************/ DWORD -ScmSetServiceGroup(PSERVICE lpService, - LPCWSTR lpGroupName) +ScmSetServiceGroup(IN OUT PSERVICE_RECORD pServiceRecord, + IN LPCWSTR lpGroupName) { - PLIST_ENTRY GroupEntry; + PLIST_ENTRY GroupEntry; PSERVICE_GROUP lpGroup; DPRINT("ScmSetServiceGroup(%S)\n", lpGroupName); - if (lpService->lpGroup != NULL) + if (pServiceRecord->lpGroup != NULL) { - lpService->lpGroup->dwRefCount--; + pServiceRecord->lpGroup->dwRefCount--; /* FIXME: What do we have to do when dwRefCount is 0? */ } - GroupEntry = GroupListHead.Flink; - while (GroupEntry != &GroupListHead) + GroupEntry = pServiceRecord->Database->GroupListHead.Flink; + while (GroupEntry != &(pServiceRecord->Database->GroupListHead)) { lpGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry); if (!_wcsicmp(lpGroup->lpGroupName, lpGroupName)) { - lpService->lpGroup = lpGroup; + pServiceRecord->lpGroup = lpGroup; return ERROR_SUCCESS; } GroupEntry = GroupEntry->Flink; } - GroupEntry = UnknownGroupListHead.Flink; - while (GroupEntry != &UnknownGroupListHead) + GroupEntry = pServiceRecord->Database->UnknownGroupListHead.Flink; + while (GroupEntry != &(pServiceRecord->Database->UnknownGroupListHead)) { lpGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry); if (!_wcsicmp(lpGroup->lpGroupName, lpGroupName)) { lpGroup->dwRefCount++; - lpService->lpGroup = lpGroup; + pServiceRecord->lpGroup = lpGroup; return ERROR_SUCCESS; } @@ -70,17 +64,17 @@ lpGroup = (PSERVICE_GROUP)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(SERVICE_GROUP) + ((wcslen(lpGroupName) + 1)* sizeof(WCHAR))); + sizeof(SERVICE_GROUP) + wcssize(lpGroupName) /* ((wcslen(lpGroupName) + 1) * sizeof(WCHAR)) */); if (lpGroup == NULL) return ERROR_NOT_ENOUGH_MEMORY; wcscpy(lpGroup->szGroupName, lpGroupName); lpGroup->lpGroupName = lpGroup->szGroupName; lpGroup->dwRefCount = 1; - lpService->lpGroup = lpGroup; + pServiceRecord->lpGroup = lpGroup; - InsertTailList(&UnknownGroupListHead, - &lpGroup->GroupListEntry); + InsertTailList(&(pServiceRecord->Database->UnknownGroupListHead), + &(lpGroup->GroupListEntry)); return ERROR_SUCCESS; } @@ -146,6 +140,7 @@ PSERVICE_GROUP Group; RTL_QUERY_REGISTRY_TABLE QueryTable[2]; NTSTATUS Status; + PSCMGR_DATABASE pScDatabase = (PSCMGR_DATABASE)Context; if (ValueType == REG_SZ) { @@ -153,18 +148,18 @@ Group = (PSERVICE_GROUP)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(SERVICE_GROUP) + ((wcslen((const wchar_t*) ValueData) + 1) * sizeof(WCHAR))); + sizeof(SERVICE_GROUP) + wcssize((LPCWSTR)ValueData) /* ((wcslen((LPCWSTR)ValueData) + 1) * sizeof(WCHAR)) */); if (Group == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } - wcscpy(Group->szGroupName, (const wchar_t*) ValueData); + wcscpy(Group->szGroupName, (LPCWSTR)ValueData); Group->lpGroupName = Group->szGroupName; Group->dwRefCount = (DWORD)-1; RtlZeroMemory(&QueryTable, sizeof(QueryTable)); - QueryTable[0].Name = (PWSTR)ValueData; + QueryTable[0].Name = (LPWSTR)ValueData; QueryTable[0].QueryRoutine = CreateGroupOrderListRoutine; Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, @@ -172,10 +167,10 @@ QueryTable, (PVOID)Group, NULL); - DPRINT("%x %d %S\n", Status, Group->TagCount, (PWSTR)ValueData); + DPRINT("%x %d %S\n", Status, Group->TagCount, (LPWSTR)ValueData); - InsertTailList(&GroupListHead, - &Group->GroupListEntry); + InsertTailList(&(pScDatabase->GroupListHead), + &(Group->GroupListEntry)); } return STATUS_SUCCESS; @@ -183,13 +178,13 @@ DWORD -ScmCreateGroupList(VOID) +ScmCreateGroupList(IN PSCMGR_DATABASE pScDatabase) { RTL_QUERY_REGISTRY_TABLE QueryTable[2]; NTSTATUS Status; - InitializeListHead(&GroupListHead); - InitializeListHead(&UnknownGroupListHead); + InitializeListHead(&(pScDatabase->GroupListHead)); + InitializeListHead(&(pScDatabase->UnknownGroupListHead)); /* Build group order list */ RtlZeroMemory(&QueryTable, @@ -201,10 +196,11 @@ Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, L"ServiceGroupOrder", QueryTable, - NULL, + pScDatabase, NULL); return RtlNtStatusToDosError(Status); } + /* EOF */ Index: base/system/services/handles.c =================================================================== --- base/system/services/handles.c (révision 0) +++ base/system/services/handles.c (copie de travail) @@ -0,0 +1,504 @@ +/* + * PROJECT: ReactOS Service Control Manager + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/system/services/handles.c + * PURPOSE: Handles management + * COPYRIGHT: Copyright 2005-2006 Eric Kohl + * Copyright 2006-2007 Hervé Poussineau + * Copyright 2007 Ged Murphy + * Copyright 2012 Hermès Bélusca - Maïto + * + */ + +/* INCLUDES ******************************************************************/ + +#include "services.h" +#include "handles.h" // TODO: put it before services.h ? + +#define NDEBUG +#include + + +/* GLOBALS *******************************************************************/ + +/* static */ GENERIC_MAPPING +ScmManagerMapping = {SC_MANAGER_READ, + SC_MANAGER_WRITE, + SC_MANAGER_EXECUTE, + SC_MANAGER_ALL_ACCESS}; + +/* static */ GENERIC_MAPPING +ScmServiceMapping = {SERVICE_READ, + SERVICE_WRITE, + SERVICE_EXECUTE, + SERVICE_ALL_ACCESS}; + +// LIST_ENTRY SCHandleListHead; // THE List of Handles. Not used for the moment. + + +/* FUNCTIONS *****************************************************************/ + +/* +VOID +ScmInitializeHandleList(VOID) +{ + InitializeListHead(&SCHandleListHead); + return; +} +*/ + +typedef enum _SC_HANDLE_TYPE +{ + Manager_Handle = 0x0000, + Service_Handle = 0x0001, + Unknown_Handle = 0xffff +} SC_HANDLE_TYPE; + +static SC_HANDLE_TYPE +ScmGetHandleType(IN PSC_HANDLE_STRUCT Handle) +{ + if (Handle->Signature == MANAGER_TAG) + return Manager_Handle; + else if (Handle->Signature == SERVICE_TAG) + return Service_Handle; + else + return Unknown_Handle; +} + + +PSC_HANDLE_STRUCT +ScmGetDataFromHandle(IN SC_RPC_HANDLE Handle) +{ + PSC_HANDLE_STRUCT pScHandle; + + // _SEH2_TRY + // { + + pScHandle = (PSC_HANDLE_STRUCT)Handle; + + if ( pScHandle && + ( (pScHandle->Signature == MANAGER_TAG) || + (pScHandle->Signature == SERVICE_TAG) ) ) + { + return pScHandle; + } + else + { + DPRINT1("Error: Invalid Manager or Service handle!\n"); + return NULL; + } + + // } + // _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + // { + // DPRINT1("Exception: Invalid Manager or Service handle!\n"); + // return NULL; + // } + // _SEH2_END; +} + + +PSC_HANDLE_STRUCT +ScmGetServiceManagerFromHandle(IN SC_RPC_HANDLE Handle) +{ + PSC_HANDLE_STRUCT pScHandle; + + // _SEH2_TRY + // { + + pScHandle = (PSC_HANDLE_STRUCT)Handle; + + if ( pScHandle && (pScHandle->Signature == MANAGER_TAG) ) + { + return pScHandle; + } + else + { + DPRINT1("Error: Invalid Service Manager handle!\n"); + return NULL; + } + + // } + // _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + // { + // DPRINT1("Exception: Invalid Service Manager handle!\n"); + // return NULL; + // } + // _SEH2_END; +} + + +PSC_HANDLE_STRUCT +ScmGetServiceFromHandle(IN SC_RPC_HANDLE Handle) +{ + PSC_HANDLE_STRUCT pScHandle; + + // _SEH2_TRY + // { + + pScHandle = (PSC_HANDLE_STRUCT)Handle; + + if ( pScHandle && (pScHandle->Signature == SERVICE_TAG) ) + { + return pScHandle; + } + else + { + DPRINT1("Error: Invalid Service handle!\n"); + return NULL; + } + + // } + // _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + // { + // DPRINT1("Exception: Invalid Service handle!\n"); + // return NULL; + // } + // _SEH2_END; +} + + +static DWORD +ScmCheckDatabaseHandleAccess(IN PSC_HANDLE_STRUCT Handle, + IN DWORD dwDesiredAccess) +{ + if (Handle->Signature == MANAGER_TAG) + { + RtlMapGenericMask(&dwDesiredAccess, + &ScmManagerMapping); + + Handle->DesiredAccess = dwDesiredAccess; + + return ERROR_SUCCESS; + } + else + { + return ERROR_INVALID_HANDLE; + } +} + + +static DWORD +ScmCheckServiceHandleAccess(IN PSC_HANDLE_STRUCT Handle, + IN DWORD dwDesiredAccess) +{ + if (Handle->Signature == SERVICE_TAG) + { + RtlMapGenericMask(&dwDesiredAccess, + &ScmServiceMapping); + + Handle->DesiredAccess = dwDesiredAccess; + + return ERROR_SUCCESS; + } + else + { + return ERROR_INVALID_HANDLE; + } +} + + +DWORD +ScmCheckAccess(IN PSC_HANDLE_STRUCT Handle, + IN DWORD dwDesiredAccess) +{ + SC_HANDLE_TYPE handle_type = ScmGetHandleType(Handle); + + if (handle_type == Manager_Handle) + { + return ScmCheckDatabaseHandleAccess(Handle, dwDesiredAccess); + } + else if (handle_type == Service_Handle) + { + return ScmCheckServiceHandleAccess(Handle, dwDesiredAccess); + } + else + return ERROR_INVALID_HANDLE; +} + + +// used in database.c +/* static */ DWORD // ScCreateScManagerHandle +ScmCreateManagerHandle(IN LPCWSTR lpDatabaseName, + OUT PSC_HANDLE_STRUCT* pHandle) +{ + PSCMGR_DATABASE pScDatabase; + + if (!pHandle) + return ERROR_INVALID_ADDRESS; // TODO: another error ?? + + if (lpDatabaseName == NULL) + lpDatabaseName = SERVICES_ACTIVE_DATABASEW; + + if ( (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0) && + (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) != 0) ) + { + DPRINT("Invalid Database name '%S'.\n", lpDatabaseName); + return ERROR_INVALID_NAME; + } + + pScDatabase = FindDatabase(lpDatabaseName); + if (!pScDatabase) + { + /* DPRINT */ DPRINT1("Database '%S' does not exist\n", lpDatabaseName); + return ERROR_DATABASE_DOES_NOT_EXIST; + } + + *pHandle = (PSC_HANDLE_STRUCT)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(SC_HANDLE_STRUCT) /* + wcssize(lpDatabaseName) */ ); + if (!*pHandle) + return ERROR_NOT_ENOUGH_MEMORY; + + (*pHandle)->Signature = MANAGER_TAG; + // (*pHandle)->DesiredAccess + // (*pHandle)->Unknown + + /* + (*pHandle)->Type.ScManagerObject.DatabaseName = (LPWSTR)(*pHandle + 1); + wcscpy((*pHandle)->Type.ScManagerObject.DatabaseName, lpDatabaseName); + */ + (*pHandle)->Type.ScManagerObject.Database = pScDatabase; + + return ERROR_SUCCESS; +} + + +// used in svcobject.c +/* static */ DWORD // ScCreateServiceHandle +ScmCreateServiceHandle(IN PSERVICE_RECORD lpServiceEntry, + OUT PSC_HANDLE_STRUCT* pHandle) +{ + if (!pHandle) + return ERROR_INVALID_ADDRESS; // TODO: another error ?? + + *pHandle = (PSC_HANDLE_STRUCT)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(SC_HANDLE_STRUCT)); + if (!*pHandle) + return ERROR_NOT_ENOUGH_MEMORY; + + (*pHandle)->Signature = SERVICE_TAG; + // (*pHandle)->DesiredAccess + // (*pHandle)->Unknown + + (*pHandle)->Type.ScServiceObject.ServiceEntry = lpServiceEntry; + + return ERROR_SUCCESS; +} + + +DWORD +ScmCloseDatabaseHandle(IN PSC_HANDLE_STRUCT Handle) +{ + BOOL bFreeSuccessful = FALSE; + + DPRINT("\tScmCloseDatabaseHandle() called\n"); + DPRINT("\tHandle = %p\n", Handle); + + if (Handle != NULL) + { + if (Handle->Signature == MANAGER_TAG) + { + bFreeSuccessful = HeapFree(GetProcessHeap(), 0, Handle); + if (!bFreeSuccessful) + { + // + // For some reason, the handle couldn't be freed. Therefore, the + // best we can do to disable it is to remove the signature. + // + Handle->Signature = 0; + } + // Handle = NULL; + + DPRINT("\tScmCloseDatabaseHandle() done\n"); + return ERROR_SUCCESS; + } + else + { + DPRINT("\tInvalid handle\n"); + return ERROR_INVALID_HANDLE; + } + } + else + { + DPRINT("\tNull handle\n"); + return ERROR_INVALID_HANDLE; + } +} + + +DWORD +ScmCloseServiceObjectHandle(IN PSC_HANDLE_STRUCT Handle) +{ + PSERVICE_RECORD lpService; + HKEY hServicesKey; + DWORD dwError; + DWORD pcbBytesNeeded = 0; + DWORD dwServicesReturned = 0; + BOOL bFreeSuccessful = FALSE; + + DPRINT("\tScmCloseServiceObjectHandle() called\n"); + DPRINT("\tHandle = %p\n", Handle); + + if (Handle != NULL) + { + if (Handle->Signature == SERVICE_TAG) + { + /* Lock the service database exlusively */ + ScmLockDatabaseExclusive(); + + /* Get the pointer to the service record */ + lpService = Handle->Type.ScServiceObject.ServiceEntry; + + /* FIXME: add handle cleanup code */ + + /* Free the handle */ + bFreeSuccessful = HeapFree(GetProcessHeap(), 0, Handle); + if (!bFreeSuccessful) + { + // + // For some reason, the handle couldn't be freed. Therefore, the + // best we can do to disable it is to remove the signature. + // + Handle->Signature = 0; + } + // Handle = NULL; + + ASSERT(lpService->dwRefCount > 0); + + lpService->dwRefCount--; + DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n", + lpService->dwRefCount); + + if (lpService->dwRefCount == 0) + { + /* If this service has been marked for deletion */ + if (lpService->bDeleted) + { + /* Open the Services Reg key */ + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + lpService->Database->RegistryKeyNames.Services, + 0, + KEY_SET_VALUE | KEY_READ, + &hServicesKey); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Failed to open services key\n"); + ScmUnlockDatabase(); + return dwError; + } + + /* Call the internal function with NULL, just to get bytes we need */ + Int_EnumDependentServicesW(hServicesKey, + lpService, + SERVICE_ACTIVE, + NULL, + &pcbBytesNeeded, + &dwServicesReturned); + + /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */ + if (pcbBytesNeeded) + { + DPRINT1("Deletion failed due to running dependencies.\n"); + RegCloseKey(hServicesKey); + ScmUnlockDatabase(); + return ERROR_SUCCESS; + } + + /* There are no references and no runnning dependencies, + it is now safe to delete the service */ + + /* Delete the Service Key */ + dwError = RegDeleteKeyW(hServicesKey, + lpService->ServiceName); + + RegCloseKey(hServicesKey); + + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Failed to Delete the Service Registry key\n"); + ScmUnlockDatabase(); + return dwError; + } + + /* Delete the Service */ + ScmDeleteServiceRecord(lpService); + } + } + + ScmUnlockDatabase(); + + DPRINT("\tScmCloseServiceObjectHandle() done\n"); + return ERROR_SUCCESS; + } + else + { + DPRINT("\tInvalid handle\n"); + return ERROR_INVALID_HANDLE; + } + } + else + { + DPRINT("\tNull handle\n"); + return ERROR_INVALID_HANDLE; + } +} + + +/* RPC SERVER FUNCTIONS ******************************************************/ + +/* Function 0 */ +DWORD +RCloseServiceHandle(IN OUT LPSC_RPC_HANDLE phSCObject) +{ + PSC_HANDLE_STRUCT hSCHandle; + DWORD dwError = ERROR_SUCCESS; + + DPRINT("RCloseServiceHandle() called\n"); + DPRINT("phSCObject = %p\n", phSCObject); + + if (!phSCObject) + return ERROR_INVALID_HANDLE; + + hSCHandle = ScmGetDataFromHandle(*phSCObject); + if (hSCHandle == NULL) + return ERROR_INVALID_HANDLE; + + if (hSCHandle->Signature == MANAGER_TAG) + { + DPRINT("Found manager handle\n"); + + dwError = ScmCloseDatabaseHandle(hSCHandle); + if (dwError == ERROR_SUCCESS) + { + // hSCHandle = NULL; + *phSCObject = NULL; + } + + DPRINT("RCloseServiceHandle() done\n"); + return dwError; + } + else if (hSCHandle->Signature == SERVICE_TAG) + { + DPRINT("Found service handle\n"); + + dwError = ScmCloseServiceObjectHandle(hSCHandle); + if (dwError == ERROR_SUCCESS) + { + // hSCHandle = NULL; + *phSCObject = NULL; + } + + DPRINT("RCloseServiceHandle() done\n"); + return dwError; + } + else + { + DPRINT("Invalid handle signature (Signature %lx)\n", hSCHandle->Signature); + return ERROR_INVALID_HANDLE; + } +} + + +/* EOF */ Index: base/system/services/handles.h =================================================================== --- base/system/services/handles.h (révision 0) +++ base/system/services/handles.h (copie de travail) @@ -0,0 +1,81 @@ +/* + * PROJECT: ReactOS Service Control Manager + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/system/services/handles.h + * PURPOSE: Handles management + * COPYRIGHT: Copyright 2005-2006 Eric Kohl + * Copyright 2006-2007 Hervé Poussineau + * Copyright 2007 Ged Murphy + * Copyright 2012 Hermès Bélusca - Maïto + * + */ + +#ifndef __HANDLES_H__ +#define __HANDLES_H__ + +#pragma once + + +/* GLOBALS *******************************************************************/ + +//// Database //// +#define SC_MANAGER_READ \ + (STANDARD_RIGHTS_READ | \ + SC_MANAGER_QUERY_LOCK_STATUS | \ + SC_MANAGER_ENUMERATE_SERVICE) + +#define SC_MANAGER_WRITE \ + (STANDARD_RIGHTS_WRITE | \ + SC_MANAGER_MODIFY_BOOT_CONFIG | \ + SC_MANAGER_CREATE_SERVICE) + +#define SC_MANAGER_EXECUTE \ + (STANDARD_RIGHTS_EXECUTE | \ + SC_MANAGER_LOCK | \ + SC_MANAGER_ENUMERATE_SERVICE | \ + SC_MANAGER_CONNECT | \ + SC_MANAGER_CREATE_SERVICE) + +extern GENERIC_MAPPING ScmManagerMapping; + +//// Services //// +#define SERVICE_READ \ + (STANDARD_RIGHTS_READ | \ + SERVICE_INTERROGATE | \ + SERVICE_ENUMERATE_DEPENDENTS | \ + SERVICE_QUERY_STATUS | \ + SERVICE_QUERY_CONFIG) + +#define SERVICE_WRITE \ + (STANDARD_RIGHTS_WRITE | \ + SERVICE_CHANGE_CONFIG) + +#define SERVICE_EXECUTE \ + (STANDARD_RIGHTS_EXECUTE | \ + SERVICE_USER_DEFINED_CONTROL | \ + SERVICE_PAUSE_CONTINUE | \ + SERVICE_STOP | \ + SERVICE_START) + +extern GENERIC_MAPPING ScmServiceMapping; + + +/* FUNCTIONS *****************************************************************/ + +PSC_HANDLE_STRUCT ScmGetDataFromHandle(IN SC_RPC_HANDLE Handle); +PSC_HANDLE_STRUCT ScmGetServiceManagerFromHandle(IN SC_RPC_HANDLE Handle); +PSC_HANDLE_STRUCT ScmGetServiceFromHandle(IN SC_RPC_HANDLE Handle); +DWORD ScmCheckAccess(IN PSC_HANDLE_STRUCT Handle, + IN DWORD dwDesiredAccess); + +// used in database.c +DWORD ScmCreateManagerHandle(IN LPCWSTR lpDatabaseName, + OUT PSC_HANDLE_STRUCT* pHandle); +// used in svcobject.c +DWORD ScmCreateServiceHandle(IN PSERVICE_RECORD lpServiceEntry, + OUT PSC_HANDLE_STRUCT* pHandle); + + +#endif // __HANDLES_H__ + +/* EOF */ Index: base/system/services/lock.c =================================================================== --- base/system/services/lock.c (révision 0) +++ base/system/services/lock.c (copie de travail) @@ -0,0 +1,248 @@ +/* + * PROJECT: ReactOS Service Control Manager + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/system/services/lock.c + * PURPOSE: Database locking interface + * COPYRIGHT: Copyright 2002-2006 Eric Kohl + * Copyright 2006 Hervé Poussineau + * Copyright 2007 Ged Murphy + * Gregor Brunmar + * Copyright 2012 Hermès Bélusca - Maïto + * + */ + +/* INCLUDES ******************************************************************/ + +#include "services.h" + +#define NDEBUG +#include + +#include + + +/* FUNCTIONS *****************************************************************/ + +static DWORD // TODO: CHECK: HACK: static for the moment... +ScmLockDatabase(IN BOOL IsServiceController, // TRUE if locked by the Service Control Manager, FALSE otherwise. + IN PSCMGR_DATABASE pScDatabase, + OUT LPSC_RPC_LOCK lpLock) +{ + DWORD bufSize = 0; + + *lpLock = NULL; + + if (!pScDatabase) + { + return ERROR_DATABASE_DOES_NOT_EXIST; + } + else + { + if (pScDatabase->DatabaseLock) + { + return ERROR_SERVICE_DATABASE_LOCKED; + } + else + { + // + // Allocate a new lock for the database. + // + if (IsServiceController) + { + bufSize = sizeof(SC_LOCK_STRUCT); + } + else + { + bufSize = sizeof(SC_LOCK_STRUCT); /* + RtlLengthSid(UserSid); */ + } + + pScDatabase->DatabaseLock = (PSC_LOCK_STRUCT)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + bufSize); + if (!pScDatabase->DatabaseLock) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + pScDatabase->DatabaseLock->Signature = API_LOCK_SIGNATURE; + + /* + if (DatabaseName) + { + pScDatabase->DatabaseLock->DatabaseName = (LPWSTR)(apiLock + 1); // Next place in memory just after DatabaseLock. + wcscpy(pScDatabase->DatabaseLock->DatabaseName, DatabaseName); + } + */ + + pScDatabase->DatabaseLock->TimeWhenLocked = (DWORD)time(NULL); + pScDatabase->DatabaseLock->LockOwnerSid = (PSID)NULL; // for the moment... TODO: implement. Use IsServiceController + + // InsertTailList(&ApiLockListHead, &(apiLock->ApiLockListEntry)); + + *lpLock = pScDatabase->DatabaseLock; + + return NO_ERROR; + } + } +} + + +BOOL +ScmLockDatabaseExclusive(VOID) +{ + return RtlAcquireResourceExclusive(&DatabaseLock, TRUE); +} + + +BOOL +ScmLockDatabaseShared(VOID) +{ + return RtlAcquireResourceShared(&DatabaseLock, TRUE); +} + + +VOID +ScmUnlockDatabase(VOID) +{ + RtlReleaseResource(&DatabaseLock); +} + + +/* RPC SERVER FUNCTIONS ******************************************************/ + +/* Function 3 */ +DWORD +RLockServiceDatabase(IN SC_RPC_HANDLE hSCManager, + OUT LPSC_RPC_LOCK lpLock) +{ + PSC_HANDLE_STRUCT hMgr; + // PSCMGR_DATABASE pScDatabase; + + DPRINT("RLockServiceDatabase() called\n"); + + // assert(lpLock); + *lpLock = NULL; + + hMgr = ScmGetServiceManagerFromHandle(hSCManager); + if (hMgr == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hMgr->DesiredAccess, + SC_MANAGER_LOCK)) + return ERROR_ACCESS_DENIED; + + // pScDatabase = FindDatabase(hMgr->DatabaseName); + return ScmLockDatabase(FALSE, hMgr->Type.ScManagerObject.Database /* pScDatabase */, lpLock); +} + + +/* Function 8 */ +DWORD RUnlockServiceDatabase(IN OUT LPSC_RPC_LOCK Lock) +{ + PSC_LOCK_STRUCT apiLock; + + // Start from the beginning of the list. + PLIST_ENTRY EntryList = DatabaseListHead.Flink; + PSCMGR_DATABASE entry = NULL; + + if (!Lock) + return ERROR_INVALID_SERVICE_LOCK; + + apiLock = *(PSC_LOCK_STRUCT*)Lock; + + if (apiLock->Signature != API_LOCK_SIGNATURE) + return ERROR_INVALID_SERVICE_LOCK; + + // Loop through the list. + while (EntryList != &DatabaseListHead) + { + entry = CONTAINING_RECORD(EntryList, SCMGR_DATABASE, DatabaseListEntry); + if (apiLock == entry->DatabaseLock) + { + // Free the handle-lock. + HeapFree(GetProcessHeap(), 0, entry->DatabaseLock); + entry->DatabaseLock = NULL; // VERY IMPORTANT !! + *Lock = NULL; + + return NO_ERROR; + } + else + { + // entry = NULL; + EntryList = EntryList->Flink; + } + } + + /* + apiLock->Database->DatabaseLock = NULL; + + // Free the handle-lock. + HeapFree(GetProcessHeap(), 0, apiLock); + */ + + return ERROR_INVALID_SERVICE_LOCK; +} + + +/* Function 18 */ +DWORD RQueryServiceLockStatusW(IN SC_RPC_HANDLE hSCManager, + OUT LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus, + IN DWORD cbBufSize, + OUT LPBOUNDED_DWORD_4K pcbBytesNeeded) +{ + PSC_HANDLE_STRUCT hMgr; + PSCMGR_DATABASE pScDatabase; + DWORD bufSize; + + // if (!pcbBytesNeeded) what to do ?? + + hMgr = ScmGetServiceManagerFromHandle(hSCManager); + if (hMgr == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hMgr->DesiredAccess, + SC_MANAGER_QUERY_LOCK_STATUS)) + return ERROR_ACCESS_DENIED; + + bufSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR); + *pcbBytesNeeded = bufSize; + if (cbBufSize < bufSize) + return ERROR_INSUFFICIENT_BUFFER; + + // pScDatabase = FindDatabase(hMgr->DatabaseName); + pScDatabase = hMgr->Type.ScManagerObject.Database; + if (pScDatabase && pScDatabase->DatabaseLock) + { + lpLockStatus->fIsLocked = TRUE; + lpLockStatus->dwLockDuration = ((DWORD)time(NULL)) - pScDatabase->DatabaseLock->TimeWhenLocked; + + return NO_ERROR; + } + else + { + lpLockStatus->fIsLocked = FALSE; + lpLockStatus->dwLockDuration = 0; + + return ERROR_INVALID_SERVICE_LOCK; + } +} + + +/* Function 30 */ +DWORD RQueryServiceLockStatusA(IN SC_RPC_HANDLE hSCManager, + OUT LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus, + IN DWORD cbBufSize, + OUT LPBOUNDED_DWORD_4K pcbBytesNeeded) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* EOF */ Index: base/system/services/rpcserver.c =================================================================== --- base/system/services/rpcserver.c (révision 56659) +++ base/system/services/rpcserver.c (copie de travail) @@ -8,94 +8,16 @@ * Copyright 2007 Ged Murphy */ -/* INCLUDES ****************************************************************/ +/* INCLUDES ******************************************************************/ #include "services.h" #define NDEBUG #include -/* GLOBALS *****************************************************************/ -#define MANAGER_TAG 0x72674D68 /* 'hMgr' */ -#define SERVICE_TAG 0x63765368 /* 'hSvc' */ +/* FUNCTIONS *****************************************************************/ -typedef struct _SCMGR_HANDLE -{ - DWORD Tag; - DWORD DesiredAccess; -} SCMGR_HANDLE; - - -typedef struct _MANAGER_HANDLE -{ - SCMGR_HANDLE Handle; - WCHAR DatabaseName[1]; -} MANAGER_HANDLE, *PMANAGER_HANDLE; - - -typedef struct _SERVICE_HANDLE -{ - SCMGR_HANDLE Handle; - PSERVICE ServiceEntry; -} SERVICE_HANDLE, *PSERVICE_HANDLE; - - -#define SC_MANAGER_READ \ - (STANDARD_RIGHTS_READ | \ - SC_MANAGER_QUERY_LOCK_STATUS | \ - SC_MANAGER_ENUMERATE_SERVICE) - -#define SC_MANAGER_WRITE \ - (STANDARD_RIGHTS_WRITE | \ - SC_MANAGER_MODIFY_BOOT_CONFIG | \ - SC_MANAGER_CREATE_SERVICE) - -#define SC_MANAGER_EXECUTE \ - (STANDARD_RIGHTS_EXECUTE | \ - SC_MANAGER_LOCK | \ - SC_MANAGER_ENUMERATE_SERVICE | \ - SC_MANAGER_CONNECT | \ - SC_MANAGER_CREATE_SERVICE) - - -#define SERVICE_READ \ - (STANDARD_RIGHTS_READ | \ - SERVICE_INTERROGATE | \ - SERVICE_ENUMERATE_DEPENDENTS | \ - SERVICE_QUERY_STATUS | \ - SERVICE_QUERY_CONFIG) - -#define SERVICE_WRITE \ - (STANDARD_RIGHTS_WRITE | \ - SERVICE_CHANGE_CONFIG) - -#define SERVICE_EXECUTE \ - (STANDARD_RIGHTS_EXECUTE | \ - SERVICE_USER_DEFINED_CONTROL | \ - SERVICE_PAUSE_CONTINUE | \ - SERVICE_STOP | \ - SERVICE_START) - -#define TAG_ARRAY_SIZE 32 - -/* VARIABLES ***************************************************************/ - -static GENERIC_MAPPING -ScmManagerMapping = {SC_MANAGER_READ, - SC_MANAGER_WRITE, - SC_MANAGER_EXECUTE, - SC_MANAGER_ALL_ACCESS}; - -static GENERIC_MAPPING -ScmServiceMapping = {SERVICE_READ, - SERVICE_WRITE, - SERVICE_EXECUTE, - SERVICE_ALL_ACCESS}; - - -/* FUNCTIONS ***************************************************************/ - VOID ScmStartRpcServer(VOID) { @@ -130,5600 +52,11 @@ } DPRINT("ScmStartRpcServer() done\n"); -} - -static DWORD -ScmCreateManagerHandle(LPWSTR lpDatabaseName, - SC_HANDLE *Handle) -{ - PMANAGER_HANDLE Ptr; - - if (lpDatabaseName == NULL) - lpDatabaseName = SERVICES_ACTIVE_DATABASEW; - - if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0) - { - DPRINT("Database %S, does not exist\n", lpDatabaseName); - return ERROR_DATABASE_DOES_NOT_EXIST; - } - else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0) - { - DPRINT("Invalid Database name %S.\n", lpDatabaseName); - return ERROR_INVALID_NAME; - } - - Ptr = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1])); - if (Ptr == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - Ptr->Handle.Tag = MANAGER_TAG; - - wcscpy(Ptr->DatabaseName, lpDatabaseName); - - *Handle = (SC_HANDLE)Ptr; - - return ERROR_SUCCESS; + return; } -static DWORD -ScmCreateServiceHandle(PSERVICE lpServiceEntry, - SC_HANDLE *Handle) -{ - PSERVICE_HANDLE Ptr; - - Ptr = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(SERVICE_HANDLE)); - if (Ptr == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - Ptr->Handle.Tag = SERVICE_TAG; - - Ptr->ServiceEntry = lpServiceEntry; - - *Handle = (SC_HANDLE)Ptr; - - return ERROR_SUCCESS; -} - - -static PMANAGER_HANDLE -ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle) -{ - PMANAGER_HANDLE pManager = NULL; - - _SEH2_TRY - { - if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG) - pManager = (PMANAGER_HANDLE)Handle; - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - DPRINT1("Exception: Invalid Service Manager handle!\n"); - } - _SEH2_END; - - return pManager; -} - - -static PSERVICE_HANDLE -ScmGetServiceFromHandle(SC_RPC_HANDLE Handle) -{ - PSERVICE_HANDLE pService = NULL; - - _SEH2_TRY - { - if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG) - pService = (PSERVICE_HANDLE)Handle; - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - DPRINT1("Exception: Invalid Service handle!\n"); - } - _SEH2_END; - - return pService; -} - - -static DWORD -ScmCheckAccess(SC_HANDLE Handle, - DWORD dwDesiredAccess) -{ - PMANAGER_HANDLE hMgr; - - hMgr = (PMANAGER_HANDLE)Handle; - if (hMgr->Handle.Tag == MANAGER_TAG) - { - RtlMapGenericMask(&dwDesiredAccess, - &ScmManagerMapping); - - hMgr->Handle.DesiredAccess = dwDesiredAccess; - - return ERROR_SUCCESS; - } - else if (hMgr->Handle.Tag == SERVICE_TAG) - { - RtlMapGenericMask(&dwDesiredAccess, - &ScmServiceMapping); - - hMgr->Handle.DesiredAccess = dwDesiredAccess; - - return ERROR_SUCCESS; - } - - return ERROR_INVALID_HANDLE; -} - - -DWORD -ScmAssignNewTag(PSERVICE lpService) -{ - HKEY hKey = NULL; - DWORD dwError; - DWORD dwGroupTagCount = 0; - PDWORD pdwGroupTags = NULL; - DWORD dwFreeTag = 0; - DWORD dwTagUsedBase = 1; - BOOLEAN TagUsed[TAG_ARRAY_SIZE]; - INT nTagOffset; - DWORD i; - DWORD cbDataSize; - PLIST_ENTRY ServiceEntry; - PSERVICE CurrentService; - - ASSERT(lpService != NULL); - ASSERT(lpService->lpGroup != NULL); - - dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"System\\CurrentControlSet\\Control\\GroupOrderList", - 0, - KEY_READ, - &hKey); - - if (dwError != ERROR_SUCCESS) - goto findFreeTag; - - /* query value length */ - cbDataSize = 0; - dwError = RegQueryValueExW(hKey, - lpService->lpGroup->szGroupName, - NULL, - NULL, - NULL, - &cbDataSize); - - if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA) - goto findFreeTag; - - pdwGroupTags = HeapAlloc(GetProcessHeap(), 0, cbDataSize); - if (!pdwGroupTags) - { - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto cleanup; - } - - dwError = RegQueryValueExW(hKey, - lpService->lpGroup->szGroupName, - NULL, - NULL, - (LPBYTE)pdwGroupTags, - &cbDataSize); - - if (dwError != ERROR_SUCCESS) - goto findFreeTag; - - if (cbDataSize < sizeof(pdwGroupTags[0])) - goto findFreeTag; - - dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1); - -findFreeTag: - do - { - /* mark all tags as unused */ - for (i = 0; i < TAG_ARRAY_SIZE; i++) - TagUsed[i] = FALSE; - - /* mark tags in GroupOrderList as used */ - for (i = 1; i <= dwGroupTagCount; i++) - { - nTagOffset = pdwGroupTags[i] - dwTagUsedBase; - if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE) - TagUsed[nTagOffset] = TRUE; - } - - /* mark tags in service list as used */ - ServiceEntry = lpService->ServiceListEntry.Flink; - while (ServiceEntry != &lpService->ServiceListEntry) - { - ASSERT(ServiceEntry != NULL); - CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); - if (CurrentService->lpGroup == lpService->lpGroup) - { - nTagOffset = CurrentService->dwTag - dwTagUsedBase; - if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE) - TagUsed[nTagOffset] = TRUE; - } - - ServiceEntry = ServiceEntry->Flink; - } - - /* find unused tag, if any */ - for (i = 0; i < TAG_ARRAY_SIZE; i++) - { - if (!TagUsed[i]) - { - dwFreeTag = dwTagUsedBase + i; - break; - } - } - - dwTagUsedBase += TAG_ARRAY_SIZE; - } while (!dwFreeTag); - -cleanup: - if (pdwGroupTags) - HeapFree(GetProcessHeap(), 0, pdwGroupTags); - - if (hKey) - RegCloseKey(hKey); - - if (dwFreeTag) - { - lpService->dwTag = dwFreeTag; - DPRINT("Assigning new tag %lu to service %S in group %S\n", - lpService->dwTag, lpService->lpServiceName, lpService->lpGroup->szGroupName); - dwError = ERROR_SUCCESS; - } - else - { - DPRINT1("Failed to assign new tag to service %S, error=%lu\n", - lpService->lpServiceName, dwError); - } - - return dwError; -} - - -/* Create a path suitable for the bootloader out of the full path */ -DWORD -ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName) -{ - DWORD ServiceNameLen, BufferSize, ExpandedLen; - WCHAR Dest; - WCHAR *Expanded; - UNICODE_STRING NtPathName, SystemRoot, LinkTarget; - OBJECT_ATTRIBUTES ObjectAttributes; - NTSTATUS Status; - HANDLE SymbolicLinkHandle; - - DPRINT("ScmConvertToBootPathName %S\n", CanonName); - - ServiceNameLen = wcslen(CanonName); - - /* First check, if it's already good */ - if (ServiceNameLen > 12 && - !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12)) - { - *RelativeName = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - (ServiceNameLen + 1) * sizeof(WCHAR)); - if (*RelativeName == NULL) - { - DPRINT("Error allocating memory for boot driver name!\n"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* Copy it */ - wcscpy(*RelativeName, CanonName); - - DPRINT("Bootdriver name %S\n", *RelativeName); - return ERROR_SUCCESS; - } - - /* If it has %SystemRoot% prefix, substitute it to \System*/ - if (ServiceNameLen > 13 && - !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13)) - { - /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */ - *RelativeName = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - ServiceNameLen * sizeof(WCHAR)); - - if (*RelativeName == NULL) - { - DPRINT("Error allocating memory for boot driver name!\n"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* Copy it */ - wcscpy(*RelativeName, L"\\SystemRoot\\"); - wcscat(*RelativeName, CanonName + 13); - - DPRINT("Bootdriver name %S\n", *RelativeName); - return ERROR_SUCCESS; - } - - /* Get buffer size needed for expanding env strings */ - BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1); - - if (BufferSize <= 1) - { - DPRINT("Error during a call to ExpandEnvironmentStringsW()\n"); - return ERROR_INVALID_ENVIRONMENT; - } - - /* Allocate memory, since the size is known now */ - Expanded = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - (BufferSize + 1) * sizeof(WCHAR)); - if (!Expanded) - { - DPRINT("Error allocating memory for boot driver name!\n"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* Expand it */ - if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) > - BufferSize) - { - DPRINT("Error during a call to ExpandEnvironmentStringsW()\n"); - HeapFree(GetProcessHeap(), 0, Expanded); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* Convert to NY-style path */ - if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL)) - { - DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n"); - return ERROR_INVALID_ENVIRONMENT; - } - - DPRINT("Converted to NT-style %wZ\n", &NtPathName); - - /* No need to keep the dos-path anymore */ - HeapFree(GetProcessHeap(), 0, Expanded); - - /* Copy it to the allocated place */ - Expanded = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - NtPathName.Length + sizeof(UNICODE_NULL)); - if (!Expanded) - { - DPRINT("Error allocating memory for boot driver name!\n"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - ExpandedLen = NtPathName.Length / sizeof(WCHAR); - wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen); - Expanded[ExpandedLen] = UNICODE_NULL; - - if (ServiceNameLen > ExpandedLen && - !_wcsnicmp(Expanded, CanonName, ExpandedLen)) - { - /* Only \SystemRoot\ is missing */ - *RelativeName = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR)); - if (*RelativeName == NULL) - { - DPRINT("Error allocating memory for boot driver name!\n"); - HeapFree(GetProcessHeap(), 0, Expanded); - return ERROR_NOT_ENOUGH_MEMORY; - } - - wcscpy(*RelativeName, L"\\SystemRoot\\"); - wcscat(*RelativeName, CanonName + ExpandedLen); - - RtlFreeUnicodeString(&NtPathName); - return ERROR_SUCCESS; - } - - /* The most complex case starts here */ - RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot"); - InitializeObjectAttributes(&ObjectAttributes, - &SystemRoot, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - - /* Open this symlink */ - Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes); - - if (NT_SUCCESS(Status)) - { - LinkTarget.Length = 0; - LinkTarget.MaximumLength = 0; - - DPRINT("Opened symbolic link object\n"); - - Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize); - if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL) - { - /* Check if required buffer size is sane */ - if (BufferSize > 0xFFFD) - { - DPRINT("Too large buffer required\n"); - *RelativeName = 0; - - if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); - HeapFree(GetProcessHeap(), 0, Expanded); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* Alloc the string */ - LinkTarget.Length = (USHORT)BufferSize; - LinkTarget.MaximumLength = LinkTarget.Length + sizeof(UNICODE_NULL); - LinkTarget.Buffer = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - LinkTarget.MaximumLength); - if (!LinkTarget.Buffer) - { - DPRINT("Unable to alloc buffer\n"); - if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); - HeapFree(GetProcessHeap(), 0, Expanded); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* Do a real query now */ - Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize); - if (NT_SUCCESS(Status)) - { - DPRINT("LinkTarget: %wZ\n", &LinkTarget); - - ExpandedLen = LinkTarget.Length / sizeof(WCHAR); - if ((ServiceNameLen > ExpandedLen) && - !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen)) - { - *RelativeName = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR)); - - if (*RelativeName == NULL) - { - DPRINT("Unable to alloc buffer\n"); - if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); - HeapFree(GetProcessHeap(), 0, Expanded); - RtlFreeUnicodeString(&NtPathName); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* Copy it over, substituting the first part - with SystemRoot */ - wcscpy(*RelativeName, L"\\SystemRoot\\"); - wcscat(*RelativeName, CanonName+ExpandedLen+1); - - /* Cleanup */ - if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); - HeapFree(GetProcessHeap(), 0, Expanded); - RtlFreeUnicodeString(&NtPathName); - - /* Return success */ - return ERROR_SUCCESS; - } - else - { - if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); - HeapFree(GetProcessHeap(), 0, Expanded); - RtlFreeUnicodeString(&NtPathName); - return ERROR_INVALID_PARAMETER; - } - } - else - { - DPRINT("Error, Status = %08X\n", Status); - if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); - HeapFree(GetProcessHeap(), 0, Expanded); - RtlFreeUnicodeString(&NtPathName); - return ERROR_INVALID_PARAMETER; - } - } - else - { - DPRINT("Error, Status = %08X\n", Status); - if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); - HeapFree(GetProcessHeap(), 0, Expanded); - RtlFreeUnicodeString(&NtPathName); - return ERROR_INVALID_PARAMETER; - } - } - else - { - DPRINT("Error, Status = %08X\n", Status); - HeapFree(GetProcessHeap(), 0, Expanded); - return ERROR_INVALID_PARAMETER; - } - - /* Failure */ - *RelativeName = NULL; - return ERROR_INVALID_PARAMETER; -} - - -DWORD -ScmCanonDriverImagePath(DWORD dwStartType, - const wchar_t *lpServiceName, - wchar_t **lpCanonName) -{ - DWORD ServiceNameLen, Result; - UNICODE_STRING NtServiceName; - WCHAR *RelativeName; - const WCHAR *SourceName = lpServiceName; - - /* Calculate the length of the service's name */ - ServiceNameLen = wcslen(lpServiceName); - - /* 12 is wcslen(L"\\SystemRoot\\") */ - if (ServiceNameLen > 12 && - !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12)) - { - /* SystemRoot prefix is already included */ - *lpCanonName = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - (ServiceNameLen + 1) * sizeof(WCHAR)); - - if (*lpCanonName == NULL) - { - DPRINT("Error allocating memory for canonized service name!\n"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* If it's a boot-time driver, it must be systemroot relative */ - if (dwStartType == SERVICE_BOOT_START) - SourceName += 12; - - /* Copy it */ - wcscpy(*lpCanonName, SourceName); - - DPRINT("Canonicalized name %S\n", *lpCanonName); - return NO_ERROR; - } - - /* Check if it has %SystemRoot% (len=13) */ - if (ServiceNameLen > 13 && - !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13)) - { - /* Substitute %SystemRoot% with \\SystemRoot\\ */ - *lpCanonName = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - (ServiceNameLen + 1) * sizeof(WCHAR)); - - if (*lpCanonName == NULL) - { - DPRINT("Error allocating memory for canonized service name!\n"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* If it's a boot-time driver, it must be systemroot relative */ - if (dwStartType == SERVICE_BOOT_START) - wcscpy(*lpCanonName, L"\\SystemRoot\\"); - - wcscat(*lpCanonName, lpServiceName + 13); - - DPRINT("Canonicalized name %S\n", *lpCanonName); - return NO_ERROR; - } - - /* Check if it's a relative path name */ - if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':') - { - *lpCanonName = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - (ServiceNameLen + 1) * sizeof(WCHAR)); - - if (*lpCanonName == NULL) - { - DPRINT("Error allocating memory for canonized service name!\n"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* Just copy it over without changing */ - wcscpy(*lpCanonName, lpServiceName); - - return NO_ERROR; - } - - /* It seems to be a DOS path, convert it */ - if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL)) - { - DPRINT("RtlDosPathNameToNtPathName_U() failed!\n"); - return ERROR_INVALID_PARAMETER; - } - - *lpCanonName = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - NtServiceName.Length + sizeof(WCHAR)); - - if (*lpCanonName == NULL) - { - DPRINT("Error allocating memory for canonized service name!\n"); - RtlFreeUnicodeString(&NtServiceName); - return ERROR_NOT_ENOUGH_MEMORY; - } - - /* Copy the string */ - wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR)); - - /* The unicode string is not needed anymore */ - RtlFreeUnicodeString(&NtServiceName); - - if (dwStartType != SERVICE_BOOT_START) - { - DPRINT("Canonicalized name %S\n", *lpCanonName); - return NO_ERROR; - } - - /* The service is boot-started, so must be relative */ - Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName); - if (Result) - { - /* There is a problem, free name and return */ - HeapFree(GetProcessHeap(), 0, *lpCanonName); - DPRINT("Error converting named!\n"); - return Result; - } - - ASSERT(RelativeName); - - /* Copy that string */ - wcscpy(*lpCanonName, RelativeName + 12); - - /* Free the allocated buffer */ - HeapFree(GetProcessHeap(), 0, RelativeName); - - DPRINT("Canonicalized name %S\n", *lpCanonName); - - /* Success */ - return NO_ERROR; -} - - -/* Internal recursive function */ -/* Need to search for every dependency on every service */ -static DWORD -Int_EnumDependentServicesW(HKEY hServicesKey, - PSERVICE lpService, - DWORD dwServiceState, - PSERVICE *lpServices, - LPDWORD pcbBytesNeeded, - LPDWORD lpServicesReturned) -{ - DWORD dwError = ERROR_SUCCESS; - WCHAR szNameBuf[MAX_PATH]; - WCHAR szValueBuf[MAX_PATH]; - WCHAR *lpszNameBuf = szNameBuf; - WCHAR *lpszValueBuf = szValueBuf; - DWORD dwSize; - DWORD dwNumSubKeys; - DWORD dwIteration; - PSERVICE lpCurrentService; - HKEY hServiceEnumKey; - DWORD dwCurrentServiceState = SERVICE_ACTIVE; - DWORD dwDependServiceStrPtr = 0; - DWORD dwRequiredSize = 0; - - /* Get the number of service keys */ - dwError = RegQueryInfoKeyW(hServicesKey, - NULL, - NULL, - NULL, - &dwNumSubKeys, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - if (dwError != ERROR_SUCCESS) - { - DPRINT("ERROR! Unable to get number of services keys.\n"); - return dwError; - } - - /* Iterate the service keys to see if another service depends on the this service */ - for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++) - { - dwSize = MAX_PATH; - dwError = RegEnumKeyExW(hServicesKey, - dwIteration, - lpszNameBuf, - &dwSize, - NULL, - NULL, - NULL, - NULL); - if (dwError != ERROR_SUCCESS) - return dwError; - - /* Open the Service key */ - dwError = RegOpenKeyExW(hServicesKey, - lpszNameBuf, - 0, - KEY_READ, - &hServiceEnumKey); - if (dwError != ERROR_SUCCESS) - return dwError; - - dwSize = MAX_PATH; - - /* Check for the DependOnService Value */ - dwError = RegQueryValueExW(hServiceEnumKey, - L"DependOnService", - NULL, - NULL, - (LPBYTE)lpszValueBuf, - &dwSize); - - /* FIXME: Handle load order. */ - - /* If the service found has a DependOnService value */ - if (dwError == ERROR_SUCCESS) - { - dwDependServiceStrPtr = 0; - - /* Can be more than one Dependencies in the DependOnService string */ - while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0) - { - if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0) - { - /* Get the current enumed service pointer */ - lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf); - - /* Check for valid Service */ - if (!lpCurrentService) - { - /* This should never happen! */ - DPRINT("This should not happen at this point, report to Developer\n"); - return ERROR_NOT_FOUND; - } - - /* Determine state the service is in */ - if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED) - dwCurrentServiceState = SERVICE_INACTIVE; - - /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */ - if ((dwCurrentServiceState == dwServiceState) || - (dwServiceState == SERVICE_STATE_ALL)) - { - /* Calculate the required size */ - dwRequiredSize += sizeof(SERVICE_STATUS); - dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR)); - dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR)); - - /* Add the size for service name and display name pointers */ - dwRequiredSize += (2 * sizeof(PVOID)); - - /* increase the BytesNeeded size */ - *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize; - - /* Don't fill callers buffer yet, as MSDN read that the last service with dependency - comes first */ - - /* Recursive call to check for its dependencies */ - Int_EnumDependentServicesW(hServicesKey, - lpCurrentService, - dwServiceState, - lpServices, - pcbBytesNeeded, - lpServicesReturned); - - /* If the lpServices is valid set the service pointer */ - if (lpServices) - lpServices[*lpServicesReturned] = lpCurrentService; - - *lpServicesReturned = *lpServicesReturned + 1; - } - } - - dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1); - } - } - else if (*pcbBytesNeeded) - { - dwError = ERROR_SUCCESS; - } - - RegCloseKey(hServiceEnumKey); - } - - return dwError; -} - - -/* Function 0 */ -DWORD RCloseServiceHandle( - LPSC_RPC_HANDLE hSCObject) -{ - PMANAGER_HANDLE hManager; - PSERVICE_HANDLE hService; - PSERVICE lpService; - HKEY hServicesKey; - DWORD dwError; - DWORD pcbBytesNeeded = 0; - DWORD dwServicesReturned = 0; - - DPRINT("RCloseServiceHandle() called\n"); - - DPRINT("hSCObject = %p\n", *hSCObject); - - if (*hSCObject == 0) - return ERROR_INVALID_HANDLE; - - hManager = ScmGetServiceManagerFromHandle(*hSCObject); - hService = ScmGetServiceFromHandle(*hSCObject); - - if (hManager != NULL) - { - DPRINT("Found manager handle\n"); - - /* FIXME: add handle cleanup code */ - - HeapFree(GetProcessHeap(), 0, hManager); - hManager = NULL; - - *hSCObject = NULL; - - DPRINT("RCloseServiceHandle() done\n"); - return ERROR_SUCCESS; - } - else if (hService != NULL) - { - DPRINT("Found service handle\n"); - - /* Lock the service database exlusively */ - ScmLockDatabaseExclusive(); - - /* Get the pointer to the service record */ - lpService = hService->ServiceEntry; - - /* FIXME: add handle cleanup code */ - - /* Free the handle */ - HeapFree(GetProcessHeap(), 0, hService); - hService = NULL; - - ASSERT(lpService->dwRefCount > 0); - - lpService->dwRefCount--; - DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n", - lpService->dwRefCount); - - if (lpService->dwRefCount == 0) - { - /* If this service has been marked for deletion */ - if (lpService->bDeleted) - { - /* Open the Services Reg key */ - dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"System\\CurrentControlSet\\Services", - 0, - KEY_SET_VALUE | KEY_READ, - &hServicesKey); - if (dwError != ERROR_SUCCESS) - { - DPRINT("Failed to open services key\n"); - ScmUnlockDatabase(); - return dwError; - } - - /* Call the internal function with NULL, just to get bytes we need */ - Int_EnumDependentServicesW(hServicesKey, - lpService, - SERVICE_ACTIVE, - NULL, - &pcbBytesNeeded, - &dwServicesReturned); - - /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */ - if (pcbBytesNeeded) - { - DPRINT("Deletion failed due to running dependencies.\n"); - RegCloseKey(hServicesKey); - ScmUnlockDatabase(); - return ERROR_SUCCESS; - } - - /* There are no references and no runnning dependencies, - it is now safe to delete the service */ - - /* Delete the Service Key */ - dwError = RegDeleteKeyW(hServicesKey, - lpService->lpServiceName); - - RegCloseKey(hServicesKey); - - if (dwError != ERROR_SUCCESS) - { - DPRINT("Failed to Delete the Service Registry key\n"); - ScmUnlockDatabase(); - return dwError; - } - - /* Delete the Service */ - ScmDeleteServiceRecord(lpService); - } - } - - ScmUnlockDatabase(); - - *hSCObject = NULL; - - DPRINT("RCloseServiceHandle() done\n"); - return ERROR_SUCCESS; - } - - DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag); - - return ERROR_INVALID_HANDLE; -} - - -/* Function 1 */ -DWORD RControlService( - SC_RPC_HANDLE hService, - DWORD dwControl, - LPSERVICE_STATUS lpServiceStatus) -{ - PSERVICE_HANDLE hSvc; - PSERVICE lpService; - ACCESS_MASK DesiredAccess; - DWORD dwError = ERROR_SUCCESS; - DWORD pcbBytesNeeded = 0; - DWORD dwServicesReturned = 0; - DWORD dwControlsAccepted; - DWORD dwCurrentState; - HKEY hServicesKey = NULL; - - DPRINT("RControlService() called\n"); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - /* Check the service handle */ - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Check the service entry point */ - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT1("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Check access rights */ - switch (dwControl) - { - case SERVICE_CONTROL_STOP: - DesiredAccess = SERVICE_STOP; - break; - - case SERVICE_CONTROL_PAUSE: - case SERVICE_CONTROL_CONTINUE: - DesiredAccess = SERVICE_PAUSE_CONTINUE; - break; - - case SERVICE_INTERROGATE: - DesiredAccess = SERVICE_INTERROGATE; - break; - - default: - if (dwControl >= 128 && dwControl <= 255) - DesiredAccess = SERVICE_USER_DEFINED_CONTROL; - else - return ERROR_INVALID_PARAMETER; - break; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - DesiredAccess)) - return ERROR_ACCESS_DENIED; - - /* Return the current service status information */ - RtlCopyMemory(lpServiceStatus, - &lpService->Status, - sizeof(SERVICE_STATUS)); - - if (dwControl == SERVICE_CONTROL_STOP) - { - /* Check if the service has dependencies running as windows - doesn't stop a service that does */ - - /* Open the Services Reg key */ - dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"System\\CurrentControlSet\\Services", - 0, - KEY_READ, - &hServicesKey); - if (dwError != ERROR_SUCCESS) - { - DPRINT("Failed to open services key\n"); - return dwError; - } - - /* Call the internal function with NULL, just to get bytes we need */ - Int_EnumDependentServicesW(hServicesKey, - lpService, - SERVICE_ACTIVE, - NULL, - &pcbBytesNeeded, - &dwServicesReturned); - - RegCloseKey(hServicesKey); - - /* If pcbBytesNeeded is not zero then there are services running that - are dependent on this service */ - if (pcbBytesNeeded != 0) - { - DPRINT("Service has running dependencies. Failed to stop service.\n"); - return ERROR_DEPENDENT_SERVICES_RUNNING; - } - } - - if (lpService->Status.dwServiceType & SERVICE_DRIVER) - { - /* Send control code to the driver */ - dwError = ScmControlDriver(lpService, - dwControl, - lpServiceStatus); - } - else - { - dwControlsAccepted = lpService->Status.dwControlsAccepted; - dwCurrentState = lpService->Status.dwCurrentState; - - /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */ - if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED) - return ERROR_SERVICE_NOT_ACTIVE; - - /* Check the current state before sending a control request */ - switch (dwCurrentState) - { - case SERVICE_STOP_PENDING: - case SERVICE_STOPPED: - return ERROR_SERVICE_CANNOT_ACCEPT_CTRL; - - case SERVICE_START_PENDING: - switch (dwControl) - { - case SERVICE_CONTROL_STOP: - break; - - case SERVICE_CONTROL_INTERROGATE: - RtlCopyMemory(lpServiceStatus, - &lpService->Status, - sizeof(SERVICE_STATUS)); - return ERROR_SUCCESS; - - default: - return ERROR_SERVICE_CANNOT_ACCEPT_CTRL; - } - break; - } - - /* Check if the control code is acceptable to the service */ - switch (dwControl) - { - case SERVICE_CONTROL_STOP: - if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0) - return ERROR_INVALID_SERVICE_CONTROL; - break; - - case SERVICE_CONTROL_PAUSE: - case SERVICE_CONTROL_CONTINUE: - if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0) - return ERROR_INVALID_SERVICE_CONTROL; - break; - } - - /* Send control code to the service */ - dwError = ScmControlService(lpService, - dwControl); - - /* Return service status information */ - RtlCopyMemory(lpServiceStatus, - &lpService->Status, - sizeof(SERVICE_STATUS)); - } - - if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded)) - dwError = ERROR_DEPENDENT_SERVICES_RUNNING; - - return dwError; -} - - -/* Function 2 */ -DWORD RDeleteService( - SC_RPC_HANDLE hService) -{ - PSERVICE_HANDLE hSvc; - PSERVICE lpService; - DWORD dwError; - - DPRINT("RDeleteService() called\n"); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - DELETE)) - return ERROR_ACCESS_DENIED; - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database exclusively */ - ScmLockDatabaseExclusive(); - - if (lpService->bDeleted) - { - DPRINT("The service has already been marked for delete!\n"); - dwError = ERROR_SERVICE_MARKED_FOR_DELETE; - goto Done; - } - - /* Mark service for delete */ - lpService->bDeleted = TRUE; - - dwError = ScmMarkServiceForDelete(lpService); - -Done:; - /* Unlock the service database */ - ScmUnlockDatabase(); - - DPRINT("RDeleteService() done\n"); - - return dwError; -} - - -/* Function 3 */ -DWORD RLockServiceDatabase( - SC_RPC_HANDLE hSCManager, - LPSC_RPC_LOCK lpLock) -{ - PMANAGER_HANDLE hMgr; - - DPRINT("RLockServiceDatabase() called\n"); - - *lpLock = 0; - - hMgr = ScmGetServiceManagerFromHandle(hSCManager); - if (hMgr == NULL) - { - DPRINT1("Invalid service manager handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess, - SC_MANAGER_LOCK)) - return ERROR_ACCESS_DENIED; - -// return ScmLockDatabase(0, hMgr->0xC, hLock); - - /* FIXME: Lock the database */ - *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */ - - return ERROR_SUCCESS; -} - - -/* Function 4 */ -DWORD RQueryServiceObjectSecurity( - SC_RPC_HANDLE hService, - SECURITY_INFORMATION dwSecurityInformation, - LPBYTE lpSecurityDescriptor, - DWORD cbBufSize, - LPBOUNDED_DWORD_256K pcbBytesNeeded) -{ - PSERVICE_HANDLE hSvc; - PSERVICE lpService; - ULONG DesiredAccess = 0; - NTSTATUS Status; - DWORD dwBytesNeeded; - DWORD dwError; - - - SECURITY_DESCRIPTOR ObjectDescriptor; - - DPRINT("RQueryServiceObjectSecurity() called\n"); - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (dwSecurityInformation & (DACL_SECURITY_INFORMATION | - GROUP_SECURITY_INFORMATION | - OWNER_SECURITY_INFORMATION)) - DesiredAccess |= READ_CONTROL; - - if (dwSecurityInformation & SACL_SECURITY_INFORMATION) - DesiredAccess |= ACCESS_SYSTEM_SECURITY; - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - DesiredAccess)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database */ - ScmLockDatabaseShared(); - - - /* hack */ - Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION); - - Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */, - dwSecurityInformation, - (PSECURITY_DESCRIPTOR)lpSecurityDescriptor, - cbBufSize, - &dwBytesNeeded); - - /* Unlock the service database */ - ScmUnlockDatabase(); - - if (NT_SUCCESS(Status)) - { - *pcbBytesNeeded = dwBytesNeeded; - dwError = STATUS_SUCCESS; - } - else if (Status == STATUS_BUFFER_TOO_SMALL) - { - *pcbBytesNeeded = dwBytesNeeded; - dwError = ERROR_INSUFFICIENT_BUFFER; - } - else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT) - { - dwError = ERROR_GEN_FAILURE; - } - else - { - dwError = RtlNtStatusToDosError(Status); - } - - return dwError; -} - - -/* Function 5 */ -DWORD RSetServiceObjectSecurity( - SC_RPC_HANDLE hService, - DWORD dwSecurityInformation, - LPBYTE lpSecurityDescriptor, - DWORD dwSecuityDescriptorSize) -{ - PSERVICE_HANDLE hSvc; - PSERVICE lpService; - ULONG DesiredAccess = 0; - /* HANDLE hToken = NULL; */ - HKEY hServiceKey; - /* NTSTATUS Status; */ - DWORD dwError; - - DPRINT("RSetServiceObjectSecurity() called\n"); - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (dwSecurityInformation == 0 || - dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION - | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)) - return ERROR_INVALID_PARAMETER; - - if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor)) - return ERROR_INVALID_PARAMETER; - - if (dwSecurityInformation & SACL_SECURITY_INFORMATION) - DesiredAccess |= ACCESS_SYSTEM_SECURITY; - - if (dwSecurityInformation & DACL_SECURITY_INFORMATION) - DesiredAccess |= WRITE_DAC; - - if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION)) - DesiredAccess |= WRITE_OWNER; - - if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) && - (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL)) - return ERROR_INVALID_PARAMETER; - - if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) && - (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL)) - return ERROR_INVALID_PARAMETER; - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - DesiredAccess)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - if (lpService->bDeleted) - return ERROR_SERVICE_MARKED_FOR_DELETE; - -#if 0 - RpcImpersonateClient(NULL); - - Status = NtOpenThreadToken(NtCurrentThread(), - 8, - TRUE, - &hToken); - if (!NT_SUCCESS(Status)) - return RtlNtStatusToDosError(Status); - - RpcRevertToSelf(); -#endif - - /* Lock the service database exclusive */ - ScmLockDatabaseExclusive(); - -#if 0 - Status = RtlSetSecurityObject(dwSecurityInformation, - (PSECURITY_DESCRIPTOR)lpSecurityDescriptor, - &lpService->lpSecurityDescriptor, - &ScmServiceMapping, - hToken); - if (!NT_SUCCESS(Status)) - { - dwError = RtlNtStatusToDosError(Status); - goto Done; - } -#endif - - dwError = ScmOpenServiceKey(lpService->lpServiceName, - READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE, - &hServiceKey); - if (dwError != ERROR_SUCCESS) - goto Done; - - UNIMPLEMENTED; - dwError = ERROR_SUCCESS; -// dwError = ScmWriteSecurityDescriptor(hServiceKey, -// lpService->lpSecurityDescriptor); - - RegFlushKey(hServiceKey); - RegCloseKey(hServiceKey); - -Done: - -#if 0 - if (hToken != NULL) - NtClose(hToken); -#endif - - /* Unlock service database */ - ScmUnlockDatabase(); - - DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 6 */ -DWORD RQueryServiceStatus( - SC_RPC_HANDLE hService, - LPSERVICE_STATUS lpServiceStatus) -{ - PSERVICE_HANDLE hSvc; - PSERVICE lpService; - - DPRINT("RQueryServiceStatus() called\n"); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_QUERY_STATUS)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database shared */ - ScmLockDatabaseShared(); - - /* Return service status information */ - RtlCopyMemory(lpServiceStatus, - &lpService->Status, - sizeof(SERVICE_STATUS)); - - /* Unlock the service database */ - ScmUnlockDatabase(); - - return ERROR_SUCCESS; -} - - -static BOOL -ScmIsValidServiceState(DWORD dwCurrentState) -{ - switch (dwCurrentState) - { - case SERVICE_STOPPED: - case SERVICE_START_PENDING: - case SERVICE_STOP_PENDING: - case SERVICE_RUNNING: - case SERVICE_CONTINUE_PENDING: - case SERVICE_PAUSE_PENDING: - case SERVICE_PAUSED: - return TRUE; - - default: - return FALSE; - } -} - - -/* Function 7 */ -DWORD RSetServiceStatus( - RPC_SERVICE_STATUS_HANDLE hServiceStatus, - LPSERVICE_STATUS lpServiceStatus) -{ - PSERVICE lpService; - DWORD dwPreviousState; - LPCWSTR lpErrorStrings[2]; - WCHAR szErrorBuffer[32]; - - DPRINT("RSetServiceStatus() called\n"); - DPRINT("hServiceStatus = %p\n", hServiceStatus); - DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType); - DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState); - DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted); - DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode); - DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode); - DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint); - DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint); - - if (hServiceStatus == 0) - { - DPRINT("hServiceStatus == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - lpService = (PSERVICE)hServiceStatus; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Check current state */ - if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState)) - { - DPRINT("Invalid service state!\n"); - return ERROR_INVALID_DATA; - } - - /* Check service type */ - if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) && - (lpServiceStatus->dwServiceType & SERVICE_DRIVER)) - { - DPRINT("Invalid service type!\n"); - return ERROR_INVALID_DATA; - } - - /* Check accepted controls */ - if (lpServiceStatus->dwControlsAccepted & ~0xFF) - { - DPRINT("Invalid controls accepted!\n"); - return ERROR_INVALID_DATA; - } - - /* Lock the service database exclusively */ - ScmLockDatabaseExclusive(); - - /* Save the current service state */ - dwPreviousState = lpService->Status.dwCurrentState; - - RtlCopyMemory(&lpService->Status, - lpServiceStatus, - sizeof(SERVICE_STATUS)); - - /* Unlock the service database */ - ScmUnlockDatabase(); - - /* Log a failed service stop */ - if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) && - (dwPreviousState != SERVICE_STOPPED)) - { - if (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS) - { - swprintf(szErrorBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode); - lpErrorStrings[0] = lpService->lpDisplayName; - lpErrorStrings[1] = szErrorBuffer; - - ScmLogError(EVENT_SERVICE_EXIT_FAILED, - 2, - lpErrorStrings); - } - } - - DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState); - DPRINT("RSetServiceStatus() done\n"); - - return ERROR_SUCCESS; -} - - -/* Function 8 */ -DWORD RUnlockServiceDatabase( - LPSC_RPC_LOCK Lock) -{ - UNIMPLEMENTED; - return ERROR_SUCCESS; -} - - -/* Function 9 */ -DWORD RNotifyBootConfigStatus( - SVCCTL_HANDLEW lpMachineName, - DWORD BootAcceptable) -{ - DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable); - return ERROR_SUCCESS; - -// UNIMPLEMENTED; -// return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 10 */ -DWORD RI_ScSetServiceBitsW( - RPC_SERVICE_STATUS_HANDLE hServiceStatus, - DWORD dwServiceBits, - int bSetBitsOn, - int bUpdateImmediately, - wchar_t *lpString) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 11 */ -DWORD RChangeServiceConfigW( - SC_RPC_HANDLE hService, - DWORD dwServiceType, - DWORD dwStartType, - DWORD dwErrorControl, - LPWSTR lpBinaryPathName, - LPWSTR lpLoadOrderGroup, - LPDWORD lpdwTagId, - LPBYTE lpDependencies, - DWORD dwDependSize, - LPWSTR lpServiceStartName, - LPBYTE lpPassword, - DWORD dwPwSize, - LPWSTR lpDisplayName) -{ - DWORD dwError = ERROR_SUCCESS; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - HKEY hServiceKey = NULL; - LPWSTR lpDisplayNameW = NULL; - LPWSTR lpImagePathW = NULL; - - DPRINT("RChangeServiceConfigW() called\n"); - DPRINT("dwServiceType = %lu\n", dwServiceType); - DPRINT("dwStartType = %lu\n", dwStartType); - DPRINT("dwErrorControl = %lu\n", dwErrorControl); - DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName); - DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup); - DPRINT("lpDisplayName = %S\n", lpDisplayName); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_CHANGE_CONFIG)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database exclusively */ - ScmLockDatabaseExclusive(); - - if (lpService->bDeleted) - { - DPRINT("The service has already been marked for delete!\n"); - dwError = ERROR_SERVICE_MARKED_FOR_DELETE; - goto done; - } - - /* Open the service key */ - dwError = ScmOpenServiceKey(lpService->szServiceName, - KEY_SET_VALUE, - &hServiceKey); - if (dwError != ERROR_SUCCESS) - goto done; - - /* Write service data to the registry */ - /* Set the display name */ - if (lpDisplayName != NULL && *lpDisplayName != 0) - { - RegSetValueExW(hServiceKey, - L"DisplayName", - 0, - REG_SZ, - (LPBYTE)lpDisplayName, - (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); - - /* Update the display name */ - lpDisplayNameW = HeapAlloc(GetProcessHeap(), - 0, - (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); - if (lpDisplayNameW == NULL) - { - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto done; - } - - if (lpService->lpDisplayName != lpService->lpServiceName) - HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName); - - lpService->lpDisplayName = lpDisplayNameW; - } - - if (dwServiceType != SERVICE_NO_CHANGE) - { - /* Set the service type */ - dwError = RegSetValueExW(hServiceKey, - L"Type", - 0, - REG_DWORD, - (LPBYTE)&dwServiceType, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - lpService->Status.dwServiceType = dwServiceType; - } - - if (dwStartType != SERVICE_NO_CHANGE) - { - /* Set the start value */ - dwError = RegSetValueExW(hServiceKey, - L"Start", - 0, - REG_DWORD, - (LPBYTE)&dwStartType, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - lpService->dwStartType = dwStartType; - } - - if (dwErrorControl != SERVICE_NO_CHANGE) - { - /* Set the error control value */ - dwError = RegSetValueExW(hServiceKey, - L"ErrorControl", - 0, - REG_DWORD, - (LPBYTE)&dwErrorControl, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - lpService->dwErrorControl = dwErrorControl; - } - - if (lpBinaryPathName != NULL && *lpBinaryPathName != 0) - { - /* Set the image path */ - lpImagePathW = lpBinaryPathName; - - if (lpService->Status.dwServiceType & SERVICE_DRIVER) - { - dwError = ScmCanonDriverImagePath(lpService->dwStartType, - lpBinaryPathName, - &lpImagePathW); - - if (dwError != ERROR_SUCCESS) - goto done; - } - - dwError = RegSetValueExW(hServiceKey, - L"ImagePath", - 0, - REG_EXPAND_SZ, - (LPBYTE)lpImagePathW, - (wcslen(lpImagePathW) + 1) * sizeof(WCHAR)); - - if (lpImagePathW != lpBinaryPathName) - HeapFree(GetProcessHeap(), 0, lpImagePathW); - - if (dwError != ERROR_SUCCESS) - goto done; - } - - /* Set the group name */ - if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) - { - dwError = RegSetValueExW(hServiceKey, - L"Group", - 0, - REG_SZ, - (LPBYTE)lpLoadOrderGroup, - (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)); - if (dwError != ERROR_SUCCESS) - goto done; - - dwError = ScmSetServiceGroup(lpService, - lpLoadOrderGroup); - if (dwError != ERROR_SUCCESS) - goto done; - } - - if (lpdwTagId != NULL) - { - dwError = ScmAssignNewTag(lpService); - if (dwError != ERROR_SUCCESS) - goto done; - - dwError = RegSetValueExW(hServiceKey, - L"Tag", - 0, - REG_DWORD, - (LPBYTE)&lpService->dwTag, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - *lpdwTagId = lpService->dwTag; - } - - /* Write dependencies */ - if (lpDependencies != NULL && *lpDependencies != 0) - { - dwError = ScmWriteDependencies(hServiceKey, - (LPWSTR)lpDependencies, - dwDependSize); - if (dwError != ERROR_SUCCESS) - goto done; - } - - if (lpPassword != NULL) - { - /* FIXME: Write password */ - } - -done: - if (hServiceKey != NULL) - RegCloseKey(hServiceKey); - - /* Unlock the service database */ - ScmUnlockDatabase(); - - DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 12 */ -DWORD RCreateServiceW( - SC_RPC_HANDLE hSCManager, - LPCWSTR lpServiceName, - LPCWSTR lpDisplayName, - DWORD dwDesiredAccess, - DWORD dwServiceType, - DWORD dwStartType, - DWORD dwErrorControl, - LPCWSTR lpBinaryPathName, - LPCWSTR lpLoadOrderGroup, - LPDWORD lpdwTagId, - LPBYTE lpDependencies, - DWORD dwDependSize, - LPCWSTR lpServiceStartName, - LPBYTE lpPassword, - DWORD dwPwSize, - LPSC_RPC_HANDLE lpServiceHandle) -{ - PMANAGER_HANDLE hManager; - DWORD dwError = ERROR_SUCCESS; - PSERVICE lpService = NULL; - SC_HANDLE hServiceHandle = NULL; - LPWSTR lpImagePath = NULL; - HKEY hServiceKey = NULL; - LPWSTR lpObjectName; - - DPRINT("RCreateServiceW() called\n"); - DPRINT("lpServiceName = %S\n", lpServiceName); - DPRINT("lpDisplayName = %S\n", lpDisplayName); - DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess); - DPRINT("dwServiceType = %lu\n", dwServiceType); - DPRINT("dwStartType = %lu\n", dwStartType); - DPRINT("dwErrorControl = %lu\n", dwErrorControl); - DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName); - DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup); - DPRINT("lpdwTagId = %p\n", lpdwTagId); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hManager = ScmGetServiceManagerFromHandle(hSCManager); - if (hManager == NULL) - { - DPRINT1("Invalid service manager handle!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Check access rights */ - if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess, - SC_MANAGER_CREATE_SERVICE)) - { - DPRINT("Insufficient access rights! 0x%lx\n", - hManager->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - if (wcslen(lpServiceName) == 0) - { - return ERROR_INVALID_NAME; - } - - if (wcslen(lpBinaryPathName) == 0) - { - return ERROR_INVALID_PARAMETER; - } - - /* Check for invalid service type value */ - if ((dwServiceType != SERVICE_KERNEL_DRIVER) && - (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) && - ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) && - ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS)) - return ERROR_INVALID_PARAMETER; - - /* Check for invalid start type value */ - if ((dwStartType != SERVICE_BOOT_START) && - (dwStartType != SERVICE_SYSTEM_START) && - (dwStartType != SERVICE_AUTO_START) && - (dwStartType != SERVICE_DEMAND_START) && - (dwStartType != SERVICE_DISABLED)) - return ERROR_INVALID_PARAMETER; - - /* Only drivers can be boot start or system start services */ - if ((dwStartType == SERVICE_BOOT_START) || - (dwStartType == SERVICE_SYSTEM_START)) - { - if ((dwServiceType != SERVICE_KERNEL_DRIVER) && - (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)) - return ERROR_INVALID_PARAMETER; - } - - /* Check for invalid error control value */ - if ((dwErrorControl != SERVICE_ERROR_IGNORE) && - (dwErrorControl != SERVICE_ERROR_NORMAL) && - (dwErrorControl != SERVICE_ERROR_SEVERE) && - (dwErrorControl != SERVICE_ERROR_CRITICAL)) - return ERROR_INVALID_PARAMETER; - - if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) && - (lpServiceStartName)) - { - return ERROR_INVALID_PARAMETER; - } - - if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup)) - { - return ERROR_INVALID_PARAMETER; - } - - /* Lock the service database exclusively */ - ScmLockDatabaseExclusive(); - - lpService = ScmGetServiceEntryByName(lpServiceName); - if (lpService) - { - /* Unlock the service database */ - ScmUnlockDatabase(); - - /* Check if it is marked for deletion */ - if (lpService->bDeleted) - return ERROR_SERVICE_MARKED_FOR_DELETE; - - /* Return Error exist */ - return ERROR_SERVICE_EXISTS; - } - - if (lpDisplayName != NULL && - ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL) - { - /* Unlock the service database */ - ScmUnlockDatabase(); - - return ERROR_DUPLICATE_SERVICE_NAME; - } - - if (dwServiceType & SERVICE_DRIVER) - { - dwError = ScmCanonDriverImagePath(dwStartType, - lpBinaryPathName, - &lpImagePath); - if (dwError != ERROR_SUCCESS) - goto done; - } - else - { - if (dwStartType == SERVICE_BOOT_START || - dwStartType == SERVICE_SYSTEM_START) - { - /* Unlock the service database */ - ScmUnlockDatabase(); - - return ERROR_INVALID_PARAMETER; - } - } - - /* Allocate a new service entry */ - dwError = ScmCreateNewServiceRecord(lpServiceName, - &lpService); - if (dwError != ERROR_SUCCESS) - goto done; - - /* Fill the new service entry */ - lpService->Status.dwServiceType = dwServiceType; - lpService->dwStartType = dwStartType; - lpService->dwErrorControl = dwErrorControl; - - /* Fill the display name */ - if (lpDisplayName != NULL && - *lpDisplayName != 0 && - _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0) - { - lpService->lpDisplayName = HeapAlloc(GetProcessHeap(), 0, - (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); - if (lpService->lpDisplayName == NULL) - { - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto done; - } - wcscpy(lpService->lpDisplayName, lpDisplayName); - } - - /* Assign the service to a group */ - if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) - { - dwError = ScmSetServiceGroup(lpService, - lpLoadOrderGroup); - if (dwError != ERROR_SUCCESS) - goto done; - } - - /* Assign a new tag */ - if (lpdwTagId != NULL) - { - dwError = ScmAssignNewTag(lpService); - if (dwError != ERROR_SUCCESS) - goto done; - } - - /* Write service data to the registry */ - /* Create the service key */ - dwError = ScmCreateServiceKey(lpServiceName, - KEY_WRITE, - &hServiceKey); - if (dwError != ERROR_SUCCESS) - goto done; - - /* Set the display name */ - if (lpDisplayName != NULL && *lpDisplayName != 0) - { - RegSetValueExW(hServiceKey, - L"DisplayName", - 0, - REG_SZ, - (LPBYTE)lpDisplayName, - (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); - } - - /* Set the service type */ - dwError = RegSetValueExW(hServiceKey, - L"Type", - 0, - REG_DWORD, - (LPBYTE)&dwServiceType, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - /* Set the start value */ - dwError = RegSetValueExW(hServiceKey, - L"Start", - 0, - REG_DWORD, - (LPBYTE)&dwStartType, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - /* Set the error control value */ - dwError = RegSetValueExW(hServiceKey, - L"ErrorControl", - 0, - REG_DWORD, - (LPBYTE)&dwErrorControl, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - /* Set the image path */ - if (dwServiceType & SERVICE_WIN32) - { - dwError = RegSetValueExW(hServiceKey, - L"ImagePath", - 0, - REG_EXPAND_SZ, - (LPBYTE)lpBinaryPathName, - (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)); - if (dwError != ERROR_SUCCESS) - goto done; - } - else if (dwServiceType & SERVICE_DRIVER) - { - dwError = RegSetValueExW(hServiceKey, - L"ImagePath", - 0, - REG_EXPAND_SZ, - (LPBYTE)lpImagePath, - (wcslen(lpImagePath) + 1) * sizeof(WCHAR)); - if (dwError != ERROR_SUCCESS) - goto done; - } - - /* Set the group name */ - if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) - { - dwError = RegSetValueExW(hServiceKey, - L"Group", - 0, - REG_SZ, - (LPBYTE)lpLoadOrderGroup, - (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)); - if (dwError != ERROR_SUCCESS) - goto done; - } - - if (lpdwTagId != NULL) - { - dwError = RegSetValueExW(hServiceKey, - L"Tag", - 0, - REG_DWORD, - (LPBYTE)&lpService->dwTag, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - } - - /* Write dependencies */ - if (lpDependencies != NULL && *lpDependencies != 0) - { - dwError = ScmWriteDependencies(hServiceKey, - (LPCWSTR)lpDependencies, - dwDependSize); - if (dwError != ERROR_SUCCESS) - goto done; - } - - /* Write service start name */ - if (dwServiceType & SERVICE_WIN32) - { - lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem"; - dwError = RegSetValueExW(hServiceKey, - L"ObjectName", - 0, - REG_SZ, - (LPBYTE)lpObjectName, - (wcslen(lpObjectName) + 1) * sizeof(WCHAR)); - if (dwError != ERROR_SUCCESS) - goto done; - } - - if (lpPassword != NULL) - { - /* FIXME: Write password */ - } - - dwError = ScmCreateServiceHandle(lpService, - &hServiceHandle); - if (dwError != ERROR_SUCCESS) - goto done; - - dwError = ScmCheckAccess(hServiceHandle, - dwDesiredAccess); - if (dwError != ERROR_SUCCESS) - goto done; - - lpService->dwRefCount = 1; - DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount); - -done:; - /* Unlock the service database */ - ScmUnlockDatabase(); - - if (hServiceKey != NULL) - RegCloseKey(hServiceKey); - - if (dwError == ERROR_SUCCESS) - { - DPRINT("hService %p\n", hServiceHandle); - *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle; - - if (lpdwTagId != NULL) - *lpdwTagId = lpService->dwTag; - } - else - { - if (lpService != NULL && - lpService->lpServiceName != NULL) - { - /* Release the display name buffer */ - HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName); - } - - if (hServiceHandle) - { - /* Remove the service handle */ - HeapFree(GetProcessHeap(), 0, hServiceHandle); - } - - if (lpService != NULL) - { - /* FIXME: remove the service entry */ - } - } - - if (lpImagePath != NULL) - HeapFree(GetProcessHeap(), 0, lpImagePath); - - DPRINT("RCreateServiceW() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 13 */ -DWORD REnumDependentServicesW( - SC_RPC_HANDLE hService, - DWORD dwServiceState, - LPBYTE lpServices, - DWORD cbBufSize, - LPBOUNDED_DWORD_256K pcbBytesNeeded, - LPBOUNDED_DWORD_256K lpServicesReturned) -{ - DWORD dwError = ERROR_SUCCESS; - DWORD dwServicesReturned = 0; - DWORD dwServiceCount; - HKEY hServicesKey = NULL; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - PSERVICE *lpServicesArray = NULL; - LPENUM_SERVICE_STATUSW lpServicesPtr = NULL; - LPWSTR lpStr; - - *pcbBytesNeeded = 0; - *lpServicesReturned = 0; - - DPRINT("REnumDependentServicesW() called\n"); - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - lpService = hSvc->ServiceEntry; - - /* Check access rights */ - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SC_MANAGER_ENUMERATE_SERVICE)) - { - DPRINT("Insufficient access rights! 0x%lx\n", - hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - /* Open the Services Reg key */ - dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"System\\CurrentControlSet\\Services", - 0, - KEY_READ, - &hServicesKey); - if (dwError != ERROR_SUCCESS) - return dwError; - - /* First determine the bytes needed and get the number of dependent services */ - dwError = Int_EnumDependentServicesW(hServicesKey, - lpService, - dwServiceState, - NULL, - pcbBytesNeeded, - &dwServicesReturned); - if (dwError != ERROR_SUCCESS) - goto Done; - - /* If buffer size is less than the bytes needed or pointer is null */ - if ((!lpServices) || (cbBufSize < *pcbBytesNeeded)) - { - dwError = ERROR_MORE_DATA; - goto Done; - } - - /* Allocate memory for array of service pointers */ - lpServicesArray = HeapAlloc(GetProcessHeap(), - 0, - (dwServicesReturned + 1) * sizeof(PSERVICE)); - if (!lpServicesArray) - { - DPRINT1("Could not allocate a buffer!!\n"); - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto Done; - } - - dwServicesReturned = 0; - *pcbBytesNeeded = 0; - - dwError = Int_EnumDependentServicesW(hServicesKey, - lpService, - dwServiceState, - lpServicesArray, - pcbBytesNeeded, - &dwServicesReturned); - if (dwError != ERROR_SUCCESS) - { - goto Done; - } - - lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices; - lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW))); - - /* Copy EnumDepenedentService to Buffer */ - for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++) - { - lpService = lpServicesArray[dwServiceCount]; - - /* Copy status info */ - memcpy(&lpServicesPtr->ServiceStatus, - &lpService->Status, - sizeof(SERVICE_STATUS)); - - /* Copy display name */ - wcscpy(lpStr, lpService->lpDisplayName); - lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); - lpStr += (wcslen(lpService->lpDisplayName) + 1); - - /* Copy service name */ - wcscpy(lpStr, lpService->lpServiceName); - lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); - lpStr += (wcslen(lpService->lpServiceName) + 1); - - lpServicesPtr ++; - } - - *lpServicesReturned = dwServicesReturned; - -Done: - if (lpServicesArray != NULL) - HeapFree(GetProcessHeap(), 0, lpServicesArray); - - RegCloseKey(hServicesKey); - - DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 14 */ -DWORD REnumServicesStatusW( - SC_RPC_HANDLE hSCManager, - DWORD dwServiceType, - DWORD dwServiceState, - LPBYTE lpBuffer, - DWORD dwBufSize, - LPBOUNDED_DWORD_256K pcbBytesNeeded, - LPBOUNDED_DWORD_256K lpServicesReturned, - LPBOUNDED_DWORD_256K lpResumeHandle) -{ - PMANAGER_HANDLE hManager; - PSERVICE lpService; - DWORD dwError = ERROR_SUCCESS; - PLIST_ENTRY ServiceEntry; - PSERVICE CurrentService; - DWORD dwState; - DWORD dwRequiredSize; - DWORD dwServiceCount; - DWORD dwSize; - DWORD dwLastResumeCount = 0; - LPENUM_SERVICE_STATUSW lpStatusPtr; - LPWSTR lpStringPtr; - - DPRINT("REnumServicesStatusW() called\n"); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hManager = ScmGetServiceManagerFromHandle(hSCManager); - if (hManager == NULL) - { - DPRINT1("Invalid service manager handle!\n"); - return ERROR_INVALID_HANDLE; - } - - - *pcbBytesNeeded = 0; - *lpServicesReturned = 0; - - if ((dwServiceType == 0) || - ((dwServiceType & ~(SERVICE_DRIVER | SERVICE_WIN32)) != 0)) - { - DPRINT("Not a valid Service Type!\n"); - return ERROR_INVALID_PARAMETER; - } - - if ((dwServiceState != SERVICE_ACTIVE) && - (dwServiceState != SERVICE_INACTIVE) && - (dwServiceState != SERVICE_STATE_ALL)) - { - DPRINT("Not a valid Service State!\n"); - return ERROR_INVALID_PARAMETER; - } - - /* Check access rights */ - if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess, - SC_MANAGER_ENUMERATE_SERVICE)) - { - DPRINT("Insufficient access rights! 0x%lx\n", - hManager->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - if (lpResumeHandle) - dwLastResumeCount = *lpResumeHandle; - - /* Lock the service database shared */ - ScmLockDatabaseShared(); - - lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount); - if (lpService == NULL) - { - dwError = ERROR_SUCCESS; - goto Done; - } - - dwRequiredSize = 0; - dwServiceCount = 0; - - for (ServiceEntry = &lpService->ServiceListEntry; - ServiceEntry != &ServiceListHead; - ServiceEntry = ServiceEntry->Flink) - { - CurrentService = CONTAINING_RECORD(ServiceEntry, - SERVICE, - ServiceListEntry); - - if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) - continue; - - dwState = SERVICE_ACTIVE; - if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) - dwState = SERVICE_INACTIVE; - - if ((dwState & dwServiceState) == 0) - continue; - - dwSize = sizeof(ENUM_SERVICE_STATUSW) + - ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + - ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)); - - if (dwRequiredSize + dwSize > dwBufSize) - { - DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName); - break; - } - - DPRINT("Service name: %S fit\n", CurrentService->lpServiceName); - dwRequiredSize += dwSize; - dwServiceCount++; - dwLastResumeCount = CurrentService->dwResumeCount; - } - - DPRINT("dwRequiredSize: %lu\n", dwRequiredSize); - DPRINT("dwServiceCount: %lu\n", dwServiceCount); - - for (; - ServiceEntry != &ServiceListHead; - ServiceEntry = ServiceEntry->Flink) - { - CurrentService = CONTAINING_RECORD(ServiceEntry, - SERVICE, - ServiceListEntry); - - if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) - continue; - - dwState = SERVICE_ACTIVE; - if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) - dwState = SERVICE_INACTIVE; - - if ((dwState & dwServiceState) == 0) - continue; - - dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) + - ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + - ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR))); - - dwError = ERROR_MORE_DATA; - } - - DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize); - - if (lpResumeHandle) - *lpResumeHandle = dwLastResumeCount; - - *lpServicesReturned = dwServiceCount; - *pcbBytesNeeded = dwRequiredSize; - - lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer; - lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer + - dwServiceCount * sizeof(ENUM_SERVICE_STATUSW)); - - dwRequiredSize = 0; - for (ServiceEntry = &lpService->ServiceListEntry; - ServiceEntry != &ServiceListHead; - ServiceEntry = ServiceEntry->Flink) - { - CurrentService = CONTAINING_RECORD(ServiceEntry, - SERVICE, - ServiceListEntry); - - if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) - continue; - - dwState = SERVICE_ACTIVE; - if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) - dwState = SERVICE_INACTIVE; - - if ((dwState & dwServiceState) == 0) - continue; - - dwSize = sizeof(ENUM_SERVICE_STATUSW) + - ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + - ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)); - - if (dwRequiredSize + dwSize > dwBufSize) - break; - - /* Copy the service name */ - wcscpy(lpStringPtr, CurrentService->lpServiceName); - lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); - lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1); - - /* Copy the display name */ - wcscpy(lpStringPtr, CurrentService->lpDisplayName); - lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); - lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1); - - /* Copy the status information */ - memcpy(&lpStatusPtr->ServiceStatus, - &CurrentService->Status, - sizeof(SERVICE_STATUS)); - - lpStatusPtr++; - dwRequiredSize += dwSize; - } - - if (dwError == ERROR_SUCCESS) - { - *pcbBytesNeeded = 0; - if (lpResumeHandle) *lpResumeHandle = 0; - } - -Done:; - /* Unlock the service database */ - ScmUnlockDatabase(); - - DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 15 */ -DWORD ROpenSCManagerW( - LPWSTR lpMachineName, - LPWSTR lpDatabaseName, - DWORD dwDesiredAccess, - LPSC_RPC_HANDLE lpScHandle) -{ - DWORD dwError; - SC_HANDLE hHandle; - - DPRINT("ROpenSCManagerW() called\n"); - DPRINT("lpMachineName = %p\n", lpMachineName); - DPRINT("lpMachineName: %S\n", lpMachineName); - DPRINT("lpDataBaseName = %p\n", lpDatabaseName); - DPRINT("lpDataBaseName: %S\n", lpDatabaseName); - DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - if (!lpScHandle) - return ERROR_INVALID_PARAMETER; - - dwError = ScmCreateManagerHandle(lpDatabaseName, - &hHandle); - if (dwError != ERROR_SUCCESS) - { - DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError); - return dwError; - } - - /* Check the desired access */ - dwError = ScmCheckAccess(hHandle, - dwDesiredAccess | SC_MANAGER_CONNECT); - if (dwError != ERROR_SUCCESS) - { - DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError); - HeapFree(GetProcessHeap(), 0, hHandle); - return dwError; - } - - *lpScHandle = (SC_RPC_HANDLE)hHandle; - DPRINT("*hScm = %p\n", *lpScHandle); - - DPRINT("ROpenSCManagerW() done\n"); - - return ERROR_SUCCESS; -} - - -/* Function 16 */ -DWORD ROpenServiceW( - SC_RPC_HANDLE hSCManager, - LPWSTR lpServiceName, - DWORD dwDesiredAccess, - LPSC_RPC_HANDLE lpServiceHandle) -{ - PSERVICE lpService; - PMANAGER_HANDLE hManager; - SC_HANDLE hHandle; - DWORD dwError = ERROR_SUCCESS; - - DPRINT("ROpenServiceW() called\n"); - DPRINT("hSCManager = %p\n", hSCManager); - DPRINT("lpServiceName = %p\n", lpServiceName); - DPRINT("lpServiceName: %S\n", lpServiceName); - DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hManager = ScmGetServiceManagerFromHandle(hSCManager); - if (hManager == NULL) - { - DPRINT1("Invalid service manager handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!lpServiceHandle) - return ERROR_INVALID_PARAMETER; - - if (!lpServiceName) - return ERROR_INVALID_ADDRESS; - - /* Lock the service database exclusive */ - ScmLockDatabaseExclusive(); - - /* Get service database entry */ - lpService = ScmGetServiceEntryByName(lpServiceName); - if (lpService == NULL) - { - DPRINT("Could not find a service!\n"); - dwError = ERROR_SERVICE_DOES_NOT_EXIST; - goto Done; - } - - /* Create a service handle */ - dwError = ScmCreateServiceHandle(lpService, - &hHandle); - if (dwError != ERROR_SUCCESS) - { - DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError); - goto Done; - } - - /* Check the desired access */ - dwError = ScmCheckAccess(hHandle, - dwDesiredAccess); - if (dwError != ERROR_SUCCESS) - { - DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError); - HeapFree(GetProcessHeap(), 0, hHandle); - goto Done; - } - - lpService->dwRefCount++; - DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount); - - *lpServiceHandle = (SC_RPC_HANDLE)hHandle; - DPRINT("*hService = %p\n", *lpServiceHandle); - -Done:; - /* Unlock the service database */ - ScmUnlockDatabase(); - - DPRINT("ROpenServiceW() done\n"); - - return dwError; -} - - -/* Function 17 */ -DWORD RQueryServiceConfigW( - SC_RPC_HANDLE hService, - LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig, - DWORD cbBufSize, - LPBOUNDED_DWORD_8K pcbBytesNeeded) -{ - LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf; - DWORD dwError = ERROR_SUCCESS; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - HKEY hServiceKey = NULL; - LPWSTR lpImagePath = NULL; - LPWSTR lpServiceStartName = NULL; - LPWSTR lpDependencies = NULL; - DWORD dwDependenciesLength = 0; - DWORD dwRequiredSize; - LPQUERY_SERVICE_CONFIGW lpConfig = NULL; - WCHAR lpEmptyString[] = {0,0}; - LPWSTR lpStr; - - DPRINT("RQueryServiceConfigW() called\n"); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_QUERY_CONFIG)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database shared */ - ScmLockDatabaseShared(); - - dwError = ScmOpenServiceKey(lpService->lpServiceName, - KEY_READ, - &hServiceKey); - if (dwError != ERROR_SUCCESS) - goto Done; - - /* Read the image path */ - dwError = ScmReadString(hServiceKey, - L"ImagePath", - &lpImagePath); - if (dwError != ERROR_SUCCESS) - goto Done; - - /* Read the service start name */ - ScmReadString(hServiceKey, - L"ObjectName", - &lpServiceStartName); - - /* Read the dependencies */ - ScmReadDependencies(hServiceKey, - &lpDependencies, - &dwDependenciesLength); - - dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW); - - if (lpImagePath != NULL) - dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR)); - else - dwRequiredSize += 2 * sizeof(WCHAR); - - if (lpService->lpGroup != NULL) - dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR)); - else - dwRequiredSize += 2 * sizeof(WCHAR); - - if (lpDependencies != NULL) - dwRequiredSize += dwDependenciesLength * sizeof(WCHAR); - else - dwRequiredSize += 2 * sizeof(WCHAR); - - if (lpServiceStartName != NULL) - dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR)); - else - dwRequiredSize += 2 * sizeof(WCHAR); - - if (lpService->lpDisplayName != NULL) - dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR)); - else - dwRequiredSize += 2 * sizeof(WCHAR); - - if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize) - { - dwError = ERROR_INSUFFICIENT_BUFFER; - } - else - { - lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig; - lpConfig->dwServiceType = lpService->Status.dwServiceType; - lpConfig->dwStartType = lpService->dwStartType; - lpConfig->dwErrorControl = lpService->dwErrorControl; - lpConfig->dwTagId = lpService->dwTag; - - lpStr = (LPWSTR)(lpConfig + 1); - - /* Append the image path */ - if (lpImagePath != NULL) - { - wcscpy(lpStr, lpImagePath); - } - else - { - wcscpy(lpStr, lpEmptyString); - } - - lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); - lpStr += (wcslen(lpStr) + 1); - - /* Append the group name */ - if (lpService->lpGroup != NULL) - { - wcscpy(lpStr, lpService->lpGroup->lpGroupName); - } - else - { - wcscpy(lpStr, lpEmptyString); - } - - lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); - lpStr += (wcslen(lpStr) + 1); - - /* Append Dependencies */ - if (lpDependencies != NULL) - { - memcpy(lpStr, - lpDependencies, - dwDependenciesLength * sizeof(WCHAR)); - } - else - { - wcscpy(lpStr, lpEmptyString); - } - - lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); - if (lpDependencies != NULL) - lpStr += dwDependenciesLength * sizeof(WCHAR); - else - lpStr += (wcslen(lpStr) + 1); - - /* Append the service start name */ - if (lpServiceStartName != NULL) - { - wcscpy(lpStr, lpServiceStartName); - } - else - { - wcscpy(lpStr, lpEmptyString); - } - - lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); - lpStr += (wcslen(lpStr) + 1); - - /* Append the display name */ - if (lpService->lpDisplayName != NULL) - { - wcscpy(lpStr, lpService->lpDisplayName); - } - else - { - wcscpy(lpStr, lpEmptyString); - } - - lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); - } - - if (pcbBytesNeeded != NULL) - *pcbBytesNeeded = dwRequiredSize; - -Done:; - /* Unlock the service database */ - ScmUnlockDatabase(); - - if (lpImagePath != NULL) - HeapFree(GetProcessHeap(), 0, lpImagePath); - - if (lpServiceStartName != NULL) - HeapFree(GetProcessHeap(), 0, lpServiceStartName); - - if (lpDependencies != NULL) - HeapFree(GetProcessHeap(), 0, lpDependencies); - - if (hServiceKey != NULL) - RegCloseKey(hServiceKey); - - DPRINT("RQueryServiceConfigW() done\n"); - - return dwError; -} - - -/* Function 18 */ -DWORD RQueryServiceLockStatusW( - SC_RPC_HANDLE hSCManager, - LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus, - DWORD cbBufSize, - LPBOUNDED_DWORD_4K pcbBytesNeeded) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 19 */ -DWORD RStartServiceW( - SC_RPC_HANDLE hService, - DWORD argc, - LPSTRING_PTRSW argv) -{ - DWORD dwError = ERROR_SUCCESS; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - DWORD i; - - DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv); - DPRINT(" argc: %lu\n", argc); - if (argv != NULL) - { - for (i = 0; i < argc; i++) - { - DPRINT(" argv[%lu]: %S\n", i, argv[i]); - } - } - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_START)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - if (lpService->dwStartType == SERVICE_DISABLED) - return ERROR_SERVICE_DISABLED; - - if (lpService->bDeleted) - return ERROR_SERVICE_MARKED_FOR_DELETE; - - /* Start the service */ - dwError = ScmStartService(lpService, argc, (LPWSTR*)argv); - - return dwError; -} - - -/* Function 20 */ -DWORD RGetServiceDisplayNameW( - SC_RPC_HANDLE hSCManager, - LPCWSTR lpServiceName, - LPWSTR lpDisplayName, - DWORD *lpcchBuffer) -{ -// PMANAGER_HANDLE hManager; - PSERVICE lpService; - DWORD dwLength; - DWORD dwError; - - DPRINT("RGetServiceDisplayNameW() called\n"); - DPRINT("hSCManager = %p\n", hSCManager); - DPRINT("lpServiceName: %S\n", lpServiceName); - DPRINT("lpDisplayName: %p\n", lpDisplayName); - DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); - -// hManager = (PMANAGER_HANDLE)hSCManager; -// if (hManager->Handle.Tag != MANAGER_TAG) -// { -// DPRINT("Invalid manager handle!\n"); -// return ERROR_INVALID_HANDLE; -// } - - /* Get service database entry */ - lpService = ScmGetServiceEntryByName(lpServiceName); - if (lpService == NULL) - { - DPRINT("Could not find a service!\n"); - - /* If the service could not be found and lpcchBuffer is less than 2, windows - puts null in lpDisplayName and puts 2 in lpcchBuffer */ - if (*lpcchBuffer < 2) - { - *lpcchBuffer = 2; - if (lpDisplayName != NULL) - { - *lpDisplayName = '\0'; - } - } - - return ERROR_SERVICE_DOES_NOT_EXIST; - } - - if (!lpService->lpDisplayName) - { - dwLength = wcslen(lpService->lpServiceName); - - if (lpDisplayName != NULL && - *lpcchBuffer > dwLength) - { - wcscpy(lpDisplayName, lpService->lpServiceName); - } - } - else - { - dwLength = wcslen(lpService->lpDisplayName); - - if (lpDisplayName != NULL && - *lpcchBuffer > dwLength) - { - wcscpy(lpDisplayName, lpService->lpDisplayName); - } - } - - dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER; - - *lpcchBuffer = dwLength; - - return dwError; -} - - -/* Function 21 */ -DWORD RGetServiceKeyNameW( - SC_RPC_HANDLE hSCManager, - LPCWSTR lpDisplayName, - LPWSTR lpServiceName, - DWORD *lpcchBuffer) -{ -// PMANAGER_HANDLE hManager; - PSERVICE lpService; - DWORD dwLength; - DWORD dwError; - - DPRINT("RGetServiceKeyNameW() called\n"); - DPRINT("hSCManager = %p\n", hSCManager); - DPRINT("lpDisplayName: %S\n", lpDisplayName); - DPRINT("lpServiceName: %p\n", lpServiceName); - DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); - -// hManager = (PMANAGER_HANDLE)hSCManager; -// if (hManager->Handle.Tag != MANAGER_TAG) -// { -// DPRINT("Invalid manager handle!\n"); -// return ERROR_INVALID_HANDLE; -// } - - /* Get service database entry */ - lpService = ScmGetServiceEntryByDisplayName(lpDisplayName); - if (lpService == NULL) - { - DPRINT("Could not find a service!\n"); - - /* If the service could not be found and lpcchBuffer is less than 2, windows - puts null in lpDisplayName and puts 2 in lpcchBuffer */ - if (*lpcchBuffer < 2) - { - *lpcchBuffer = 2; - if (lpServiceName != NULL) - { - *lpServiceName = '\0'; - } - } - - return ERROR_SERVICE_DOES_NOT_EXIST; - } - - dwLength = wcslen(lpService->lpServiceName); - - if (lpServiceName != NULL && - *lpcchBuffer > dwLength) - { - wcscpy(lpServiceName, lpService->lpServiceName); - *lpcchBuffer = dwLength; - return ERROR_SUCCESS; - } - - dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER; - - *lpcchBuffer = dwLength; - - return dwError; -} - - -/* Function 22 */ -DWORD RI_ScSetServiceBitsA( - RPC_SERVICE_STATUS_HANDLE hServiceStatus, - DWORD dwServiceBits, - int bSetBitsOn, - int bUpdateImmediately, - char *lpString) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 23 */ -DWORD RChangeServiceConfigA( - SC_RPC_HANDLE hService, - DWORD dwServiceType, - DWORD dwStartType, - DWORD dwErrorControl, - LPSTR lpBinaryPathName, - LPSTR lpLoadOrderGroup, - LPDWORD lpdwTagId, - LPSTR lpDependencies, - DWORD dwDependSize, - LPSTR lpServiceStartName, - LPBYTE lpPassword, - DWORD dwPwSize, - LPSTR lpDisplayName) -{ - DWORD dwError = ERROR_SUCCESS; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - HKEY hServiceKey = NULL; - LPWSTR lpDisplayNameW = NULL; - LPWSTR lpBinaryPathNameW = NULL; - LPWSTR lpCanonicalImagePathW = NULL; - LPWSTR lpLoadOrderGroupW = NULL; - LPWSTR lpDependenciesW = NULL; - // LPWSTR lpPasswordW = NULL; - - DPRINT("RChangeServiceConfigA() called\n"); - DPRINT("dwServiceType = %lu\n", dwServiceType); - DPRINT("dwStartType = %lu\n", dwStartType); - DPRINT("dwErrorControl = %lu\n", dwErrorControl); - DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName); - DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup); - DPRINT("lpDisplayName = %s\n", lpDisplayName); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_CHANGE_CONFIG)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database exclusively */ - ScmLockDatabaseExclusive(); - - if (lpService->bDeleted) - { - DPRINT("The service has already been marked for delete!\n"); - dwError = ERROR_SERVICE_MARKED_FOR_DELETE; - goto done; - } - - /* Open the service key */ - dwError = ScmOpenServiceKey(lpService->szServiceName, - KEY_SET_VALUE, - &hServiceKey); - if (dwError != ERROR_SUCCESS) - goto done; - - /* Write service data to the registry */ - - if (lpDisplayName != NULL && *lpDisplayName != 0) - { - /* Set the display name */ - lpDisplayNameW = HeapAlloc(GetProcessHeap(), - 0, - (strlen(lpDisplayName) + 1) * sizeof(WCHAR)); - if (lpDisplayNameW == NULL) - { - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto done; - } - - MultiByteToWideChar(CP_ACP, - 0, - lpDisplayName, - -1, - lpDisplayNameW, - strlen(lpDisplayName) + 1); - - RegSetValueExW(hServiceKey, - L"DisplayName", - 0, - REG_SZ, - (LPBYTE)lpDisplayNameW, - (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR)); - - /* Update lpService->lpDisplayName */ - if (lpService->lpDisplayName) - HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName); - - lpService->lpDisplayName = lpDisplayNameW; - } - - if (dwServiceType != SERVICE_NO_CHANGE) - { - /* Set the service type */ - dwError = RegSetValueExW(hServiceKey, - L"Type", - 0, - REG_DWORD, - (LPBYTE)&dwServiceType, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - lpService->Status.dwServiceType = dwServiceType; - } - - if (dwStartType != SERVICE_NO_CHANGE) - { - /* Set the start value */ - dwError = RegSetValueExW(hServiceKey, - L"Start", - 0, - REG_DWORD, - (LPBYTE)&dwStartType, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - lpService->dwStartType = dwStartType; - } - - if (dwErrorControl != SERVICE_NO_CHANGE) - { - /* Set the error control value */ - dwError = RegSetValueExW(hServiceKey, - L"ErrorControl", - 0, - REG_DWORD, - (LPBYTE)&dwErrorControl, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - lpService->dwErrorControl = dwErrorControl; - } - - if (lpBinaryPathName != NULL && *lpBinaryPathName != 0) - { - /* Set the image path */ - lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), - 0, - (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR)); - if (lpBinaryPathNameW == NULL) - { - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto done; - } - - MultiByteToWideChar(CP_ACP, - 0, - lpBinaryPathName, - -1, - lpBinaryPathNameW, - strlen(lpBinaryPathName) + 1); - - if (lpService->Status.dwServiceType & SERVICE_DRIVER) - { - dwError = ScmCanonDriverImagePath(lpService->dwStartType, - lpBinaryPathNameW, - &lpCanonicalImagePathW); - - HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW); - - if (dwError != ERROR_SUCCESS) - goto done; - - lpBinaryPathNameW = lpCanonicalImagePathW; - } - - dwError = RegSetValueExW(hServiceKey, - L"ImagePath", - 0, - REG_EXPAND_SZ, - (LPBYTE)lpBinaryPathNameW, - (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR)); - - HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW); - - if (dwError != ERROR_SUCCESS) - goto done; - } - - /* Set the group name */ - if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) - { - lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), - 0, - (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)); - if (lpLoadOrderGroupW == NULL) - { - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto done; - } - - MultiByteToWideChar(CP_ACP, - 0, - lpLoadOrderGroup, - -1, - lpLoadOrderGroupW, - strlen(lpLoadOrderGroup) + 1); - - dwError = RegSetValueExW(hServiceKey, - L"Group", - 0, - REG_SZ, - (LPBYTE)lpLoadOrderGroupW, - (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR)); - if (dwError != ERROR_SUCCESS) - { - HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW); - goto done; - } - - dwError = ScmSetServiceGroup(lpService, - lpLoadOrderGroupW); - - HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW); - - if (dwError != ERROR_SUCCESS) - goto done; - } - - if (lpdwTagId != NULL) - { - dwError = ScmAssignNewTag(lpService); - if (dwError != ERROR_SUCCESS) - goto done; - - dwError = RegSetValueExW(hServiceKey, - L"Tag", - 0, - REG_DWORD, - (LPBYTE)&lpService->dwTag, - sizeof(DWORD)); - if (dwError != ERROR_SUCCESS) - goto done; - - *lpdwTagId = lpService->dwTag; - } - - /* Write dependencies */ - if (lpDependencies != NULL && *lpDependencies != 0) - { - lpDependenciesW = HeapAlloc(GetProcessHeap(), - 0, - (strlen(lpDependencies) + 1) * sizeof(WCHAR)); - if (lpDependenciesW == NULL) - { - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto done; - } - - MultiByteToWideChar(CP_ACP, - 0, - lpDependencies, - dwDependSize, - lpDependenciesW, - strlen(lpDependencies) + 1); - - dwError = ScmWriteDependencies(hServiceKey, - (LPWSTR)lpDependenciesW, - dwDependSize); - - HeapFree(GetProcessHeap(), 0, lpDependenciesW); - } - - if (lpPassword != NULL) - { - /* FIXME: Write password */ - } - -done: - /* Unlock the service database */ - ScmUnlockDatabase(); - - if (hServiceKey != NULL) - RegCloseKey(hServiceKey); - - DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 24 */ -DWORD RCreateServiceA( - SC_RPC_HANDLE hSCManager, - LPSTR lpServiceName, - LPSTR lpDisplayName, - DWORD dwDesiredAccess, - DWORD dwServiceType, - DWORD dwStartType, - DWORD dwErrorControl, - LPSTR lpBinaryPathName, - LPSTR lpLoadOrderGroup, - LPDWORD lpdwTagId, - LPBYTE lpDependencies, - DWORD dwDependSize, - LPSTR lpServiceStartName, - LPBYTE lpPassword, - DWORD dwPwSize, - LPSC_RPC_HANDLE lpServiceHandle) -{ - DWORD dwError = ERROR_SUCCESS; - LPWSTR lpServiceNameW = NULL; - LPWSTR lpDisplayNameW = NULL; - LPWSTR lpBinaryPathNameW = NULL; - LPWSTR lpLoadOrderGroupW = NULL; - LPWSTR lpDependenciesW = NULL; - LPWSTR lpServiceStartNameW = NULL; - DWORD dwDependenciesLength = 0; - DWORD dwLength; - int len; - LPCSTR lpStr; - - if (lpServiceName) - { - len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0); - lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (!lpServiceNameW) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len); - } - - if (lpDisplayName) - { - len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0); - lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (!lpDisplayNameW) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len); - } - - if (lpBinaryPathName) - { - len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0); - lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (!lpBinaryPathNameW) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len); - } - - if (lpLoadOrderGroup) - { - len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0); - lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (!lpLoadOrderGroupW) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len); - } - - if (lpDependencies) - { - lpStr = (LPCSTR)lpDependencies; - while (*lpStr) - { - dwLength = strlen(lpStr) + 1; - dwDependenciesLength += dwLength; - lpStr = lpStr + dwLength; - } - dwDependenciesLength++; - - lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR)); - if (!lpDependenciesW) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength); - } - - if (lpServiceStartName) - { - len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0); - lpServiceStartNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (!lpServiceStartNameW) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len); - } - - dwError = RCreateServiceW(hSCManager, - lpServiceNameW, - lpDisplayNameW, - dwDesiredAccess, - dwServiceType, - dwStartType, - dwErrorControl, - lpBinaryPathNameW, - lpLoadOrderGroupW, - lpdwTagId, - (LPBYTE)lpDependenciesW, - dwDependenciesLength, - lpServiceStartNameW, - lpPassword, - dwPwSize, - lpServiceHandle); - -cleanup: - if (lpServiceNameW !=NULL) - HeapFree(GetProcessHeap(), 0, lpServiceNameW); - - if (lpDisplayNameW != NULL) - HeapFree(GetProcessHeap(), 0, lpDisplayNameW); - - if (lpBinaryPathNameW != NULL) - HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW); - - if (lpLoadOrderGroupW != NULL) - HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW); - - if (lpDependenciesW != NULL) - HeapFree(GetProcessHeap(), 0, lpDependenciesW); - - if (lpServiceStartNameW != NULL) - HeapFree(GetProcessHeap(), 0, lpServiceStartNameW); - - return dwError; -} - - -/* Function 25 */ -DWORD REnumDependentServicesA( - SC_RPC_HANDLE hService, - DWORD dwServiceState, - LPBYTE lpServices, - DWORD cbBufSize, - LPBOUNDED_DWORD_256K pcbBytesNeeded, - LPBOUNDED_DWORD_256K lpServicesReturned) -{ - DWORD dwError = ERROR_SUCCESS; - DWORD dwServicesReturned = 0; - DWORD dwServiceCount; - HKEY hServicesKey = NULL; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - PSERVICE *lpServicesArray = NULL; - LPENUM_SERVICE_STATUSA lpServicesPtr = NULL; - LPSTR lpStr; - - *pcbBytesNeeded = 0; - *lpServicesReturned = 0; - - DPRINT("REnumDependentServicesA() called\n"); - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - lpService = hSvc->ServiceEntry; - - /* Check access rights */ - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SC_MANAGER_ENUMERATE_SERVICE)) - { - DPRINT("Insufficient access rights! 0x%lx\n", - hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - /* Open the Services Reg key */ - dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"System\\CurrentControlSet\\Services", - 0, - KEY_READ, - &hServicesKey); - - if (dwError != ERROR_SUCCESS) - return dwError; - - /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for - both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded - are the same for both. Verified in WINXP. */ - - /* First determine the bytes needed and get the number of dependent services*/ - dwError = Int_EnumDependentServicesW(hServicesKey, - lpService, - dwServiceState, - NULL, - pcbBytesNeeded, - &dwServicesReturned); - if (dwError != ERROR_SUCCESS) - goto Done; - - /* If buffer size is less than the bytes needed or pointer is null*/ - if ((!lpServices) || (cbBufSize < *pcbBytesNeeded)) - { - dwError = ERROR_MORE_DATA; - goto Done; - } - - /* Allocate memory for array of service pointers */ - lpServicesArray = HeapAlloc(GetProcessHeap(), - 0, - (dwServicesReturned + 1) * sizeof(PSERVICE)); - if (!lpServicesArray) - { - DPRINT("Could not allocate a buffer!!\n"); - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto Done; - } - - dwServicesReturned = 0; - *pcbBytesNeeded = 0; - - dwError = Int_EnumDependentServicesW(hServicesKey, - lpService, - dwServiceState, - lpServicesArray, - pcbBytesNeeded, - &dwServicesReturned); - if (dwError != ERROR_SUCCESS) - { - goto Done; - } - - lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices; - lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA))); - - /* Copy EnumDepenedentService to Buffer */ - for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++) - { - lpService = lpServicesArray[dwServiceCount]; - - /* Copy the status info */ - memcpy(&lpServicesPtr->ServiceStatus, - &lpService->Status, - sizeof(SERVICE_STATUS)); - - /* Copy display name */ - WideCharToMultiByte(CP_ACP, - 0, - lpService->lpDisplayName, - -1, - lpStr, - wcslen(lpService->lpDisplayName), - 0, - 0); - lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); - lpStr += strlen(lpStr) + 1; - - /* Copy service name */ - WideCharToMultiByte(CP_ACP, - 0, - lpService->lpServiceName, - -1, - lpStr, - wcslen(lpService->lpServiceName), - 0, - 0); - lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); - lpStr += strlen(lpStr) + 1; - - lpServicesPtr ++; - } - - *lpServicesReturned = dwServicesReturned; - -Done: - if (lpServicesArray) - HeapFree(GetProcessHeap(), 0, lpServicesArray); - - RegCloseKey(hServicesKey); - - DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 26 */ -DWORD REnumServicesStatusA( - SC_RPC_HANDLE hSCManager, - DWORD dwServiceType, - DWORD dwServiceState, - LPBYTE lpBuffer, - DWORD dwBufSize, - LPBOUNDED_DWORD_256K pcbBytesNeeded, - LPBOUNDED_DWORD_256K lpServicesReturned, - LPBOUNDED_DWORD_256K lpResumeHandle) -{ - LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL; - LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL; - LPWSTR lpStringPtrW; - LPSTR lpStringPtrA; - DWORD dwError; - DWORD dwServiceCount; - - DPRINT("REnumServicesStatusA() called\n"); - - if ((dwBufSize > 0) && (lpBuffer)) - { - lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize); - if (!lpStatusPtrW) - { - DPRINT("Failed to allocate buffer!\n"); - return ERROR_NOT_ENOUGH_MEMORY; - } - } - - dwError = REnumServicesStatusW(hSCManager, - dwServiceType, - dwServiceState, - (LPBYTE)lpStatusPtrW, - dwBufSize, - pcbBytesNeeded, - lpServicesReturned, - lpResumeHandle); - - /* if no services were returned then we are Done */ - if (*lpServicesReturned == 0) - goto Done; - - lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer; - lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer + - *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA)); - lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW + - *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW)); - - for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++) - { - /* Copy the service name */ - WideCharToMultiByte(CP_ACP, - 0, - lpStringPtrW, - -1, - lpStringPtrA, - wcslen(lpStringPtrW), - 0, - 0); - - lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); - lpStringPtrA += wcslen(lpStringPtrW) + 1; - lpStringPtrW += wcslen(lpStringPtrW) + 1; - - /* Copy the display name */ - WideCharToMultiByte(CP_ACP, - 0, - lpStringPtrW, - -1, - lpStringPtrA, - wcslen(lpStringPtrW), - 0, - 0); - - lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); - lpStringPtrA += wcslen(lpStringPtrW) + 1; - lpStringPtrW += wcslen(lpStringPtrW) + 1; - - /* Copy the status information */ - memcpy(&lpStatusPtrA->ServiceStatus, - &lpStatusPtrW->ServiceStatus, - sizeof(SERVICE_STATUS)); - - lpStatusPtrA++; - } - -Done:; - if (lpStatusPtrW) - HeapFree(GetProcessHeap(), 0, lpStatusPtrW); - - DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 27 */ -DWORD ROpenSCManagerA( - LPSTR lpMachineName, - LPSTR lpDatabaseName, - DWORD dwDesiredAccess, - LPSC_RPC_HANDLE lpScHandle) -{ - UNICODE_STRING MachineName; - UNICODE_STRING DatabaseName; - DWORD dwError; - - DPRINT("ROpenSCManagerA() called\n"); - - if (lpMachineName) - RtlCreateUnicodeStringFromAsciiz(&MachineName, - lpMachineName); - - if (lpDatabaseName) - RtlCreateUnicodeStringFromAsciiz(&DatabaseName, - lpDatabaseName); - - dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL, - lpDatabaseName ? DatabaseName.Buffer : NULL, - dwDesiredAccess, - lpScHandle); - - if (lpMachineName) - RtlFreeUnicodeString(&MachineName); - - if (lpDatabaseName) - RtlFreeUnicodeString(&DatabaseName); - - return dwError; -} - - -/* Function 28 */ -DWORD ROpenServiceA( - SC_RPC_HANDLE hSCManager, - LPSTR lpServiceName, - DWORD dwDesiredAccess, - LPSC_RPC_HANDLE lpServiceHandle) -{ - UNICODE_STRING ServiceName; - DWORD dwError; - - DPRINT("ROpenServiceA() called\n"); - - if (lpServiceName) - RtlCreateUnicodeStringFromAsciiz(&ServiceName, - lpServiceName); - - dwError = ROpenServiceW(hSCManager, - lpServiceName ? ServiceName.Buffer : NULL, - dwDesiredAccess, - lpServiceHandle); - - if (lpServiceName) - RtlFreeUnicodeString(&ServiceName); - - return dwError; -} - - -/* Function 29 */ -DWORD RQueryServiceConfigA( - SC_RPC_HANDLE hService, - LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig, - DWORD cbBufSize, - LPBOUNDED_DWORD_8K pcbBytesNeeded) -{ - LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf; - DWORD dwError = ERROR_SUCCESS; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - HKEY hServiceKey = NULL; - LPWSTR lpImagePath = NULL; - LPWSTR lpServiceStartName = NULL; - LPWSTR lpDependencies = NULL; - DWORD dwDependenciesLength = 0; - DWORD dwRequiredSize; - LPQUERY_SERVICE_CONFIGA lpConfig = NULL; - CHAR lpEmptyString[]={0,0}; - LPSTR lpStr; - - DPRINT("RQueryServiceConfigA() called\n"); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_QUERY_CONFIG)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database shared */ - ScmLockDatabaseShared(); - - dwError = ScmOpenServiceKey(lpService->lpServiceName, - KEY_READ, - &hServiceKey); - if (dwError != ERROR_SUCCESS) - goto Done; - - /* Read the image path */ - dwError = ScmReadString(hServiceKey, - L"ImagePath", - &lpImagePath); - if (dwError != ERROR_SUCCESS) - goto Done; - - /* Read the service start name */ - ScmReadString(hServiceKey, - L"ObjectName", - &lpServiceStartName); - - /* Read the dependencies */ - ScmReadDependencies(hServiceKey, - &lpDependencies, - &dwDependenciesLength); - - dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW); - - if (lpImagePath != NULL) - dwRequiredSize += wcslen(lpImagePath) + 1; - else - dwRequiredSize += 2; - - if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL)) - dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1; - else - dwRequiredSize += 2; - - /* Add Dependencies length */ - if (lpDependencies != NULL) - dwRequiredSize += dwDependenciesLength; - else - dwRequiredSize += 2; - - if (lpServiceStartName != NULL) - dwRequiredSize += wcslen(lpServiceStartName) + 1; - else - dwRequiredSize += 2; - - if (lpService->lpDisplayName != NULL) - dwRequiredSize += wcslen(lpService->lpDisplayName) + 1; - else - dwRequiredSize += 2; - - if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize) - { - dwError = ERROR_INSUFFICIENT_BUFFER; - } - else - { - lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig; - lpConfig->dwServiceType = lpService->Status.dwServiceType; - lpConfig->dwStartType = lpService->dwStartType; - lpConfig->dwErrorControl = lpService->dwErrorControl; - lpConfig->dwTagId = lpService->dwTag; - - lpStr = (LPSTR)(lpServiceConfig + 1); - - /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings. - Verified in WINXP*/ - - if (lpImagePath) - { - WideCharToMultiByte(CP_ACP, - 0, - lpImagePath, - -1, - lpStr, - wcslen(lpImagePath) + 1, - 0, - 0); - } - else - { - strcpy(lpStr, lpEmptyString); - } - - lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); - lpStr += (strlen((LPSTR)lpStr) + 1); - - if (lpService->lpGroup && lpService->lpGroup->lpGroupName) - { - WideCharToMultiByte(CP_ACP, - 0, - lpService->lpGroup->lpGroupName, - -1, - lpStr, - wcslen(lpService->lpGroup->lpGroupName) + 1, - 0, - 0); - } - else - { - strcpy(lpStr, lpEmptyString); - } - - lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); - lpStr += (strlen(lpStr) + 1); - - /* Append Dependencies */ - if (lpDependencies) - { - WideCharToMultiByte(CP_ACP, - 0, - lpDependencies, - dwDependenciesLength, - lpStr, - dwDependenciesLength, - 0, - 0); - } - else - { - strcpy(lpStr, lpEmptyString); - } - - lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); - if (lpDependencies) - lpStr += dwDependenciesLength; - else - lpStr += (strlen(lpStr) + 1); - - if (lpServiceStartName) - { - WideCharToMultiByte(CP_ACP, - 0, - lpServiceStartName, - -1, - lpStr, - wcslen(lpServiceStartName) + 1, - 0, - 0); - } - else - { - strcpy(lpStr, lpEmptyString); - } - - lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); - lpStr += (strlen(lpStr) + 1); - - if (lpService->lpDisplayName) - { - WideCharToMultiByte(CP_ACP, - 0, - lpService->lpDisplayName, - -1, - lpStr, - wcslen(lpService->lpDisplayName) + 1, - 0, - 0); - } - else - { - strcpy(lpStr, lpEmptyString); - } - - lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); - } - - if (pcbBytesNeeded != NULL) - *pcbBytesNeeded = dwRequiredSize; - -Done:; - /* Unlock the service database */ - ScmUnlockDatabase(); - - if (lpImagePath != NULL) - HeapFree(GetProcessHeap(), 0, lpImagePath); - - if (lpServiceStartName != NULL) - HeapFree(GetProcessHeap(), 0, lpServiceStartName); - - if (lpDependencies != NULL) - HeapFree(GetProcessHeap(), 0, lpDependencies); - - if (hServiceKey != NULL) - RegCloseKey(hServiceKey); - - DPRINT("RQueryServiceConfigA() done\n"); - - return dwError; -} - - -/* Function 30 */ -DWORD RQueryServiceLockStatusA( - SC_RPC_HANDLE hSCManager, - LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus, - DWORD cbBufSize, - LPBOUNDED_DWORD_4K pcbBytesNeeded) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 31 */ -DWORD RStartServiceA( - SC_RPC_HANDLE hService, - DWORD argc, - LPSTRING_PTRSA argv) -{ - DWORD dwError = ERROR_SUCCESS; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - LPWSTR *lpVector = NULL; - DWORD i; - DWORD dwLength; - - DPRINT("RStartServiceA() called\n"); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_START)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - if (lpService->dwStartType == SERVICE_DISABLED) - return ERROR_SERVICE_DISABLED; - - if (lpService->bDeleted) - return ERROR_SERVICE_MARKED_FOR_DELETE; - - /* Build a Unicode argument vector */ - if (argc > 0) - { - lpVector = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - argc * sizeof(LPWSTR)); - if (lpVector == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - for (i = 0; i < argc; i++) - { - dwLength = MultiByteToWideChar(CP_ACP, - 0, - ((LPSTR*)argv)[i], - -1, - NULL, - 0); - - lpVector[i] = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - dwLength * sizeof(WCHAR)); - if (lpVector[i] == NULL) - { - dwError = ERROR_NOT_ENOUGH_MEMORY; - goto done; - } - - MultiByteToWideChar(CP_ACP, - 0, - ((LPSTR*)argv)[i], - -1, - lpVector[i], - dwLength); - } - } - - /* Start the service */ - dwError = ScmStartService(lpService, argc, lpVector); - -done: - /* Free the Unicode argument vector */ - if (lpVector != NULL) - { - for (i = 0; i < argc; i++) - { - if (lpVector[i] != NULL) - HeapFree(GetProcessHeap(), 0, lpVector[i]); - } - HeapFree(GetProcessHeap(), 0, lpVector); - } - - return dwError; -} - - -/* Function 32 */ -DWORD RGetServiceDisplayNameA( - SC_RPC_HANDLE hSCManager, - LPCSTR lpServiceName, - LPSTR lpDisplayName, - LPBOUNDED_DWORD_4K lpcchBuffer) -{ -// PMANAGER_HANDLE hManager; - PSERVICE lpService = NULL; - DWORD dwLength; - DWORD dwError; - LPWSTR lpServiceNameW; - - DPRINT("RGetServiceDisplayNameA() called\n"); - DPRINT("hSCManager = %p\n", hSCManager); - DPRINT("lpServiceName: %s\n", lpServiceName); - DPRINT("lpDisplayName: %p\n", lpDisplayName); - DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); - -// hManager = (PMANAGER_HANDLE)hSCManager; -// if (hManager->Handle.Tag != MANAGER_TAG) -// { -// DPRINT("Invalid manager handle!\n"); -// return ERROR_INVALID_HANDLE; -// } - - if (lpServiceName != NULL) - { - dwLength = strlen(lpServiceName) + 1; - lpServiceNameW = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - dwLength * sizeof(WCHAR)); - if (!lpServiceNameW) - return ERROR_NOT_ENOUGH_MEMORY; - - MultiByteToWideChar(CP_ACP, - 0, - lpServiceName, - -1, - lpServiceNameW, - dwLength); - - lpService = ScmGetServiceEntryByName(lpServiceNameW); - - HeapFree(GetProcessHeap(), 0, lpServiceNameW); - } - - if (lpService == NULL) - { - DPRINT("Could not find a service!\n"); - - /* If the service could not be found and lpcchBuffer is 0, windows - puts null in lpDisplayName and puts 1 in lpcchBuffer */ - if (*lpcchBuffer == 0) - { - *lpcchBuffer = 1; - if (lpDisplayName != NULL) - { - *lpDisplayName = '\0'; - } - } - return ERROR_SERVICE_DOES_NOT_EXIST; - } - - if (!lpService->lpDisplayName) - { - dwLength = wcslen(lpService->lpServiceName); - if (lpDisplayName != NULL && - *lpcchBuffer > dwLength) - { - WideCharToMultiByte(CP_ACP, - 0, - lpService->lpServiceName, - wcslen(lpService->lpServiceName), - lpDisplayName, - dwLength + 1, - NULL, - NULL); - return ERROR_SUCCESS; - } - } - else - { - dwLength = wcslen(lpService->lpDisplayName); - if (lpDisplayName != NULL && - *lpcchBuffer > dwLength) - { - WideCharToMultiByte(CP_ACP, - 0, - lpService->lpDisplayName, - wcslen(lpService->lpDisplayName), - lpDisplayName, - dwLength + 1, - NULL, - NULL); - return ERROR_SUCCESS; - } - } - - dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER; - - *lpcchBuffer = dwLength * 2; - - return dwError; -} - - -/* Function 33 */ -DWORD RGetServiceKeyNameA( - SC_RPC_HANDLE hSCManager, - LPCSTR lpDisplayName, - LPSTR lpServiceName, - LPBOUNDED_DWORD_4K lpcchBuffer) -{ - PSERVICE lpService; - DWORD dwLength; - DWORD dwError; - LPWSTR lpDisplayNameW; - - DPRINT("RGetServiceKeyNameA() called\n"); - DPRINT("hSCManager = %p\n", hSCManager); - DPRINT("lpDisplayName: %s\n", lpDisplayName); - DPRINT("lpServiceName: %p\n", lpServiceName); - DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); - - dwLength = strlen(lpDisplayName) + 1; - lpDisplayNameW = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - dwLength * sizeof(WCHAR)); - if (!lpDisplayNameW) - return ERROR_NOT_ENOUGH_MEMORY; - - MultiByteToWideChar(CP_ACP, - 0, - lpDisplayName, - -1, - lpDisplayNameW, - dwLength); - - lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW); - - HeapFree(GetProcessHeap(), 0, lpDisplayNameW); - - if (lpService == NULL) - { - DPRINT("Could not find the service!\n"); - - /* If the service could not be found and lpcchBuffer is 0, - put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */ - if (*lpcchBuffer == 0) - { - *lpcchBuffer = 1; - if (lpServiceName != NULL) - { - *lpServiceName = '\0'; - } - } - - return ERROR_SERVICE_DOES_NOT_EXIST; - } - - dwLength = wcslen(lpService->lpServiceName); - if (lpServiceName != NULL && - *lpcchBuffer > dwLength) - { - WideCharToMultiByte(CP_ACP, - 0, - lpService->lpServiceName, - wcslen(lpService->lpServiceName), - lpServiceName, - dwLength + 1, - NULL, - NULL); - return ERROR_SUCCESS; - } - - dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER; - - *lpcchBuffer = dwLength * 2; - - return dwError; -} - - -/* Function 34 */ -DWORD RI_ScGetCurrentGroupStateW( - SC_RPC_HANDLE hSCManager, - LPWSTR lpLoadOrderGroup, - LPDWORD lpState) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 35 */ -DWORD REnumServiceGroupW( - SC_RPC_HANDLE hSCManager, - DWORD dwServiceType, - DWORD dwServiceState, - LPBYTE lpBuffer, - DWORD cbBufSize, - LPBOUNDED_DWORD_256K pcbBytesNeeded, - LPBOUNDED_DWORD_256K lpServicesReturned, - LPBOUNDED_DWORD_256K lpResumeIndex, - LPCWSTR pszGroupName) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -// -// WARNING: This function is untested -// -/* Function 36 */ -DWORD RChangeServiceConfig2A( - SC_RPC_HANDLE hService, - SC_RPC_CONFIG_INFOA Info) -{ - SC_RPC_CONFIG_INFOW InfoW; - DWORD dwRet, dwLength; - PVOID ptr = NULL; - - DPRINT("RChangeServiceConfig2A() called\n"); - DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel); - - InfoW.dwInfoLevel = Info.dwInfoLevel; - - if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) - { - LPSERVICE_DESCRIPTIONW lpServiceDescriptonW; - //LPSERVICE_DESCRIPTIONA lpServiceDescriptonA; - - //lpServiceDescriptonA = Info.psd; - - ///if (lpServiceDescriptonA && - ///lpServiceDescriptonA->lpDescription) - ///{ - dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR); - - lpServiceDescriptonW = HeapAlloc(GetProcessHeap(), - 0, - dwLength + sizeof(SERVICE_DESCRIPTIONW)); - if (!lpServiceDescriptonW) - { - return ERROR_NOT_ENOUGH_MEMORY; - } - - lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1); - - MultiByteToWideChar(CP_ACP, - 0, - Info.lpDescription, - -1, - lpServiceDescriptonW->lpDescription, - dwLength); - - ptr = lpServiceDescriptonW; - InfoW.psd = lpServiceDescriptonW; - ///} - } - else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) - { - LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW; - LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA; - DWORD dwRebootLen = 0; - DWORD dwCommandLen = 0; - - lpServiceFailureActionsA = Info.psfa; - - if (lpServiceFailureActionsA) - { - if (lpServiceFailureActionsA->lpRebootMsg) - { - dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR); - } - if (lpServiceFailureActionsA->lpCommand) - { - dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR); - } - dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW); - - lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(), - 0, - dwLength); - if (!lpServiceFailureActionsW) - { - return ERROR_NOT_ENOUGH_MEMORY; - } - - lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions; - lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod; - CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION)); - - if (lpServiceFailureActionsA->lpRebootMsg) - { - MultiByteToWideChar(CP_ACP, - 0, - lpServiceFailureActionsA->lpRebootMsg, - -1, - lpServiceFailureActionsW->lpRebootMsg, - dwRebootLen); - } - - if (lpServiceFailureActionsA->lpCommand) - { - MultiByteToWideChar(CP_ACP, - 0, - lpServiceFailureActionsA->lpCommand, - -1, - lpServiceFailureActionsW->lpCommand, - dwCommandLen); - } - - ptr = lpServiceFailureActionsW; - } - } - - dwRet = RChangeServiceConfig2W(hService, InfoW); - - HeapFree(GetProcessHeap(), 0, ptr); - - return dwRet; -} - - -/* Function 37 */ -DWORD RChangeServiceConfig2W( - SC_RPC_HANDLE hService, - SC_RPC_CONFIG_INFOW Info) -{ - DWORD dwError = ERROR_SUCCESS; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - HKEY hServiceKey = NULL; - - DPRINT("RChangeServiceConfig2W() called\n"); - DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_CHANGE_CONFIG)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database exclusively */ - ScmLockDatabaseExclusive(); - - if (lpService->bDeleted) - { - DPRINT("The service has already been marked for delete!\n"); - dwError = ERROR_SERVICE_MARKED_FOR_DELETE; - goto done; - } - - /* Open the service key */ - dwError = ScmOpenServiceKey(lpService->szServiceName, - KEY_SET_VALUE, - &hServiceKey); - if (dwError != ERROR_SUCCESS) - goto done; - - if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) - { - LPSERVICE_DESCRIPTIONW lpServiceDescription; - - lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd; - - if (lpServiceDescription != NULL && - lpServiceDescription->lpDescription != NULL) - { - DPRINT("Setting value %S\n", lpServiceDescription->lpDescription); - dwError = RegSetValueExW(hServiceKey, - L"Description", - 0, - REG_SZ, - (LPBYTE)lpServiceDescription->lpDescription, - (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR)); - if (dwError != ERROR_SUCCESS) - goto done; - } - } - else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) - { - UNIMPLEMENTED; - dwError = ERROR_CALL_NOT_IMPLEMENTED; - goto done; - } - -done: - /* Unlock the service database */ - ScmUnlockDatabase(); - - if (hServiceKey != NULL) - RegCloseKey(hServiceKey); - - DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 38 */ -DWORD RQueryServiceConfig2A( - SC_RPC_HANDLE hService, - DWORD dwInfoLevel, - LPBYTE lpBuffer, - DWORD cbBufSize, - LPBOUNDED_DWORD_8K pcbBytesNeeded) -{ - DWORD dwError = ERROR_SUCCESS; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - HKEY hServiceKey = NULL; - LPWSTR lpDescriptionW = NULL; - - DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n", - hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded); - - if (!lpBuffer) - return ERROR_INVALID_ADDRESS; - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_QUERY_CONFIG)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database shared */ - ScmLockDatabaseShared(); - - dwError = ScmOpenServiceKey(lpService->lpServiceName, - KEY_READ, - &hServiceKey); - if (dwError != ERROR_SUCCESS) - goto done; - - if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) - { - LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer; - LPSTR lpStr; - - dwError = ScmReadString(hServiceKey, - L"Description", - &lpDescriptionW); - if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND) - goto done; - - *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA); - if (dwError == ERROR_SUCCESS) - *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR)); - - if (cbBufSize < *pcbBytesNeeded) - { - dwError = ERROR_INSUFFICIENT_BUFFER; - goto done; - } - - if (dwError == ERROR_SUCCESS) - { - lpStr = (LPSTR)(lpServiceDescription + 1); - - WideCharToMultiByte(CP_ACP, - 0, - lpDescriptionW, - -1, - lpStr, - wcslen(lpDescriptionW), - NULL, - NULL); - lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription); - } - else - { - lpServiceDescription->lpDescription = NULL; - dwError = ERROR_SUCCESS; - goto done; - } - } - else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS) - { - UNIMPLEMENTED; - dwError = ERROR_CALL_NOT_IMPLEMENTED; - goto done; - } - -done: - /* Unlock the service database */ - ScmUnlockDatabase(); - - if (lpDescriptionW != NULL) - HeapFree(GetProcessHeap(), 0, lpDescriptionW); - - if (hServiceKey != NULL) - RegCloseKey(hServiceKey); - - DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 39 */ -DWORD RQueryServiceConfig2W( - SC_RPC_HANDLE hService, - DWORD dwInfoLevel, - LPBYTE lpBuffer, - DWORD cbBufSize, - LPBOUNDED_DWORD_8K pcbBytesNeeded) -{ - DWORD dwError = ERROR_SUCCESS; - PSERVICE_HANDLE hSvc; - PSERVICE lpService = NULL; - HKEY hServiceKey = NULL; - DWORD dwRequiredSize; - LPWSTR lpDescription = NULL; - LPWSTR lpFailureCommand = NULL; - LPWSTR lpRebootMessage = NULL; - - DPRINT("RQueryServiceConfig2W() called\n"); - - if (!lpBuffer) - return ERROR_INVALID_ADDRESS; - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_QUERY_CONFIG)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database shared */ - ScmLockDatabaseShared(); - - dwError = ScmOpenServiceKey(lpService->lpServiceName, - KEY_READ, - &hServiceKey); - if (dwError != ERROR_SUCCESS) - goto done; - - if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) - { - LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer; - LPWSTR lpStr; - - dwError = ScmReadString(hServiceKey, - L"Description", - &lpDescription); - if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND) - goto done; - - *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW); - if (dwError == ERROR_SUCCESS) - *pcbBytesNeeded += ((wcslen(lpDescription) + 1) * sizeof(WCHAR)); - - if (cbBufSize < *pcbBytesNeeded) - { - dwError = ERROR_INSUFFICIENT_BUFFER; - goto done; - } - - if (dwError == ERROR_SUCCESS) - { - lpStr = (LPWSTR)(lpServiceDescription + 1); - wcscpy(lpStr, lpDescription); - lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription); - } - else - { - lpServiceDescription->lpDescription = NULL; - dwError = ERROR_SUCCESS; - } - } - else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) - { - LPWSTR lpStr; - LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer; - - UNIMPLEMENTED; - - dwError = ScmReadString(hServiceKey, - L"FailureCommand", - &lpFailureCommand); - - dwError = ScmReadString(hServiceKey, - L"RebootMessage", - &lpRebootMessage); - - dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW); - - if (lpFailureCommand) - dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR); - - if (lpRebootMessage) - dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR); - - if (cbBufSize < dwRequiredSize) - { - *pcbBytesNeeded = dwRequiredSize; - dwError = ERROR_INSUFFICIENT_BUFFER; - goto done; - } - - lpFailureActions->cActions = 0; - lpFailureActions->dwResetPeriod = 0; - lpFailureActions->lpCommand = NULL; - lpFailureActions->lpRebootMsg = NULL; - lpFailureActions->lpsaActions = NULL; - - lpStr = (LPWSTR)(lpFailureActions + 1); - if (lpRebootMessage) - { - wcscpy(lpStr, lpRebootMessage); - lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage); - lpStr += wcslen(lpRebootMessage) + 1; - } - - if (lpFailureCommand) - { - wcscpy(lpStr, lpFailureCommand); - lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand); - lpStr += wcslen(lpRebootMessage) + 1; - } - dwError = STATUS_SUCCESS; - goto done; - } - -done: - /* Unlock the service database */ - ScmUnlockDatabase(); - - if (lpDescription != NULL) - HeapFree(GetProcessHeap(), 0, lpDescription); - - if (lpRebootMessage != NULL) - HeapFree(GetProcessHeap(), 0, lpRebootMessage); - - if (lpFailureCommand != NULL) - HeapFree(GetProcessHeap(), 0, lpFailureCommand); - - if (hServiceKey != NULL) - RegCloseKey(hServiceKey); - - DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 40 */ -DWORD RQueryServiceStatusEx( - SC_RPC_HANDLE hService, - SC_STATUS_TYPE InfoLevel, - LPBYTE lpBuffer, - DWORD cbBufSize, - LPBOUNDED_DWORD_8K pcbBytesNeeded) -{ - LPSERVICE_STATUS_PROCESS lpStatus; - PSERVICE_HANDLE hSvc; - PSERVICE lpService; - - DPRINT("RQueryServiceStatusEx() called\n"); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - if (InfoLevel != SC_STATUS_PROCESS_INFO) - return ERROR_INVALID_LEVEL; - - *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS); - - if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS)) - return ERROR_INSUFFICIENT_BUFFER; - - hSvc = ScmGetServiceFromHandle(hService); - if (hSvc == NULL) - { - DPRINT1("Invalid service handle!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_QUERY_STATUS)) - { - DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Lock the service database shared */ - ScmLockDatabaseShared(); - - lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer; - - /* Return service status information */ - RtlCopyMemory(lpStatus, - &lpService->Status, - sizeof(SERVICE_STATUS)); - - lpStatus->dwProcessId = (lpService->lpImage != NULL) ? lpService->lpImage->dwProcessId : 0; /* FIXME */ - lpStatus->dwServiceFlags = 0; /* FIXME */ - - /* Unlock the service database */ - ScmUnlockDatabase(); - - return ERROR_SUCCESS; -} - - -/* Function 41 */ -DWORD REnumServicesStatusExA( - SC_RPC_HANDLE hSCManager, - SC_ENUM_TYPE InfoLevel, - DWORD dwServiceType, - DWORD dwServiceState, - LPBYTE lpBuffer, - DWORD cbBufSize, - LPBOUNDED_DWORD_256K pcbBytesNeeded, - LPBOUNDED_DWORD_256K lpServicesReturned, - LPBOUNDED_DWORD_256K lpResumeIndex, - LPCSTR pszGroupName) -{ - LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL; - LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL; - LPWSTR lpStringPtrW; - LPSTR lpStringPtrA; - LPWSTR pszGroupNameW = NULL; - DWORD dwError; - DWORD dwServiceCount; - - DPRINT("REnumServicesStatusExA() called\n"); - - if (pszGroupName) - { - pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR)); - if (!pszGroupNameW) - { - DPRINT("Failed to allocate buffer!\n"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - MultiByteToWideChar(CP_ACP, - 0, - pszGroupName, - -1, - pszGroupNameW, - strlen(pszGroupName) + 1); - } - - if ((cbBufSize > 0) && (lpBuffer)) - { - lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize); - if (!lpStatusPtrW) - { - DPRINT("Failed to allocate buffer!\n"); - return ERROR_NOT_ENOUGH_MEMORY; - } - } - - dwError = REnumServicesStatusExW(hSCManager, - InfoLevel, - dwServiceType, - dwServiceState, - (LPBYTE)lpStatusPtrW, - cbBufSize, - pcbBytesNeeded, - lpServicesReturned, - lpResumeIndex, - pszGroupNameW); - - /* if no services were returned then we are Done */ - if (*lpServicesReturned == 0) - goto Done; - - lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer; - lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer + - *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA)); - lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW + - *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW)); - - for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++) - { - /* Copy the service name */ - WideCharToMultiByte(CP_ACP, - 0, - lpStringPtrW, - -1, - lpStringPtrA, - wcslen(lpStringPtrW), - 0, - 0); - - lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); - lpStringPtrA += wcslen(lpStringPtrW) + 1; - lpStringPtrW += wcslen(lpStringPtrW) + 1; - - /* Copy the display name */ - WideCharToMultiByte(CP_ACP, - 0, - lpStringPtrW, - -1, - lpStringPtrA, - wcslen(lpStringPtrW), - 0, - 0); - - lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); - lpStringPtrA += wcslen(lpStringPtrW) + 1; - lpStringPtrW += wcslen(lpStringPtrW) + 1; - - /* Copy the status information */ - memcpy(&lpStatusPtrA->ServiceStatusProcess, - &lpStatusPtrW->ServiceStatusProcess, - sizeof(SERVICE_STATUS)); - - lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */ - lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */ - lpStatusPtrA++; - } - -Done:; - if (pszGroupNameW) - HeapFree(GetProcessHeap(), 0, pszGroupNameW); - - if (lpStatusPtrW) - HeapFree(GetProcessHeap(), 0, lpStatusPtrW); - - DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 42 */ -DWORD REnumServicesStatusExW( - SC_RPC_HANDLE hSCManager, - SC_ENUM_TYPE InfoLevel, - DWORD dwServiceType, - DWORD dwServiceState, - LPBYTE lpBuffer, - DWORD cbBufSize, - LPBOUNDED_DWORD_256K pcbBytesNeeded, - LPBOUNDED_DWORD_256K lpServicesReturned, - LPBOUNDED_DWORD_256K lpResumeIndex, - LPCWSTR pszGroupName) -{ - PMANAGER_HANDLE hManager; - PSERVICE lpService; - DWORD dwError = ERROR_SUCCESS; - PLIST_ENTRY ServiceEntry; - PSERVICE CurrentService; - DWORD dwState; - DWORD dwRequiredSize; - DWORD dwServiceCount; - DWORD dwSize; - DWORD dwLastResumeCount = 0; - LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr; - LPWSTR lpStringPtr; - - DPRINT("REnumServicesStatusExW() called\n"); - - if (ScmShutdown) - return ERROR_SHUTDOWN_IN_PROGRESS; - - if (InfoLevel != SC_ENUM_PROCESS_INFO) - return ERROR_INVALID_LEVEL; - - hManager = ScmGetServiceManagerFromHandle(hSCManager); - if (hManager == NULL) - { - DPRINT1("Invalid service manager handle!\n"); - return ERROR_INVALID_HANDLE; - } - - *pcbBytesNeeded = 0; - *lpServicesReturned = 0; - - if ((dwServiceType == 0) || - ((dwServiceType & ~(SERVICE_DRIVER | SERVICE_WIN32)) != 0)) - { - DPRINT("Not a valid Service Type!\n"); - return ERROR_INVALID_PARAMETER; - } - - if ((dwServiceState != SERVICE_ACTIVE) && - (dwServiceState != SERVICE_INACTIVE) && - (dwServiceState != SERVICE_STATE_ALL)) - { - DPRINT("Not a valid Service State!\n"); - return ERROR_INVALID_PARAMETER; - } - - /* Check access rights */ - if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess, - SC_MANAGER_ENUMERATE_SERVICE)) - { - DPRINT("Insufficient access rights! 0x%lx\n", - hManager->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - if (lpResumeIndex) - dwLastResumeCount = *lpResumeIndex; - - /* Lock the service database shared */ - ScmLockDatabaseShared(); - - lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount); - if (lpService == NULL) - { - dwError = ERROR_SUCCESS; - goto Done; - } - - dwRequiredSize = 0; - dwServiceCount = 0; - - for (ServiceEntry = &lpService->ServiceListEntry; - ServiceEntry != &ServiceListHead; - ServiceEntry = ServiceEntry->Flink) - { - CurrentService = CONTAINING_RECORD(ServiceEntry, - SERVICE, - ServiceListEntry); - - if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) - continue; - - dwState = SERVICE_ACTIVE; - if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) - dwState = SERVICE_INACTIVE; - - if ((dwState & dwServiceState) == 0) - continue; - - if (pszGroupName) - { - if (*pszGroupName == 0) - { - if (CurrentService->lpGroup != NULL) - continue; - } - else - { - if ((CurrentService->lpGroup == NULL) || - _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName)) - continue; - } - } - - dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) + - ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + - ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)); - - if (dwRequiredSize + dwSize <= cbBufSize) - { - DPRINT("Service name: %S fit\n", CurrentService->lpServiceName); - dwRequiredSize += dwSize; - dwServiceCount++; - dwLastResumeCount = CurrentService->dwResumeCount; - } - else - { - DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName); - break; - } - - } - - DPRINT("dwRequiredSize: %lu\n", dwRequiredSize); - DPRINT("dwServiceCount: %lu\n", dwServiceCount); - - for (; - ServiceEntry != &ServiceListHead; - ServiceEntry = ServiceEntry->Flink) - { - CurrentService = CONTAINING_RECORD(ServiceEntry, - SERVICE, - ServiceListEntry); - - if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) - continue; - - dwState = SERVICE_ACTIVE; - if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) - dwState = SERVICE_INACTIVE; - - if ((dwState & dwServiceState) == 0) - continue; - - if (pszGroupName) - { - if (*pszGroupName == 0) - { - if (CurrentService->lpGroup != NULL) - continue; - } - else - { - if ((CurrentService->lpGroup == NULL) || - _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName)) - continue; - } - } - - dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) + - ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + - ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR))); - - dwError = ERROR_MORE_DATA; - } - - DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize); - - if (lpResumeIndex) - *lpResumeIndex = dwLastResumeCount; - - *lpServicesReturned = dwServiceCount; - *pcbBytesNeeded = dwRequiredSize; - - /* If there was no services that matched */ - if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA)) - { - dwError = ERROR_SERVICE_DOES_NOT_EXIST; - goto Done; - } - - lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer; - lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer + - dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW)); - - dwRequiredSize = 0; - for (ServiceEntry = &lpService->ServiceListEntry; - ServiceEntry != &ServiceListHead; - ServiceEntry = ServiceEntry->Flink) - { - CurrentService = CONTAINING_RECORD(ServiceEntry, - SERVICE, - ServiceListEntry); - - if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) - continue; - - dwState = SERVICE_ACTIVE; - if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) - dwState = SERVICE_INACTIVE; - - if ((dwState & dwServiceState) == 0) - continue; - - if (pszGroupName) - { - if (*pszGroupName == 0) - { - if (CurrentService->lpGroup != NULL) - continue; - } - else - { - if ((CurrentService->lpGroup == NULL) || - _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName)) - continue; - } - } - - dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) + - ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + - ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)); - - if (dwRequiredSize + dwSize <= cbBufSize) - { - /* Copy the service name */ - wcscpy(lpStringPtr, - CurrentService->lpServiceName); - lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); - lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1); - - /* Copy the display name */ - wcscpy(lpStringPtr, - CurrentService->lpDisplayName); - lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); - lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1); - - /* Copy the status information */ - memcpy(&lpStatusPtr->ServiceStatusProcess, - &CurrentService->Status, - sizeof(SERVICE_STATUS)); - lpStatusPtr->ServiceStatusProcess.dwProcessId = - (CurrentService->lpImage != NULL) ? CurrentService->lpImage->dwProcessId : 0; /* FIXME */ - lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */ - - lpStatusPtr++; - dwRequiredSize += dwSize; - } - else - { - break; - } - } - - if (dwError == 0) - { - *pcbBytesNeeded = 0; - if (lpResumeIndex) - *lpResumeIndex = 0; - } - -Done:; - /* Unlock the service database */ - ScmUnlockDatabase(); - - DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError); - - return dwError; -} - - -/* Function 43 */ -DWORD RSendTSMessage( - handle_t BindingHandle) /* FIXME */ -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 44 */ -DWORD RCreateServiceWOW64A( - handle_t BindingHandle, - LPSTR lpServiceName, - LPSTR lpDisplayName, - DWORD dwDesiredAccess, - DWORD dwServiceType, - DWORD dwStartType, - DWORD dwErrorControl, - LPSTR lpBinaryPathName, - LPSTR lpLoadOrderGroup, - LPDWORD lpdwTagId, - LPBYTE lpDependencies, - DWORD dwDependSize, - LPSTR lpServiceStartName, - LPBYTE lpPassword, - DWORD dwPwSize, - LPSC_RPC_HANDLE lpServiceHandle) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 45 */ -DWORD RCreateServiceWOW64W( - handle_t BindingHandle, - LPWSTR lpServiceName, - LPWSTR lpDisplayName, - DWORD dwDesiredAccess, - DWORD dwServiceType, - DWORD dwStartType, - DWORD dwErrorControl, - LPWSTR lpBinaryPathName, - LPWSTR lpLoadOrderGroup, - LPDWORD lpdwTagId, - LPBYTE lpDependencies, - DWORD dwDependSize, - LPWSTR lpServiceStartName, - LPBYTE lpPassword, - DWORD dwPwSize, - LPSC_RPC_HANDLE lpServiceHandle) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 46 */ -DWORD RQueryServiceTagInfo( - handle_t BindingHandle) /* FIXME */ -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 47 */ -DWORD RNotifyServiceStatusChange( - SC_RPC_HANDLE hService, - SC_RPC_NOTIFY_PARAMS NotifyParams, - GUID *pClientProcessGuid, - GUID *pSCMProcessGuid, - PBOOL pfCreateRemoteQueue, - LPSC_NOTIFY_RPC_HANDLE phNotify) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 48 */ -DWORD RGetNotifyResults( - SC_NOTIFY_RPC_HANDLE hNotify, - PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 49 */ -DWORD RCloseNotifyHandle( - LPSC_NOTIFY_RPC_HANDLE phNotify, - PBOOL pfApcFired) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 50 */ -DWORD RControlServiceExA( - SC_RPC_HANDLE hService, - DWORD dwControl, - DWORD dwInfoLevel) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 51 */ -DWORD RControlServiceExW( - SC_RPC_HANDLE hService, - DWORD dwControl, - DWORD dwInfoLevel) -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 52 */ -DWORD RSendPnPMessage( - handle_t BindingHandle) /* FIXME */ -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 53 */ -DWORD RValidatePnPService( - handle_t BindingHandle) /* FIXME */ -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 54 */ -DWORD ROpenServiceStatusHandle( - handle_t BindingHandle) /* FIXME */ -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 55 */ -DWORD RFunction55( - handle_t BindingHandle) /* FIXME */ -{ - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; -} - - void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len) { return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); @@ -5733,21 +66,30 @@ void __RPC_USER midl_user_free(void __RPC_FAR * ptr) { HeapFree(GetProcessHeap(), 0, ptr); + return; } void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject) { + // Close the handle. + RCloseServiceHandle(&hSCObject); + return; } void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock) { + // Unlock the database. + RUnlockServiceDatabase(&Lock); + return; } void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify) { + return; } + /* EOF */ Index: base/system/services/service.c =================================================================== --- base/system/services/service.c (révision 0) +++ base/system/services/service.c (copie de travail) @@ -0,0 +1,1104 @@ +/* + * PROJECT: ReactOS Service Control Manager + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/system/services/service.c + * PURPOSE: Win32 service control interface + * COPYRIGHT: Copyright 2005-2006 Eric Kohl + * + */ + +/* INCLUDES ******************************************************************/ + +#include "services.h" + +#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 *******************************************************************/ + +static CRITICAL_SECTION ControlServiceCriticalSection; +static DWORD dwPipeTimeout = 30000; /* 30 Seconds */ + + +/* FUNCTIONS *****************************************************************/ + +VOID +ScmInitNamedPipeCriticalSection(VOID) +{ + HKEY hKey; + DWORD dwKeySize; + DWORD dwError; + + InitializeCriticalSection(&ControlServiceCriticalSection); + + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Control", + 0, + KEY_READ, + &hKey); + if (dwError == ERROR_SUCCESS) + { + dwKeySize = sizeof(DWORD); + RegQueryValueExW(hKey, + L"ServicesPipeTimeout", + 0, + NULL, + (LPBYTE)&dwPipeTimeout, + &dwKeySize); + + RegCloseKey(hKey); + } +} + + +VOID +ScmDeleteNamedPipeCriticalSection(VOID) +{ + DeleteCriticalSection(&ControlServiceCriticalSection); +} + + +static DWORD +ScmCreateNewControlPipe(PIMAGE_RECORD pServiceImage) +{ + WCHAR szControlPipeName[MAX_PATH + 1]; + HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE; + DWORD ServiceCurrent = 0; + DWORD KeyDisposition; + 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) + { + 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); + + if (dwError != ERROR_SUCCESS) + { + RegCloseKey(hServiceCurrentKey); + DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError); + return dwError; + } + + ServiceCurrent++; + } + + dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent)); + + RegCloseKey(hServiceCurrentKey); + + if (dwError != ERROR_SUCCESS) + { + DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError); + return dwError; + } + + /* Create '\\.\pipe\net\NtControlPipeXXX' instance */ + swprintf(szControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", 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, + 4, + dwPipeTimeout, + NULL); + DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName); + if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE) + { + DPRINT1("Failed to create control pipe!\n"); + return GetLastError(); + } + + return ERROR_SUCCESS; +} + + +static PIMAGE_RECORD +ScmGetServiceImageByImagePath(IN PSCMGR_DATABASE pScDatabase, + IN LPWSTR lpImagePath) +{ + PLIST_ENTRY ImageEntry; + PIMAGE_RECORD CurrentImage; + + DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath); + + ImageEntry = pScDatabase->ImageListHead.Flink; + while (ImageEntry != &(pScDatabase->ImageListHead)) + { + CurrentImage = CONTAINING_RECORD(ImageEntry, IMAGE_RECORD, ImageListEntry); + if (_wcsicmp(CurrentImage->szImagePath, lpImagePath) == 0) + { + DPRINT("Found image: '%S'\n", CurrentImage->szImagePath); + return CurrentImage; + } + + ImageEntry = ImageEntry->Flink; + } + + DPRINT("Couldn't find a matching image\n"); + + return NULL; + +} + + +static DWORD +ScmCreateOrReferenceServiceImage(PSERVICE_RECORD pService) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + UNICODE_STRING ImagePath; + PIMAGE_RECORD pServiceImage = NULL; + NTSTATUS Status; + DWORD dwError = ERROR_SUCCESS; + + DPRINT("ScmCreateOrReferenceServiceImage(%p), name '%S'\n", pService, pService->ServiceName); + + RtlInitUnicodeString(&ImagePath, NULL); + + /* Get service data */ + RtlZeroMemory(&QueryTable, + sizeof(QueryTable)); + + QueryTable[0].Name = L"ImagePath"; + QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; + QueryTable[0].EntryContext = &ImagePath; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, + pService->ServiceName, + QueryTable, + NULL, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); + return RtlNtStatusToDosError(Status); + } + + DPRINT("ImagePath: '%wZ'\n", &ImagePath); + + pServiceImage = ScmGetServiceImageByImagePath(pService->Database, ImagePath.Buffer); + if (pServiceImage == NULL) + { + /* Create a new service image */ + pServiceImage = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + FIELD_OFFSET(IMAGE_RECORD, szImagePath[ImagePath.Length / sizeof(WCHAR) + 1])); + if (pServiceImage == NULL) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + pServiceImage->dwImageRunCount = 1; + pServiceImage->hControlPipe = INVALID_HANDLE_VALUE; + + /* Set the image path */ + wcscpy(pServiceImage->szImagePath, + ImagePath.Buffer); + + RtlFreeUnicodeString(&ImagePath); + + /* Create the control pipe */ + dwError = ScmCreateNewControlPipe(pServiceImage); + if (dwError != ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(), 0, pServiceImage); + goto done; + } + + /* FIXME: Add more initialization code here */ + + + /* Append service record */ + InsertTailList(&(pService->Database->ImageListHead), + &(pServiceImage->ImageListEntry)); + } + else + { + /* Increment the run counter */ + pServiceImage->dwImageRunCount++; + } + + DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount); + + /* Link the service image to the service */ + pService->lpImage = pServiceImage; + +done: + RtlFreeUnicodeString(&ImagePath); + + DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError); + + return dwError; +} + + +// TODO: was static but now is used in database.c +/* static */ VOID +ScmDereferenceServiceImage(PIMAGE_RECORD pServiceImage) +{ + DPRINT1("ScmDereferenceServiceImage() called\n"); + + pServiceImage->dwImageRunCount--; + + if (pServiceImage->dwImageRunCount == 0) + { + DPRINT1("dwImageRunCount == 0\n"); + + /* FIXME: Terminate the process */ + + /* Remove the service image from the list */ + RemoveEntryList(&pServiceImage->ImageListEntry); + + /* Close the control pipe */ + if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE) + CloseHandle(pServiceImage->hControlPipe); + + /* Release the service image */ + HeapFree(GetProcessHeap(), 0, pServiceImage); + } +} + + +static DWORD +ScmSendStartCommand(PSERVICE_RECORD Service, + DWORD argc, + LPWSTR *argv) +{ + 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 *pOffPtr; + PWSTR pArgPtr; + BOOL bResult; +#ifdef USE_ASYNCHRONOUS_IO + OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; +#endif + + DPRINT("ScmSendStartCommand() called\n"); + + /* Calculate the total length of the start command line */ + PacketSize = sizeof(SCM_CONTROL_PACKET); + PacketSize += (wcslen(Service->ServiceName) + 1) * sizeof(WCHAR); + + /* Calculate the required packet size for the start arguments */ + if (argc > 0 && argv != NULL) + { + PacketSize = ALIGN_UP(PacketSize, LPWSTR); + + DPRINT("Argc: %lu\n", argc); + for (i = 0; i < argc; i++) + { + DPRINT("Argv[%lu]: %S\n", i, argv[i]); + PacketSize += (wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR); + } + } + + /* Allocate a control packet */ + ControlPacket = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + PacketSize); + if (ControlPacket == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + ControlPacket->dwSize = PacketSize; + ControlPacket->dwControl = SERVICE_CONTROL_START; + ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service; + ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); + + Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); + wcscpy(Ptr, Service->ServiceName); + + ControlPacket->dwArgumentsCount = 0; + ControlPacket->dwArgumentsOffset = 0; + + /* Copy argument list */ + if (argc > 0 && argv != NULL) + { + Ptr += wcslen(Service->ServiceName) + 1; + pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR); + pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR)); + + ControlPacket->dwArgumentsCount = argc; + ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket); + + DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount); + DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset); + + 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++; + } + } + +#ifdef USE_ASYNCHRONOUS_IO + bResult = WriteFile(Service->lpImage->hControlPipe, + ControlPacket, + PacketSize, + &dwWriteCount, + &Overlapped); + if (bResult == FALSE) + { + DPRINT1("WriteFile() returned FALSE\n"); + + dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) + { + DPRINT1("dwError: ERROR_IO_PENDING\n"); + + dwError = WaitForSingleObject(Service->lpImage->hControlPipe, + dwPipeTimeout); + DPRINT1("WaitForSingleObject() returned %lu\n", dwError); + + if (dwError == WAIT_TIMEOUT) + { + bResult = CancelIo(Service->lpImage->hControlPipe); + if (bResult == FALSE) + { + DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); + } + + dwError = ERROR_SERVICE_REQUEST_TIMEOUT; + goto Done; + } + else if (dwError == ERROR_SUCCESS) + { + bResult = GetOverlappedResult(Service->lpImage->hControlPipe, + &Overlapped, + &dwWriteCount, + TRUE); + if (bResult == FALSE) + { + dwError = GetLastError(); + DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); + + goto Done; + } + } + } + else + { + DPRINT1("WriteFile() failed (Error %lu)\n", dwError); + goto Done; + } + } + + /* Read the reply */ + Overlapped.hEvent = (HANDLE) NULL; + + bResult = ReadFile(Service->lpImage->hControlPipe, + &ReplyPacket, + sizeof(SCM_REPLY_PACKET), + &dwReadCount, + &Overlapped); + if (bResult == FALSE) + { + DPRINT1("ReadFile() returned FALSE\n"); + + dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) + { + DPRINT1("dwError: ERROR_IO_PENDING\n"); + + dwError = WaitForSingleObject(Service->lpImage->hControlPipe, + dwPipeTimeout); + DPRINT1("WaitForSingleObject() returned %lu\n", dwError); + + if (dwError == WAIT_TIMEOUT) + { + bResult = CancelIo(Service->lpImage->hControlPipe); + if (bResult == FALSE) + { + DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); + } + + dwError = ERROR_SERVICE_REQUEST_TIMEOUT; + goto Done; + } + else if (dwError == ERROR_SUCCESS) + { + bResult = GetOverlappedResult(Service->lpImage->hControlPipe, + &Overlapped, + &dwReadCount, + TRUE); + if (bResult == FALSE) + { + dwError = GetLastError(); + DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); + + goto Done; + } + } + } + else + { + DPRINT1("ReadFile() failed (Error %lu)\n", dwError); + goto Done; + } + } + +#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 */ + HeapFree(GetProcessHeap(), + 0, + ControlPacket); + + if (dwReadCount == sizeof(SCM_REPLY_PACKET)) + { + dwError = ReplyPacket.dwError; + } + + DPRINT("ScmSendStartCommand() done\n"); + + return dwError; +} + + +static DWORD +ScmWaitForServiceConnect(PSERVICE_RECORD Service) +{ + DWORD dwRead = 0; + DWORD dwProcessId = 0; + DWORD dwError = ERROR_SUCCESS; + BOOL bResult; +#ifdef USE_ASYNCHRONOUS_IO + OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; +#endif + + DPRINT("ScmWaitForServiceConnect()\n"); + +#ifdef USE_ASYNCHRONOUS_IO + Overlapped.hEvent = (HANDLE)NULL; + + bResult = ConnectNamedPipe(Service->lpImage->hControlPipe, + &Overlapped); + if (bResult == FALSE) + { + DPRINT("ConnectNamedPipe() returned FALSE\n"); + + dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) + { + DPRINT("dwError: ERROR_IO_PENDING\n"); + + dwError = WaitForSingleObject(Service->lpImage->hControlPipe, + dwPipeTimeout); + DPRINT("WaitForSingleObject() returned %lu\n", dwError); + + if (dwError == WAIT_TIMEOUT) + { + DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n"); + + bResult = CancelIo(Service->lpImage->hControlPipe); + if (bResult == FALSE) + { + DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); + } + + return ERROR_SERVICE_REQUEST_TIMEOUT; + } + else if (dwError == WAIT_OBJECT_0) + { + bResult = GetOverlappedResult(Service->lpImage->hControlPipe, + &Overlapped, + &dwRead, + TRUE); + if (bResult == FALSE) + { + dwError = GetLastError(); + DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError); + + return dwError; + } + } + } + else if (dwError != ERROR_PIPE_CONNECTED) + { + DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError); + return dwError; + } + } + + DPRINT("Control pipe connected!\n"); + + Overlapped.hEvent = (HANDLE) NULL; + + /* Read the process id from pipe */ + bResult = ReadFile(Service->lpImage->hControlPipe, + (LPVOID)&dwProcessId, + sizeof(DWORD), + &dwRead, + &Overlapped); + if (bResult == FALSE) + { + DPRINT("ReadFile() returned FALSE\n"); + + dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) + { + DPRINT("dwError: ERROR_IO_PENDING\n"); + + dwError = WaitForSingleObject(Service->lpImage->hControlPipe, + dwPipeTimeout); + if (dwError == WAIT_TIMEOUT) + { + DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n"); + + bResult = CancelIo(Service->lpImage->hControlPipe); + if (bResult == FALSE) + { + DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); + } + + return ERROR_SERVICE_REQUEST_TIMEOUT; + } + else if (dwError == ERROR_SUCCESS) + { + DPRINT("WaitForSingleObject() returned ERROR_SUCCESS\n"); + + DPRINT("Process Id: %lu\n", dwProcessId); + + bResult = GetOverlappedResult(Service->lpImage->hControlPipe, + &Overlapped, + &dwRead, + TRUE); + if (bResult == FALSE) + { + dwError = GetLastError(); + DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); + + return dwError; + } + } + else + { + DPRINT1("WaitForSingleObject() returned %lu\n", dwError); + } + } + else + { + DPRINT1("ReadFile() failed (Error %lu)\n", dwError); + return dwError; + } + } + + DPRINT1("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 +} + + +static DWORD +ScmStartUserModeService(PSERVICE_RECORD Service, + DWORD argc, + LPWSTR *argv) +{ + PROCESS_INFORMATION ProcessInformation; + STARTUPINFOW StartupInfo; + BOOL Result; + DWORD dwError = ERROR_SUCCESS; + + DPRINT("ScmStartUserModeService(%p)\n", Service); + + /* If the image is already running ... */ + if (Service->lpImage->dwImageRunCount > 1) + { + /* ... just send a start command */ + return ScmSendStartCommand(Service, argc, argv); + } + + StartupInfo.cb = sizeof(StartupInfo); + StartupInfo.lpReserved = NULL; + StartupInfo.lpDesktop = NULL; + StartupInfo.lpTitle = NULL; + StartupInfo.dwFlags = 0; + StartupInfo.cbReserved2 = 0; + StartupInfo.lpReserved2 = 0; + + Result = CreateProcessW(NULL, + Service->lpImage->szImagePath, + NULL, + NULL, + FALSE, + DETACHED_PROCESS | CREATE_SUSPENDED, + NULL, + NULL, + &StartupInfo, + &ProcessInformation); + if (!Result) + { + dwError = GetLastError(); + DPRINT1("Starting '%S' failed!\n", Service->ServiceName); + return dwError; + } + + DPRINT("Process Id: %lu Handle %p\n", + ProcessInformation.dwProcessId, + ProcessInformation.hProcess); + DPRINT("Thread Id: %lu Handle %p\n", + ProcessInformation.dwThreadId, + ProcessInformation.hThread); + + /* Get process handle and id */ + Service->lpImage->dwProcessId = ProcessInformation.dwProcessId; + + /* Resume Thread */ + ResumeThread(ProcessInformation.hThread); + + /* Connect control pipe */ + dwError = ScmWaitForServiceConnect(Service); + if (dwError == ERROR_SUCCESS) + { + /* Send start command */ + dwError = ScmSendStartCommand(Service, + argc, + argv); + } + else + { + DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); + Service->lpImage->dwProcessId = 0; + } + + /* Close thread and process handle */ + CloseHandle(ProcessInformation.hThread); + CloseHandle(ProcessInformation.hProcess); + + return dwError; +} + + +DWORD +ScmStartService(PSERVICE_RECORD Service, DWORD argc, LPWSTR *argv) +{ + PSERVICE_GROUP Group = Service->lpGroup; + DWORD dwError = ERROR_SUCCESS; + LPCWSTR ErrorLogStrings[2]; + WCHAR szErrorBuffer[32]; + + DPRINT("ScmStartService() called\n"); + DPRINT("Start Service %p (%S)\n", Service, Service->ServiceName); + + EnterCriticalSection(&ControlServiceCriticalSection); + + // At this point, IsActiveDatabase(lpService->Database) is TRUE. + + if (Service->Status.dwCurrentState != SERVICE_STOPPED) + { + DPRINT("Service %S is already running!\n", Service->ServiceName); + LeaveCriticalSection(&ControlServiceCriticalSection); + return ERROR_SERVICE_ALREADY_RUNNING; + } + + DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType); + + 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; + } + } + else + { + /* Start user-mode service */ + dwError = ScmCreateOrReferenceServiceImage(Service); + if (dwError == ERROR_SUCCESS) + { + 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 + } + else + { + ScmDereferenceServiceImage(Service->lpImage); + Service->lpImage = NULL; + } + } + } + + LeaveCriticalSection(&ControlServiceCriticalSection); + + DPRINT("ScmStartService() done (Error %lu)\n", dwError); + + if (dwError == ERROR_SUCCESS) + { + if (Group != NULL) + { + Group->ServicesRunning = TRUE; + } + } + else + { + if (Service->dwErrorControl != SERVICE_ERROR_IGNORE) + { + /* Log a failed service start */ + swprintf(szErrorBuffer, L"%lu", dwError); + ErrorLogStrings[0] = Service->ServiceName; + ErrorLogStrings[1] = szErrorBuffer; + ScmLogError(EVENT_SERVICE_START_FAILED, + 2, + ErrorLogStrings); + } + +#if 0 + switch (Service->dwErrorControl) + { + case SERVICE_ERROR_SEVERE: + if (IsLastKnownGood == FALSE) + { + /* FIXME: Boot last known good configuration */ + } + break; + + case SERVICE_ERROR_CRITICAL: + if (IsLastKnownGood == FALSE) + { + /* FIXME: Boot last known good configuration */ + } + else + { + /* FIXME: BSOD! */ + } + break; + } +#endif + } + + return dwError; +} + + +DWORD +ScmControlService(PSERVICE_RECORD Service, + DWORD dwControl) +{ + PSCM_CONTROL_PACKET ControlPacket; + SCM_REPLY_PACKET ReplyPacket; + + DWORD dwWriteCount = 0; + DWORD dwReadCount = 0; + DWORD PacketSize; + PWSTR Ptr; + DWORD dwError = ERROR_SUCCESS; + BOOL bResult; +#ifdef USE_ASYNCHRONOUS_IO + OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; +#endif + + DPRINT("ScmControlService() called\n"); + + EnterCriticalSection(&ControlServiceCriticalSection); + + // At this point, IsActiveDatabase(lpService->Database) is TRUE. + + /* Calculate the total length of the start command line */ + PacketSize = sizeof(SCM_CONTROL_PACKET); + PacketSize += (wcslen(Service->ServiceName) + 1) * sizeof(WCHAR); + + ControlPacket = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + PacketSize); + if (ControlPacket == NULL) + { + LeaveCriticalSection(&ControlServiceCriticalSection); + return ERROR_NOT_ENOUGH_MEMORY; + } + + ControlPacket->dwSize = PacketSize; + ControlPacket->dwControl = dwControl; + ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service; + + ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); + + Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); + wcscpy(Ptr, Service->ServiceName); + + ControlPacket->dwArgumentsCount = 0; + ControlPacket->dwArgumentsOffset = 0; + +#ifdef USE_ASYNCHRONOUS_IO + bResult = WriteFile(Service->lpImage->hControlPipe, + ControlPacket, + PacketSize, + &dwWriteCount, + &Overlapped); + if (bResult == FALSE) + { + DPRINT1("WriteFile() returned FALSE\n"); + + dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) + { + DPRINT1("dwError: ERROR_IO_PENDING\n"); + + dwError = WaitForSingleObject(Service->lpImage->hControlPipe, + dwPipeTimeout); + DPRINT1("WaitForSingleObject() returned %lu\n", dwError); + + if (dwError == WAIT_TIMEOUT) + { + bResult = CancelIo(Service->lpImage->hControlPipe); + if (bResult == FALSE) + { + DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); + } + + dwError = ERROR_SERVICE_REQUEST_TIMEOUT; + goto Done; + } + else if (dwError == ERROR_SUCCESS) + { + bResult = GetOverlappedResult(Service->lpImage->hControlPipe, + &Overlapped, + &dwWriteCount, + TRUE); + if (bResult == FALSE) + { + dwError = GetLastError(); + DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); + + goto Done; + } + } + } + else + { + DPRINT1("WriteFile() failed (Error %lu)\n", dwError); + goto Done; + } + } + + /* Read the reply */ + Overlapped.hEvent = (HANDLE) NULL; + + bResult = ReadFile(Service->lpImage->hControlPipe, + &ReplyPacket, + sizeof(SCM_REPLY_PACKET), + &dwReadCount, + &Overlapped); + if (bResult == FALSE) + { + DPRINT1("ReadFile() returned FALSE\n"); + + dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) + { + DPRINT1("dwError: ERROR_IO_PENDING\n"); + + dwError = WaitForSingleObject(Service->lpImage->hControlPipe, + dwPipeTimeout); + DPRINT1("WaitForSingleObject() returned %lu\n", dwError); + + if (dwError == WAIT_TIMEOUT) + { + bResult = CancelIo(Service->lpImage->hControlPipe); + if (bResult == FALSE) + { + DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); + } + + dwError = ERROR_SERVICE_REQUEST_TIMEOUT; + goto Done; + } + else if (dwError == ERROR_SUCCESS) + { + bResult = GetOverlappedResult(Service->lpImage->hControlPipe, + &Overlapped, + &dwReadCount, + TRUE); + if (bResult == FALSE) + { + dwError = GetLastError(); + DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); + + goto Done; + } + } + } + else + { + DPRINT1("ReadFile() failed (Error %lu)\n", dwError); + goto Done; + } + } + +#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 */ + HeapFree(GetProcessHeap(), + 0, + ControlPacket); + + if (dwReadCount == sizeof(SCM_REPLY_PACKET)) + { + dwError = ReplyPacket.dwError; + } + + if (dwError == ERROR_SUCCESS && + dwControl == SERVICE_CONTROL_STOP) + { + ScmDereferenceServiceImage(Service->lpImage); + } + + LeaveCriticalSection(&ControlServiceCriticalSection); + + DPRINT("ScmControlService() done\n"); + + return dwError; +} + + +/* EOF */ Index: base/system/services/services.c =================================================================== --- base/system/services/services.c (révision 56659) +++ base/system/services/services.c (copie de travail) @@ -6,26 +6,37 @@ * COPYRIGHT: Copyright 2001-2005 Eric Kohl * Copyright 2007 Ged Murphy * + * NOTES: - This program has an Open Specification description + * on MSDN Library. For more information, see: + * http://msdn.microsoft.com/en-us/library/cc245832(v=prot.10) or + * http://msdn.microsoft.com/en-us/library/cc245832(v=prot.13) + * + * The following reference can also be reviewed: + * http://msdn.microsoft.com/en-us/library/ms685141.aspx + * + * - Services.exe is NOT a native application, it is a GUI app. + * */ -/* NOTE: - * - Services.exe is NOT a native application, it is a GUI app. - */ +/* INCLUDES ******************************************************************/ -/* INCLUDES *****************************************************************/ - #include "services.h" #define NDEBUG #include +// Undocumented function. int WINAPI RegisterServicesProcess(DWORD ServicesProcessId); -/* GLOBALS ******************************************************************/ +/* GLOBALS *******************************************************************/ + #define PIPE_BUFSIZE 1024 #define PIPE_TIMEOUT 1000 +#define SC_INTERNAL_START_EVENT L"SvcctrlStartEvent_A3752DX" +#define LSA_RPC_SERVER_ACTIVE L"LSA_RPC_SERVER_ACTIVE" + BOOL ScmShutdown = FALSE; static HANDLE hScmShutdownEvent = NULL; @@ -55,8 +66,7 @@ { HANDLE hLog; - hLog = RegisterEventSourceW(NULL, - L"Service Control Manager"); + hLog = RegisterEventSourceW(NULL, L"Service Control Manager"); if (hLog == NULL) { DPRINT1("ScmLogEvent: RegisterEventSourceW failed %d\n", GetLastError()); @@ -80,22 +90,22 @@ } -BOOL +static BOOL ScmCreateStartEvent(PHANDLE StartEvent) { HANDLE hEvent; - hEvent = CreateEvent(NULL, - TRUE, - FALSE, - TEXT("SvcctrlStartEvent_A3752DX")); + hEvent = CreateEventW(NULL, + TRUE, + FALSE, + SC_INTERNAL_START_EVENT); if (hEvent == NULL) { if (GetLastError() == ERROR_ALREADY_EXISTS) { - hEvent = OpenEvent(EVENT_ALL_ACCESS, - FALSE, - TEXT("SvcctrlStartEvent_A3752DX")); + hEvent = OpenEventW(EVENT_ALL_ACCESS, + FALSE, + SC_INTERNAL_START_EVENT); if (hEvent == NULL) { return FALSE; @@ -113,26 +123,28 @@ } -static VOID -ScmWaitForLsass(VOID) +VOID +ScmWaitForLsa(VOID) { - HANDLE hEvent; - DWORD dwError; + HANDLE hEvent ; + DWORD dwError; + DPRINT("ScmWaitForLsa() called\n"); + hEvent = CreateEventW(NULL, TRUE, FALSE, - L"LSA_RPC_SERVER_ACTIVE"); + LSA_RPC_SERVER_ACTIVE); if (hEvent == NULL) { dwError = GetLastError(); - DPRINT("Failed to create the notication event (Error %lu)\n", dwError); + /* DPRINT */ DPRINT1("Failed to create the notication event (Error %lu)\n", dwError); if (dwError == ERROR_ALREADY_EXISTS) { hEvent = OpenEventW(SYNCHRONIZE, FALSE, - L"LSA_RPC_SERVER_ACTIVE"); + LSA_RPC_SERVER_ACTIVE); if (hEvent == NULL) { DPRINT1("Could not open the notification event (Error %lu)\n", GetLastError()); @@ -146,10 +158,14 @@ DPRINT("LSA server running!\n"); CloseHandle(hEvent); + + DPRINT("ScmWaitForLsa() done\n"); + + return; } -BOOL +static BOOL ScmNamedPipeHandleRequest(PVOID Request, DWORD RequestSize, PVOID Reply, @@ -215,7 +231,7 @@ } -BOOL +static BOOL ScmCreateNamedPipe(VOID) { DWORD dwThreadId; @@ -223,9 +239,9 @@ HANDLE hThread; HANDLE hPipe; - DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n"); + DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\ntsvcs\")\n"); - hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Ntsvcs"), + hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\ntsvcs"), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, @@ -301,7 +317,7 @@ } -BOOL +/* static */ BOOL // TODO: Not used ?? StartScmNamedPipeThreadListener(VOID) { DWORD dwThreadId; @@ -325,7 +341,7 @@ } -VOID FASTCALL +static VOID /* FASTCALL */ AcquireLoadDriverPrivilege(VOID) { HANDLE hToken; @@ -358,9 +374,9 @@ ScmShutdown = TRUE; ScmAutoShutdownServices(); - ScmShutdownServiceDatabase(); + ScmShutdownServiceDatabases(); - /* Set the shutdwon event */ + /* Set the shutdown event */ SetEvent(hScmShutdownEvent); } @@ -377,7 +393,7 @@ HANDLE hScmStartEvent; DWORD dwError; - DPRINT("SERVICES: Service Control Manager\n"); + /* DPRINT */ DPRINT1("SERVICES: Service Control Manager\n"); /* Create start event */ if (!ScmCreateStartEvent(&hScmStartEvent)) @@ -386,32 +402,29 @@ ExitThread(0); } - DPRINT("SERVICES: created start event with handle %p.\n", hScmStartEvent); + /* DPRINT */ DPRINT1("SERVICES: created start event with handle %p.\n", hScmStartEvent); // ScmInitThreadManager(); /* FIXME: more initialization */ - /* Create the service database */ - dwError = ScmCreateServiceDatabase(); + /* Create the service databases */ + dwError = ScmCreateServiceDatabases(); if (dwError != ERROR_SUCCESS) { - DPRINT1("SERVICES: failed to create SCM database (Error %lu)\n", dwError); + DPRINT1("SERVICES: failed to create SCM databases (Error %lu)\n", dwError); CloseHandle(hScmStartEvent); ExitThread(0); } - /* Update service database */ - ScmGetBootAndSystemDriverState(); - /* Start the RPC server */ ScmStartRpcServer(); - /* Register service process with CSRSS */ + /* Register service process with CSRSS (undocumented) */ RegisterServicesProcess(GetCurrentProcessId()); - DPRINT("SERVICES: Initialized.\n"); + /* DPRINT */ DPRINT1("SERVICES: Initialized.\n"); /* Signal start event */ SetEvent(hScmStartEvent); @@ -420,7 +433,7 @@ SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE); /* Wait for the LSA server */ - ScmWaitForLsass(); + ScmWaitForLsa(); /* Acquire privileges to load drivers */ AcquireLoadDriverPrivilege(); @@ -428,15 +441,16 @@ ScmInitNamedPipeCriticalSection(); /* Start auto-start services */ + DPRINT1("Starting auto-start services...\n"); ScmAutoStartServices(); /* FIXME: more to do ? */ - DPRINT("SERVICES: Running.\n"); + /* DPRINT */ DPRINT1("SERVICES: Running.\n"); /* Create the shutdown event and wait until it gets set */ - hScmShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + hScmShutdownEvent = CreateEventW(NULL, TRUE, FALSE, NULL); if (hScmShutdownEvent) WaitForSingleObject(hScmShutdownEvent, INFINITE); @@ -448,11 +462,12 @@ /* Close the start event */ CloseHandle(hScmStartEvent); - DPRINT("SERVICES: Finished.\n"); + /* DPRINT */ DPRINT1("SERVICES: Finished.\n"); ExitThread(0); return 0; } + /* EOF */ Index: base/system/services/services.h =================================================================== --- base/system/services/services.h (révision 56659) +++ base/system/services/services.h (copie de travail) @@ -1,7 +1,29 @@ /* - * services.h + * PROJECT: ReactOS Service Control Manager + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/system/services/services.h + * PURPOSE: Main SCM controller + * COPYRIGHT: Copyright 2001-2005 Eric Kohl + * Copyright 2007 Ged Murphy + * + * NOTES: - This program has an Open Specification description + * on MSDN Library. For more information, see: + * http://msdn.microsoft.com/en-us/library/cc245832(v=prot.10) or + * http://msdn.microsoft.com/en-us/library/cc245832(v=prot.13) + * + * The following reference can also be reviewed: + * http://msdn.microsoft.com/en-us/library/ms685141.aspx + * + * - Services.exe is NOT a native application, it is a GUI app. + * */ +#ifndef __SERVICES_H__ +#define __SERVICES_H__ + + +/* INCLUDES ******************************************************************/ + #include #define WIN32_NO_STATUS #include @@ -14,6 +36,107 @@ #include "svcctl_s.h" +/* STRUCTURES ****************************************************************/ + +/* + * Structure describing a database lock. + */ +extern RTL_RESOURCE DatabaseLock; // HACK: !!!!!!!!!!!!!!!!!!!!!!!!!! + +#define API_LOCK_SIGNATURE 'ApiL' // 0x4C697041 + +typedef struct _SC_LOCK_STRUCT +{ + // LIST_ENTRY ApiLockListEntry; + DWORD Signature; // Must be API_LOCK_SIGNATURE. + + //// RTL_RESOURCE DatabaseLock; //// + + // LPWSTR DatabaseName; + // struct _SCMGR_DATABASE* /* PSCMGR_DATABASE */ Database; // Unused for the moment... + DWORD TimeWhenLocked; // Seconds since 1970. + PSID LockOwnerSid; // It is NULL if SC Manager + // grabbed the lock. +} SC_LOCK_STRUCT, *PSC_LOCK_STRUCT; + + +/* + * Structure describing one database existing + * on this machine. + * All available databases are loaded during + * SC startup and are stored into a linked-list. + */ + +// +// Registry key names under the "HKEY_LOCAL_MACHINE\\SYSTEM" key: +// "CurrentControlSet" for the active database, or one of the +// "ControlSet00n" specified in the values of the +// "HKEY_LOCAL_MACHINE\\SYSTEM\\Select" key. +// +typedef struct _REG_KEY_NAMES +{ + LPWSTR Control; // Format: L"SYSTEM\\\\Control" + LPWSTR Control_GroupOrderList; // Format: L"SYSTEM\\\\Control\\GroupOrderList" + LPWSTR Control_SafeBoot; // Format: L"SYSTEM\\\\Control\\SafeBoot" + LPWSTR Control_ServiceCurrent; // Format: L"SYSTEM\\\\Control\\ServiceCurrent" + LPWSTR Services; // Format: L"SYSTEM\\\\Services" +} REG_KEY_NAMES; + +typedef struct _SCMGR_DATABASE +{ + LIST_ENTRY DatabaseListEntry; + + LPWSTR DatabaseName; + REG_KEY_NAMES RegistryKeyNames; + + LIST_ENTRY ImageListHead; + LIST_ENTRY ServiceListHead; + + LIST_ENTRY GroupListHead; + LIST_ENTRY UnknownGroupListHead; + + struct _SC_LOCK_STRUCT* /* PSC_LOCK_STRUCT */ DatabaseLock; // Points to a valid lock if the database is locked. Is NULL otherwise. + + /// BYTE DatabaseName[(wcslen(DatabaseName) + 1)*sizeof(WCHAR)] /// + /// BYTE RegistryKeyNames[...] /// +} SCMGR_DATABASE, *PSCMGR_DATABASE; + + +/* + * Structure describing a SC handle. + * It can be either a handle to a SC database + * or a handle to a service entry. + * + * This definition comes from http://forum.sysinternals.com/service-name-by-handle_topic21996.html + */ +#define MANAGER_TAG 'hMgr' // 0x72674D68 +#define SERVICE_TAG 'hSvc' // 0x63765368 + +typedef struct _SC_HANDLE_STRUCT +{ + DWORD Signature; // Signature (ID) of the handle. Defines the "type" of the handle. + DWORD UnknownFlag; + DWORD DesiredAccess; + + union // Object specific data + { + struct + { + // LPWSTR DatabaseName; + PSCMGR_DATABASE Database; + } ScManagerObject; + + struct + { + // PSERVICE_RECORD ServiceEntry; + struct _SERVICE_RECORD* ServiceEntry; + } ScServiceObject; + + } Type; + +} SC_HANDLE_STRUCT, *PSC_HANDLE_STRUCT; + + typedef struct _SERVICE_GROUP { LIST_ENTRY GroupListEntry; @@ -27,8 +150,7 @@ WCHAR szGroupName[1]; } SERVICE_GROUP, *PSERVICE_GROUP; - -typedef struct _SERVICE_IMAGE +typedef struct _IMAGE_RECORD { LIST_ENTRY ImageListEntry; DWORD dwImageRunCount; @@ -38,24 +160,29 @@ DWORD dwProcessId; WCHAR szImagePath[1]; -} SERVICE_IMAGE, *PSERVICE_IMAGE; +} IMAGE_RECORD, *PIMAGE_RECORD; - -typedef struct _SERVICE +typedef struct _SERVICE_RECORD { LIST_ENTRY ServiceListEntry; - LPWSTR lpServiceName; - LPWSTR lpDisplayName; + + PSCMGR_DATABASE Database; // Points to the (valid) database the service belongs to. + + LPWSTR ServiceName; + LPWSTR DisplayName; + PSERVICE_GROUP lpGroup; - PSERVICE_IMAGE lpImage; - BOOL bDeleted; + + PIMAGE_RECORD lpImage; + + BOOL bDeleted; DWORD dwResumeCount; DWORD dwRefCount; SERVICE_STATUS Status; - DWORD dwStartType; - DWORD dwErrorControl; - DWORD dwTag; + DWORD dwStartType; + DWORD dwErrorControl; + DWORD dwTag; ULONG Flags; @@ -63,27 +190,28 @@ BOOLEAN ServiceVisited; - WCHAR szServiceName[1]; -} SERVICE, *PSERVICE; + // WCHAR szServiceName[1]; + /// BYTE ServiceName[(wcslen(ServiceName) + 1)*sizeof(WCHAR)] /// + /// BYTE DisplayName[(wcslen(DisplayName) + 1)*sizeof(WCHAR)] /// +} SERVICE_RECORD, *PSERVICE_RECORD, *LPSERVICE_RECORD; -/* VARIABLES ***************************************************************/ +/* VARIABLES *****************************************************************/ -extern LIST_ENTRY ServiceListHead; -extern LIST_ENTRY GroupListHead; -extern LIST_ENTRY ImageListHead; +extern LIST_ENTRY DatabaseListHead; +// extern LIST_ENTRY SCHandleListHead; // Unused for the moment. extern BOOL ScmShutdown; -/* FUNCTIONS ***************************************************************/ +/* FUNCTIONS *****************************************************************/ /* config.c */ -DWORD ScmOpenServiceKey(LPWSTR lpServiceName, +DWORD ScmOpenServiceKey(PSERVICE_RECORD pServiceRecord, REGSAM samDesired, PHKEY phKey); -DWORD ScmCreateServiceKey(LPCWSTR lpServiceName, +DWORD ScmCreateServiceKey(PSERVICE_RECORD pServiceRecord, REGSAM samDesired, PHKEY phKey); @@ -91,7 +219,7 @@ LPCWSTR lpDependencies, DWORD dwDependenciesLength); -DWORD ScmMarkServiceForDelete(PSERVICE pService); +DWORD ScmMarkServiceForDelete(PSERVICE_RECORD pService); BOOL ScmIsDeleteFlagSet(HKEY hServiceKey); DWORD ScmReadString(HKEY hServiceKey, @@ -106,61 +234,105 @@ /* database.c */ -DWORD ScmCreateServiceDatabase(VOID); -VOID ScmShutdownServiceDatabase(VOID); -VOID ScmGetBootAndSystemDriverState(VOID); +/******** there are used only in svcobject.c ************/ +PSERVICE_RECORD ScmGetServiceEntryByName(IN PSCMGR_DATABASE pScDatabase, + IN LPCWSTR lpServiceName); +PSERVICE_RECORD ScmGetServiceEntryByDisplayName(IN PSCMGR_DATABASE pScDatabase, + IN LPCWSTR lpDisplayName); +PSERVICE_RECORD ScmGetServiceEntryByResumeCount(IN PSCMGR_DATABASE pScDatabase, + IN DWORD dwResumeCount); +/********************************************************/ + +DWORD ScmCreateNewServiceRecord(IN PSCMGR_DATABASE pScDatabase, + IN LPCWSTR lpServiceName, + OUT PSERVICE_RECORD* ppServiceRecord); +VOID ScmDeleteServiceRecord(IN PSERVICE_RECORD pServiceRecord); + VOID ScmAutoStartServices(VOID); VOID ScmAutoShutdownServices(VOID); -DWORD ScmStartService(PSERVICE Service, - DWORD argc, - LPWSTR *argv); -PSERVICE ScmGetServiceEntryByName(LPCWSTR lpServiceName); -PSERVICE ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName); -PSERVICE ScmGetServiceEntryByResumeCount(DWORD dwResumeCount); -DWORD ScmCreateNewServiceRecord(LPCWSTR lpServiceName, - PSERVICE *lpServiceRecord); -VOID ScmDeleteServiceRecord(PSERVICE lpService); -DWORD ScmMarkServiceForDelete(PSERVICE pService); +DWORD ScmCreateServiceDatabases(VOID); +VOID ScmShutdownServiceDatabases(VOID); -DWORD ScmControlService(PSERVICE Service, - DWORD dwControl); +PSCMGR_DATABASE FindDatabase(IN LPCWSTR DatabaseName); +BOOL IsActiveDatabase(IN PSCMGR_DATABASE pScDatabase); -BOOL ScmLockDatabaseExclusive(VOID); -BOOL ScmLockDatabaseShared(VOID); -VOID ScmUnlockDatabase(VOID); -VOID ScmInitNamedPipeCriticalSection(VOID); -VOID ScmDeleteNamedPipeCriticalSection(VOID); - - /* driver.c */ -DWORD ScmLoadDriver(PSERVICE lpService); -DWORD ScmUnloadDriver(PSERVICE lpService); -DWORD ScmControlDriver(PSERVICE lpService, +VOID ScmGetBootAndSystemDriverState(IN PSCMGR_DATABASE pScDatabase); +DWORD ScmLoadDriver(PSERVICE_RECORD lpService); +DWORD ScmControlDriver(PSERVICE_RECORD lpService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus); /* groupdb.c */ -DWORD ScmCreateGroupList(VOID); -DWORD ScmSetServiceGroup(PSERVICE lpService, - LPCWSTR lpGroupName); +DWORD ScmSetServiceGroup(IN OUT PSERVICE_RECORD pServiceRecord, + IN LPCWSTR lpGroupName); +DWORD ScmCreateGroupList(IN PSCMGR_DATABASE pScDatabase); +/* handles.c */ +#include "handles.h" + + +/* lock.c */ + +BOOL ScmLockDatabaseExclusive(VOID); +BOOL ScmLockDatabaseShared(VOID); +VOID ScmUnlockDatabase(VOID); + + /* rpcserver.c */ VOID ScmStartRpcServer(VOID); +/* service.c */ + +VOID ScmInitNamedPipeCriticalSection(VOID); +VOID ScmDeleteNamedPipeCriticalSection(VOID); +VOID ScmDereferenceServiceImage(PIMAGE_RECORD pServiceImage); + +DWORD ScmStartService(PSERVICE_RECORD Service, + DWORD argc, + LPWSTR *argv); + +DWORD ScmControlService(PSERVICE_RECORD Service, + DWORD dwControl); + + /* services.c */ VOID PrintString(LPCSTR fmt, ...); VOID ScmLogError(DWORD dwEventId, WORD wStrings, LPCWSTR *lpStrings); +VOID ScmWaitForLsa(VOID); + +/* svcobject.c */ + +DWORD // TODO: Was static but now is used in handles.c +Int_EnumDependentServicesW(HKEY hServicesKey, + PSERVICE_RECORD lpService, + DWORD dwServiceState, + PSERVICE_RECORD* lpServices, + LPDWORD pcbBytesNeeded, + LPDWORD lpServicesReturned); + + +/* utils.c */ + +BOOL ScDatabaseNamesMatch(const LPCWSTR lpszDbName1, + const LPCWSTR lpszDbName2); +size_t wcssize(const LPCWSTR lpszStr); +DWORD ScmCanonDriverImagePath(DWORD dwStartType, + LPCWSTR lpServiceName, + LPWSTR* lpCanonName); + +#endif // __SERVICES_H__ + /* EOF */ - Index: base/system/services/svcobject.c =================================================================== --- base/system/services/svcobject.c (révision 0) +++ base/system/services/svcobject.c (copie de travail) @@ -0,0 +1,4695 @@ +/* + * PROJECT: ReactOS Service Control Manager + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/system/services/svcobject.c + * PURPOSE: Common service-object control interface + * COPYRIGHT: Copyright 2005-2006 Eric Kohl + * + */ + +/* INCLUDES ******************************************************************/ + +#include "services.h" + +#define NDEBUG +#include + + +/* GLOBALS *******************************************************************/ + +#define TAG_ARRAY_SIZE 32 + + +/* FUNCTIONS *****************************************************************/ + +/* Internal recursive function */ +/* Need to search for every dependency on every service */ +/* static */ DWORD // TODO: Was static but now is used in handles.c +Int_EnumDependentServicesW(HKEY hServicesKey, + PSERVICE_RECORD lpService, + DWORD dwServiceState, + PSERVICE_RECORD* lpServices, + LPDWORD pcbBytesNeeded, + LPDWORD lpServicesReturned) +{ + DWORD dwError = ERROR_SUCCESS; + WCHAR szNameBuf[MAX_PATH]; + WCHAR szValueBuf[MAX_PATH]; + WCHAR *lpszNameBuf = szNameBuf; + WCHAR *lpszValueBuf = szValueBuf; + DWORD dwSize; + DWORD dwNumSubKeys; + DWORD dwIteration; + PSERVICE_RECORD lpCurrentService; + HKEY hServiceEnumKey; + DWORD dwCurrentServiceState = SERVICE_ACTIVE; + DWORD dwDependServiceStrPtr = 0; + DWORD dwRequiredSize = 0; + + /* Get the number of service keys */ + dwError = RegQueryInfoKeyW(hServicesKey, + NULL, + NULL, + NULL, + &dwNumSubKeys, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + if (dwError != ERROR_SUCCESS) + { + DPRINT("ERROR! Unable to get number of services keys.\n"); + return dwError; + } + + /* Iterate the service keys to see if another service depends on the this service */ + for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++) + { + dwSize = MAX_PATH; + dwError = RegEnumKeyExW(hServicesKey, + dwIteration, + lpszNameBuf, + &dwSize, + NULL, + NULL, + NULL, + NULL); + if (dwError != ERROR_SUCCESS) + return dwError; + + /* Open the Service key */ + dwError = RegOpenKeyExW(hServicesKey, + lpszNameBuf, + 0, + KEY_READ, + &hServiceEnumKey); + if (dwError != ERROR_SUCCESS) + return dwError; + + dwSize = MAX_PATH; + + /* Check for the DependOnService Value */ + dwError = RegQueryValueExW(hServiceEnumKey, + L"DependOnService", + NULL, + NULL, + (LPBYTE)lpszValueBuf, + &dwSize); + + /* FIXME: Handle load order. */ + + /* If the service found has a DependOnService value */ + if (dwError == ERROR_SUCCESS) + { + dwDependServiceStrPtr = 0; + + /* Can be more than one Dependencies in the DependOnService string */ + while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0) + { + if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->ServiceName) == 0) + { + /* Get the current enumed service pointer */ + lpCurrentService = ScmGetServiceEntryByName(lpService->Database, lpszNameBuf); + + /* Check for valid Service */ + if (!lpCurrentService) + { + /* This should never happen! */ + DPRINT("This should not happen at this point, report to Developer\n"); + return ERROR_NOT_FOUND; + } + + /* Determine state the service is in */ + if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED) + dwCurrentServiceState = SERVICE_INACTIVE; + + /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */ + if ((dwCurrentServiceState == dwServiceState) || + (dwServiceState == SERVICE_STATE_ALL)) + { + /* Calculate the required size */ + dwRequiredSize += sizeof(SERVICE_STATUS); + dwRequiredSize += ((wcslen(lpCurrentService->ServiceName) + 1) * sizeof(WCHAR)); + dwRequiredSize += ((wcslen(lpCurrentService->DisplayName) + 1) * sizeof(WCHAR)); + + /* Add the size for service name and display name pointers */ + dwRequiredSize += (2 * sizeof(PVOID)); + + /* increase the BytesNeeded size */ + *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize; + + /* Don't fill callers buffer yet, as MSDN read that the last service with dependency + comes first */ + + /* Recursive call to check for its dependencies */ + Int_EnumDependentServicesW(hServicesKey, + lpCurrentService, + dwServiceState, + lpServices, + pcbBytesNeeded, + lpServicesReturned); + + /* If the lpServices is valid set the service pointer */ + if (lpServices) + lpServices[*lpServicesReturned] = lpCurrentService; + + *lpServicesReturned = *lpServicesReturned + 1; + } + } + + dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1); + } + } + else if (*pcbBytesNeeded) + { + dwError = ERROR_SUCCESS; + } + + RegCloseKey(hServiceEnumKey); + } + + return dwError; +} + + +static DWORD +ScmAssignNewTag(PSERVICE_RECORD lpService) +{ + HKEY hKey = NULL; + DWORD dwError; + DWORD dwGroupTagCount = 0; + PDWORD pdwGroupTags = NULL; + DWORD dwFreeTag = 0; + DWORD dwTagUsedBase = 1; + BOOLEAN TagUsed[TAG_ARRAY_SIZE]; + INT nTagOffset; + DWORD i; + DWORD cbDataSize; + PLIST_ENTRY ServiceEntry; + PSERVICE_RECORD CurrentService; + + ASSERT(lpService != NULL); + ASSERT(lpService->lpGroup != NULL); + + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + lpService->Database->RegistryKeyNames.Control_GroupOrderList, + 0, + KEY_READ, + &hKey); + + if (dwError != ERROR_SUCCESS) + goto findFreeTag; + + /* query value length */ + cbDataSize = 0; + dwError = RegQueryValueExW(hKey, + lpService->lpGroup->szGroupName, + NULL, + NULL, + NULL, + &cbDataSize); + + if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA) + goto findFreeTag; + + pdwGroupTags = HeapAlloc(GetProcessHeap(), 0, cbDataSize); + if (!pdwGroupTags) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + + dwError = RegQueryValueExW(hKey, + lpService->lpGroup->szGroupName, + NULL, + NULL, + (LPBYTE)pdwGroupTags, + &cbDataSize); + + if (dwError != ERROR_SUCCESS) + goto findFreeTag; + + if (cbDataSize < sizeof(pdwGroupTags[0])) + goto findFreeTag; + + dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1); + +findFreeTag: + do + { + /* mark all tags as unused */ + for (i = 0; i < TAG_ARRAY_SIZE; i++) + TagUsed[i] = FALSE; + + /* mark tags in GroupOrderList as used */ + for (i = 1; i <= dwGroupTagCount; i++) + { + nTagOffset = pdwGroupTags[i] - dwTagUsedBase; + if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE) + TagUsed[nTagOffset] = TRUE; + } + + /* mark tags in service list as used */ + ServiceEntry = lpService->ServiceListEntry.Flink; + while (ServiceEntry != &lpService->ServiceListEntry) + { + ASSERT(ServiceEntry != NULL); + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE_RECORD, ServiceListEntry); + if (CurrentService->lpGroup == lpService->lpGroup) + { + nTagOffset = CurrentService->dwTag - dwTagUsedBase; + if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE) + TagUsed[nTagOffset] = TRUE; + } + + ServiceEntry = ServiceEntry->Flink; + } + + /* find unused tag, if any */ + for (i = 0; i < TAG_ARRAY_SIZE; i++) + { + if (!TagUsed[i]) + { + dwFreeTag = dwTagUsedBase + i; + break; + } + } + + dwTagUsedBase += TAG_ARRAY_SIZE; + } while (!dwFreeTag); + +cleanup: + if (pdwGroupTags) + HeapFree(GetProcessHeap(), 0, pdwGroupTags); + + if (hKey) + RegCloseKey(hKey); + + if (dwFreeTag) + { + lpService->dwTag = dwFreeTag; + DPRINT("Assigning new tag %lu to service %S in group %S\n", + lpService->dwTag, lpService->ServiceName, lpService->lpGroup->szGroupName); + dwError = ERROR_SUCCESS; + } + else + { + DPRINT1("Failed to assign new tag to service %S, error=%lu\n", + lpService->ServiceName, dwError); + } + + return dwError; +} + + +static BOOL +ScmIsValidServiceState(DWORD dwCurrentState) +{ + switch (dwCurrentState) + { + case SERVICE_STOPPED: + case SERVICE_START_PENDING: + case SERVICE_STOP_PENDING: + case SERVICE_RUNNING: + case SERVICE_CONTINUE_PENDING: + case SERVICE_PAUSE_PENDING: + case SERVICE_PAUSED: + return TRUE; + + default: + return FALSE; + } +} + + +/* RPC SERVER FUNCTIONS ******************************************************/ + +/* Function 1 */ +DWORD RControlService( + SC_RPC_HANDLE hService, + DWORD dwControl, + LPSERVICE_STATUS lpServiceStatus) +{ + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService; + ACCESS_MASK DesiredAccess; + DWORD dwError = ERROR_SUCCESS; + DWORD pcbBytesNeeded = 0; + DWORD dwServicesReturned = 0; + DWORD dwControlsAccepted; + DWORD dwCurrentState; + HKEY hServicesKey = NULL; + + DPRINT("RControlService() called\n"); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + /* Check the service handle */ + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Check the service entry point */ + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT1("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* + * We can control services only if the + * database is the active database. + */ + if (!IsActiveDatabase(lpService->Database)) + return ERROR_ACCESS_DENIED; + + /* Check access rights */ + switch (dwControl) + { + case SERVICE_CONTROL_STOP: + DesiredAccess = SERVICE_STOP; + break; + + case SERVICE_CONTROL_PAUSE: + case SERVICE_CONTROL_CONTINUE: + DesiredAccess = SERVICE_PAUSE_CONTINUE; + break; + + case SERVICE_INTERROGATE: + DesiredAccess = SERVICE_INTERROGATE; + break; + + default: + if (dwControl >= 128 && dwControl <= 255) + DesiredAccess = SERVICE_USER_DEFINED_CONTROL; + else + return ERROR_INVALID_PARAMETER; + break; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + DesiredAccess)) + return ERROR_ACCESS_DENIED; + + /* Return the current service status information */ + RtlCopyMemory(lpServiceStatus, + &lpService->Status, + sizeof(SERVICE_STATUS)); + + if (dwControl == SERVICE_CONTROL_STOP) + { + /* Check if the service has dependencies running as windows + doesn't stop a service that does */ + + /* Open the Services Reg key */ + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + lpService->Database->RegistryKeyNames.Services, + 0, + KEY_READ, + &hServicesKey); + if (dwError != ERROR_SUCCESS) + { + DPRINT("Failed to open services key\n"); + return dwError; + } + + /* Call the internal function with NULL, just to get bytes we need */ + Int_EnumDependentServicesW(hServicesKey, + lpService, + SERVICE_ACTIVE, + NULL, + &pcbBytesNeeded, + &dwServicesReturned); + + RegCloseKey(hServicesKey); + + /* If pcbBytesNeeded is not zero then there are services running that + are dependent on this service */ + if (pcbBytesNeeded != 0) + { + DPRINT("Service has running dependencies. Failed to stop service.\n"); + return ERROR_DEPENDENT_SERVICES_RUNNING; + } + } + + if (lpService->Status.dwServiceType & SERVICE_DRIVER) + { + /* Send control code to the driver */ + dwError = ScmControlDriver(lpService, + dwControl, + lpServiceStatus); + } + else + { + dwControlsAccepted = lpService->Status.dwControlsAccepted; + dwCurrentState = lpService->Status.dwCurrentState; + + /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */ + if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED) + return ERROR_SERVICE_NOT_ACTIVE; + + /* Check the current state before sending a control request */ + switch (dwCurrentState) + { + case SERVICE_STOP_PENDING: + case SERVICE_STOPPED: + return ERROR_SERVICE_CANNOT_ACCEPT_CTRL; + + case SERVICE_START_PENDING: + switch (dwControl) + { + case SERVICE_CONTROL_STOP: + break; + + case SERVICE_CONTROL_INTERROGATE: + RtlCopyMemory(lpServiceStatus, + &lpService->Status, + sizeof(SERVICE_STATUS)); + return ERROR_SUCCESS; + + default: + return ERROR_SERVICE_CANNOT_ACCEPT_CTRL; + } + break; + } + + /* Check if the control code is acceptable to the service */ + switch (dwControl) + { + case SERVICE_CONTROL_STOP: + if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0) + return ERROR_INVALID_SERVICE_CONTROL; + break; + + case SERVICE_CONTROL_PAUSE: + case SERVICE_CONTROL_CONTINUE: + if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0) + return ERROR_INVALID_SERVICE_CONTROL; + break; + } + + /* Send control code to the service */ + dwError = ScmControlService(lpService, + dwControl); + + /* Return service status information */ + RtlCopyMemory(lpServiceStatus, + &lpService->Status, + sizeof(SERVICE_STATUS)); + } + + if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded)) + dwError = ERROR_DEPENDENT_SERVICES_RUNNING; + + return dwError; +} + + +/* Function 2 */ +DWORD RDeleteService( + SC_RPC_HANDLE hService) +{ + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService; + DWORD dwError; + + DPRINT("RDeleteService() called\n"); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + DELETE)) + return ERROR_ACCESS_DENIED; + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database exclusively */ + ScmLockDatabaseExclusive(); + + if (lpService->bDeleted) + { + DPRINT("The service has already been marked for delete!\n"); + dwError = ERROR_SERVICE_MARKED_FOR_DELETE; + goto Done; + } + + /* Mark service for delete */ + lpService->bDeleted = TRUE; + + dwError = ScmMarkServiceForDelete(lpService); + +Done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + DPRINT("RDeleteService() done\n"); + + return dwError; +} + + +/* Function 4 */ +DWORD RQueryServiceObjectSecurity( + SC_RPC_HANDLE hService, + SECURITY_INFORMATION dwSecurityInformation, + LPBYTE lpSecurityDescriptor, + DWORD cbBufSize, + LPBOUNDED_DWORD_256K pcbBytesNeeded) +{ + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService; + ULONG DesiredAccess = 0; + NTSTATUS Status; + DWORD dwBytesNeeded; + DWORD dwError; + + + SECURITY_DESCRIPTOR ObjectDescriptor; + + DPRINT("RQueryServiceObjectSecurity() called\n"); + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (dwSecurityInformation & (DACL_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION)) + DesiredAccess |= READ_CONTROL; + + if (dwSecurityInformation & SACL_SECURITY_INFORMATION) + DesiredAccess |= ACCESS_SYSTEM_SECURITY; + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + DesiredAccess)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database */ + ScmLockDatabaseShared(); + + + /* hack */ + Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION); + + Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */, + dwSecurityInformation, + (PSECURITY_DESCRIPTOR)lpSecurityDescriptor, + cbBufSize, + &dwBytesNeeded); + + /* Unlock the service database */ + ScmUnlockDatabase(); + + if (NT_SUCCESS(Status)) + { + *pcbBytesNeeded = dwBytesNeeded; + dwError = STATUS_SUCCESS; + } + else if (Status == STATUS_BUFFER_TOO_SMALL) + { + *pcbBytesNeeded = dwBytesNeeded; + dwError = ERROR_INSUFFICIENT_BUFFER; + } + else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT) + { + dwError = ERROR_GEN_FAILURE; + } + else + { + dwError = RtlNtStatusToDosError(Status); + } + + return dwError; +} + + +/* Function 5 */ +DWORD RSetServiceObjectSecurity( + SC_RPC_HANDLE hService, + SECURITY_INFORMATION dwSecurityInformation, + LPBYTE lpSecurityDescriptor, + DWORD cbBufSize) +{ + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService; + ULONG DesiredAccess = 0; + /* HANDLE hToken = NULL; */ + HKEY hServiceKey; + /* NTSTATUS Status; */ + DWORD dwError; + + DPRINT("RSetServiceObjectSecurity() called\n"); + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (dwSecurityInformation == 0 || + dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION + | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)) + return ERROR_INVALID_PARAMETER; + + if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor)) + return ERROR_INVALID_PARAMETER; + + if (dwSecurityInformation & SACL_SECURITY_INFORMATION) + DesiredAccess |= ACCESS_SYSTEM_SECURITY; + + if (dwSecurityInformation & DACL_SECURITY_INFORMATION) + DesiredAccess |= WRITE_DAC; + + if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION)) + DesiredAccess |= WRITE_OWNER; + + if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) && + (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL)) + return ERROR_INVALID_PARAMETER; + + if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) && + (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL)) + return ERROR_INVALID_PARAMETER; + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + DesiredAccess)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + if (lpService->bDeleted) + return ERROR_SERVICE_MARKED_FOR_DELETE; + +#if 0 + RpcImpersonateClient(NULL); + + Status = NtOpenThreadToken(NtCurrentThread(), + 8, + TRUE, + &hToken); + if (!NT_SUCCESS(Status)) + return RtlNtStatusToDosError(Status); + + RpcRevertToSelf(); +#endif + + /* Lock the service database exclusive */ + ScmLockDatabaseExclusive(); + +#if 0 + Status = RtlSetSecurityObject(dwSecurityInformation, + (PSECURITY_DESCRIPTOR)lpSecurityDescriptor, + &lpService->lpSecurityDescriptor, + &ScmServiceMapping, + hToken); + if (!NT_SUCCESS(Status)) + { + dwError = RtlNtStatusToDosError(Status); + goto Done; + } +#endif + + dwError = ScmOpenServiceKey(lpService, + READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE, + &hServiceKey); + if (dwError != ERROR_SUCCESS) + goto Done; + + UNIMPLEMENTED; + dwError = ERROR_SUCCESS; +// dwError = ScmWriteSecurityDescriptor(hServiceKey, +// lpService->lpSecurityDescriptor); + + RegFlushKey(hServiceKey); + RegCloseKey(hServiceKey); + +Done: + +#if 0 + if (hToken != NULL) + NtClose(hToken); +#endif + + /* Unlock service database */ + ScmUnlockDatabase(); + + DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 6 */ +DWORD RQueryServiceStatus( + SC_RPC_HANDLE hService, + LPSERVICE_STATUS lpServiceStatus) +{ + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService; + + DPRINT("RQueryServiceStatus() called\n"); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_QUERY_STATUS)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database shared */ + ScmLockDatabaseShared(); + + /* Return service status information */ + RtlCopyMemory(lpServiceStatus, + &lpService->Status, + sizeof(SERVICE_STATUS)); + + /* Unlock the service database */ + ScmUnlockDatabase(); + + return ERROR_SUCCESS; +} + + +/* Function 7 */ +DWORD RSetServiceStatus(// IN SC_RPC_HANDLE hServiceStatus, + IN RPC_SERVICE_STATUS_HANDLE hServiceStatus, + IN LPSERVICE_STATUS lpServiceStatus) +{ + // PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService; + DWORD dwPreviousState; + LPCWSTR lpErrorStrings[2]; + WCHAR szErrorBuffer[32]; + + DPRINT("RSetServiceStatus() called\n"); + DPRINT("hServiceStatus = %p\n", hServiceStatus); + DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType); + DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState); + DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted); + DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode); + DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode); + DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint); + DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint); + + /* + hSvc = ScmGetServiceFromHandle(hServiceStatus); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_SET_STATUS /\* 0x00008000 *\/)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + */ + lpService = (PSERVICE_RECORD)hServiceStatus; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Check current state */ + if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState)) + { + DPRINT("Invalid service state!\n"); + return ERROR_INVALID_DATA; + } + + /* Check service type */ + if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) && + (lpServiceStatus->dwServiceType & SERVICE_DRIVER)) + { + DPRINT("Invalid service type!\n"); + return ERROR_INVALID_DATA; + } + + /* Check accepted controls */ + if (lpServiceStatus->dwControlsAccepted & ~0xFF) + { + DPRINT("Invalid controls accepted!\n"); + return ERROR_INVALID_DATA; + } + + /* Lock the service database exclusively */ + ScmLockDatabaseExclusive(); + + /* Save the current service state */ + dwPreviousState = lpService->Status.dwCurrentState; + + RtlCopyMemory(&lpService->Status, + lpServiceStatus, + sizeof(SERVICE_STATUS)); + + /* Unlock the service database */ + ScmUnlockDatabase(); + + /* Log a failed service stop */ + if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) && + (dwPreviousState != SERVICE_STOPPED)) + { + if (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS) + { + swprintf(szErrorBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode); + lpErrorStrings[0] = lpService->DisplayName; + lpErrorStrings[1] = szErrorBuffer; + + ScmLogError(EVENT_SERVICE_EXIT_FAILED, + 2, + lpErrorStrings); + } + } + + DPRINT("Set %S to %lu\n", lpService->DisplayName, lpService->Status.dwCurrentState); + DPRINT("RSetServiceStatus() done\n"); + + return ERROR_SUCCESS; +} + + +/* Function 10 */ +DWORD RI_ScSetServiceBitsW( + RPC_SERVICE_STATUS_HANDLE hServiceStatus, + DWORD dwServiceBits, + BOOL bSetBitsOn, + BOOL bUpdateImmediately, + LPWSTR pszTransportName) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 11 */ +DWORD RChangeServiceConfigW( + SC_RPC_HANDLE hService, + DWORD dwServiceType, + DWORD dwStartType, + DWORD dwErrorControl, + LPWSTR lpBinaryPathName, + LPWSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, + LPBYTE lpDependencies, + DWORD dwDependSize, + LPWSTR lpServiceStartName, + LPBYTE lpPassword, + DWORD dwPwSize, + LPWSTR lpDisplayName) +{ + DWORD dwError = ERROR_SUCCESS; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + HKEY hServiceKey = NULL; + LPWSTR lpDisplayNameW = NULL; + LPWSTR lpImagePathW = NULL; + + DPRINT("RChangeServiceConfigW() called\n"); + DPRINT("dwServiceType = %lu\n", dwServiceType); + DPRINT("dwStartType = %lu\n", dwStartType); + DPRINT("dwErrorControl = %lu\n", dwErrorControl); + DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName); + DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup); + DPRINT("lpDisplayName = %S\n", lpDisplayName); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_CHANGE_CONFIG)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database exclusively */ + ScmLockDatabaseExclusive(); + + if (lpService->bDeleted) + { + DPRINT("The service has already been marked for delete!\n"); + dwError = ERROR_SERVICE_MARKED_FOR_DELETE; + goto done; + } + + /* Open the service key */ + dwError = ScmOpenServiceKey(lpService, + KEY_SET_VALUE, + &hServiceKey); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Write service data to the registry */ + /* Set the display name */ + if (lpDisplayName != NULL && *lpDisplayName != 0) + { + RegSetValueExW(hServiceKey, + L"DisplayName", + 0, + REG_SZ, + (LPBYTE)lpDisplayName, + (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); + + /* Update the display name */ + lpDisplayNameW = HeapAlloc(GetProcessHeap(), + 0, + (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); + if (lpDisplayNameW == NULL) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + if (lpService->DisplayName != lpService->ServiceName) + HeapFree(GetProcessHeap(), 0, lpService->DisplayName); + + lpService->DisplayName = lpDisplayNameW; + } + + if (dwServiceType != SERVICE_NO_CHANGE) + { + /* Set the service type */ + dwError = RegSetValueExW(hServiceKey, + L"Type", + 0, + REG_DWORD, + (LPBYTE)&dwServiceType, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + lpService->Status.dwServiceType = dwServiceType; + } + + if (dwStartType != SERVICE_NO_CHANGE) + { + /* Set the start value */ + dwError = RegSetValueExW(hServiceKey, + L"Start", + 0, + REG_DWORD, + (LPBYTE)&dwStartType, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + lpService->dwStartType = dwStartType; + } + + if (dwErrorControl != SERVICE_NO_CHANGE) + { + /* Set the error control value */ + dwError = RegSetValueExW(hServiceKey, + L"ErrorControl", + 0, + REG_DWORD, + (LPBYTE)&dwErrorControl, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + lpService->dwErrorControl = dwErrorControl; + } + + if (lpBinaryPathName != NULL && *lpBinaryPathName != 0) + { + /* Set the image path */ + lpImagePathW = lpBinaryPathName; + + if (lpService->Status.dwServiceType & SERVICE_DRIVER) + { + dwError = ScmCanonDriverImagePath(lpService->dwStartType, + lpBinaryPathName, + &lpImagePathW); + + if (dwError != ERROR_SUCCESS) + goto done; + } + + dwError = RegSetValueExW(hServiceKey, + L"ImagePath", + 0, + REG_EXPAND_SZ, + (LPBYTE)lpImagePathW, + (wcslen(lpImagePathW) + 1) * sizeof(WCHAR)); + + if (lpImagePathW != lpBinaryPathName) + HeapFree(GetProcessHeap(), 0, lpImagePathW); + + if (dwError != ERROR_SUCCESS) + goto done; + } + + /* Set the group name */ + if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) + { + dwError = RegSetValueExW(hServiceKey, + L"Group", + 0, + REG_SZ, + (LPBYTE)lpLoadOrderGroup, + (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + goto done; + + dwError = ScmSetServiceGroup(lpService, + lpLoadOrderGroup); + if (dwError != ERROR_SUCCESS) + goto done; + } + + if (lpdwTagId != NULL) + { + dwError = ScmAssignNewTag(lpService); + if (dwError != ERROR_SUCCESS) + goto done; + + dwError = RegSetValueExW(hServiceKey, + L"Tag", + 0, + REG_DWORD, + (LPBYTE)&lpService->dwTag, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + *lpdwTagId = lpService->dwTag; + } + + /* Write dependencies */ + if (lpDependencies != NULL && *(LPWSTR)lpDependencies != 0) + { + dwError = ScmWriteDependencies(hServiceKey, + (LPWSTR)lpDependencies, + dwDependSize); + if (dwError != ERROR_SUCCESS) + goto done; + } + + if (lpPassword != NULL) + { + /* FIXME: Write password */ + } + +done: + if (hServiceKey != NULL) + RegCloseKey(hServiceKey); + + /* Unlock the service database */ + ScmUnlockDatabase(); + + DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 12 */ +DWORD RCreateServiceW( + SC_RPC_HANDLE hSCManager, + LPCWSTR lpServiceName, + LPCWSTR lpDisplayName, + DWORD dwDesiredAccess, + DWORD dwServiceType, + DWORD dwStartType, + DWORD dwErrorControl, + LPCWSTR lpBinaryPathName, + LPCWSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, + LPBYTE lpDependencies, + DWORD dwDependSize, + LPCWSTR lpServiceStartName, + LPBYTE lpPassword, + DWORD dwPwSize, + LPSC_RPC_HANDLE lpServiceHandle) +{ + PSC_HANDLE_STRUCT hManager; + DWORD dwError = ERROR_SUCCESS; + PSERVICE_RECORD lpService = NULL; + PSC_HANDLE_STRUCT hServiceHandle = NULL; + LPWSTR lpImagePath = NULL; + HKEY hServiceKey = NULL; + LPWSTR lpObjectName; + + DPRINT("RCreateServiceW() called\n"); + DPRINT("lpServiceName = %S\n", lpServiceName); + DPRINT("lpDisplayName = %S\n", lpDisplayName); + DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess); + DPRINT("dwServiceType = %lu\n", dwServiceType); + DPRINT("dwStartType = %lu\n", dwStartType); + DPRINT("dwErrorControl = %lu\n", dwErrorControl); + DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName); + DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup); + DPRINT("lpdwTagId = %p\n", lpdwTagId); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hManager = ScmGetServiceManagerFromHandle(hSCManager); + if (hManager == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Check access rights */ + if (!RtlAreAllAccessesGranted(hManager->DesiredAccess, + SC_MANAGER_CREATE_SERVICE)) + { + DPRINT("Insufficient access rights! 0x%lx\n", + hManager->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + if (wcslen(lpServiceName) == 0) + { + return ERROR_INVALID_NAME; + } + + if (wcslen(lpBinaryPathName) == 0) + { + return ERROR_INVALID_PARAMETER; + } + + /* Check for invalid service type value */ + if ((dwServiceType != SERVICE_KERNEL_DRIVER) && + (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) && + ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) && + ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS)) + return ERROR_INVALID_PARAMETER; + + /* Check for invalid start type value */ + if ((dwStartType != SERVICE_BOOT_START) && + (dwStartType != SERVICE_SYSTEM_START) && + (dwStartType != SERVICE_AUTO_START) && + (dwStartType != SERVICE_DEMAND_START) && + (dwStartType != SERVICE_DISABLED)) + return ERROR_INVALID_PARAMETER; + + /* Only drivers can be boot start or system start services */ + if ((dwStartType == SERVICE_BOOT_START) || + (dwStartType == SERVICE_SYSTEM_START)) + { + if ((dwServiceType != SERVICE_KERNEL_DRIVER) && + (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)) + return ERROR_INVALID_PARAMETER; + } + + /* Check for invalid error control value */ + if ((dwErrorControl != SERVICE_ERROR_IGNORE) && + (dwErrorControl != SERVICE_ERROR_NORMAL) && + (dwErrorControl != SERVICE_ERROR_SEVERE) && + (dwErrorControl != SERVICE_ERROR_CRITICAL)) + return ERROR_INVALID_PARAMETER; + + if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) && + (lpServiceStartName)) + { + return ERROR_INVALID_PARAMETER; + } + + if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup)) + { + return ERROR_INVALID_PARAMETER; + } + + /* Lock the service database exclusively */ + ScmLockDatabaseExclusive(); + + lpService = ScmGetServiceEntryByName(hManager->Type.ScManagerObject.Database, lpServiceName); + if (lpService) + { + /* Unlock the service database */ + ScmUnlockDatabase(); + + /* Check if it is marked for deletion */ + if (lpService->bDeleted) + return ERROR_SERVICE_MARKED_FOR_DELETE; + + /* Return Error exist */ + return ERROR_SERVICE_EXISTS; + } + + if (lpDisplayName != NULL && + ScmGetServiceEntryByDisplayName(hManager->Type.ScManagerObject.Database, lpDisplayName) != NULL) + { + /* Unlock the service database */ + ScmUnlockDatabase(); + + return ERROR_DUPLICATE_SERVICE_NAME; + } + + if (dwServiceType & SERVICE_DRIVER) + { + dwError = ScmCanonDriverImagePath(dwStartType, + lpBinaryPathName, + &lpImagePath); + if (dwError != ERROR_SUCCESS) + goto done; + } + else + { + if (dwStartType == SERVICE_BOOT_START || + dwStartType == SERVICE_SYSTEM_START) + { + /* Unlock the service database */ + ScmUnlockDatabase(); + + return ERROR_INVALID_PARAMETER; + } + } + + /* Allocate a new service entry */ + dwError = ScmCreateNewServiceRecord(hManager->Type.ScManagerObject.Database, + lpServiceName, + &lpService); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Fill the new service entry */ + lpService->Status.dwServiceType = dwServiceType; + lpService->dwStartType = dwStartType; + lpService->dwErrorControl = dwErrorControl; + + /* Fill the display name */ + if (lpDisplayName != NULL && + *lpDisplayName != 0 && + _wcsicmp(lpService->DisplayName, lpDisplayName) != 0) + { + lpService->DisplayName = HeapAlloc(GetProcessHeap(), 0, + (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); + if (lpService->DisplayName == NULL) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + wcscpy(lpService->DisplayName, lpDisplayName); + } + + /* Assign the service to a group */ + if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) + { + dwError = ScmSetServiceGroup(lpService, + lpLoadOrderGroup); + if (dwError != ERROR_SUCCESS) + goto done; + } + + /* Assign a new tag */ + if (lpdwTagId != NULL) + { + dwError = ScmAssignNewTag(lpService); + if (dwError != ERROR_SUCCESS) + goto done; + } + + /* Write service data to the registry */ + /* Create the service key */ + dwError = ScmCreateServiceKey(lpService, + KEY_WRITE, + &hServiceKey); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Set the display name */ + if (lpDisplayName != NULL && *lpDisplayName != 0) + { + RegSetValueExW(hServiceKey, + L"DisplayName", + 0, + REG_SZ, + (LPBYTE)lpDisplayName, + (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); + } + + /* Set the service type */ + dwError = RegSetValueExW(hServiceKey, + L"Type", + 0, + REG_DWORD, + (LPBYTE)&dwServiceType, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Set the start value */ + dwError = RegSetValueExW(hServiceKey, + L"Start", + 0, + REG_DWORD, + (LPBYTE)&dwStartType, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Set the error control value */ + dwError = RegSetValueExW(hServiceKey, + L"ErrorControl", + 0, + REG_DWORD, + (LPBYTE)&dwErrorControl, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Set the image path */ + if (dwServiceType & SERVICE_WIN32) + { + dwError = RegSetValueExW(hServiceKey, + L"ImagePath", + 0, + REG_EXPAND_SZ, + (LPBYTE)lpBinaryPathName, + (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + goto done; + } + else if (dwServiceType & SERVICE_DRIVER) + { + dwError = RegSetValueExW(hServiceKey, + L"ImagePath", + 0, + REG_EXPAND_SZ, + (LPBYTE)lpImagePath, + (wcslen(lpImagePath) + 1) * sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + goto done; + } + + /* Set the group name */ + if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) + { + dwError = RegSetValueExW(hServiceKey, + L"Group", + 0, + REG_SZ, + (LPBYTE)lpLoadOrderGroup, + (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + goto done; + } + + if (lpdwTagId != NULL) + { + dwError = RegSetValueExW(hServiceKey, + L"Tag", + 0, + REG_DWORD, + (LPBYTE)&lpService->dwTag, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + } + + /* Write dependencies */ + if (lpDependencies != NULL && *lpDependencies != 0) + { + dwError = ScmWriteDependencies(hServiceKey, + (LPCWSTR)lpDependencies, + dwDependSize); + if (dwError != ERROR_SUCCESS) + goto done; + } + + /* Write service start name */ + if (dwServiceType & SERVICE_WIN32) + { + lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem"; + dwError = RegSetValueExW(hServiceKey, + L"ObjectName", + 0, + REG_SZ, + (LPBYTE)lpObjectName, + (wcslen(lpObjectName) + 1) * sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + goto done; + } + + if (lpPassword != NULL) + { + /* FIXME: Write password */ + } + + dwError = ScmCreateServiceHandle(lpService, + &hServiceHandle); + if (dwError != ERROR_SUCCESS) + goto done; + + dwError = ScmCheckAccess(hServiceHandle, + dwDesiredAccess); + if (dwError != ERROR_SUCCESS) + goto done; + + lpService->dwRefCount = 1; + DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount); + +done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + if (hServiceKey != NULL) + RegCloseKey(hServiceKey); + + if (dwError == ERROR_SUCCESS) + { + DPRINT("hService %p\n", hServiceHandle); + *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle; + + if (lpdwTagId != NULL) + *lpdwTagId = lpService->dwTag; + } + else + { + if (lpService != NULL && + lpService->ServiceName != NULL) + { + /* Release the display name buffer */ + HeapFree(GetProcessHeap(), 0, lpService->DisplayName); + } + + if (hServiceHandle) + { + /* Remove the service handle */ + HeapFree(GetProcessHeap(), 0, hServiceHandle); + } + + if (lpService != NULL) + { + /* FIXME: remove the service entry */ + } + } + + if (lpImagePath != NULL) + HeapFree(GetProcessHeap(), 0, lpImagePath); + + DPRINT("RCreateServiceW() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 13 */ +DWORD REnumDependentServicesW( + SC_RPC_HANDLE hService, + DWORD dwServiceState, + LPBYTE lpServices, + DWORD cbBufSize, + LPBOUNDED_DWORD_256K pcbBytesNeeded, + LPBOUNDED_DWORD_256K lpServicesReturned) +{ + DWORD dwError = ERROR_SUCCESS; + DWORD dwServicesReturned = 0; + DWORD dwServiceCount; + HKEY hServicesKey = NULL; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + PSERVICE_RECORD *lpServicesArray = NULL; + LPENUM_SERVICE_STATUSW lpServicesPtr = NULL; + LPWSTR lpStr; + + *pcbBytesNeeded = 0; + *lpServicesReturned = 0; + + DPRINT("REnumDependentServicesW() called\n"); + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + + /* Check access rights */ + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SC_MANAGER_ENUMERATE_SERVICE)) + { + DPRINT("Insufficient access rights! 0x%lx\n", + hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + /* Open the Services Reg key */ + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + lpService->Database->RegistryKeyNames.Services, + 0, + KEY_READ, + &hServicesKey); + if (dwError != ERROR_SUCCESS) + return dwError; + + /* First determine the bytes needed and get the number of dependent services */ + dwError = Int_EnumDependentServicesW(hServicesKey, + lpService, + dwServiceState, + NULL, + pcbBytesNeeded, + &dwServicesReturned); + if (dwError != ERROR_SUCCESS) + goto Done; + + /* If buffer size is less than the bytes needed or pointer is null */ + if ((!lpServices) || (cbBufSize < *pcbBytesNeeded)) + { + dwError = ERROR_MORE_DATA; + goto Done; + } + + /* Allocate memory for array of service pointers */ + lpServicesArray = HeapAlloc(GetProcessHeap(), + 0, + (dwServicesReturned + 1) * sizeof(PSERVICE_RECORD)); + if (!lpServicesArray) + { + DPRINT1("Could not allocate a buffer!!\n"); + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto Done; + } + + dwServicesReturned = 0; + *pcbBytesNeeded = 0; + + dwError = Int_EnumDependentServicesW(hServicesKey, + lpService, + dwServiceState, + lpServicesArray, + pcbBytesNeeded, + &dwServicesReturned); + if (dwError != ERROR_SUCCESS) + { + goto Done; + } + + lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices; + lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW))); + + /* Copy EnumDepenedentService to Buffer */ + for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++) + { + lpService = lpServicesArray[dwServiceCount]; + + /* Copy status info */ + memcpy(&lpServicesPtr->ServiceStatus, + &lpService->Status, + sizeof(SERVICE_STATUS)); + + /* Copy display name */ + wcscpy(lpStr, lpService->DisplayName); + lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); + lpStr += (wcslen(lpService->DisplayName) + 1); + + /* Copy service name */ + wcscpy(lpStr, lpService->ServiceName); + lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); + lpStr += (wcslen(lpService->ServiceName) + 1); + + lpServicesPtr ++; + } + + *lpServicesReturned = dwServicesReturned; + +Done: + if (lpServicesArray != NULL) + HeapFree(GetProcessHeap(), 0, lpServicesArray); + + RegCloseKey(hServicesKey); + + DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 14 */ +DWORD REnumServicesStatusW( + SC_RPC_HANDLE hSCManager, + DWORD dwServiceType, + DWORD dwServiceState, + LPBYTE lpBuffer, + DWORD cbBufSize, + LPBOUNDED_DWORD_256K pcbBytesNeeded, + LPBOUNDED_DWORD_256K lpServicesReturned, + LPBOUNDED_DWORD_256K lpResumeIndex) +{ + PSC_HANDLE_STRUCT hManager; + PSERVICE_RECORD lpService; + DWORD dwError = ERROR_SUCCESS; + PLIST_ENTRY ServiceEntry; + PSERVICE_RECORD CurrentService; + DWORD dwState; + DWORD dwRequiredSize; + DWORD dwServiceCount; + DWORD dwSize; + DWORD dwLastResumeCount = 0; + LPENUM_SERVICE_STATUSW lpStatusPtr; + LPWSTR lpStringPtr; + + DPRINT("REnumServicesStatusW() called\n"); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hManager = ScmGetServiceManagerFromHandle(hSCManager); + if (hManager == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + + *pcbBytesNeeded = 0; + *lpServicesReturned = 0; + + if ((dwServiceType == 0) || + ((dwServiceType & ~(SERVICE_DRIVER | SERVICE_WIN32)) != 0)) + { + DPRINT("Not a valid Service Type!\n"); + return ERROR_INVALID_PARAMETER; + } + + if ((dwServiceState != SERVICE_ACTIVE) && + (dwServiceState != SERVICE_INACTIVE) && + (dwServiceState != SERVICE_STATE_ALL)) + { + DPRINT("Not a valid Service State!\n"); + return ERROR_INVALID_PARAMETER; + } + + /* Check access rights */ + if (!RtlAreAllAccessesGranted(hManager->DesiredAccess, + SC_MANAGER_ENUMERATE_SERVICE)) + { + DPRINT("Insufficient access rights! 0x%lx\n", + hManager->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + if (lpResumeIndex) + dwLastResumeCount = *lpResumeIndex; + + /* Lock the service database shared */ + ScmLockDatabaseShared(); + + lpService = ScmGetServiceEntryByResumeCount(hManager->Type.ScManagerObject.Database, dwLastResumeCount); + if (lpService == NULL) + { + dwError = ERROR_SUCCESS; + goto Done; + } + + dwRequiredSize = 0; + dwServiceCount = 0; + + for (ServiceEntry = &lpService->ServiceListEntry; + ServiceEntry != &(hManager->Type.ScManagerObject.Database->ServiceListHead); + ServiceEntry = ServiceEntry->Flink) + { + CurrentService = CONTAINING_RECORD(ServiceEntry, + SERVICE_RECORD, + ServiceListEntry); + + if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) + continue; + + dwState = SERVICE_ACTIVE; + if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) + dwState = SERVICE_INACTIVE; + + if ((dwState & dwServiceState) == 0) + continue; + + dwSize = sizeof(ENUM_SERVICE_STATUSW) + + ((wcslen(CurrentService->ServiceName) + 1) * sizeof(WCHAR)) + + ((wcslen(CurrentService->DisplayName) + 1) * sizeof(WCHAR)); + + if (dwRequiredSize + dwSize > cbBufSize) + { + DPRINT("Service name: %S no fit\n", CurrentService->ServiceName); + break; + } + + DPRINT("Service name: %S fit\n", CurrentService->ServiceName); + dwRequiredSize += dwSize; + dwServiceCount++; + dwLastResumeCount = CurrentService->dwResumeCount; + } + + DPRINT("dwRequiredSize: %lu\n", dwRequiredSize); + DPRINT("dwServiceCount: %lu\n", dwServiceCount); + + for (; + ServiceEntry != &(hManager->Type.ScManagerObject.Database->ServiceListHead); + ServiceEntry = ServiceEntry->Flink) + { + CurrentService = CONTAINING_RECORD(ServiceEntry, + SERVICE_RECORD, + ServiceListEntry); + + if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) + continue; + + dwState = SERVICE_ACTIVE; + if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) + dwState = SERVICE_INACTIVE; + + if ((dwState & dwServiceState) == 0) + continue; + + dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) + + ((wcslen(CurrentService->ServiceName) + 1) * sizeof(WCHAR)) + + ((wcslen(CurrentService->DisplayName) + 1) * sizeof(WCHAR))); + + dwError = ERROR_MORE_DATA; + } + + DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize); + + if (lpResumeIndex) + *lpResumeIndex = dwLastResumeCount; + + *lpServicesReturned = dwServiceCount; + *pcbBytesNeeded = dwRequiredSize; + + lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer; + lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer + + dwServiceCount * sizeof(ENUM_SERVICE_STATUSW)); + + dwRequiredSize = 0; + for (ServiceEntry = &lpService->ServiceListEntry; + ServiceEntry != &(hManager->Type.ScManagerObject.Database->ServiceListHead); + ServiceEntry = ServiceEntry->Flink) + { + CurrentService = CONTAINING_RECORD(ServiceEntry, + SERVICE_RECORD, + ServiceListEntry); + + if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) + continue; + + dwState = SERVICE_ACTIVE; + if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) + dwState = SERVICE_INACTIVE; + + if ((dwState & dwServiceState) == 0) + continue; + + dwSize = sizeof(ENUM_SERVICE_STATUSW) + + ((wcslen(CurrentService->ServiceName) + 1) * sizeof(WCHAR)) + + ((wcslen(CurrentService->DisplayName) + 1) * sizeof(WCHAR)); + + if (dwRequiredSize + dwSize > cbBufSize) + break; + + /* Copy the service name */ + wcscpy(lpStringPtr, CurrentService->ServiceName); + lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); + lpStringPtr += (wcslen(CurrentService->ServiceName) + 1); + + /* Copy the display name */ + wcscpy(lpStringPtr, CurrentService->DisplayName); + lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); + lpStringPtr += (wcslen(CurrentService->DisplayName) + 1); + + /* Copy the status information */ + memcpy(&lpStatusPtr->ServiceStatus, + &CurrentService->Status, + sizeof(SERVICE_STATUS)); + + lpStatusPtr++; + dwRequiredSize += dwSize; + } + + if (dwError == ERROR_SUCCESS) + { + *pcbBytesNeeded = 0; + if (lpResumeIndex) *lpResumeIndex = 0; + } + +Done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 16 */ +DWORD ROpenServiceW( + SC_RPC_HANDLE hSCManager, + LPWSTR lpServiceName, + DWORD dwDesiredAccess, + LPSC_RPC_HANDLE lpServiceHandle) +{ + PSERVICE_RECORD lpService; + PSC_HANDLE_STRUCT hManager; + PSC_HANDLE_STRUCT hHandle; + DWORD dwError = ERROR_SUCCESS; + + DPRINT("ROpenServiceW() called\n"); + DPRINT("hSCManager = %p\n", hSCManager); + DPRINT("lpServiceName = %p\n", lpServiceName); + DPRINT("lpServiceName: %S\n", lpServiceName); + DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hManager = ScmGetServiceManagerFromHandle(hSCManager); + if (hManager == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!lpServiceHandle) + return ERROR_INVALID_PARAMETER; + + if (!lpServiceName) + return ERROR_INVALID_ADDRESS; + + /* Lock the service database exclusive */ + ScmLockDatabaseExclusive(); + + /* Get service database entry */ + lpService = ScmGetServiceEntryByName(hManager->Type.ScManagerObject.Database, lpServiceName); + if (lpService == NULL) + { + DPRINT("Could not find a service!\n"); + dwError = ERROR_SERVICE_DOES_NOT_EXIST; + goto Done; + } + + /* Create a service handle */ + dwError = ScmCreateServiceHandle(lpService, + &hHandle); + if (dwError != ERROR_SUCCESS) + { + DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError); + goto Done; + } + + /* Check the desired access */ + dwError = ScmCheckAccess(hHandle, + dwDesiredAccess); + if (dwError != ERROR_SUCCESS) + { + DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError); + HeapFree(GetProcessHeap(), 0, hHandle); + goto Done; + } + + lpService->dwRefCount++; + DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount); + + *lpServiceHandle = (SC_RPC_HANDLE)hHandle; + DPRINT("*hService = %p\n", *lpServiceHandle); + +Done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + DPRINT("ROpenServiceW() done\n"); + + return dwError; +} + + +/* Function 17 */ +DWORD RQueryServiceConfigW( + SC_RPC_HANDLE hService, + LPBYTE lpServiceConfig_, // FIXME: LPQUERY_SERVICE_CONFIGW lpServiceConfig, + DWORD cbBufSize, + LPBOUNDED_DWORD_8K pcbBytesNeeded) +{ + LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig_; + DWORD dwError = ERROR_SUCCESS; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + HKEY hServiceKey = NULL; + LPWSTR lpImagePath = NULL; + LPWSTR lpServiceStartName = NULL; + LPWSTR lpDependencies = NULL; + DWORD dwDependenciesLength = 0; + DWORD dwRequiredSize; + LPQUERY_SERVICE_CONFIGW lpConfig = NULL; + WCHAR lpEmptyString[] = {0,0}; + LPWSTR lpStr; + + DPRINT("RQueryServiceConfigW() called\n"); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_QUERY_CONFIG)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database shared */ + ScmLockDatabaseShared(); + + dwError = ScmOpenServiceKey(lpService, + KEY_READ, + &hServiceKey); + if (dwError != ERROR_SUCCESS) + goto Done; + + /* Read the image path */ + dwError = ScmReadString(hServiceKey, + L"ImagePath", + &lpImagePath); + if (dwError != ERROR_SUCCESS) + goto Done; + + /* Read the service start name */ + ScmReadString(hServiceKey, + L"ObjectName", + &lpServiceStartName); + + /* Read the dependencies */ + ScmReadDependencies(hServiceKey, + &lpDependencies, + &dwDependenciesLength); + + dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW); + + if (lpImagePath != NULL) + dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR)); + else + dwRequiredSize += 2 * sizeof(WCHAR); + + if (lpService->lpGroup != NULL) + dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR)); + else + dwRequiredSize += 2 * sizeof(WCHAR); + + if (lpDependencies != NULL) + dwRequiredSize += dwDependenciesLength * sizeof(WCHAR); + else + dwRequiredSize += 2 * sizeof(WCHAR); + + if (lpServiceStartName != NULL) + dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR)); + else + dwRequiredSize += 2 * sizeof(WCHAR); + + if (lpService->DisplayName != NULL) + dwRequiredSize += ((wcslen(lpService->DisplayName) + 1) * sizeof(WCHAR)); + else + dwRequiredSize += 2 * sizeof(WCHAR); + + if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize) + { + dwError = ERROR_INSUFFICIENT_BUFFER; + } + else + { + lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig; + lpConfig->dwServiceType = lpService->Status.dwServiceType; + lpConfig->dwStartType = lpService->dwStartType; + lpConfig->dwErrorControl = lpService->dwErrorControl; + lpConfig->dwTagId = lpService->dwTag; + + lpStr = (LPWSTR)(lpConfig + 1); + + /* Append the image path */ + if (lpImagePath != NULL) + { + wcscpy(lpStr, lpImagePath); + } + else + { + wcscpy(lpStr, lpEmptyString); + } + + lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); + lpStr += (wcslen(lpStr) + 1); + + /* Append the group name */ + if (lpService->lpGroup != NULL) + { + wcscpy(lpStr, lpService->lpGroup->lpGroupName); + } + else + { + wcscpy(lpStr, lpEmptyString); + } + + lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); + lpStr += (wcslen(lpStr) + 1); + + /* Append Dependencies */ + if (lpDependencies != NULL) + { + memcpy(lpStr, + lpDependencies, + dwDependenciesLength * sizeof(WCHAR)); + } + else + { + wcscpy(lpStr, lpEmptyString); + } + + lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); + if (lpDependencies != NULL) + lpStr += dwDependenciesLength * sizeof(WCHAR); + else + lpStr += (wcslen(lpStr) + 1); + + /* Append the service start name */ + if (lpServiceStartName != NULL) + { + wcscpy(lpStr, lpServiceStartName); + } + else + { + wcscpy(lpStr, lpEmptyString); + } + + lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); + lpStr += (wcslen(lpStr) + 1); + + /* Append the display name */ + if (lpService->DisplayName != NULL) + { + wcscpy(lpStr, lpService->DisplayName); + } + else + { + wcscpy(lpStr, lpEmptyString); + } + + lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); + } + + if (pcbBytesNeeded != NULL) + *pcbBytesNeeded = dwRequiredSize; + +Done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + if (lpImagePath != NULL) + HeapFree(GetProcessHeap(), 0, lpImagePath); + + if (lpServiceStartName != NULL) + HeapFree(GetProcessHeap(), 0, lpServiceStartName); + + if (lpDependencies != NULL) + HeapFree(GetProcessHeap(), 0, lpDependencies); + + if (hServiceKey != NULL) + RegCloseKey(hServiceKey); + + DPRINT("RQueryServiceConfigW() done\n"); + + return dwError; +} + + +/* Function 19 */ +DWORD RStartServiceW( + SC_RPC_HANDLE hService, + DWORD argc, + LPSTRING_PTRSW argv) +{ + DWORD dwError = ERROR_SUCCESS; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + DWORD i; + + DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv); + DPRINT(" argc: %lu\n", argc); + if (argv != NULL) + { + for (i = 0; i < argc; i++) + { + DPRINT(" argv[%lu]: %S\n", i, argv[i]); + } + } + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_START)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* + * We can control services only if the + * database is the active database. + */ + if (!IsActiveDatabase(lpService->Database)) + return ERROR_ACCESS_DENIED; + + if (lpService->dwStartType == SERVICE_DISABLED) + return ERROR_SERVICE_DISABLED; + + if (lpService->bDeleted) + return ERROR_SERVICE_MARKED_FOR_DELETE; + + /* Start the service */ + dwError = ScmStartService(lpService, argc, (LPWSTR*)argv); + + return dwError; +} + + +/* Function 20 */ +DWORD RGetServiceDisplayNameW( + SC_RPC_HANDLE hSCManager, + LPCWSTR lpServiceName, + LPWSTR lpDisplayName, + DWORD* lpcchBuffer) +{ + PSC_HANDLE_STRUCT hManager; + PSERVICE_RECORD lpService; + DWORD dwLength; + DWORD dwError; + + DPRINT("RGetServiceDisplayNameW() called\n"); + DPRINT("hSCManager = %p\n", hSCManager); + DPRINT("lpServiceName: %S\n", lpServiceName); + DPRINT("lpDisplayName: %p\n", lpDisplayName); + DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); + + hManager = ScmGetServiceManagerFromHandle(hSCManager); + if (hManager == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Get service database entry */ + lpService = ScmGetServiceEntryByName(hManager->Type.ScManagerObject.Database, lpServiceName); + if (lpService == NULL) + { + DPRINT("Could not find a service!\n"); + + /* If the service could not be found and lpcchBuffer is less than 2, windows + puts null in lpDisplayName and puts 2 in lpcchBuffer */ + if (*lpcchBuffer < 2) + { + *lpcchBuffer = 2; + if (lpDisplayName != NULL) + { + *lpDisplayName = '\0'; + } + } + + return ERROR_SERVICE_DOES_NOT_EXIST; + } + + if (!lpService->DisplayName) + { + dwLength = wcslen(lpService->ServiceName); + + if (lpDisplayName != NULL && + *lpcchBuffer > dwLength) + { + wcscpy(lpDisplayName, lpService->ServiceName); + } + } + else + { + dwLength = wcslen(lpService->DisplayName); + + if (lpDisplayName != NULL && + *lpcchBuffer > dwLength) + { + wcscpy(lpDisplayName, lpService->DisplayName); + } + } + + dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER; + + *lpcchBuffer = dwLength; + + return dwError; +} + + +/* Function 21 */ +DWORD RGetServiceKeyNameW( + SC_RPC_HANDLE hSCManager, + LPCWSTR lpDisplayName, + LPWSTR lpServiceName, + DWORD* lpcchBuffer) +{ + PSC_HANDLE_STRUCT hManager; + PSERVICE_RECORD lpService; + DWORD dwLength; + DWORD dwError; + + DPRINT("RGetServiceKeyNameW() called\n"); + DPRINT("hSCManager = %p\n", hSCManager); + DPRINT("lpDisplayName: %S\n", lpDisplayName); + DPRINT("lpServiceName: %p\n", lpServiceName); + DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); + + hManager = ScmGetServiceManagerFromHandle(hSCManager); + if (hManager == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Get service database entry */ + lpService = ScmGetServiceEntryByDisplayName(hManager->Type.ScManagerObject.Database, lpDisplayName); + if (lpService == NULL) + { + DPRINT("Could not find a service!\n"); + + /* If the service could not be found and lpcchBuffer is less than 2, windows + puts null in lpDisplayName and puts 2 in lpcchBuffer */ + if (*lpcchBuffer < 2) + { + *lpcchBuffer = 2; + if (lpServiceName != NULL) + { + *lpServiceName = '\0'; + } + } + + return ERROR_SERVICE_DOES_NOT_EXIST; + } + + dwLength = wcslen(lpService->ServiceName); + + if (lpServiceName != NULL && + *lpcchBuffer > dwLength) + { + wcscpy(lpServiceName, lpService->ServiceName); + *lpcchBuffer = dwLength; + return ERROR_SUCCESS; + } + + dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER; + + *lpcchBuffer = dwLength; + + return dwError; +} + + +/* Function 22 */ +DWORD RI_ScSetServiceBitsA( + RPC_SERVICE_STATUS_HANDLE hServiceStatus, + DWORD dwServiceBits, + BOOL bSetBitsOn, + BOOL bUpdateImmediately, + LPSTR pszTransportName) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 23 */ +DWORD RChangeServiceConfigA( + SC_RPC_HANDLE hService, + DWORD dwServiceType, + DWORD dwStartType, + DWORD dwErrorControl, + LPSTR lpBinaryPathName, + LPSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, + LPBYTE lpDependencies, + DWORD dwDependSize, + LPSTR lpServiceStartName, + LPBYTE lpPassword, + DWORD dwPwSize, + LPSTR lpDisplayName) +{ + DWORD dwError = ERROR_SUCCESS; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + HKEY hServiceKey = NULL; + LPWSTR lpDisplayNameW = NULL; + LPWSTR lpBinaryPathNameW = NULL; + LPWSTR lpCanonicalImagePathW = NULL; + LPWSTR lpLoadOrderGroupW = NULL; + LPWSTR lpDependenciesW = NULL; + // LPWSTR lpPasswordW = NULL; + + DPRINT("RChangeServiceConfigA() called\n"); + DPRINT("dwServiceType = %lu\n", dwServiceType); + DPRINT("dwStartType = %lu\n", dwStartType); + DPRINT("dwErrorControl = %lu\n", dwErrorControl); + DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName); + DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup); + DPRINT("lpDisplayName = %s\n", lpDisplayName); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_CHANGE_CONFIG)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database exclusively */ + ScmLockDatabaseExclusive(); + + if (lpService->bDeleted) + { + DPRINT("The service has already been marked for delete!\n"); + dwError = ERROR_SERVICE_MARKED_FOR_DELETE; + goto done; + } + + /* Open the service key */ + dwError = ScmOpenServiceKey(lpService, + KEY_SET_VALUE, + &hServiceKey); + if (dwError != ERROR_SUCCESS) + goto done; + + /* Write service data to the registry */ + + if (lpDisplayName != NULL && *lpDisplayName != 0) + { + /* Set the display name */ + lpDisplayNameW = HeapAlloc(GetProcessHeap(), + 0, + (strlen(lpDisplayName) + 1) * sizeof(WCHAR)); + if (lpDisplayNameW == NULL) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + MultiByteToWideChar(CP_ACP, + 0, + lpDisplayName, + -1, + lpDisplayNameW, + strlen(lpDisplayName) + 1); + + RegSetValueExW(hServiceKey, + L"DisplayName", + 0, + REG_SZ, + (LPBYTE)lpDisplayNameW, + (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR)); + + /* Update lpService->DisplayName */ + if (lpService->DisplayName) + HeapFree(GetProcessHeap(), 0, lpService->DisplayName); + + lpService->DisplayName = lpDisplayNameW; + } + + if (dwServiceType != SERVICE_NO_CHANGE) + { + /* Set the service type */ + dwError = RegSetValueExW(hServiceKey, + L"Type", + 0, + REG_DWORD, + (LPBYTE)&dwServiceType, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + lpService->Status.dwServiceType = dwServiceType; + } + + if (dwStartType != SERVICE_NO_CHANGE) + { + /* Set the start value */ + dwError = RegSetValueExW(hServiceKey, + L"Start", + 0, + REG_DWORD, + (LPBYTE)&dwStartType, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + lpService->dwStartType = dwStartType; + } + + if (dwErrorControl != SERVICE_NO_CHANGE) + { + /* Set the error control value */ + dwError = RegSetValueExW(hServiceKey, + L"ErrorControl", + 0, + REG_DWORD, + (LPBYTE)&dwErrorControl, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + lpService->dwErrorControl = dwErrorControl; + } + + if (lpBinaryPathName != NULL && *lpBinaryPathName != 0) + { + /* Set the image path */ + lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), + 0, + (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR)); + if (lpBinaryPathNameW == NULL) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + MultiByteToWideChar(CP_ACP, + 0, + lpBinaryPathName, + -1, + lpBinaryPathNameW, + strlen(lpBinaryPathName) + 1); + + if (lpService->Status.dwServiceType & SERVICE_DRIVER) + { + dwError = ScmCanonDriverImagePath(lpService->dwStartType, + lpBinaryPathNameW, + &lpCanonicalImagePathW); + + HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW); + + if (dwError != ERROR_SUCCESS) + goto done; + + lpBinaryPathNameW = lpCanonicalImagePathW; + } + + dwError = RegSetValueExW(hServiceKey, + L"ImagePath", + 0, + REG_EXPAND_SZ, + (LPBYTE)lpBinaryPathNameW, + (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR)); + + HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW); + + if (dwError != ERROR_SUCCESS) + goto done; + } + + /* Set the group name */ + if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) + { + lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), + 0, + (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)); + if (lpLoadOrderGroupW == NULL) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + MultiByteToWideChar(CP_ACP, + 0, + lpLoadOrderGroup, + -1, + lpLoadOrderGroupW, + strlen(lpLoadOrderGroup) + 1); + + dwError = RegSetValueExW(hServiceKey, + L"Group", + 0, + REG_SZ, + (LPBYTE)lpLoadOrderGroupW, + (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW); + goto done; + } + + dwError = ScmSetServiceGroup(lpService, + lpLoadOrderGroupW); + + HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW); + + if (dwError != ERROR_SUCCESS) + goto done; + } + + if (lpdwTagId != NULL) + { + dwError = ScmAssignNewTag(lpService); + if (dwError != ERROR_SUCCESS) + goto done; + + dwError = RegSetValueExW(hServiceKey, + L"Tag", + 0, + REG_DWORD, + (LPBYTE)&lpService->dwTag, + sizeof(DWORD)); + if (dwError != ERROR_SUCCESS) + goto done; + + *lpdwTagId = lpService->dwTag; + } + + /* Write dependencies */ + if (lpDependencies != NULL && *(LPSTR)lpDependencies != 0) + { + lpDependenciesW = HeapAlloc(GetProcessHeap(), + 0, + (strlen((LPSTR)lpDependencies) + 1) * sizeof(WCHAR)); + if (lpDependenciesW == NULL) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + MultiByteToWideChar(CP_ACP, + 0, + (LPSTR)lpDependencies, + dwDependSize, + lpDependenciesW, + strlen((LPSTR)lpDependencies) + 1); + + dwError = ScmWriteDependencies(hServiceKey, + (LPWSTR)lpDependenciesW, + dwDependSize); + + HeapFree(GetProcessHeap(), 0, lpDependenciesW); + } + + if (lpPassword != NULL) + { + /* FIXME: Write password */ + } + +done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + if (hServiceKey != NULL) + RegCloseKey(hServiceKey); + + DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 24 */ +DWORD RCreateServiceA( + SC_RPC_HANDLE hSCManager, + LPSTR lpServiceName, + LPSTR lpDisplayName, + DWORD dwDesiredAccess, + DWORD dwServiceType, + DWORD dwStartType, + DWORD dwErrorControl, + LPSTR lpBinaryPathName, + LPSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, + LPBYTE lpDependencies, + DWORD dwDependSize, + LPSTR lpServiceStartName, + LPBYTE lpPassword, + DWORD dwPwSize, + LPSC_RPC_HANDLE lpServiceHandle) +{ + DWORD dwError = ERROR_SUCCESS; + LPWSTR lpServiceNameW = NULL; + LPWSTR lpDisplayNameW = NULL; + LPWSTR lpBinaryPathNameW = NULL; + LPWSTR lpLoadOrderGroupW = NULL; + LPWSTR lpDependenciesW = NULL; + LPWSTR lpServiceStartNameW = NULL; + DWORD dwDependenciesLength = 0; + DWORD dwLength; + int len; + LPCSTR lpStr; + + if (lpServiceName) + { + len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0); + lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!lpServiceNameW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len); + } + + if (lpDisplayName) + { + len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0); + lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!lpDisplayNameW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len); + } + + if (lpBinaryPathName) + { + len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0); + lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!lpBinaryPathNameW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len); + } + + if (lpLoadOrderGroup) + { + len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0); + lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!lpLoadOrderGroupW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len); + } + + if (lpDependencies) + { + lpStr = (LPCSTR)lpDependencies; + while (*lpStr) + { + dwLength = strlen(lpStr) + 1; + dwDependenciesLength += dwLength; + lpStr = lpStr + dwLength; + } + dwDependenciesLength++; + + lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR)); + if (!lpDependenciesW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength); + } + + if (lpServiceStartName) + { + len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0); + lpServiceStartNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!lpServiceStartNameW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len); + } + + dwError = RCreateServiceW(hSCManager, + lpServiceNameW, + lpDisplayNameW, + dwDesiredAccess, + dwServiceType, + dwStartType, + dwErrorControl, + lpBinaryPathNameW, + lpLoadOrderGroupW, + lpdwTagId, + (LPBYTE)lpDependenciesW, + dwDependenciesLength, + lpServiceStartNameW, + lpPassword, + dwPwSize, + lpServiceHandle); + +cleanup: + if (lpServiceNameW !=NULL) + HeapFree(GetProcessHeap(), 0, lpServiceNameW); + + if (lpDisplayNameW != NULL) + HeapFree(GetProcessHeap(), 0, lpDisplayNameW); + + if (lpBinaryPathNameW != NULL) + HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW); + + if (lpLoadOrderGroupW != NULL) + HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW); + + if (lpDependenciesW != NULL) + HeapFree(GetProcessHeap(), 0, lpDependenciesW); + + if (lpServiceStartNameW != NULL) + HeapFree(GetProcessHeap(), 0, lpServiceStartNameW); + + return dwError; +} + + +/* Function 25 */ +DWORD REnumDependentServicesA( + SC_RPC_HANDLE hService, + DWORD dwServiceState, + LPBYTE lpServices, + DWORD cbBufSize, + LPBOUNDED_DWORD_256K pcbBytesNeeded, + LPBOUNDED_DWORD_256K lpServicesReturned) +{ + DWORD dwError = ERROR_SUCCESS; + DWORD dwServicesReturned = 0; + DWORD dwServiceCount; + HKEY hServicesKey = NULL; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + PSERVICE_RECORD *lpServicesArray = NULL; + LPENUM_SERVICE_STATUSA lpServicesPtr = NULL; + LPSTR lpStr; + + *pcbBytesNeeded = 0; + *lpServicesReturned = 0; + + DPRINT("REnumDependentServicesA() called\n"); + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + + /* Check access rights */ + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SC_MANAGER_ENUMERATE_SERVICE)) + { + DPRINT("Insufficient access rights! 0x%lx\n", + hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + /* Open the Services Reg key */ + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + lpService->Database->RegistryKeyNames.Services, + 0, + KEY_READ, + &hServicesKey); + + if (dwError != ERROR_SUCCESS) + return dwError; + + /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for + both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded + are the same for both. Verified in WINXP. */ + + /* First determine the bytes needed and get the number of dependent services*/ + dwError = Int_EnumDependentServicesW(hServicesKey, + lpService, + dwServiceState, + NULL, + pcbBytesNeeded, + &dwServicesReturned); + if (dwError != ERROR_SUCCESS) + goto Done; + + /* If buffer size is less than the bytes needed or pointer is null*/ + if ((!lpServices) || (cbBufSize < *pcbBytesNeeded)) + { + dwError = ERROR_MORE_DATA; + goto Done; + } + + /* Allocate memory for array of service pointers */ + lpServicesArray = HeapAlloc(GetProcessHeap(), + 0, + (dwServicesReturned + 1) * sizeof(PSERVICE_RECORD)); + if (!lpServicesArray) + { + DPRINT("Could not allocate a buffer!!\n"); + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto Done; + } + + dwServicesReturned = 0; + *pcbBytesNeeded = 0; + + dwError = Int_EnumDependentServicesW(hServicesKey, + lpService, + dwServiceState, + lpServicesArray, + pcbBytesNeeded, + &dwServicesReturned); + if (dwError != ERROR_SUCCESS) + { + goto Done; + } + + lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices; + lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA))); + + /* Copy EnumDepenedentService to Buffer */ + for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++) + { + lpService = lpServicesArray[dwServiceCount]; + + /* Copy the status info */ + memcpy(&lpServicesPtr->ServiceStatus, + &lpService->Status, + sizeof(SERVICE_STATUS)); + + /* Copy display name */ + WideCharToMultiByte(CP_ACP, + 0, + lpService->DisplayName, + -1, + lpStr, + wcslen(lpService->DisplayName), + 0, + 0); + lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); + lpStr += strlen(lpStr) + 1; + + /* Copy service name */ + WideCharToMultiByte(CP_ACP, + 0, + lpService->ServiceName, + -1, + lpStr, + wcslen(lpService->ServiceName), + 0, + 0); + lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); + lpStr += strlen(lpStr) + 1; + + lpServicesPtr ++; + } + + *lpServicesReturned = dwServicesReturned; + +Done: + if (lpServicesArray) + HeapFree(GetProcessHeap(), 0, lpServicesArray); + + RegCloseKey(hServicesKey); + + DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 26 */ +DWORD REnumServicesStatusA( + SC_RPC_HANDLE hSCManager, + DWORD dwServiceType, + DWORD dwServiceState, + LPBYTE lpBuffer, + DWORD cbBufSize, + LPBOUNDED_DWORD_256K pcbBytesNeeded, + LPBOUNDED_DWORD_256K lpServicesReturned, + LPBOUNDED_DWORD_256K lpResumeIndex) +{ + LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL; + LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL; + LPWSTR lpStringPtrW; + LPSTR lpStringPtrA; + DWORD dwError; + DWORD dwServiceCount; + + DPRINT("REnumServicesStatusA() called\n"); + + if ((cbBufSize > 0) && (lpBuffer)) + { + lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize); + if (!lpStatusPtrW) + { + DPRINT("Failed to allocate buffer!\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + } + + dwError = REnumServicesStatusW(hSCManager, + dwServiceType, + dwServiceState, + (LPBYTE)lpStatusPtrW, + cbBufSize, + pcbBytesNeeded, + lpServicesReturned, + lpResumeIndex); + + /* if no services were returned then we are Done */ + if (*lpServicesReturned == 0) + goto Done; + + lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer; + lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer + + *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA)); + lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW + + *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW)); + + for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++) + { + /* Copy the service name */ + WideCharToMultiByte(CP_ACP, + 0, + lpStringPtrW, + -1, + lpStringPtrA, + wcslen(lpStringPtrW), + 0, + 0); + + lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); + lpStringPtrA += wcslen(lpStringPtrW) + 1; + lpStringPtrW += wcslen(lpStringPtrW) + 1; + + /* Copy the display name */ + WideCharToMultiByte(CP_ACP, + 0, + lpStringPtrW, + -1, + lpStringPtrA, + wcslen(lpStringPtrW), + 0, + 0); + + lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); + lpStringPtrA += wcslen(lpStringPtrW) + 1; + lpStringPtrW += wcslen(lpStringPtrW) + 1; + + /* Copy the status information */ + memcpy(&lpStatusPtrA->ServiceStatus, + &lpStatusPtrW->ServiceStatus, + sizeof(SERVICE_STATUS)); + + lpStatusPtrA++; + } + +Done: + if (lpStatusPtrW) + HeapFree(GetProcessHeap(), 0, lpStatusPtrW); + + DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 28 */ +DWORD ROpenServiceA( + SC_RPC_HANDLE hSCManager, + LPSTR lpServiceName, + DWORD dwDesiredAccess, + LPSC_RPC_HANDLE lpServiceHandle) +{ + UNICODE_STRING ServiceName; + DWORD dwError; + + DPRINT("ROpenServiceA() called\n"); + + if (lpServiceName) + RtlCreateUnicodeStringFromAsciiz(&ServiceName, + lpServiceName); + + dwError = ROpenServiceW(hSCManager, + lpServiceName ? ServiceName.Buffer : NULL, + dwDesiredAccess, + lpServiceHandle); + + if (lpServiceName) + RtlFreeUnicodeString(&ServiceName); + + return dwError; +} + + +/* Function 29 */ +DWORD RQueryServiceConfigA( + SC_RPC_HANDLE hService, + LPBYTE lpServiceConfig_, // FIXME: LPQUERY_SERVICE_CONFIGA lpServiceConfig, + DWORD cbBufSize, + LPBOUNDED_DWORD_8K pcbBytesNeeded) +{ + LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig_; + DWORD dwError = ERROR_SUCCESS; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + HKEY hServiceKey = NULL; + LPWSTR lpImagePath = NULL; + LPWSTR lpServiceStartName = NULL; + LPWSTR lpDependencies = NULL; + DWORD dwDependenciesLength = 0; + DWORD dwRequiredSize; + LPQUERY_SERVICE_CONFIGA lpConfig = NULL; + CHAR lpEmptyString[]={0,0}; + LPSTR lpStr; + + DPRINT("RQueryServiceConfigA() called\n"); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_QUERY_CONFIG)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database shared */ + ScmLockDatabaseShared(); + + dwError = ScmOpenServiceKey(lpService, + KEY_READ, + &hServiceKey); + if (dwError != ERROR_SUCCESS) + goto Done; + + /* Read the image path */ + dwError = ScmReadString(hServiceKey, + L"ImagePath", + &lpImagePath); + if (dwError != ERROR_SUCCESS) + goto Done; + + /* Read the service start name */ + ScmReadString(hServiceKey, + L"ObjectName", + &lpServiceStartName); + + /* Read the dependencies */ + ScmReadDependencies(hServiceKey, + &lpDependencies, + &dwDependenciesLength); + + dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW); + + if (lpImagePath != NULL) + dwRequiredSize += wcslen(lpImagePath) + 1; + else + dwRequiredSize += 2; + + if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL)) + dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1; + else + dwRequiredSize += 2; + + /* Add Dependencies length */ + if (lpDependencies != NULL) + dwRequiredSize += dwDependenciesLength; + else + dwRequiredSize += 2; + + if (lpServiceStartName != NULL) + dwRequiredSize += wcslen(lpServiceStartName) + 1; + else + dwRequiredSize += 2; + + if (lpService->DisplayName != NULL) + dwRequiredSize += wcslen(lpService->DisplayName) + 1; + else + dwRequiredSize += 2; + + if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize) + { + dwError = ERROR_INSUFFICIENT_BUFFER; + } + else + { + lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig; + lpConfig->dwServiceType = lpService->Status.dwServiceType; + lpConfig->dwStartType = lpService->dwStartType; + lpConfig->dwErrorControl = lpService->dwErrorControl; + lpConfig->dwTagId = lpService->dwTag; + + lpStr = (LPSTR)(lpServiceConfig + 1); + + /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings. + Verified in WINXP*/ + + if (lpImagePath) + { + WideCharToMultiByte(CP_ACP, + 0, + lpImagePath, + -1, + lpStr, + wcslen(lpImagePath) + 1, + 0, + 0); + } + else + { + strcpy(lpStr, lpEmptyString); + } + + lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); + lpStr += (strlen((LPSTR)lpStr) + 1); + + if (lpService->lpGroup && lpService->lpGroup->lpGroupName) + { + WideCharToMultiByte(CP_ACP, + 0, + lpService->lpGroup->lpGroupName, + -1, + lpStr, + wcslen(lpService->lpGroup->lpGroupName) + 1, + 0, + 0); + } + else + { + strcpy(lpStr, lpEmptyString); + } + + lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); + lpStr += (strlen(lpStr) + 1); + + /* Append Dependencies */ + if (lpDependencies) + { + WideCharToMultiByte(CP_ACP, + 0, + lpDependencies, + dwDependenciesLength, + lpStr, + dwDependenciesLength, + 0, + 0); + } + else + { + strcpy(lpStr, lpEmptyString); + } + + lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); + if (lpDependencies) + lpStr += dwDependenciesLength; + else + lpStr += (strlen(lpStr) + 1); + + if (lpServiceStartName) + { + WideCharToMultiByte(CP_ACP, + 0, + lpServiceStartName, + -1, + lpStr, + wcslen(lpServiceStartName) + 1, + 0, + 0); + } + else + { + strcpy(lpStr, lpEmptyString); + } + + lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); + lpStr += (strlen(lpStr) + 1); + + if (lpService->DisplayName) + { + WideCharToMultiByte(CP_ACP, + 0, + lpService->DisplayName, + -1, + lpStr, + wcslen(lpService->DisplayName) + 1, + 0, + 0); + } + else + { + strcpy(lpStr, lpEmptyString); + } + + lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig); + } + + if (pcbBytesNeeded != NULL) + *pcbBytesNeeded = dwRequiredSize; + +Done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + if (lpImagePath != NULL) + HeapFree(GetProcessHeap(), 0, lpImagePath); + + if (lpServiceStartName != NULL) + HeapFree(GetProcessHeap(), 0, lpServiceStartName); + + if (lpDependencies != NULL) + HeapFree(GetProcessHeap(), 0, lpDependencies); + + if (hServiceKey != NULL) + RegCloseKey(hServiceKey); + + DPRINT("RQueryServiceConfigA() done\n"); + + return dwError; +} + + +/* Function 31 */ +DWORD RStartServiceA( + SC_RPC_HANDLE hService, + DWORD argc, + LPSTRING_PTRSA argv) +{ + DWORD dwError = ERROR_SUCCESS; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + LPWSTR *lpVector = NULL; + DWORD i; + DWORD dwLength; + + DPRINT("RStartServiceA() called\n"); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_START)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* + * We can control services only if the + * database is the active database. + */ + if (!IsActiveDatabase(lpService->Database)) + return ERROR_ACCESS_DENIED; + + if (lpService->dwStartType == SERVICE_DISABLED) + return ERROR_SERVICE_DISABLED; + + if (lpService->bDeleted) + return ERROR_SERVICE_MARKED_FOR_DELETE; + + /* Build a Unicode argument vector */ + if (argc > 0) + { + lpVector = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + argc * sizeof(LPWSTR)); + if (lpVector == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + for (i = 0; i < argc; i++) + { + dwLength = MultiByteToWideChar(CP_ACP, + 0, + ((LPSTR*)argv)[i], + -1, + NULL, + 0); + + lpVector[i] = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + dwLength * sizeof(WCHAR)); + if (lpVector[i] == NULL) + { + dwError = ERROR_NOT_ENOUGH_MEMORY; + goto done; + } + + MultiByteToWideChar(CP_ACP, + 0, + ((LPSTR*)argv)[i], + -1, + lpVector[i], + dwLength); + } + } + + /* Start the service */ + dwError = ScmStartService(lpService, argc, lpVector); + +done: + /* Free the Unicode argument vector */ + if (lpVector != NULL) + { + for (i = 0; i < argc; i++) + { + if (lpVector[i] != NULL) + HeapFree(GetProcessHeap(), 0, lpVector[i]); + } + HeapFree(GetProcessHeap(), 0, lpVector); + } + + return dwError; +} + + +/* Function 32 */ +DWORD RGetServiceDisplayNameA( + SC_RPC_HANDLE hSCManager, + LPCSTR lpServiceName, + LPSTR lpDisplayName, + LPBOUNDED_DWORD_4K lpcchBuffer) +{ + PSC_HANDLE_STRUCT hManager; + PSERVICE_RECORD lpService = NULL; + DWORD dwLength; + DWORD dwError; + LPWSTR lpServiceNameW; + + DPRINT("RGetServiceDisplayNameA() called\n"); + DPRINT("hSCManager = %p\n", hSCManager); + DPRINT("lpServiceName: %s\n", lpServiceName); + DPRINT("lpDisplayName: %p\n", lpDisplayName); + DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); + + hManager = ScmGetServiceManagerFromHandle(hSCManager); + if (hManager == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (lpServiceName != NULL) + { + dwLength = strlen(lpServiceName) + 1; + lpServiceNameW = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + dwLength * sizeof(WCHAR)); + if (!lpServiceNameW) + return ERROR_NOT_ENOUGH_MEMORY; + + MultiByteToWideChar(CP_ACP, + 0, + lpServiceName, + -1, + lpServiceNameW, + dwLength); + + lpService = ScmGetServiceEntryByName(hManager->Type.ScManagerObject.Database, lpServiceNameW); + + HeapFree(GetProcessHeap(), 0, lpServiceNameW); + } + + if (lpService == NULL) + { + DPRINT("Could not find a service!\n"); + + /* If the service could not be found and lpcchBuffer is 0, windows + puts null in lpDisplayName and puts 1 in lpcchBuffer */ + if (*lpcchBuffer == 0) + { + *lpcchBuffer = 1; + if (lpDisplayName != NULL) + { + *lpDisplayName = '\0'; + } + } + return ERROR_SERVICE_DOES_NOT_EXIST; + } + + if (!lpService->DisplayName) + { + dwLength = wcslen(lpService->ServiceName); + if (lpDisplayName != NULL && + *lpcchBuffer > dwLength) + { + WideCharToMultiByte(CP_ACP, + 0, + lpService->ServiceName, + wcslen(lpService->ServiceName), + lpDisplayName, + dwLength + 1, + NULL, + NULL); + return ERROR_SUCCESS; + } + } + else + { + dwLength = wcslen(lpService->DisplayName); + if (lpDisplayName != NULL && + *lpcchBuffer > dwLength) + { + WideCharToMultiByte(CP_ACP, + 0, + lpService->DisplayName, + wcslen(lpService->DisplayName), + lpDisplayName, + dwLength + 1, + NULL, + NULL); + return ERROR_SUCCESS; + } + } + + dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER; + + *lpcchBuffer = dwLength * 2; + + return dwError; +} + + +/* Function 33 */ +DWORD RGetServiceKeyNameA( + SC_RPC_HANDLE hSCManager, + LPCSTR lpDisplayName, + LPSTR lpServiceName, + LPBOUNDED_DWORD_4K lpcchBuffer) +{ + PSC_HANDLE_STRUCT hManager; + PSERVICE_RECORD lpService; + DWORD dwLength; + DWORD dwError; + LPWSTR lpDisplayNameW; + + DPRINT("RGetServiceKeyNameA() called\n"); + DPRINT("hSCManager = %p\n", hSCManager); + DPRINT("lpDisplayName: %s\n", lpDisplayName); + DPRINT("lpServiceName: %p\n", lpServiceName); + DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); + + hManager = ScmGetServiceManagerFromHandle(hSCManager); + if (hManager == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + dwLength = strlen(lpDisplayName) + 1; + lpDisplayNameW = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + dwLength * sizeof(WCHAR)); + if (!lpDisplayNameW) + return ERROR_NOT_ENOUGH_MEMORY; + + MultiByteToWideChar(CP_ACP, + 0, + lpDisplayName, + -1, + lpDisplayNameW, + dwLength); + + lpService = ScmGetServiceEntryByDisplayName(hManager->Type.ScManagerObject.Database, lpDisplayNameW); + + HeapFree(GetProcessHeap(), 0, lpDisplayNameW); + + if (lpService == NULL) + { + DPRINT("Could not find the service!\n"); + + /* If the service could not be found and lpcchBuffer is 0, + put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */ + if (*lpcchBuffer == 0) + { + *lpcchBuffer = 1; + if (lpServiceName != NULL) + { + *lpServiceName = '\0'; + } + } + + return ERROR_SERVICE_DOES_NOT_EXIST; + } + + dwLength = wcslen(lpService->ServiceName); + if (lpServiceName != NULL && + *lpcchBuffer > dwLength) + { + WideCharToMultiByte(CP_ACP, + 0, + lpService->ServiceName, + wcslen(lpService->ServiceName), + lpServiceName, + dwLength + 1, + NULL, + NULL); + return ERROR_SUCCESS; + } + + dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER; + + *lpcchBuffer = dwLength * 2; + + return dwError; +} + + +/* Function 34 */ +DWORD RI_ScGetCurrentGroupStateW( + SC_RPC_HANDLE hSCManager, + LPWSTR pszGroupName, + LPDWORD pdwCurrentState) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 35 */ +DWORD REnumServiceGroupW( + SC_RPC_HANDLE hSCManager, + DWORD dwServiceType, + DWORD dwServiceState, + LPBYTE lpBuffer, + DWORD cbBufSize, + LPBOUNDED_DWORD_256K pcbBytesNeeded, + LPBOUNDED_DWORD_256K lpServicesReturned, + LPBOUNDED_DWORD_256K lpResumeIndex, + LPCWSTR pszGroupName) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +// +// WARNING: This function is untested +// +/* Function 36 */ +DWORD RChangeServiceConfig2A( + SC_RPC_HANDLE hService, + SC_RPC_CONFIG_INFOA Info) +{ + SC_RPC_CONFIG_INFOW InfoW; + DWORD dwRet, dwLength; + PVOID ptr = NULL; + + DPRINT("RChangeServiceConfig2A() called\n"); + DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel); + + InfoW.dwInfoLevel = Info.dwInfoLevel; + + if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) + { + LPSERVICE_DESCRIPTIONW lpServiceDescriptonW; + //LPSERVICE_DESCRIPTIONA lpServiceDescriptonA; + + //lpServiceDescriptonA = Info.psd; + + ///if (lpServiceDescriptonA && + ///lpServiceDescriptonA->lpDescription) + ///{ + dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR); + + lpServiceDescriptonW = HeapAlloc(GetProcessHeap(), + 0, + dwLength + sizeof(SERVICE_DESCRIPTIONW)); + if (!lpServiceDescriptonW) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1); + + MultiByteToWideChar(CP_ACP, + 0, + Info.lpDescription, + -1, + lpServiceDescriptonW->lpDescription, + dwLength); + + ptr = lpServiceDescriptonW; + InfoW.psd = lpServiceDescriptonW; + ///} + } + else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) + { + LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW; + LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA; + DWORD dwRebootLen = 0; + DWORD dwCommandLen = 0; + + lpServiceFailureActionsA = Info.psfa; + + if (lpServiceFailureActionsA) + { + if (lpServiceFailureActionsA->lpRebootMsg) + { + dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR); + } + if (lpServiceFailureActionsA->lpCommand) + { + dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR); + } + dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW); + + lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(), + 0, + dwLength); + if (!lpServiceFailureActionsW) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions; + lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod; + CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION)); + + if (lpServiceFailureActionsA->lpRebootMsg) + { + MultiByteToWideChar(CP_ACP, + 0, + lpServiceFailureActionsA->lpRebootMsg, + -1, + lpServiceFailureActionsW->lpRebootMsg, + dwRebootLen); + } + + if (lpServiceFailureActionsA->lpCommand) + { + MultiByteToWideChar(CP_ACP, + 0, + lpServiceFailureActionsA->lpCommand, + -1, + lpServiceFailureActionsW->lpCommand, + dwCommandLen); + } + + ptr = lpServiceFailureActionsW; + } + } + + dwRet = RChangeServiceConfig2W(hService, InfoW); + + HeapFree(GetProcessHeap(), 0, ptr); + + return dwRet; +} + + +/* Function 37 */ +DWORD RChangeServiceConfig2W( + SC_RPC_HANDLE hService, + SC_RPC_CONFIG_INFOW Info) +{ + DWORD dwError = ERROR_SUCCESS; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + HKEY hServiceKey = NULL; + + DPRINT("RChangeServiceConfig2W() called\n"); + DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_CHANGE_CONFIG)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database exclusively */ + ScmLockDatabaseExclusive(); + + if (lpService->bDeleted) + { + DPRINT("The service has already been marked for delete!\n"); + dwError = ERROR_SERVICE_MARKED_FOR_DELETE; + goto done; + } + + /* Open the service key */ + dwError = ScmOpenServiceKey(lpService, + KEY_SET_VALUE, + &hServiceKey); + if (dwError != ERROR_SUCCESS) + goto done; + + if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) + { + LPSERVICE_DESCRIPTIONW lpServiceDescription; + + lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd; + + if (lpServiceDescription != NULL && + lpServiceDescription->lpDescription != NULL) + { + DPRINT("Setting value %S\n", lpServiceDescription->lpDescription); + dwError = RegSetValueExW(hServiceKey, + L"Description", + 0, + REG_SZ, + (LPBYTE)lpServiceDescription->lpDescription, + (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + goto done; + } + } + else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) + { + UNIMPLEMENTED; + dwError = ERROR_CALL_NOT_IMPLEMENTED; + goto done; + } + +done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + if (hServiceKey != NULL) + RegCloseKey(hServiceKey); + + DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 38 */ +DWORD RQueryServiceConfig2A( + SC_RPC_HANDLE hService, + DWORD dwInfoLevel, + LPBYTE lpBuffer, + DWORD cbBufSize, + LPBOUNDED_DWORD_8K pcbBytesNeeded) +{ + DWORD dwError = ERROR_SUCCESS; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + HKEY hServiceKey = NULL; + LPWSTR lpDescriptionW = NULL; + + DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n", + hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded); + + if (!lpBuffer) + return ERROR_INVALID_ADDRESS; + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_QUERY_CONFIG)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database shared */ + ScmLockDatabaseShared(); + + dwError = ScmOpenServiceKey(lpService, + KEY_READ, + &hServiceKey); + if (dwError != ERROR_SUCCESS) + goto done; + + if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) + { + LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer; + LPSTR lpStr; + + dwError = ScmReadString(hServiceKey, + L"Description", + &lpDescriptionW); + if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND) + goto done; + + *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA); + if (dwError == ERROR_SUCCESS) + *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR)); + + if (cbBufSize < *pcbBytesNeeded) + { + dwError = ERROR_INSUFFICIENT_BUFFER; + goto done; + } + + if (dwError == ERROR_SUCCESS) + { + lpStr = (LPSTR)(lpServiceDescription + 1); + + WideCharToMultiByte(CP_ACP, + 0, + lpDescriptionW, + -1, + lpStr, + wcslen(lpDescriptionW), + NULL, + NULL); + lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription); + } + else + { + lpServiceDescription->lpDescription = NULL; + dwError = ERROR_SUCCESS; + goto done; + } + } + else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS) + { + UNIMPLEMENTED; + dwError = ERROR_CALL_NOT_IMPLEMENTED; + goto done; + } + +done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + if (lpDescriptionW != NULL) + HeapFree(GetProcessHeap(), 0, lpDescriptionW); + + if (hServiceKey != NULL) + RegCloseKey(hServiceKey); + + DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 39 */ +DWORD RQueryServiceConfig2W( + SC_RPC_HANDLE hService, + DWORD dwInfoLevel, + LPBYTE lpBuffer, + DWORD cbBufSize, + LPBOUNDED_DWORD_8K pcbBytesNeeded) +{ + DWORD dwError = ERROR_SUCCESS; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService = NULL; + HKEY hServiceKey = NULL; + DWORD dwRequiredSize; + LPWSTR lpDescription = NULL; + LPWSTR lpFailureCommand = NULL; + LPWSTR lpRebootMessage = NULL; + + DPRINT("RQueryServiceConfig2W() called\n"); + + if (!lpBuffer) + return ERROR_INVALID_ADDRESS; + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_QUERY_CONFIG)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database shared */ + ScmLockDatabaseShared(); + + dwError = ScmOpenServiceKey(lpService, + KEY_READ, + &hServiceKey); + if (dwError != ERROR_SUCCESS) + goto done; + + if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) + { + LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer; + LPWSTR lpStr; + + dwError = ScmReadString(hServiceKey, + L"Description", + &lpDescription); + if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND) + goto done; + + *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW); + if (dwError == ERROR_SUCCESS) + *pcbBytesNeeded += ((wcslen(lpDescription) + 1) * sizeof(WCHAR)); + + if (cbBufSize < *pcbBytesNeeded) + { + dwError = ERROR_INSUFFICIENT_BUFFER; + goto done; + } + + if (dwError == ERROR_SUCCESS) + { + lpStr = (LPWSTR)(lpServiceDescription + 1); + wcscpy(lpStr, lpDescription); + lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription); + } + else + { + lpServiceDescription->lpDescription = NULL; + dwError = ERROR_SUCCESS; + } + } + else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) + { + LPWSTR lpStr; + LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer; + + UNIMPLEMENTED; + + dwError = ScmReadString(hServiceKey, + L"FailureCommand", + &lpFailureCommand); + + dwError = ScmReadString(hServiceKey, + L"RebootMessage", + &lpRebootMessage); + + dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW); + + if (lpFailureCommand) + dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR); + + if (lpRebootMessage) + dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR); + + if (cbBufSize < dwRequiredSize) + { + *pcbBytesNeeded = dwRequiredSize; + dwError = ERROR_INSUFFICIENT_BUFFER; + goto done; + } + + lpFailureActions->cActions = 0; + lpFailureActions->dwResetPeriod = 0; + lpFailureActions->lpCommand = NULL; + lpFailureActions->lpRebootMsg = NULL; + lpFailureActions->lpsaActions = NULL; + + lpStr = (LPWSTR)(lpFailureActions + 1); + if (lpRebootMessage) + { + wcscpy(lpStr, lpRebootMessage); + lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage); + lpStr += wcslen(lpRebootMessage) + 1; + } + + if (lpFailureCommand) + { + wcscpy(lpStr, lpFailureCommand); + lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand); + lpStr += wcslen(lpRebootMessage) + 1; + } + dwError = STATUS_SUCCESS; + goto done; + } + +done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + if (lpDescription != NULL) + HeapFree(GetProcessHeap(), 0, lpDescription); + + if (lpRebootMessage != NULL) + HeapFree(GetProcessHeap(), 0, lpRebootMessage); + + if (lpFailureCommand != NULL) + HeapFree(GetProcessHeap(), 0, lpFailureCommand); + + if (hServiceKey != NULL) + RegCloseKey(hServiceKey); + + DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 40 */ +DWORD RQueryServiceStatusEx( + SC_RPC_HANDLE hService, + SC_STATUS_TYPE InfoLevel, + LPBYTE lpBuffer, + DWORD cbBufSize, + LPBOUNDED_DWORD_8K pcbBytesNeeded) +{ + LPSERVICE_STATUS_PROCESS lpStatus; + PSC_HANDLE_STRUCT hSvc; + PSERVICE_RECORD lpService; + + DPRINT("RQueryServiceStatusEx() called\n"); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + if (InfoLevel != SC_STATUS_PROCESS_INFO) + return ERROR_INVALID_LEVEL; + + *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS); + + if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS)) + return ERROR_INSUFFICIENT_BUFFER; + + hSvc = ScmGetServiceFromHandle(hService); + if (hSvc == NULL) + { + DPRINT1("Invalid service handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->DesiredAccess, + SERVICE_QUERY_STATUS)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hSvc->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->Type.ScServiceObject.ServiceEntry; + if (lpService == NULL) + { + DPRINT("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Lock the service database shared */ + ScmLockDatabaseShared(); + + lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer; + + /* Return service status information */ + RtlCopyMemory(lpStatus, + &lpService->Status, + sizeof(SERVICE_STATUS)); + + lpStatus->dwProcessId = (lpService->lpImage != NULL) ? lpService->lpImage->dwProcessId : 0; /* FIXME */ + lpStatus->dwServiceFlags = 0; /* FIXME */ + + /* Unlock the service database */ + ScmUnlockDatabase(); + + return ERROR_SUCCESS; +} + + +/* Function 41 */ +DWORD REnumServicesStatusExA( + SC_RPC_HANDLE hSCManager, + SC_ENUM_TYPE InfoLevel, + DWORD dwServiceType, + DWORD dwServiceState, + LPBYTE lpBuffer, + DWORD cbBufSize, + LPBOUNDED_DWORD_256K pcbBytesNeeded, + LPBOUNDED_DWORD_256K lpServicesReturned, + LPBOUNDED_DWORD_256K lpResumeIndex, + LPCSTR pszGroupName) +{ + LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL; + LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL; + LPWSTR lpStringPtrW; + LPSTR lpStringPtrA; + LPWSTR pszGroupNameW = NULL; + DWORD dwError; + DWORD dwServiceCount; + + DPRINT("REnumServicesStatusExA() called\n"); + + if (pszGroupName) + { + pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR)); + if (!pszGroupNameW) + { + DPRINT("Failed to allocate buffer!\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + + MultiByteToWideChar(CP_ACP, + 0, + pszGroupName, + -1, + pszGroupNameW, + strlen(pszGroupName) + 1); + } + + if ((cbBufSize > 0) && (lpBuffer)) + { + lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize); + if (!lpStatusPtrW) + { + DPRINT("Failed to allocate buffer!\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + } + + dwError = REnumServicesStatusExW(hSCManager, + InfoLevel, + dwServiceType, + dwServiceState, + (LPBYTE)lpStatusPtrW, + cbBufSize, + pcbBytesNeeded, + lpServicesReturned, + lpResumeIndex, + pszGroupNameW); + + /* if no services were returned then we are Done */ + if (*lpServicesReturned == 0) + goto Done; + + lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer; + lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer + + *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA)); + lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW + + *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW)); + + for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++) + { + /* Copy the service name */ + WideCharToMultiByte(CP_ACP, + 0, + lpStringPtrW, + -1, + lpStringPtrA, + wcslen(lpStringPtrW), + 0, + 0); + + lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); + lpStringPtrA += wcslen(lpStringPtrW) + 1; + lpStringPtrW += wcslen(lpStringPtrW) + 1; + + /* Copy the display name */ + WideCharToMultiByte(CP_ACP, + 0, + lpStringPtrW, + -1, + lpStringPtrA, + wcslen(lpStringPtrW), + 0, + 0); + + lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); + lpStringPtrA += wcslen(lpStringPtrW) + 1; + lpStringPtrW += wcslen(lpStringPtrW) + 1; + + /* Copy the status information */ + memcpy(&lpStatusPtrA->ServiceStatusProcess, + &lpStatusPtrW->ServiceStatusProcess, + sizeof(SERVICE_STATUS)); + + lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */ + lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */ + lpStatusPtrA++; + } + +Done: + if (pszGroupNameW) + HeapFree(GetProcessHeap(), 0, pszGroupNameW); + + if (lpStatusPtrW) + HeapFree(GetProcessHeap(), 0, lpStatusPtrW); + + DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* Function 42 */ +DWORD REnumServicesStatusExW( + SC_RPC_HANDLE hSCManager, + SC_ENUM_TYPE InfoLevel, + DWORD dwServiceType, + DWORD dwServiceState, + LPBYTE lpBuffer, + DWORD cbBufSize, + LPBOUNDED_DWORD_256K pcbBytesNeeded, + LPBOUNDED_DWORD_256K lpServicesReturned, + LPBOUNDED_DWORD_256K lpResumeIndex, + LPCWSTR pszGroupName) +{ + PSC_HANDLE_STRUCT hManager; + PSERVICE_RECORD lpService; + DWORD dwError = ERROR_SUCCESS; + PLIST_ENTRY ServiceEntry; + PSERVICE_RECORD CurrentService; + DWORD dwState; + DWORD dwRequiredSize; + DWORD dwServiceCount; + DWORD dwSize; + DWORD dwLastResumeCount = 0; + LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr; + LPWSTR lpStringPtr; + + DPRINT("REnumServicesStatusExW() called\n"); + + if (ScmShutdown) + return ERROR_SHUTDOWN_IN_PROGRESS; + + if (InfoLevel != SC_ENUM_PROCESS_INFO) + return ERROR_INVALID_LEVEL; + + hManager = ScmGetServiceManagerFromHandle(hSCManager); + if (hManager == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + *pcbBytesNeeded = 0; + *lpServicesReturned = 0; + + if ((dwServiceType == 0) || + ((dwServiceType & ~(SERVICE_DRIVER | SERVICE_WIN32)) != 0)) + { + DPRINT("Not a valid Service Type!\n"); + return ERROR_INVALID_PARAMETER; + } + + if ((dwServiceState != SERVICE_ACTIVE) && + (dwServiceState != SERVICE_INACTIVE) && + (dwServiceState != SERVICE_STATE_ALL)) + { + DPRINT("Not a valid Service State!\n"); + return ERROR_INVALID_PARAMETER; + } + + /* Check access rights */ + if (!RtlAreAllAccessesGranted(hManager->DesiredAccess, + SC_MANAGER_ENUMERATE_SERVICE)) + { + DPRINT("Insufficient access rights! 0x%lx\n", + hManager->DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + if (lpResumeIndex) + dwLastResumeCount = *lpResumeIndex; + + /* Lock the service database shared */ + ScmLockDatabaseShared(); + + lpService = ScmGetServiceEntryByResumeCount(hManager->Type.ScManagerObject.Database, dwLastResumeCount); + if (lpService == NULL) + { + dwError = ERROR_SUCCESS; + goto Done; + } + + dwRequiredSize = 0; + dwServiceCount = 0; + + for (ServiceEntry = &lpService->ServiceListEntry; + ServiceEntry != &(hManager->Type.ScManagerObject.Database->ServiceListHead); // lpService->Database->ServiceListHead + ServiceEntry = ServiceEntry->Flink) + { + CurrentService = CONTAINING_RECORD(ServiceEntry, + SERVICE_RECORD, + ServiceListEntry); + + if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) + continue; + + dwState = SERVICE_ACTIVE; + if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) + dwState = SERVICE_INACTIVE; + + if ((dwState & dwServiceState) == 0) + continue; + + if (pszGroupName) + { + if (*pszGroupName == 0) + { + if (CurrentService->lpGroup != NULL) + continue; + } + else + { + if ((CurrentService->lpGroup == NULL) || + _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName)) + continue; + } + } + + dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) + + ((wcslen(CurrentService->ServiceName) + 1) * sizeof(WCHAR)) + + ((wcslen(CurrentService->DisplayName) + 1) * sizeof(WCHAR)); + + if (dwRequiredSize + dwSize <= cbBufSize) + { + DPRINT("Service name: %S fit\n", CurrentService->ServiceName); + dwRequiredSize += dwSize; + dwServiceCount++; + dwLastResumeCount = CurrentService->dwResumeCount; + } + else + { + DPRINT("Service name: %S no fit\n", CurrentService->ServiceName); + break; + } + + } + + DPRINT("dwRequiredSize: %lu\n", dwRequiredSize); + DPRINT("dwServiceCount: %lu\n", dwServiceCount); + + for (; + ServiceEntry != &(hManager->Type.ScManagerObject.Database->ServiceListHead); + ServiceEntry = ServiceEntry->Flink) + { + CurrentService = CONTAINING_RECORD(ServiceEntry, + SERVICE_RECORD, + ServiceListEntry); + + if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) + continue; + + dwState = SERVICE_ACTIVE; + if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) + dwState = SERVICE_INACTIVE; + + if ((dwState & dwServiceState) == 0) + continue; + + if (pszGroupName) + { + if (*pszGroupName == 0) + { + if (CurrentService->lpGroup != NULL) + continue; + } + else + { + if ((CurrentService->lpGroup == NULL) || + _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName)) + continue; + } + } + + dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) + + ((wcslen(CurrentService->ServiceName) + 1) * sizeof(WCHAR)) + + ((wcslen(CurrentService->DisplayName) + 1) * sizeof(WCHAR))); + + dwError = ERROR_MORE_DATA; + } + + DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize); + + if (lpResumeIndex) + *lpResumeIndex = dwLastResumeCount; + + *lpServicesReturned = dwServiceCount; + *pcbBytesNeeded = dwRequiredSize; + + /* If there was no services that matched */ + if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA)) + { + dwError = ERROR_SERVICE_DOES_NOT_EXIST; + goto Done; + } + + lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer; + lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer + + dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW)); + + dwRequiredSize = 0; + for (ServiceEntry = &lpService->ServiceListEntry; + ServiceEntry != &(hManager->Type.ScManagerObject.Database->ServiceListHead); + ServiceEntry = ServiceEntry->Flink) + { + CurrentService = CONTAINING_RECORD(ServiceEntry, + SERVICE_RECORD, + ServiceListEntry); + + if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) + continue; + + dwState = SERVICE_ACTIVE; + if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) + dwState = SERVICE_INACTIVE; + + if ((dwState & dwServiceState) == 0) + continue; + + if (pszGroupName) + { + if (*pszGroupName == 0) + { + if (CurrentService->lpGroup != NULL) + continue; + } + else + { + if ((CurrentService->lpGroup == NULL) || + _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName)) + continue; + } + } + + dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) + + ((wcslen(CurrentService->ServiceName) + 1) * sizeof(WCHAR)) + + ((wcslen(CurrentService->DisplayName) + 1) * sizeof(WCHAR)); + + if (dwRequiredSize + dwSize <= cbBufSize) + { + /* Copy the service name */ + wcscpy(lpStringPtr, + CurrentService->ServiceName); + lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); + lpStringPtr += (wcslen(CurrentService->ServiceName) + 1); + + /* Copy the display name */ + wcscpy(lpStringPtr, + CurrentService->DisplayName); + lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); + lpStringPtr += (wcslen(CurrentService->DisplayName) + 1); + + /* Copy the status information */ + memcpy(&lpStatusPtr->ServiceStatusProcess, + &CurrentService->Status, + sizeof(SERVICE_STATUS)); + lpStatusPtr->ServiceStatusProcess.dwProcessId = + (CurrentService->lpImage != NULL) ? CurrentService->lpImage->dwProcessId : 0; /* FIXME */ + lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */ + + lpStatusPtr++; + dwRequiredSize += dwSize; + } + else + { + break; + } + } + + if (dwError == 0) + { + *pcbBytesNeeded = 0; + if (lpResumeIndex) + *lpResumeIndex = 0; + } + +Done: + /* Unlock the service database */ + ScmUnlockDatabase(); + + DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError); + + return dwError; +} + + +/* EOF */ Index: base/system/services/unimplemented.c =================================================================== --- base/system/services/unimplemented.c (révision 0) +++ base/system/services/unimplemented.c (copie de travail) @@ -0,0 +1,193 @@ +/* + * PROJECT: ReactOS Service Control Manager + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/system/services/unimplemented.c + * PURPOSE: Unimplemented RPC functions + * COPYRIGHT: Copyright 2005-2006 Eric Kohl + * Copyright 2006-2007 Hervé Poussineau + * Copyright 2007 Ged Murphy + */ + +/* INCLUDES ******************************************************************/ + +#include "services.h" + +#define NDEBUG +#include + + +/* RPC SERVER FUNCTIONS ******************************************************/ + +/* Function 43 */ +DWORD RSendTSMessage( + handle_t BindingHandle) /* FIXME */ +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 44 */ +DWORD RCreateServiceWOW64A( + SC_RPC_HANDLE hSCManager, + LPSTR lpServiceName, + LPSTR lpDisplayName, + DWORD dwDesiredAccess, + DWORD dwServiceType, + DWORD dwStartType, + DWORD dwErrorControl, + LPSTR lpBinaryPathName, + LPSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, + LPBYTE lpDependencies, + DWORD dwDependSize, + LPSTR lpServiceStartName, + LPBYTE lpPassword, + DWORD dwPwSize, + LPSC_RPC_HANDLE lpServiceHandle) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 45 */ +DWORD RCreateServiceWOW64W( + SC_RPC_HANDLE hSCManager, + LPWSTR lpServiceName, + LPWSTR lpDisplayName, + DWORD dwDesiredAccess, + DWORD dwServiceType, + DWORD dwStartType, + DWORD dwErrorControl, + LPWSTR lpBinaryPathName, + LPWSTR lpLoadOrderGroup, + LPDWORD lpdwTagId, + LPBYTE lpDependencies, + DWORD dwDependSize, + LPWSTR lpServiceStartName, + LPBYTE lpPassword, + DWORD dwPwSize, + LPSC_RPC_HANDLE lpServiceHandle) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 46 */ +DWORD RQueryServiceTagInfo( + handle_t BindingHandle) /* FIXME */ +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 47 */ +DWORD RNotifyServiceStatusChange( + SC_RPC_HANDLE hService, + SC_RPC_NOTIFY_PARAMS NotifyParams, + GUID* pClientProcessGuid, + GUID* pSCMProcessGuid, + PBOOL pfCreateRemoteQueue, + LPSC_NOTIFY_RPC_HANDLE phNotify) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 48 */ +/* error_status_t */ DWORD RGetNotifyResults( + SC_NOTIFY_RPC_HANDLE hNotify, + PSC_RPC_NOTIFY_PARAMS_LIST* ppNotifyParams) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 49 */ +DWORD RCloseNotifyHandle( + LPSC_NOTIFY_RPC_HANDLE phNotify, + PBOOL pfApcFired) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 50 */ +DWORD RControlServiceExA( + SC_RPC_HANDLE hService, + DWORD dwControl, + DWORD dwInfoLevel/*, + PSC_RPC_SERVICE_CONTROL_IN_PARAMSA pControlInParams, + PSC_RPC_SERVICE_CONTROL_OUT_PARAMSA pControlOutParams*/) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 51 */ +DWORD RControlServiceExW( + SC_RPC_HANDLE hService, + DWORD dwControl, + DWORD dwInfoLevel/*, + PSC_RPC_SERVICE_CONTROL_IN_PARAMSW pControlInParams, + PSC_RPC_SERVICE_CONTROL_OUT_PARAMSW pControlOutParams*/) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 52 */ +DWORD RSendPnPMessage( + handle_t BindingHandle) /* FIXME */ +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 53 */ +DWORD RValidatePnPService( + handle_t BindingHandle) /* FIXME */ +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 54 */ +DWORD ROpenServiceStatusHandle( + handle_t BindingHandle) /* FIXME */ +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 55 */ +DWORD RFunction55( + handle_t BindingHandle) /* FIXME */ +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 56 */ +DWORD RQueryServiceConfigEx( + SC_RPC_HANDLE hService, + DWORD dwInfoLevel, + SC_RPC_CONFIG_INFOW* pInfo) +{ + UNIMPLEMENTED; + return ERROR_CALL_NOT_IMPLEMENTED; +} + +/* EOF */ Index: base/system/services/utils.c =================================================================== --- base/system/services/utils.c (révision 0) +++ base/system/services/utils.c (copie de travail) @@ -0,0 +1,443 @@ +/* + * PROJECT: ReactOS Service Control Manager + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/system/services/utils.c + * PURPOSE: Helper functions + * COPYRIGHT: Copyright 2005-2006 Eric Kohl + * Copyright 2006-2007 Hervé Poussineau + * Copyright 2007 Ged Murphy + * Copyright 2012 Hermès Bélusca - Maïto + */ + +/* INCLUDES ******************************************************************/ + +#include "services.h" + +#define NDEBUG +#include + + +/* FUNCTIONS *****************************************************************/ + +BOOL +ScDatabaseNamesMatch(const LPCWSTR lpszDbName1, + const LPCWSTR lpszDbName2) +{ + if (lpszDbName1 && lpszDbName2) + { + return (_wcsicmp(lpszDbName1, lpszDbName2) == 0); + } + else if ( (!lpszDbName1 && lpszDbName2 && !*lpszDbName2) || + (!lpszDbName2 && lpszDbName1 && !*lpszDbName1) || + (!lpszDbName1 && !lpszDbName2) ) + { + return TRUE; + } + else + { + return FALSE; + } +} + + +size_t +wcssize(const LPCWSTR lpszStr) +{ + return (lpszStr ? (wcslen(lpszStr) + 1) * sizeof(WCHAR) : 0); +} + + +/* Create a path suitable for the bootloader out of the full path */ +static DWORD +ScmConvertToBootPathName(LPWSTR CanonName, LPWSTR* RelativeName) +{ + DWORD ServiceNameLen, BufferSize, ExpandedLen; + WCHAR Dest; + WCHAR *Expanded; + UNICODE_STRING NtPathName, SystemRoot, LinkTarget; + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE SymbolicLinkHandle; + + DPRINT("ScmConvertToBootPathName %S\n", CanonName); + + ServiceNameLen = wcslen(CanonName); + + /* First check, if it's already good */ + if (ServiceNameLen > 12 && + !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12)) + { + *RelativeName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (ServiceNameLen + 1) * sizeof(WCHAR)); + if (*RelativeName == NULL) + { + DPRINT("Error allocating memory for boot driver name!\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* Copy it */ + wcscpy(*RelativeName, CanonName); + + DPRINT("Bootdriver name %S\n", *RelativeName); + return ERROR_SUCCESS; + } + + /* If it has %SystemRoot% prefix, substitute it to \System*/ + if (ServiceNameLen > 13 && + !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13)) + { + /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */ + *RelativeName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + ServiceNameLen * sizeof(WCHAR)); + + if (*RelativeName == NULL) + { + DPRINT("Error allocating memory for boot driver name!\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* Copy it */ + wcscpy(*RelativeName, L"\\SystemRoot\\"); + wcscat(*RelativeName, CanonName + 13); + + DPRINT("Bootdriver name %S\n", *RelativeName); + return ERROR_SUCCESS; + } + + /* Get buffer size needed for expanding env strings */ + BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1); + + if (BufferSize <= 1) + { + DPRINT("Error during a call to ExpandEnvironmentStringsW()\n"); + return ERROR_INVALID_ENVIRONMENT; + } + + /* Allocate memory, since the size is known now */ + Expanded = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (BufferSize + 1) * sizeof(WCHAR)); + if (!Expanded) + { + DPRINT("Error allocating memory for boot driver name!\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* Expand it */ + if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) > + BufferSize) + { + DPRINT("Error during a call to ExpandEnvironmentStringsW()\n"); + HeapFree(GetProcessHeap(), 0, Expanded); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* Convert to NY-style path */ + if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL)) + { + DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n"); + return ERROR_INVALID_ENVIRONMENT; + } + + DPRINT("Converted to NT-style %wZ\n", &NtPathName); + + /* No need to keep the dos-path anymore */ + HeapFree(GetProcessHeap(), 0, Expanded); + + /* Copy it to the allocated place */ + Expanded = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + NtPathName.Length + sizeof(UNICODE_NULL)); + if (!Expanded) + { + DPRINT("Error allocating memory for boot driver name!\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + + ExpandedLen = NtPathName.Length / sizeof(WCHAR); + wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen); + Expanded[ExpandedLen] = UNICODE_NULL; + + if (ServiceNameLen > ExpandedLen && + !_wcsnicmp(Expanded, CanonName, ExpandedLen)) + { + /* Only \SystemRoot\ is missing */ + *RelativeName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR)); + if (*RelativeName == NULL) + { + DPRINT("Error allocating memory for boot driver name!\n"); + HeapFree(GetProcessHeap(), 0, Expanded); + return ERROR_NOT_ENOUGH_MEMORY; + } + + wcscpy(*RelativeName, L"\\SystemRoot\\"); + wcscat(*RelativeName, CanonName + ExpandedLen); + + RtlFreeUnicodeString(&NtPathName); + return ERROR_SUCCESS; + } + + /* The most complex case starts here */ + RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot"); + InitializeObjectAttributes(&ObjectAttributes, + &SystemRoot, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Open this symlink */ + Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes); + + if (NT_SUCCESS(Status)) + { + LinkTarget.Length = 0; + LinkTarget.MaximumLength = 0; + + DPRINT("Opened symbolic link object\n"); + + Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize); + if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL) + { + /* Check if required buffer size is sane */ + if (BufferSize > 0xFFFD) + { + DPRINT("Too large buffer required\n"); + *RelativeName = 0; + + if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); + HeapFree(GetProcessHeap(), 0, Expanded); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* Alloc the string */ + LinkTarget.Length = (USHORT)BufferSize; + LinkTarget.MaximumLength = LinkTarget.Length + sizeof(UNICODE_NULL); + LinkTarget.Buffer = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + LinkTarget.MaximumLength); + if (!LinkTarget.Buffer) + { + DPRINT("Unable to alloc buffer\n"); + if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); + HeapFree(GetProcessHeap(), 0, Expanded); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* Do a real query now */ + Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize); + if (NT_SUCCESS(Status)) + { + DPRINT("LinkTarget: %wZ\n", &LinkTarget); + + ExpandedLen = LinkTarget.Length / sizeof(WCHAR); + if ((ServiceNameLen > ExpandedLen) && + !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen)) + { + *RelativeName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR)); + + if (*RelativeName == NULL) + { + DPRINT("Unable to alloc buffer\n"); + if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); + HeapFree(GetProcessHeap(), 0, Expanded); + RtlFreeUnicodeString(&NtPathName); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* Copy it over, substituting the first part + with SystemRoot */ + wcscpy(*RelativeName, L"\\SystemRoot\\"); + wcscat(*RelativeName, CanonName+ExpandedLen+1); + + /* Cleanup */ + if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); + HeapFree(GetProcessHeap(), 0, Expanded); + RtlFreeUnicodeString(&NtPathName); + + /* Return success */ + return ERROR_SUCCESS; + } + else + { + if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); + HeapFree(GetProcessHeap(), 0, Expanded); + RtlFreeUnicodeString(&NtPathName); + return ERROR_INVALID_PARAMETER; + } + } + else + { + DPRINT("Error, Status = %08X\n", Status); + if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); + HeapFree(GetProcessHeap(), 0, Expanded); + RtlFreeUnicodeString(&NtPathName); + return ERROR_INVALID_PARAMETER; + } + } + else + { + DPRINT("Error, Status = %08X\n", Status); + if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle); + HeapFree(GetProcessHeap(), 0, Expanded); + RtlFreeUnicodeString(&NtPathName); + return ERROR_INVALID_PARAMETER; + } + } + else + { + DPRINT("Error, Status = %08X\n", Status); + HeapFree(GetProcessHeap(), 0, Expanded); + return ERROR_INVALID_PARAMETER; + } + + /* Failure */ + *RelativeName = NULL; + return ERROR_INVALID_PARAMETER; +} + + +DWORD +ScmCanonDriverImagePath(DWORD dwStartType, + LPCWSTR lpServiceName, + LPWSTR* lpCanonName) +{ + DWORD ServiceNameLen, Result; + UNICODE_STRING NtServiceName; + WCHAR *RelativeName; + const WCHAR *SourceName = lpServiceName; + + /* Calculate the length of the service's name */ + ServiceNameLen = wcslen(lpServiceName); + + /* 12 is wcslen(L"\\SystemRoot\\") */ + if (ServiceNameLen > 12 && + !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12)) + { + /* SystemRoot prefix is already included */ + *lpCanonName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (ServiceNameLen + 1) * sizeof(WCHAR)); + + if (*lpCanonName == NULL) + { + DPRINT("Error allocating memory for canonized service name!\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* If it's a boot-time driver, it must be systemroot relative */ + if (dwStartType == SERVICE_BOOT_START) + SourceName += 12; + + /* Copy it */ + wcscpy(*lpCanonName, SourceName); + + DPRINT("Canonicalized name %S\n", *lpCanonName); + return NO_ERROR; + } + + /* Check if it has %SystemRoot% (len=13) */ + if (ServiceNameLen > 13 && + !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13)) + { + /* Substitute %SystemRoot% with \\SystemRoot\\ */ + *lpCanonName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (ServiceNameLen + 1) * sizeof(WCHAR)); + + if (*lpCanonName == NULL) + { + DPRINT("Error allocating memory for canonized service name!\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* If it's a boot-time driver, it must be systemroot relative */ + if (dwStartType == SERVICE_BOOT_START) + wcscpy(*lpCanonName, L"\\SystemRoot\\"); + + wcscat(*lpCanonName, lpServiceName + 13); + + DPRINT("Canonicalized name %S\n", *lpCanonName); + return NO_ERROR; + } + + /* Check if it's a relative path name */ + if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':') + { + *lpCanonName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (ServiceNameLen + 1) * sizeof(WCHAR)); + + if (*lpCanonName == NULL) + { + DPRINT("Error allocating memory for canonized service name!\n"); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* Just copy it over without changing */ + wcscpy(*lpCanonName, lpServiceName); + + return NO_ERROR; + } + + /* It seems to be a DOS path, convert it */ + if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL)) + { + DPRINT("RtlDosPathNameToNtPathName_U() failed!\n"); + return ERROR_INVALID_PARAMETER; + } + + *lpCanonName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + NtServiceName.Length + sizeof(WCHAR)); + + if (*lpCanonName == NULL) + { + DPRINT("Error allocating memory for canonized service name!\n"); + RtlFreeUnicodeString(&NtServiceName); + return ERROR_NOT_ENOUGH_MEMORY; + } + + /* Copy the string */ + wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR)); + + /* The unicode string is not needed anymore */ + RtlFreeUnicodeString(&NtServiceName); + + if (dwStartType != SERVICE_BOOT_START) + { + DPRINT("Canonicalized name %S\n", *lpCanonName); + return NO_ERROR; + } + + /* The service is boot-started, so must be relative */ + Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName); + if (Result) + { + /* There is a problem, free name and return */ + HeapFree(GetProcessHeap(), 0, *lpCanonName); + DPRINT("Error converting named!\n"); + return Result; + } + + ASSERT(RelativeName); + + /* Copy that string */ + wcscpy(*lpCanonName, RelativeName + 12); + + /* Free the allocated buffer */ + HeapFree(GetProcessHeap(), 0, RelativeName); + + DPRINT("Canonicalized name %S\n", *lpCanonName); + + /* Success */ + return NO_ERROR; +} + + +/* EOF */ Index: dll/win32/advapi32/service/scm.c =================================================================== --- dll/win32/advapi32/service/scm.c (révision 56659) +++ dll/win32/advapi32/service/scm.c (copie de travail) @@ -317,7 +317,7 @@ (LPSTR)lpBinaryPathName, (LPSTR)lpLoadOrderGroup, lpdwTagId, - (LPSTR)lpDependencies, + (LPBYTE)lpDependencies, dwDependenciesLength, (LPSTR)lpServiceStartName, NULL, /* FIXME: lpPassword */ Index: include/reactos/idl/svcctl.idl =================================================================== --- include/reactos/idl/svcctl.idl (révision 56659) +++ include/reactos/idl/svcctl.idl (copie de travail) @@ -1,10 +1,12 @@ /* * Service Control Manager (SCM) interface definition + * + * NOTE: See http://msdn.microsoft.com/en-us/library/cc245860(v=prot.13) */ #include -const unsigned int MAX_SERVICE_NAME_LENGTH = 255; +const unsigned int MAX_SERVICE_NAME_LENGTH = 256; const unsigned short SC_MAX_DEPEND_SIZE = 4 * 1024; const unsigned short SC_MAX_NAME_LENGTH = MAX_SERVICE_NAME_LENGTH + 1; const unsigned short SC_MAX_PATH_LENGTH = 32 * 1024; @@ -15,8 +17,9 @@ const unsigned short SC_MAX_ARGUMENT_LENGTH = 1024; const unsigned short SC_MAX_ARGUMENTS = 1024; -typedef [handle] LPSTR SVCCTL_HANDLEA; -typedef [handle] LPWSTR SVCCTL_HANDLEW; +typedef [handle] LPSTR SVCCTL_HANDLEA; +typedef [handle] LPWSTR SVCCTL_HANDLEW; // wchar_t* + typedef [handle] ULONG_PTR RPC_SERVICE_STATUS_HANDLE; typedef [context_handle] PVOID SC_RPC_HANDLE; typedef SC_RPC_HANDLE* LPSC_RPC_HANDLE; @@ -24,6 +27,7 @@ typedef SC_RPC_LOCK* LPSC_RPC_LOCK; typedef [context_handle] PVOID SC_NOTIFY_RPC_HANDLE; typedef SC_NOTIFY_RPC_HANDLE* LPSC_NOTIFY_RPC_HANDLE; + typedef [range(0, 1024 * 4)] DWORD BOUNDED_DWORD_4K; typedef BOUNDED_DWORD_4K* LPBOUNDED_DWORD_4K; typedef [range(0, 1024 * 8)] DWORD BOUNDED_DWORD_8K; @@ -31,6 +35,14 @@ typedef [range(0, 1024 * 256)] DWORD BOUNDED_DWORD_256K; typedef BOUNDED_DWORD_256K* LPBOUNDED_DWORD_256K; +typedef struct _STRING_PTRSA { + [string /*, range(0, SC_MAX_ARGUMENT_LENGTH)*/] LPSTR StringPtr; +} STRING_PTRSA, *PSTRING_PTRSA, *LPSTRING_PTRSA; + +typedef struct _STRING_PTRSW { + [string /*, range(0, SC_MAX_ARGUMENT_LENGTH)*/] LPWSTR StringPtr; // wchar_t* +} STRING_PTRSW, *PSTRING_PTRSW, *LPSTRING_PTRSW; + cpp_quote("#if 0") typedef struct _SERVICE_STATUS { @@ -242,26 +254,26 @@ cpp_quote("#if 0") -#if 0 +#if 0 // Because switch_type is unrecognized. typedef [switch_type(DWORD)] union _SC_RPC_SERVICE_CONTROL_IN_PARAMSA { [case(1)] PSERVICE_CONTROL_STATUS_REASON_IN_PARAMSA psrInParams; -} SC_RPC_SERVICE_CONTROL_IN_PARAMSA, *LPSC_RPC_SERVICE_CONTROL_IN_PARAMSA; +} SC_RPC_SERVICE_CONTROL_IN_PARAMSA, *PSC_RPC_SERVICE_CONTROL_IN_PARAMSA; typedef [switch_type(DWORD)] union _SC_RPC_SERVICE_CONTROL_IN_PARAMSW { [case(1)] PSERVICE_CONTROL_STATUS_REASON_IN_PARAMSW psrInParams; -} SC_RPC_SERVICE_CONTROL_IN_PARAMSW, *LPSC_RPC_SERVICE_CONTROL_IN_PARAMSW; +} SC_RPC_SERVICE_CONTROL_IN_PARAMSW, *PSC_RPC_SERVICE_CONTROL_IN_PARAMSW; typedef [switch_type(DWORD)] union _SC_RPC_SERVICE_CONTROL_OUT_PARAMSA { [case(1)] PSERVICE_CONTROL_STATUS_REASON_OUT_PARAMS psrOutParams; -} SC_RPC_SERVICE_CONTROL_OUT_PARAMSA, *LPSC_RPC_SERVICE_CONTROL_OUT_PARAMSA; +} SC_RPC_SERVICE_CONTROL_OUT_PARAMSA, *PSC_RPC_SERVICE_CONTROL_OUT_PARAMSA; typedef [switch_type(DWORD)] union _SC_RPC_SERVICE_CONTROL_OUT_PARAMSW { [case(1)] PSERVICE_CONTROL_STATUS_REASON_OUT_PARAMS psrOutParams; -} SC_RPC_SERVICE_CONTROL_OUT_PARAMSW, *LPSC_RPC_SERVICE_CONTROL_OUT_PARAMSW; +} SC_RPC_SERVICE_CONTROL_OUT_PARAMSW, *PSC_RPC_SERVICE_CONTROL_OUT_PARAMSW; #endif typedef [v1_enum] enum _SC_STATUS_TYPE { @@ -286,40 +298,37 @@ cpp_quote("#endif") -typedef struct _STRING_PTRSA { - [string] LPSTR StringPtr; -} STRING_PTRSA, *PSTRING_PTRSA, *LPSTRING_PTRSA; - -typedef struct _STRING_PTRSW { - [string] LPWSTR StringPtr; -} STRING_PTRSW, *PSTRING_PTRSW, *LPSTRING_PTRSW; - [ - uuid(367abb81-9844-35f1-ad32-98f038001003), - version(2.0), - pointer_default(unique), - endpoint("ncacn_np:[\\pipe\\ntsvcs]") + uuid(367abb81-9844-35f1-ad32-98f038001003), + version(2.0), + pointer_default(unique), + endpoint("ncacn_np:[\\pipe\\ntsvcs]") + // endpoint("ncacn_np:[\\pipe\\svcctl]") <-- Wine <-- MSDN Spec !! ] interface svcctl { /* Function 0 */ DWORD RCloseServiceHandle( - [in, out] LPSC_RPC_HANDLE hSCObject); + [in, out] LPSC_RPC_HANDLE hSCObject + ); /* Function 1 */ DWORD RControlService( [in] SC_RPC_HANDLE hService, [in] DWORD dwControl, - [out] LPSERVICE_STATUS lpServiceStatus); + [out] LPSERVICE_STATUS lpServiceStatus + ); /* Function 2 */ DWORD RDeleteService( - [in] SC_RPC_HANDLE hService); + [in] SC_RPC_HANDLE hService + ); /* Function 3 */ DWORD RLockServiceDatabase( [in] SC_RPC_HANDLE hSCManager, - [out] LPSC_RPC_LOCK lpLock); + [out] LPSC_RPC_LOCK lpLock + ); /* Function 4 */ DWORD RQueryServiceObjectSecurity( @@ -327,33 +336,40 @@ [in] SECURITY_INFORMATION dwSecurityInformation, [out, size_is(cbBufSize)] LPBYTE lpSecurityDescriptor, [in, range(0, 1024 * 256)] DWORD cbBufSize, - [out] LPBOUNDED_DWORD_256K pcbBytesNeeded); + [out] LPBOUNDED_DWORD_256K pcbBytesNeeded + ); /* Function 5 */ DWORD RSetServiceObjectSecurity( [in] SC_RPC_HANDLE hService, - [in] DWORD dwSecurityInformation, - [in, size_is(dwSecuityDescriptorSize)] LPBYTE lpSecurityDescriptor, - [in] DWORD dwSecuityDescriptorSize); + [in] SECURITY_INFORMATION dwSecurityInformation, + [in, size_is(cbBufSize)] LPBYTE lpSecurityDescriptor, + [in] DWORD cbBufSize + ); /* Function 6 */ DWORD RQueryServiceStatus( [in] SC_RPC_HANDLE hService, - [out] LPSERVICE_STATUS lpServiceStatus); + [out] LPSERVICE_STATUS lpServiceStatus + ); /* Function 7 */ DWORD RSetServiceStatus( - [in] RPC_SERVICE_STATUS_HANDLE hServiceStatus, - [in] LPSERVICE_STATUS lpServiceStatus); + // [in] SC_RPC_HANDLE hServiceStatus, + [in] RPC_SERVICE_STATUS_HANDLE hServiceStatus, + [in] LPSERVICE_STATUS lpServiceStatus + ); /* Function 8 */ DWORD RUnlockServiceDatabase( - [in, out] LPSC_RPC_LOCK Lock); + [in, out] LPSC_RPC_LOCK Lock + ); /* Function 9 */ DWORD RNotifyBootConfigStatus( - [in, string, unique] SVCCTL_HANDLEW lpMachineName, - [in] DWORD BootAcceptable); + [in, string, unique /*, range(0, SC_MAX_COMPUTER_NAME_LENGTH)*/] SVCCTL_HANDLEW lpMachineName, + [in] DWORD BootAcceptable + ); /* Function 10 */ DWORD RI_ScSetServiceBitsW( @@ -361,7 +377,8 @@ [in] DWORD dwServiceBits, [in] BOOL bSetBitsOn, [in] BOOL bUpdateImmediately, - [in, string, unique] LPWSTR lpString); + [in, string, unique] LPWSTR pszTransportName // wchar_t* + ); /* Function 11 */ DWORD RChangeServiceConfigW( @@ -369,103 +386,113 @@ [in] DWORD dwServiceType, [in] DWORD dwStartType, [in] DWORD dwErrorControl, - [in, string, unique] LPWSTR lpBinaryPathName, - [in, string, unique] LPWSTR lpLoadOrderGroup, + [in, string, unique /*, range(0, SC_MAX_PATH_LENGTH)*/] LPWSTR lpBinaryPathName, // wchar_t* + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPWSTR lpLoadOrderGroup, // wchar_t* [in, out, unique] LPDWORD lpdwTagId, [in, unique, size_is(dwDependSize)] LPBYTE lpDependencies, [in, range(0, SC_MAX_DEPEND_SIZE)] DWORD dwDependSize, - [in, string, unique] LPWSTR lpServiceStartName, + [in, string, unique /*, range(0, SC_MAX_ACCOUNT_NAME_LENGTH)*/] LPWSTR lpServiceStartName, // wchar_t* [in, unique, size_is(dwPwSize)] LPBYTE lpPassword, [in, range(0, SC_MAX_PWD_SIZE)] DWORD dwPwSize, - [in, string, unique] LPWSTR lpDisplayName); + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPWSTR lpDisplayName // wchar_t* + ); /* Function 12 */ DWORD RCreateServiceW( [in] SC_RPC_HANDLE hSCManager, - [in, string] LPCWSTR lpServiceName, - [in, string, unique] LPCWSTR lpDisplayName, + [in, string /*, range(0, SC_MAX_NAME_LENGTH)*/] LPCWSTR lpServiceName, // wchar_t* + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPCWSTR lpDisplayName, // wchar_t* [in] DWORD dwDesiredAccess, [in] DWORD dwServiceType, [in] DWORD dwStartType, [in] DWORD dwErrorControl, - [in, string] LPCWSTR lpBinaryPathName, - [in, string, unique] LPCWSTR lpLoadOrderGroup, + [in, string /*, range(0, SC_MAX_PATH_LENGTH)*/] LPCWSTR lpBinaryPathName, // wchar_t* + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPCWSTR lpLoadOrderGroup, // wchar_t* [in, out, unique] LPDWORD lpdwTagId, [in, unique, size_is(dwDependSize)] LPBYTE lpDependencies, [in, range(0, SC_MAX_DEPEND_SIZE)] DWORD dwDependSize, - [in, string, unique] LPCWSTR lpServiceStartName, + [in, string, unique /*, range(0, SC_MAX_ACCOUNT_NAME_LENGTH)*/] LPCWSTR lpServiceStartName, // wchar_t* [in, unique, size_is(dwPwSize)] LPBYTE lpPassword, [in, range(0, SC_MAX_PWD_SIZE)] DWORD dwPwSize, - [out] LPSC_RPC_HANDLE lpServiceHandle); + [out] LPSC_RPC_HANDLE lpServiceHandle + ); /* Function 13 */ DWORD REnumDependentServicesW( [in] SC_RPC_HANDLE hService, [in] DWORD dwServiceState, [out, size_is(cbBufSize)] LPBYTE lpServices, - [in, range(0, 1024*256)] DWORD cbBufSize, + [in, range(0, 1024 * 256)] DWORD cbBufSize, [out] LPBOUNDED_DWORD_256K pcbBytesNeeded, - [out] LPBOUNDED_DWORD_256K lpServicesReturned); + [out] LPBOUNDED_DWORD_256K lpServicesReturned + ); /* Function 14 */ DWORD REnumServicesStatusW( [in] SC_RPC_HANDLE hSCManager, [in] DWORD dwServiceType, [in] DWORD dwServiceState, - [out, size_is(dwBufSize)] LPBYTE lpBuffer, - [in, range(0, 1024*256)] DWORD dwBufSize, + [out, size_is(cbBufSize)] LPBYTE lpBuffer, + [in, range(0, 1024 * 256)] DWORD cbBufSize, [out] LPBOUNDED_DWORD_256K pcbBytesNeeded, [out] LPBOUNDED_DWORD_256K lpServicesReturned, - [in, out, unique] LPBOUNDED_DWORD_256K lpResumeHandle); + [in, out, unique] LPBOUNDED_DWORD_256K lpResumeIndex + ); /* Function 15 */ DWORD ROpenSCManagerW( - [in, string, unique] SVCCTL_HANDLEW lpMachineName, - [in, string, unique] LPWSTR lpDatabaseName, + [in, string, unique /*, range(0, SC_MAX_COMPUTER_NAME_LENGTH)*/] SVCCTL_HANDLEW lpMachineName, + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPWSTR lpDatabaseName, // wchar_t* [in] DWORD dwDesiredAccess, - [out] LPSC_RPC_HANDLE lpScHandle); + [out] LPSC_RPC_HANDLE lpScHandle + ); /* Function 16 */ DWORD ROpenServiceW( [in] SC_RPC_HANDLE hSCManager, - [in, string] LPWSTR lpServiceName, + [in, string /*, range(0, SC_MAX_NAME_LENGTH)*/] LPWSTR lpServiceName, // wchar_t* [in] DWORD dwDesiredAccess, - [out] LPSC_RPC_HANDLE lpServiceHandle); + [out] LPSC_RPC_HANDLE lpServiceHandle + ); /* Function 17 */ DWORD RQueryServiceConfigW( [in] SC_RPC_HANDLE hService, - [out, size_is(cbBufSize)] LPBYTE lpServiceConfig, - /* FIXME: should be [out] LPQUERY_SERVICE_CONFIGW lpServiceConfig, */ - [in, range(0, 1024*8)] DWORD cbBufSize, - [out] LPBOUNDED_DWORD_8K pcbBytesNeeded); + [out, size_is(cbBufSize)] LPBYTE lpServiceConfig, // FIXME: [out] LPQUERY_SERVICE_CONFIGW lpServiceConfig, + [in, range(0, 1024 * 8)] DWORD cbBufSize, + [out] LPBOUNDED_DWORD_8K pcbBytesNeeded + ); /* Function 18 */ DWORD RQueryServiceLockStatusW( [in] SC_RPC_HANDLE hSCManager, [out] LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus, - [in, range(0, 1024*4)] DWORD cbBufSize, - [out] LPBOUNDED_DWORD_4K pcbBytesNeeded); + [in, range(0, 1024 * 4)] DWORD cbBufSize, + [out] LPBOUNDED_DWORD_4K pcbBytesNeeded + ); /* Function 19 */ DWORD RStartServiceW( [in] SC_RPC_HANDLE hService, [in, range(0, SC_MAX_ARGUMENTS)] DWORD argc, - [in, unique, size_is(argc)] LPSTRING_PTRSW argv); + [in, unique, size_is(argc)] LPSTRING_PTRSW argv + ); /* Function 20 */ DWORD RGetServiceDisplayNameW( [in] SC_RPC_HANDLE hSCManager, - [in, string] LPCWSTR lpServiceName, - [out, string, size_is(*lpcchBuffer + 1)] LPWSTR lpDisplayName, - [in, out] DWORD* lpcchBuffer); + [in, string /*, range(0, SC_MAX_NAME_LENGTH)*/] LPCWSTR lpServiceName, // wchar_t* + [out, string /*, range(1, 4 * 1024 + 1)*/, size_is(*lpcchBuffer + 1)] LPWSTR lpDisplayName, // wchar_t* + [in, out] DWORD* lpcchBuffer // and NOT LPBOUNDED_DWORD_4K because of the range for the string ! + ); /* Function 21 */ DWORD RGetServiceKeyNameW( [in] SC_RPC_HANDLE hSCManager, - [in, string] LPCWSTR lpDisplayName, - [out, string, size_is(*lpcchBuffer + 1)] LPWSTR lpServiceName, - [in, out] DWORD* lpcchBuffer); + [in, string /*, range(0, SC_MAX_NAME_LENGTH)*/] LPCWSTR lpDisplayName, // wchar_t* + [out, string /*, range(1, 4 * 1024 + 1)*/, size_is(*lpcchBuffer + 1)] LPWSTR lpServiceName, // wchar_t* + [in, out] DWORD* lpcchBuffer // and NOT LPBOUNDED_DWORD_4K because of the range for the string ! + ); /* Function 22 */ DWORD RI_ScSetServiceBitsA( @@ -473,7 +500,8 @@ [in] DWORD dwServiceBits, [in] BOOL bSetBitsOn, [in] BOOL bUpdateImmediately, - [in, string, unique] LPSTR lpString); + [in, string, unique] LPSTR pszTransportName + ); /* Function 23 */ DWORD RChangeServiceConfigA( @@ -481,109 +509,120 @@ [in] DWORD dwServiceType, [in] DWORD dwStartType, [in] DWORD dwErrorControl, - [in, string, unique] LPSTR lpBinaryPathName, - [in, string, unique] LPSTR lpLoadOrderGroup, + [in, string, unique /*, range(0, SC_MAX_PATH_LENGTH)*/] LPSTR lpBinaryPathName, + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPSTR lpLoadOrderGroup, [in, out, unique] LPDWORD lpdwTagId, - [in, unique, size_is(dwDependSize)] LPSTR lpDependencies, + [in, unique, size_is(dwDependSize)] LPBYTE lpDependencies, [in, range(0, SC_MAX_DEPEND_SIZE)] DWORD dwDependSize, - [in, string, unique] LPSTR lpServiceStartName, + [in, string, unique /*, range(0, SC_MAX_ACCOUNT_NAME_LENGTH)*/] LPSTR lpServiceStartName, [in, unique, size_is(dwPwSize)] LPBYTE lpPassword, [in, range(0, SC_MAX_PWD_SIZE)] DWORD dwPwSize, - [in, string, unique] LPSTR lpDisplayName); + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPSTR lpDisplayName + ); /* Function 24 */ DWORD RCreateServiceA( [in] SC_RPC_HANDLE hSCManager, - [in, string] LPSTR lpServiceName, - [in, string, unique] LPSTR lpDisplayName, + [in, string /*, range(0, SC_MAX_NAME_LENGTH)*/] LPSTR lpServiceName, + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPSTR lpDisplayName, [in] DWORD dwDesiredAccess, [in] DWORD dwServiceType, [in] DWORD dwStartType, [in] DWORD dwErrorControl, - [in, string] LPSTR lpBinaryPathName, - [in, string, unique] LPSTR lpLoadOrderGroup, + [in, string /*, range(0, SC_MAX_PATH_LENGTH)*/] LPSTR lpBinaryPathName, + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPSTR lpLoadOrderGroup, [in, out, unique] LPDWORD lpdwTagId, [in, unique, size_is(dwDependSize)] LPBYTE lpDependencies, [in, range(0, SC_MAX_DEPEND_SIZE)] DWORD dwDependSize, - [in, string, unique] LPSTR lpServiceStartName, + [in, string, unique /*, range(0, SC_MAX_ACCOUNT_NAME_LENGTH)*/] LPSTR lpServiceStartName, [in, unique, size_is(dwPwSize)] LPBYTE lpPassword, [in, range(0, SC_MAX_PWD_SIZE)] DWORD dwPwSize, - [out] LPSC_RPC_HANDLE lpServiceHandle); + [out] LPSC_RPC_HANDLE lpServiceHandle + ); /* Function 25 */ DWORD REnumDependentServicesA( [in] SC_RPC_HANDLE hService, [in] DWORD dwServiceState, [out, size_is(cbBufSize)] LPBYTE lpServices, - [in, range(0, 1024*256)] DWORD cbBufSize, + [in, range(0, 1024 * 256)] DWORD cbBufSize, [out] LPBOUNDED_DWORD_256K pcbBytesNeeded, - [out] LPBOUNDED_DWORD_256K lpServicesReturned); + [out] LPBOUNDED_DWORD_256K lpServicesReturned + ); /* Function 26 */ DWORD REnumServicesStatusA( [in] SC_RPC_HANDLE hSCManager, [in] DWORD dwServiceType, [in] DWORD dwServiceState, - [out, size_is(dwBufSize)] LPBYTE lpBuffer, - [in, range(0, 1024*256)] DWORD dwBufSize, + [out, size_is(cbBufSize)] LPBYTE lpBuffer, + [in, range(0, 1024 * 256)] DWORD cbBufSize, [out] LPBOUNDED_DWORD_256K pcbBytesNeeded, [out] LPBOUNDED_DWORD_256K lpServicesReturned, - [in, out, unique] LPBOUNDED_DWORD_256K lpResumeHandle); + [in, out, unique] LPBOUNDED_DWORD_256K lpResumeIndex + ); /* Function 27 */ DWORD ROpenSCManagerA( - [in, string, unique] SVCCTL_HANDLEA lpMachineName, - [in, string, unique] LPSTR lpDatabaseName, + [in, string, unique /*, range(0, SC_MAX_COMPUTER_NAME_LENGTH)*/] SVCCTL_HANDLEA lpMachineName, + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPSTR lpDatabaseName, [in] DWORD dwDesiredAccess, - [out] LPSC_RPC_HANDLE lpScHandle); + [out] LPSC_RPC_HANDLE lpScHandle + ); /* Function 28 */ DWORD ROpenServiceA( [in] SC_RPC_HANDLE hSCManager, - [in, string] LPSTR lpServiceName, + [in, string /*, range(0, SC_MAX_NAME_LENGTH)*/] LPSTR lpServiceName, [in] DWORD dwDesiredAccess, - [out] LPSC_RPC_HANDLE lpServiceHandle); + [out] LPSC_RPC_HANDLE lpServiceHandle + ); /* Function 29 */ DWORD RQueryServiceConfigA( [in] SC_RPC_HANDLE hService, - [out, size_is(cbBufSize)] LPBYTE lpServiceConfig, - /* FIXME: should be [out] LPQUERY_SERVICE_CONFIGA lpServiceConfig, */ - [in, range(0, 1024*8)] DWORD cbBufSize, - [out] LPBOUNDED_DWORD_8K pcbBytesNeeded); + [out, size_is(cbBufSize)] LPBYTE lpServiceConfig, // FIXME: [out] LPQUERY_SERVICE_CONFIGA lpServiceConfig, + [in, range(0, 1024 * 8)] DWORD cbBufSize, + [out] LPBOUNDED_DWORD_8K pcbBytesNeeded + ); /* Function 30 */ DWORD RQueryServiceLockStatusA( [in] SC_RPC_HANDLE hSCManager, [out] LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus, - [in, range(0, 1024*4)] DWORD cbBufSize, - [out] LPBOUNDED_DWORD_4K pcbBytesNeeded); + [in, range(0, 1024 * 4)] DWORD cbBufSize, + [out] LPBOUNDED_DWORD_4K pcbBytesNeeded + ); /* Function 31 */ DWORD RStartServiceA( [in] SC_RPC_HANDLE hService, [in, range(0, SC_MAX_ARGUMENTS)] DWORD argc, - [in, unique, size_is(argc)] LPSTRING_PTRSA argv); + [in, unique, size_is(argc)] LPSTRING_PTRSA argv + ); /* Function 32 */ DWORD RGetServiceDisplayNameA( [in] SC_RPC_HANDLE hSCManager, - [in, string] LPCSTR lpServiceName, + [in, string /*, range(0, SC_MAX_NAME_LENGTH)*/] LPCSTR lpServiceName, // LPSTR [out, string, size_is(*lpcchBuffer)] LPSTR lpDisplayName, - [in, out] LPBOUNDED_DWORD_4K lpcchBuffer); + [in, out] LPBOUNDED_DWORD_4K lpcchBuffer + ); /* Function 33 */ DWORD RGetServiceKeyNameA( [in] SC_RPC_HANDLE hSCManager, - [in, string] LPCSTR lpDisplayName, + [in, string /*, range(0, SC_MAX_NAME_LENGTH)*/] LPCSTR lpDisplayName, // LPSTR [out, string, size_is(*lpcchBuffer)] LPSTR lpKeyName, - [in, out] LPBOUNDED_DWORD_4K lpcchBuffer); + [in, out] LPBOUNDED_DWORD_4K lpcchBuffer + ); /* Function 34 */ DWORD RI_ScGetCurrentGroupStateW( [in] SC_RPC_HANDLE hSCManager, - [in, string, unique] LPWSTR lpLoadOrderGroup, - [out] LPDWORD lpState); + [in, string, unique] LPWSTR pszGroupName, + [out] LPDWORD pdwCurrentState + ); /* Function 35 */ DWORD REnumServiceGroupW( @@ -591,45 +630,51 @@ [in] DWORD dwServiceType, [in] DWORD dwServiceState, [out, size_is(cbBufSize)] LPBYTE lpBuffer, - [in, range(0, 1024*256)] DWORD cbBufSize, + [in, range(0, 1024 * 256)] DWORD cbBufSize, [out] LPBOUNDED_DWORD_256K pcbBytesNeeded, [out] LPBOUNDED_DWORD_256K lpServicesReturned, [in, out, unique] LPBOUNDED_DWORD_256K lpResumeIndex, - [in, string, unique] LPCWSTR pszGroupName); + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPCWSTR pszGroupName + ); /* Function 36 */ DWORD RChangeServiceConfig2A( [in] SC_RPC_HANDLE hService, - [in] SC_RPC_CONFIG_INFOA Info); + [in] SC_RPC_CONFIG_INFOA Info + ); /* Function 37 */ DWORD RChangeServiceConfig2W( [in] SC_RPC_HANDLE hService, - [in] SC_RPC_CONFIG_INFOW Info); + [in] SC_RPC_CONFIG_INFOW Info + ); /* Function 38 */ DWORD RQueryServiceConfig2A( [in] SC_RPC_HANDLE hService, [in] DWORD dwInfoLevel, [out, size_is(cbBufSize)] LPBYTE lpBuffer, - [in, range(0, 1024*8)] DWORD cbBufSize, - [out] LPBOUNDED_DWORD_8K pcbBytesNeeded); + [in, range(0, 1024 * 8)] DWORD cbBufSize, + [out] LPBOUNDED_DWORD_8K pcbBytesNeeded + ); /* Function 39 */ DWORD RQueryServiceConfig2W( [in] SC_RPC_HANDLE hService, [in] DWORD dwInfoLevel, [out, size_is(cbBufSize)] LPBYTE lpBuffer, - [in, range(0, 1024*8)] DWORD cbBufSize, - [out] LPBOUNDED_DWORD_8K pcbBytesNeeded); + [in, range(0, 1024 * 8)] DWORD cbBufSize, + [out] LPBOUNDED_DWORD_8K pcbBytesNeeded + ); /* Function 40 */ DWORD RQueryServiceStatusEx( [in] SC_RPC_HANDLE hService, [in] SC_STATUS_TYPE InfoLevel, [out, size_is(cbBufSize)] LPBYTE lpBuffer, - [in, range(0, 1024*8)] DWORD cbBufSize, - [out] LPBOUNDED_DWORD_8K pcbBytesNeeded); + [in, range(0, 1024 * 8)] DWORD cbBufSize, + [out] LPBOUNDED_DWORD_8K pcbBytesNeeded + ); /* Function 41 */ DWORD REnumServicesStatusExA( @@ -642,7 +687,8 @@ [out] LPBOUNDED_DWORD_256K pcbBytesNeeded, [out] LPBOUNDED_DWORD_256K lpServicesReturned, [in, out, unique] LPBOUNDED_DWORD_256K lpResumeIndex, - [in, string, unique] LPCSTR pszGroupName); + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPCSTR pszGroupName + ); /* Function 42 */ DWORD REnumServicesStatusExW( @@ -655,7 +701,8 @@ [out] LPBOUNDED_DWORD_256K pcbBytesNeeded, [out] LPBOUNDED_DWORD_256K lpServicesReturned, [in, out, unique] LPBOUNDED_DWORD_256K lpResumeIndex, - [in, string, unique] LPCWSTR pszGroupName); + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPCWSTR pszGroupName + ); /* Function 43 */ DWORD RSendTSMessage( @@ -663,41 +710,43 @@ /* Function 44 */ DWORD RCreateServiceWOW64A( - [in] handle_t BindingHandle, - [in, string] LPSTR lpServiceName, - [in, string, unique] LPSTR lpDisplayName, + [in] SC_RPC_HANDLE hSCManager, + [in, string /*, range(0, SC_MAX_NAME_LENGTH)*/] LPSTR lpServiceName, + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPSTR lpDisplayName, [in] DWORD dwDesiredAccess, [in] DWORD dwServiceType, [in] DWORD dwStartType, [in] DWORD dwErrorControl, - [in, string] LPSTR lpBinaryPathName, - [in, string, unique] LPSTR lpLoadOrderGroup, + [in, string /*, range(0, SC_MAX_PATH_LENGTH)*/] LPSTR lpBinaryPathName, + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPSTR lpLoadOrderGroup, [in, out, unique] LPDWORD lpdwTagId, [in, unique, size_is(dwDependSize)] LPBYTE lpDependencies, [in, range(0, SC_MAX_DEPEND_SIZE)] DWORD dwDependSize, - [in, string, unique] LPSTR lpServiceStartName, + [in, string, unique /*, range(0, SC_MAX_ACCOUNT_NAME_LENGTH)*/] LPSTR lpServiceStartName, [in, unique, size_is(dwPwSize)] LPBYTE lpPassword, [in, range(0, SC_MAX_PWD_SIZE)] DWORD dwPwSize, - [out] LPSC_RPC_HANDLE lpServiceHandle); + [out] LPSC_RPC_HANDLE lpServiceHandle + ); /* Function 45 */ DWORD RCreateServiceWOW64W( - [in] handle_t BindingHandle, - [in, string] LPWSTR lpServiceName, - [in, string, unique] LPWSTR lpDisplayName, + [in] SC_RPC_HANDLE hSCManager, + [in, string /*, range(0, SC_MAX_NAME_LENGTH)*/] LPWSTR lpServiceName, // wchar_t* + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPWSTR lpDisplayName, // wchar_t* [in] DWORD dwDesiredAccess, [in] DWORD dwServiceType, [in] DWORD dwStartType, [in] DWORD dwErrorControl, - [in, string] LPWSTR lpBinaryPathName, - [in, string, unique] LPWSTR lpLoadOrderGroup, + [in, string /*, range(0, SC_MAX_PATH_LENGTH)*/] LPWSTR lpBinaryPathName, // wchar_t* + [in, string, unique /*, range(0, SC_MAX_NAME_LENGTH)*/] LPWSTR lpLoadOrderGroup, // wchar_t* [in, out, unique] LPDWORD lpdwTagId, [in, unique, size_is(dwDependSize)] LPBYTE lpDependencies, [in, range(0, SC_MAX_DEPEND_SIZE)] DWORD dwDependSize, - [in, string, unique] LPWSTR lpServiceStartName, + [in, string, unique /*, range(0, SC_MAX_ACCOUNT_NAME_LENGTH)*/] LPWSTR lpServiceStartName, // wchar_t* [in, unique, size_is(dwPwSize)] LPBYTE lpPassword, [in, range(0, SC_MAX_PWD_SIZE)] DWORD dwPwSize, - [out] LPSC_RPC_HANDLE lpServiceHandle); + [out] LPSC_RPC_HANDLE lpServiceHandle + ); /* Function 46 */ DWORD RQueryServiceTagInfo( @@ -710,17 +759,20 @@ [in] GUID* pClientProcessGuid, [out] GUID* pSCMProcessGuid, [out] PBOOL pfCreateRemoteQueue, - [out] LPSC_NOTIFY_RPC_HANDLE phNotify); + [out] LPSC_NOTIFY_RPC_HANDLE phNotify + ); /* Function 48 */ - DWORD RGetNotifyResults( + /* error_status_t */ DWORD RGetNotifyResults( [in] SC_NOTIFY_RPC_HANDLE hNotify, - [out] PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams); + [out] PSC_RPC_NOTIFY_PARAMS_LIST* ppNotifyParams + ); /* Function 49 */ DWORD RCloseNotifyHandle( [in, out] LPSC_NOTIFY_RPC_HANDLE phNotify, - [out] PBOOL pfApcFired); + [out] PBOOL pfApcFired + ); /* Function 50 */ DWORD RControlServiceExA( @@ -728,7 +780,8 @@ [in] DWORD dwControl, [in] DWORD dwInfoLevel/*, [in, switch_is(dwInfoLevel)] PSC_RPC_SERVICE_CONTROL_IN_PARAMSA pControlInParams, - [out, switch_is(dwInfoLevel)] PSC_RPC_SERVICE_CONTROL_IN_PARAMSA pControlOutParams*/); + [out, switch_is(dwInfoLevel)] PSC_RPC_SERVICE_CONTROL_OUT_PARAMSA pControlOutParams*/ + ); /* Function 51 */ DWORD RControlServiceExW( @@ -736,7 +789,8 @@ [in] DWORD dwControl, [in] DWORD dwInfoLevel/*, [in, switch_is(dwInfoLevel)] PSC_RPC_SERVICE_CONTROL_IN_PARAMSW pControlInParams, - [out, switch_is(dwInfoLevel)] PSC_RPC_SERVICE_CONTROL_IN_PARAMSW pControlOutParams*/); + [out, switch_is(dwInfoLevel)] PSC_RPC_SERVICE_CONTROL_OUT_PARAMSW pControlOutParams*/ + ); /* Function 52 */ DWORD RSendPnPMessage( @@ -753,4 +807,11 @@ /* Function 55 */ DWORD RFunction55( [in] handle_t BindingHandle); /* FIXME */ + + /* Function 56 */ + DWORD RQueryServiceConfigEx( + [in] SC_RPC_HANDLE hService, + [in] DWORD dwInfoLevel, + [out] SC_RPC_CONFIG_INFOW* pInfo + ); }