mirror of
https://github.com/reactos/reactos.git
synced 2025-05-20 09:36:16 +00:00
- Add a reference counter to the service record.
- Implement a common service record delete function. - RCloseServiceHandle: Remove a service if it has been marked for deletion and the reference counter reaches 0. - RControlService: Stop a service only if there are no dependent services running. Patch based on bug report #3669 by Michael Martin (aka bugboy) <martinmnet@hotmail.com> just like the patches r35748, r35750, r35752 and r35753. svn path=/trunk/; revision=35767
This commit is contained in:
parent
78adf1b7db
commit
36e3b2153e
2 changed files with 138 additions and 13 deletions
|
@ -404,6 +404,12 @@ 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");
|
||||
|
||||
|
@ -413,6 +419,7 @@ DWORD RCloseServiceHandle(
|
|||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
hManager = (PMANAGER_HANDLE)*hSCObject;
|
||||
hService = (PSERVICE_HANDLE)*hSCObject;
|
||||
if (hManager->Handle.Tag == MANAGER_TAG)
|
||||
{
|
||||
DPRINT("Found manager handle\n");
|
||||
|
@ -420,24 +427,92 @@ DWORD RCloseServiceHandle(
|
|||
hManager->Handle.RefCount--;
|
||||
if (hManager->Handle.RefCount == 0)
|
||||
{
|
||||
/* FIXME: add cleanup code */
|
||||
/* FIXME: add handle cleanup code */
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, hManager);
|
||||
hManager = NULL;
|
||||
}
|
||||
|
||||
DPRINT("RCloseServiceHandle() done\n");
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else if (hManager->Handle.Tag == SERVICE_TAG)
|
||||
else if (hService->Handle.Tag == SERVICE_TAG)
|
||||
{
|
||||
DPRINT("Found service handle\n");
|
||||
|
||||
hManager->Handle.RefCount--;
|
||||
if (hManager->Handle.RefCount == 0)
|
||||
{
|
||||
/* FIXME: add cleanup code */
|
||||
/* Get the pointer to the service record */
|
||||
lpService = hService->ServiceEntry;
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, hManager);
|
||||
ASSERT(hService->Handle.RefCount > 0);
|
||||
|
||||
hService->Handle.RefCount--;
|
||||
if (hService->Handle.RefCount == 0)
|
||||
{
|
||||
/* FIXME: add handle cleanup code */
|
||||
|
||||
/* Free the handle */
|
||||
HeapFree(GetProcessHeap(), 0, hService);
|
||||
hService = NULL;
|
||||
}
|
||||
|
||||
ASSERT(lpService->dwRefCount > 0);
|
||||
|
||||
lpService->dwRefCount--;
|
||||
DPRINT1("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)
|
||||
{
|
||||
DPRINT1("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);
|
||||
|
||||
/* if pcbBytesNeeded returned a value then there are services running that are dependent on this service*/
|
||||
if (pcbBytesNeeded)
|
||||
{
|
||||
DPRINT1("Deletion failed due to running dependencies.\n",
|
||||
lpService->lpServiceName);
|
||||
RegCloseKey(hServicesKey);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/* There are no references and no runnning dependencies,
|
||||
it is now safe to delete the service */
|
||||
|
||||
/* Delete the Service Key */
|
||||
dwError = RegDeleteKey(hServicesKey,
|
||||
lpService->lpServiceName);
|
||||
|
||||
RegCloseKey(hServicesKey);
|
||||
|
||||
if (dwError != ERROR_SUCCESS)
|
||||
{
|
||||
DPRINT1("Failed to Delete the Service Registry key\n");
|
||||
return dwError;
|
||||
}
|
||||
|
||||
/* Delete the Service */
|
||||
ScmDeleteServiceRecord(lpService);
|
||||
}
|
||||
}
|
||||
|
||||
DPRINT("RCloseServiceHandle() done\n");
|
||||
|
@ -461,6 +536,9 @@ DWORD RControlService(
|
|||
PSERVICE lpService;
|
||||
ACCESS_MASK DesiredAccess;
|
||||
DWORD dwError = ERROR_SUCCESS;
|
||||
DWORD pcbBytesNeeded = 0;
|
||||
DWORD dwServicesReturned = 0;
|
||||
HKEY hServicesKey = NULL;
|
||||
|
||||
DPRINT("RControlService() called\n");
|
||||
|
||||
|
@ -475,6 +553,14 @@ DWORD RControlService(
|
|||
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)
|
||||
{
|
||||
|
@ -507,12 +593,40 @@ DWORD RControlService(
|
|||
DesiredAccess))
|
||||
return ERROR_ACCESS_DENIED;
|
||||
|
||||
/* Check the service entry point */
|
||||
lpService = hSvc->ServiceEntry;
|
||||
if (lpService == NULL)
|
||||
if (dwControl == SERVICE_CONTROL_STOP)
|
||||
{
|
||||
DPRINT1("lpService == NULL!\n");
|
||||
return ERROR_INVALID_HANDLE;
|
||||
/* 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)
|
||||
{
|
||||
DPRINT1("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)
|
||||
|
@ -530,6 +644,9 @@ DWORD RControlService(
|
|||
lpServiceStatus);
|
||||
}
|
||||
|
||||
if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
|
||||
dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
|
||||
|
||||
/* Return service status information */
|
||||
RtlCopyMemory(lpServiceStatus,
|
||||
&lpService->Status,
|
||||
|
@ -1120,7 +1237,7 @@ DWORD RChangeServiceConfigW(
|
|||
(wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
|
||||
if (dwError != ERROR_SUCCESS)
|
||||
goto done;
|
||||
/* FIXME: update lpService->lpServiceGroup */
|
||||
/* FIXME: Update lpService->lpServiceGroup */
|
||||
}
|
||||
|
||||
if (lpdwTagId != NULL)
|
||||
|
@ -1836,6 +1953,9 @@ DWORD RCreateServiceW(
|
|||
if (dwError != ERROR_SUCCESS)
|
||||
goto done;
|
||||
|
||||
lpService->dwRefCount = 1;
|
||||
DPRINT1("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
|
||||
|
||||
done:;
|
||||
if (hServiceKey != NULL)
|
||||
RegCloseKey(hServiceKey);
|
||||
|
@ -2309,6 +2429,9 @@ DWORD ROpenServiceW(
|
|||
return dwError;
|
||||
}
|
||||
|
||||
lpService->dwRefCount++;
|
||||
DPRINT1("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
|
||||
|
||||
*lpServiceHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
|
||||
DPRINT("*hService = %p\n", *lpServiceHandle);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ typedef struct _SERVICE
|
|||
PSERVICE_IMAGE lpImage;
|
||||
BOOL bDeleted;
|
||||
DWORD dwResumeCount;
|
||||
DWORD dwRefCount;
|
||||
|
||||
CLIENT_HANDLE hClient;
|
||||
SERVICE_STATUS Status;
|
||||
|
@ -109,6 +110,7 @@ PSERVICE ScmGetServiceEntryByResumeCount(DWORD dwResumeCount);
|
|||
PSERVICE ScmGetServiceEntryByClientHandle(ULONG ThreadId);
|
||||
DWORD ScmCreateNewServiceRecord(LPWSTR lpServiceName,
|
||||
PSERVICE *lpServiceRecord);
|
||||
VOID ScmDeleteServiceRecord(PSERVICE lpService);
|
||||
DWORD ScmMarkServiceForDelete(PSERVICE pService);
|
||||
|
||||
DWORD ScmControlService(PSERVICE Service,
|
||||
|
|
Loading…
Reference in a new issue