[SERVICES]

Fix yet another MSDN bug: ChangeServiceConfig2 ALWAYS requires SERVICE_CHANGE_CONFIG and SERVICE_START access rights and an enabled SE_SHUTDOWN_PRIVILEGE privilege when you try to set the failure actions. Otherwise, you will just get a STATUS_ACCESS_DENIED.

- Remove the access and privilege checks from ScmSetFailureActions and move them to RChangeServiceConfig2W.

svn path=/trunk/; revision=71814
This commit is contained in:
Eric Kohl 2016-07-04 21:37:24 +00:00
parent 8fdfbb5bd0
commit 8b24e1b048

View file

@ -5018,18 +5018,13 @@ DWORD RChangeServiceConfig2A(
static DWORD static DWORD
ScmSetFailureActions(PSERVICE_HANDLE hSvc, ScmSetFailureActions(HKEY hServiceKey,
PSERVICE lpService,
HKEY hServiceKey,
LPSERVICE_FAILURE_ACTIONSW lpFailureActions) LPSERVICE_FAILURE_ACTIONSW lpFailureActions)
{ {
LPSERVICE_FAILURE_ACTIONSW lpReadBuffer = NULL; LPSERVICE_FAILURE_ACTIONSW lpReadBuffer = NULL;
LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer = NULL; LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer = NULL;
BOOL bIsActionRebootSet = FALSE;
DWORD dwDesiredAccess = SERVICE_CHANGE_CONFIG;
DWORD dwRequiredSize = 0; DWORD dwRequiredSize = 0;
DWORD dwType = 0; DWORD dwType = 0;
DWORD i = 0;
DWORD dwError; DWORD dwError;
/* There is nothing to be done if we have no failure actions */ /* There is nothing to be done if we have no failure actions */
@ -5037,48 +5032,7 @@ ScmSetFailureActions(PSERVICE_HANDLE hSvc,
return ERROR_SUCCESS; return ERROR_SUCCESS;
/* /*
* 1- Check whether or not we can set * 1- Retrieve the original value of FailureActions.
* failure actions for this service.
*/
/* Failure actions can only be set for Win32 services, not for drivers */
if (lpService->Status.dwServiceType & SERVICE_DRIVER)
return ERROR_CANNOT_DETECT_DRIVER_FAILURE;
/*
* If the service controller handles the SC_ACTION_RESTART action,
* hService must have the SERVICE_START access right.
*
* If you specify SC_ACTION_REBOOT, the caller must have the
* SE_SHUTDOWN_NAME privilege.
*/
if (lpFailureActions->cActions > 0 &&
lpFailureActions->lpsaActions != NULL)
{
for (i = 0; i < lpFailureActions->cActions; ++i)
{
if (lpFailureActions->lpsaActions[i].Type == SC_ACTION_RESTART)
dwDesiredAccess |= SERVICE_START;
else if (lpFailureActions->lpsaActions[i].Type == SC_ACTION_REBOOT)
bIsActionRebootSet = TRUE;
}
}
/* Re-check the access rights */
if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
dwDesiredAccess))
{
DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
return ERROR_ACCESS_DENIED;
}
/* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
if (bIsActionRebootSet)
{
}
/*
* 2- Retrieve the original value of FailureActions.
*/ */
/* Query value length */ /* Query value length */
@ -5145,7 +5099,7 @@ ScmSetFailureActions(PSERVICE_HANDLE hSvc,
lpReadBuffer->lpCommand = NULL; lpReadBuffer->lpCommand = NULL;
/* /*
* 3- Initialize the new value to set. * 2- Initialize the new value to set.
*/ */
dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW); dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
@ -5292,6 +5246,7 @@ DWORD RChangeServiceConfig2W(
PSERVICE_HANDLE hSvc; PSERVICE_HANDLE hSvc;
PSERVICE lpService = NULL; PSERVICE lpService = NULL;
HKEY hServiceKey = NULL; HKEY hServiceKey = NULL;
ACCESS_MASK RequiredAccess = SERVICE_CHANGE_CONFIG;
DPRINT("RChangeServiceConfig2W() called\n"); DPRINT("RChangeServiceConfig2W() called\n");
DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel); DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
@ -5302,17 +5257,27 @@ DWORD RChangeServiceConfig2W(
hSvc = ScmGetServiceFromHandle(hService); hSvc = ScmGetServiceFromHandle(hService);
if (hSvc == NULL) if (hSvc == NULL)
{ {
DPRINT1("Invalid service handle!\n"); DPRINT("Invalid service handle!\n");
return ERROR_INVALID_HANDLE; return ERROR_INVALID_HANDLE;
} }
if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
RequiredAccess |= SERVICE_START;
/* Check the access rights */
if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
SERVICE_CHANGE_CONFIG)) RequiredAccess))
{ {
DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
return ERROR_ACCESS_DENIED; return ERROR_ACCESS_DENIED;
} }
if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
{
/* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
}
lpService = hSvc->ServiceEntry; lpService = hSvc->ServiceEntry;
if (lpService == NULL) if (lpService == NULL)
{ {
@ -5320,6 +5285,13 @@ DWORD RChangeServiceConfig2W(
return ERROR_INVALID_HANDLE; return ERROR_INVALID_HANDLE;
} }
/* Failure actions can only be set for Win32 services, not for drivers */
if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
{
if (lpService->Status.dwServiceType & SERVICE_DRIVER)
return ERROR_CANNOT_DETECT_DRIVER_FAILURE;
}
/* Lock the service database exclusively */ /* Lock the service database exclusively */
ScmLockDatabaseExclusive(); ScmLockDatabaseExclusive();
@ -5372,9 +5344,7 @@ DWORD RChangeServiceConfig2W(
} }
else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
{ {
dwError = ScmSetFailureActions(hSvc, dwError = ScmSetFailureActions(hServiceKey,
lpService,
hServiceKey,
(LPSERVICE_FAILURE_ACTIONSW)Info.psfa); (LPSERVICE_FAILURE_ACTIONSW)Info.psfa);
} }