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/rpcse…
==============================================================================
--- 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,