- 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:
Eric Kohl 2008-08-29 20:43:12 +00:00
parent 78adf1b7db
commit 36e3b2153e
2 changed files with 138 additions and 13 deletions

View file

@ -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);

View file

@ -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,