How to specify access control on Window NT, Windows 2000, and Windows XP container objects (188760)



The information in this article applies to:

  • Microsoft Win32 Application Programming Interface (API), when used with:
    • the operating system: Microsoft Windows 2000
    • the operating system: Microsoft Windows NT 3.5
    • the operating system: Microsoft Windows NT 3.51
    • the operating system: Microsoft Windows NT 4.0
    • the operating system: Microsoft Windows XP

This article was previously published under Q188760

SUMMARY

Programmatically specifying access control for Windows NT container objects is more complex than for other Win32 objects. This is because access control on container objects allows you to specify access to the container and access for objects that will be created in the container in the future.

MORE INFORMATION

A Windows NT securable object is a container if it can logically contain other securable objects. The following table shows the relationship between a container object and the objects it might contain:
   Container Object         Objects Contained
   -----------------------------------------------

   Directory                Files/Directories

   Registry Key             Registry Subkeys

   Windowstation            Desktop

   Printer                  Print Jobs
				
Windows NT, Windows 2000, and Windows XP support Access Control List (ACL) inheritance. This means that when a new object is created within a container object, the new object inherits permissions (access control entries marked as inheritable) from the parent container object by default.

When you programmatically assign access control to container objects, you must explicitly set the inheritance attribute of each access control entry (ACE). Use the following flags to set the ACE inheritance properties:
  • CONTAINER_INHERIT_ACE - Child objects that are containers, such as directories, inherit the ACE as an effective ACE.
  • OBJECT_INHERIT_ACE - Noncontainer child objects, such as files, inherit the ACE as an effective ACE.
  • INHERIT_ONLY_ACE - The ACE does not apply to the object to which it is attached but can be inherited by child objects.
For a complete description of these and the other possible AceFlags values, see the Win32 Platform SDK documentation for the ACE_HEADER structure.

There are two ways to assign inheritance flags to an access control entry, described below. Both require familiarity with access control. For additional information, see the Win32 Platform SDK and the following article in the Microsoft Knowledge Base:

102102 How To Add an Access-Allowed ACE to a File

  • Once the ACE is in the discretionary access-control list (DACL) through AddAccessAllowed/DeniedAce(), set the AceFlags member of the new ACE. You do this by using the GetAce() API to retrieve a pointer to the new ACE. Use this pointer to set the AceFlags member of the ACE header structure as follows:
    {
       // You can add this after step 14 of Q102102, which demonstrates adding
       // an Access Allowed ACE to a DACL.
    
       BYTE bAceFlags = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
    
       // Get pointer to ACE you just added, so you can change the AceFlags.
       if (!GetAce(pNewACL,
                   newAceIndex,
                   &pTempAce))
       {
          _tprintf(TEXT("GetAce() failed. Error %d\n"),
                GetLastError());
          __leave;
       }
    
       // Set AceFlags member.
       ((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags = bAceFlags;
    }
    
    						
    This extra step is necessary because the AddAccessAllowedAce() API does not have a parameter to specify this attribute of a new ACE. Windows 2000 and Windows XP introduces the AddAccessAllowedAceEx() API, which does have a parameter to specify the AceFlags member of a new ACE. Applications should check for the existence of AddAccessAllowedAceEx() in Advapi32.dll by calling the LoadLibrary() and GetProcAddress() APIs.
  • Alternatively, you can build the entire ACE and set the AceFlags member of the ACE_Header Structure as follows:
    {
       BYTE bAceFlags = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
       DWORD sidlen = GetLengthSid(pUserSID);
       ACCESS_ALLOWED_ACE *pAce = (ACCESS_ALLOWED_ACE *)
              myheapalloc(sizeof(ACCESS_ALLOWED_ACE) + sidlen - sizeof(DWORD));
    
       if (!pAce) {
          _tprintf(TEXT("HeapAlloc() failed. Error %d\n"), GetLastError());
          __leave;
       }
    
       // Fill in ACCESS_ALLOWED_ACE structure.
       pAce->Mask = dwAccessMask; 
       pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; 
       pAce->Header.AceFlags = bAceFlags;
       pAce->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE) 
                                             + sidlen - sizeof(DWORD);
       memcpy (&(pAce->SidStart), pUserSID, sidlen);      
       if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, 
                                          pAce, pAce->Header.AceSize))
       {
          _tprintf(TEXT("AddAce() failed. Error %d\n"),
                GetLastError());
          myheapfree(pAce);
          __leave;
       }
    
       myheapfree(pAce);
    }
    					

Modification Type:MinorLast Reviewed:7/8/2005
Keywords:kbACL kbAPI kbhowto kbKernBase kbSecurity KB188760