mirror of
https://github.com/reactos/reactos.git
synced 2025-07-23 04:03:37 +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)
|
LPSC_RPC_HANDLE hSCObject)
|
||||||
{
|
{
|
||||||
PMANAGER_HANDLE hManager;
|
PMANAGER_HANDLE hManager;
|
||||||
|
PSERVICE_HANDLE hService;
|
||||||
|
PSERVICE lpService;
|
||||||
|
HKEY hServicesKey;
|
||||||
|
DWORD dwError;
|
||||||
|
DWORD pcbBytesNeeded = 0;
|
||||||
|
DWORD dwServicesReturned = 0;
|
||||||
|
|
||||||
DPRINT("RCloseServiceHandle() called\n");
|
DPRINT("RCloseServiceHandle() called\n");
|
||||||
|
|
||||||
|
@ -413,6 +419,7 @@ DWORD RCloseServiceHandle(
|
||||||
return ERROR_INVALID_HANDLE;
|
return ERROR_INVALID_HANDLE;
|
||||||
|
|
||||||
hManager = (PMANAGER_HANDLE)*hSCObject;
|
hManager = (PMANAGER_HANDLE)*hSCObject;
|
||||||
|
hService = (PSERVICE_HANDLE)*hSCObject;
|
||||||
if (hManager->Handle.Tag == MANAGER_TAG)
|
if (hManager->Handle.Tag == MANAGER_TAG)
|
||||||
{
|
{
|
||||||
DPRINT("Found manager handle\n");
|
DPRINT("Found manager handle\n");
|
||||||
|
@ -420,24 +427,92 @@ DWORD RCloseServiceHandle(
|
||||||
hManager->Handle.RefCount--;
|
hManager->Handle.RefCount--;
|
||||||
if (hManager->Handle.RefCount == 0)
|
if (hManager->Handle.RefCount == 0)
|
||||||
{
|
{
|
||||||
/* FIXME: add cleanup code */
|
/* FIXME: add handle cleanup code */
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, hManager);
|
HeapFree(GetProcessHeap(), 0, hManager);
|
||||||
|
hManager = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT("RCloseServiceHandle() done\n");
|
DPRINT("RCloseServiceHandle() done\n");
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
else if (hManager->Handle.Tag == SERVICE_TAG)
|
else if (hService->Handle.Tag == SERVICE_TAG)
|
||||||
{
|
{
|
||||||
DPRINT("Found service handle\n");
|
DPRINT("Found service handle\n");
|
||||||
|
|
||||||
hManager->Handle.RefCount--;
|
/* Get the pointer to the service record */
|
||||||
if (hManager->Handle.RefCount == 0)
|
lpService = hService->ServiceEntry;
|
||||||
{
|
|
||||||
/* FIXME: add cleanup code */
|
|
||||||
|
|
||||||
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");
|
DPRINT("RCloseServiceHandle() done\n");
|
||||||
|
@ -461,6 +536,9 @@ DWORD RControlService(
|
||||||
PSERVICE lpService;
|
PSERVICE lpService;
|
||||||
ACCESS_MASK DesiredAccess;
|
ACCESS_MASK DesiredAccess;
|
||||||
DWORD dwError = ERROR_SUCCESS;
|
DWORD dwError = ERROR_SUCCESS;
|
||||||
|
DWORD pcbBytesNeeded = 0;
|
||||||
|
DWORD dwServicesReturned = 0;
|
||||||
|
HKEY hServicesKey = NULL;
|
||||||
|
|
||||||
DPRINT("RControlService() called\n");
|
DPRINT("RControlService() called\n");
|
||||||
|
|
||||||
|
@ -475,6 +553,14 @@ DWORD RControlService(
|
||||||
return ERROR_INVALID_HANDLE;
|
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 */
|
/* Check access rights */
|
||||||
switch (dwControl)
|
switch (dwControl)
|
||||||
{
|
{
|
||||||
|
@ -507,12 +593,40 @@ DWORD RControlService(
|
||||||
DesiredAccess))
|
DesiredAccess))
|
||||||
return ERROR_ACCESS_DENIED;
|
return ERROR_ACCESS_DENIED;
|
||||||
|
|
||||||
/* Check the service entry point */
|
if (dwControl == SERVICE_CONTROL_STOP)
|
||||||
lpService = hSvc->ServiceEntry;
|
|
||||||
if (lpService == NULL)
|
|
||||||
{
|
{
|
||||||
DPRINT1("lpService == NULL!\n");
|
/* Check if the service has dependencies running as windows
|
||||||
return ERROR_INVALID_HANDLE;
|
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)
|
if (lpService->Status.dwServiceType & SERVICE_DRIVER)
|
||||||
|
@ -530,6 +644,9 @@ DWORD RControlService(
|
||||||
lpServiceStatus);
|
lpServiceStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
|
||||||
|
dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
|
||||||
|
|
||||||
/* Return service status information */
|
/* Return service status information */
|
||||||
RtlCopyMemory(lpServiceStatus,
|
RtlCopyMemory(lpServiceStatus,
|
||||||
&lpService->Status,
|
&lpService->Status,
|
||||||
|
@ -1120,7 +1237,7 @@ DWORD RChangeServiceConfigW(
|
||||||
(wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
|
(wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
|
||||||
if (dwError != ERROR_SUCCESS)
|
if (dwError != ERROR_SUCCESS)
|
||||||
goto done;
|
goto done;
|
||||||
/* FIXME: update lpService->lpServiceGroup */
|
/* FIXME: Update lpService->lpServiceGroup */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lpdwTagId != NULL)
|
if (lpdwTagId != NULL)
|
||||||
|
@ -1836,6 +1953,9 @@ DWORD RCreateServiceW(
|
||||||
if (dwError != ERROR_SUCCESS)
|
if (dwError != ERROR_SUCCESS)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
lpService->dwRefCount = 1;
|
||||||
|
DPRINT1("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
|
||||||
|
|
||||||
done:;
|
done:;
|
||||||
if (hServiceKey != NULL)
|
if (hServiceKey != NULL)
|
||||||
RegCloseKey(hServiceKey);
|
RegCloseKey(hServiceKey);
|
||||||
|
@ -2309,6 +2429,9 @@ DWORD ROpenServiceW(
|
||||||
return dwError;
|
return dwError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lpService->dwRefCount++;
|
||||||
|
DPRINT1("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
|
||||||
|
|
||||||
*lpServiceHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
|
*lpServiceHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
|
||||||
DPRINT("*hService = %p\n", *lpServiceHandle);
|
DPRINT("*hService = %p\n", *lpServiceHandle);
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ typedef struct _SERVICE
|
||||||
PSERVICE_IMAGE lpImage;
|
PSERVICE_IMAGE lpImage;
|
||||||
BOOL bDeleted;
|
BOOL bDeleted;
|
||||||
DWORD dwResumeCount;
|
DWORD dwResumeCount;
|
||||||
|
DWORD dwRefCount;
|
||||||
|
|
||||||
CLIENT_HANDLE hClient;
|
CLIENT_HANDLE hClient;
|
||||||
SERVICE_STATUS Status;
|
SERVICE_STATUS Status;
|
||||||
|
@ -109,6 +110,7 @@ PSERVICE ScmGetServiceEntryByResumeCount(DWORD dwResumeCount);
|
||||||
PSERVICE ScmGetServiceEntryByClientHandle(ULONG ThreadId);
|
PSERVICE ScmGetServiceEntryByClientHandle(ULONG ThreadId);
|
||||||
DWORD ScmCreateNewServiceRecord(LPWSTR lpServiceName,
|
DWORD ScmCreateNewServiceRecord(LPWSTR lpServiceName,
|
||||||
PSERVICE *lpServiceRecord);
|
PSERVICE *lpServiceRecord);
|
||||||
|
VOID ScmDeleteServiceRecord(PSERVICE lpService);
|
||||||
DWORD ScmMarkServiceForDelete(PSERVICE pService);
|
DWORD ScmMarkServiceForDelete(PSERVICE pService);
|
||||||
|
|
||||||
DWORD ScmControlService(PSERVICE Service,
|
DWORD ScmControlService(PSERVICE Service,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue