Microsoft KB Archive/180116

{|
 * width="100%"|

HOWTO: Control Access to a Windows NT Service

 * }

Q180116

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), used with:
 * the operating system: Microsoft Windows NT 4.0
 * the operating system: Microsoft Windows 2000

-

SUMMARY
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

MORE INFORMATION
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.

Sample Code
Libraries required: ADVAPI32.LIB

 #include   #include    #include    #include 

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); } Additional query words:

Keywords : _IK kbAccCtrl kbAPI kbKernBase kbOSWinNT400 kbOSWin2000 kbSecurity kbService kbDSupport kbGrpDSKernBase

Issue type : kbhowto

Technology : kbAudDeveloper kbWin32sSearch kbWin32API