Author: tfaber Date: Thu Nov 10 22:21:11 2011 New Revision: 54345
URL: http://svn.reactos.org/svn/reactos?rev=54345&view=rev Log: [SERVICES] - Move utility functions to the top
Modified: trunk/reactos/base/system/services/rpcserver.c
Modified: trunk/reactos/base/system/services/rpcserver.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/rpcser... ============================================================================== --- trunk/reactos/base/system/services/rpcserver.c [iso-8859-1] (original) +++ trunk/reactos/base/system/services/rpcserver.c [iso-8859-1] Thu Nov 10 22:21:11 2011 @@ -387,1172 +387,6 @@ DPRINT1("Failed to assign new tag to service %S, error=%lu\n", lpService->lpServiceName, dwError); } - - return dwError; -} - - -/* 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; - - 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; - - /* 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; - - 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(); - - RtlCopyMemory(&lpService->Status, - lpServiceStatus, - sizeof(SERVICE_STATUS)); - - /* Unlock the service database */ - ScmUnlockDatabase(); - - 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; - - 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 0 - /* FIXME: set the new ImagePath value */ - - /* Set the image path */ - if (dwServiceType & SERVICE_WIN32) - { - if (lpBinaryPathName != NULL && *lpBinaryPathName != 0) - { - 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) - { - if (lpImagePath != NULL && *lpImagePath != 0) - { - dwError = RegSetValueExW(hServiceKey, - L"ImagePath", - 0, - REG_EXPAND_SZ, - (LPBYTE)lpImagePath, - (wcslen(lpImagePath) + 1) *sizeof(WCHAR)); - if (dwError != ERROR_SUCCESS) - goto done; - } - } -#endif - - /* 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; } @@ -1950,6 +784,1172 @@ }
+/* 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; + + 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; + + /* 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; + + 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(); + + RtlCopyMemory(&lpService->Status, + lpServiceStatus, + sizeof(SERVICE_STATUS)); + + /* Unlock the service database */ + ScmUnlockDatabase(); + + 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; + + 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 0 + /* FIXME: set the new ImagePath value */ + + /* Set the image path */ + if (dwServiceType & SERVICE_WIN32) + { + if (lpBinaryPathName != NULL && *lpBinaryPathName != 0) + { + 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) + { + if (lpImagePath != NULL && *lpImagePath != 0) + { + dwError = RegSetValueExW(hServiceKey, + L"ImagePath", + 0, + REG_EXPAND_SZ, + (LPBYTE)lpImagePath, + (wcslen(lpImagePath) + 1) *sizeof(WCHAR)); + if (dwError != ERROR_SUCCESS) + goto done; + } + } +#endif + + /* 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,