ID: Q180116
The information in this article applies to:
Windows NT Services are securable objects in that they are associated with a Security Descriptor and a Discretionary Access Control List (DACL). The DACL associated with the Service has sole control over access to the Service. No special user rights or privileges are needed to manipulate a Service. An application requests a handle to a Service via the OpenService or CreateService API. If the user has the requested access to the Service object, a valid handle is returned. If the requested access is denied by the system, an error code 5 or "access denied" is returned. The following specific access types are defined for a Service:
Access Description
---------------------------------------------------------------
SERVICE_CHANGE_CONFIG Change Service configuration
information
SERVICE_ENUMERATE_DEPENDENTS Enumerate all Services dependent
on the Service
SERVICE_INTERROGATE Ask the Service to report status
immediately
SERVICE_PAUSE_CONTINUE Pause or continue
SERVICE_QUERY_CONFIG Query Service configuration
information
SERVICE_QUERY_STATUS Query the status
SERVICE_START Start
SERVICE_STOP Stop
SERVICE_USER_DEFINED_CONTROL Send a user defined control
Other access types defined for a Service include READ_CONTROL, WRITE_OWNER,
WRITE_DAC, and DELETE. These access types apply to all securable objects.
Please refer to the Platform SDK Documentation for more information.
When installing a Service through the CreateService API, the operating system creates a DACL for the Service. The following DACL is created:
User or Group Access
---------------------------------------------------------------
The Everyone Group SERVICE_ENUMERATE_DEPENDENTS
SERVICE_INTERROGATE
SERVICE_QUERY_CONFIG
SERVICE_QUERY_STATUS
SERVICE_USER_DEFINED_CONTROL
READ_CONTROL
The Power Users Group SERVICE_ENUMERATE_DEPENDENTS
LocalSystem (System) SERVICE_INTERROGATE
SERVICE_PAUSE_CONTINUE
SERVICE_QUERY_CONFIG
SERVICE_QUERY_STATUS
SERVICE_START
SERVICE_STOP
SERVICE_USER_DEFINED_CONTROL
READ_CONTROL
The Administrators Group SERVICE_CHANGE_CONFIG
The Server Operators Group SERVICE_ENUMERATE_DEPENDENTS
SERVICE_INTERROGATE
SERVICE_PAUSE_CONTINUE
SERVICE_QUERY_CONFIG
SERVICE_QUERY_STATUS
SERVICE_START
SERVICE_STOP
SERVICE_USER_DEFINED_CONTROL
READ_CONTROL
WRITE_OWNER
WRITE_DAC
DELETE
An application can create or modify the DACL associated with a Service object to control access. Unfortunately, the CreateService API does not allow you to pass a SECURITY_ATTRIBUTES or SECURITY_DESCRIPTOR structure. The DACL associated with a Service object can be obtained via the QueryServiceObjectSecurity API and can be set via the SetServiceObjectSecurity API. Any changes made to the SECURITY_DESCRIPTOR associated with the Service object are persistent until the Service is removed from the system.
The following sample code creates and sets a new DACL for the Service specified in the command line. The sample code merges one Access Control Entry (ACE) to the existing DACL for the Service. The new ACE grants the Guest account start, stop, delete and READ_CONTROL access to the specified Service. Access to the Service can be modified by the AccessPermissions parameter passed to BuildExplicitAccessWithName().
Libraries required: ADVAPI32.LIB
#include <windows.h>
#include <aclapi.h>
#include <stdio.h>
#include <tchar.h>
void DisplayError(DWORD dwError, LPTSTR pszAPI)
{
LPVOID lpvMessageBuffer;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpvMessageBuffer, 0, NULL);
//Now display this string.
_tprintf(TEXT("ERROR: API = %s.\n"), pszAPI);
_tprintf(TEXT(" error code = %u.\n"), dwError);
_tprintf(TEXT(" message = %s.\n"),
(LPTSTR)lpvMessageBuffer);
// Free the buffer allocated by the system.
LocalFree(lpvMessageBuffer);
ExitProcess(dwError);
}
void _tmain(int argc, TCHAR *argv[])
{
BOOL bDaclPresent = FALSE;
BOOL bDaclDefaulted = FALSE;
DWORD dwError = 0;
DWORD dwSize = 0;
EXPLICIT_ACCESS ea;
PACL pacl = NULL;
PACL pNewAcl = NULL;
PSECURITY_DESCRIPTOR psd;
SC_HANDLE schManager = NULL;
SC_HANDLE schService = NULL;
SECURITY_DESCRIPTOR sd;
if (argc != 2){
_tprintf(TEXT("Usage: %s [service name]\n"), argv[0]);
return;
}
//
// Obtain a handle to the Service Controller.
//
schManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (schManager == NULL)
DisplayError(GetLastError(), TEXT("OpenSCManager"));
//
// Obtain a handle to the service.
//
schService = OpenService(schManager, argv[1],
READ_CONTROL | WRITE_DAC);
if (schService == NULL)
DisplayError(GetLastError(), TEXT("OpenService"));
//
// Get the current security descriptor.
//
if (!QueryServiceObjectSecurity(schService,
DACL_SECURITY_INFORMATION, psd, 0, &dwSize)){
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwSize);
if (psd == NULL){
DisplayError(0, TEXT("HeapAlloc"));
// note HeapAlloc does not support GetLastError()
}
if (!QueryServiceObjectSecurity(schService,
DACL_SECURITY_INFORMATION, psd, dwSize, &dwSize))
DisplayError(GetLastError(),
TEXT("QueryServiceObjectSecurity"));
}
else
DisplayError(GetLastError(),
TEXT("QueryServiceObjectSecurity"));
}
//
// Get the DACL.
//
if (!GetSecurityDescriptorDacl(psd, &bDaclPresent, &pacl,
&bDaclDefaulted))
DisplayError(GetLastError(), TEXT("GetSecurityDescriptorDacl"));
//
// Build the ACE.
//
BuildExplicitAccessWithName(&ea, TEXT("GUEST"),
SERVICE_START | SERVICE_STOP | READ_CONTROL | DELETE,
SET_ACCESS, NO_INHERITANCE);
dwError = SetEntriesInAcl(1, &ea, pacl, &pNewAcl);
if (dwError != ERROR_SUCCESS)
DisplayError(dwError, TEXT("SetEntriesInAcl"));
//
// Initialize a NEW Security Descriptor.
//
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
DisplayError(GetLastError(),
TEXT("InitializeSecurityDescriptor"));
//
// Set the new DACL in the Security Descriptor.
//
if (!SetSecurityDescriptorDacl(&sd, TRUE, pNewAcl, FALSE))
DisplayError(GetLastError(), TEXT("SetSecurityDescriptorDacl"));
//
// Set the new DACL for the service object.
//
if (!SetServiceObjectSecurity(schService, DACL_SECURITY_INFORMATION,
&sd))
DisplayError(GetLastError(), TEXT("SetServiceObjectSecurity"));
//
// Close the handles.
//
if (!CloseServiceHandle(schManager))
DisplayError(GetLastError(), TEXT("CloseServiceHandle"));
if (!CloseServiceHandle(schService))
DisplayError(GetLastError(), TEXT("CloseServiceHandle"));
//
// Free buffers.
//
LocalFree((HLOCAL)pNewAcl);
HeapFree(GetProcessHeap(), 0, (LPVOID)psd);
}
Keywords : kbcode kbAPI kbKernBase kbService kbGrpKernBase
Version : WINNT:4.0
Platform : winnt
Issue type : kbhowto
Last Reviewed: August 26, 1998