by Marcin Policht
Active Directory Services Interface is typically used for management of various account repositories, such as Windows NT SAM database, IIS
Metabase, or LDAP-based directories such as AD or NDS. However, the capabilities of ADSI go far beyond simple group and user account manipulation. For
example, ADSI can be used to manipulate permissions on the NTFS file system level.
In order to understand the mechanism that ADSI uses to accomplish this task, we need to take a closer look at the way the Windows operating system
secures its components. Information about security settings of an object (this applies to the NTFS file system, the Windows Registry, or Active Directory
objects) is stored in a structure called Security Descriptor.
Security Descriptor for an object contains some or all of the following information:
- Security identifier (SID) of a user who owns the object.
- Security identifier (SID) of a group which owns the object (typically this is the primary group of the object's owner).
- Discretionary Access Control List (DACL), consisting of multiple Access Control Entries (ACE), which determine access rights assigned on the object.
- System Access Control List (SACL), determining how the system audits the object's access. Its format is similar to DACL - each entry specifies the SID of a user or group and its associated auditing criteria.
- Control flags - affect additional aspects of the security descriptor (such as permission inheritance in case of DACL or success or failure audit in case of SACL)
An access control entry consists, in turn, of several subentries:
- A SID of a security principal (such as a group or a user) to which the entry applies.
- An access mask (represented by the sequence of bits) defining access permissions for the security principal (such as read, write, execute, take ownership, set permissions, etc.).
- Sequence of bits determining type of access permissions (allow or deny - in case of DACL entry).
- Sequence of bits determining the inheritance level for this particular entry (e.g. when applied to a folder, this flag would determine whether
permissions apply to this folder only, or to subfolders and files as well).
The graphical representation of these settings can be viewed by launching Windows Explorer and checking the properties of a file or folder. After
selecting Security Tab, click on the Advanced button and you will see the list of Access Control Entries presented in a friendly fashion.
Dealing with ACEs, DACLs, and SACLs using scripting (or programming) is a fairly difficult task because the objects used to represent structures
described above are rather complex. Also, even small mistakes when changing permissions on file system, registry, or Active Directory objects can
have serious implications, so make sure you test your scripts appropriately.
Fortunately, Microsoft provides a number of samples documenting the way to manipulate permissions via scripting (programming methods are
extensively documented in the MSDN Library at msdn.microsoft.com). The Knowledge Base article Q279682 "How to Use ADsSecurity.dll to Add an Access Control
Entry to an NTFS Folder" outlines such a procedure. However, the sample code sets permissions on a folder level only, and the changes do not
propagate to any of its subfolders. The reason for this is the fact that the SetSecurityInfo API function (contained in ADsSecurity.dll, which is used
by the script) fails to propagate inheritable ACEs to any of the subfolders. Q266461 "How to Use ADSI to Set Automatic Inheritance of File/Folder
Permissions" describes a workaround for this.
In order to be able to manipulate Security Descriptors through scripting, you will need to start by obtaining AdsSecurity.dll, which is available
as part of ADSI Software Development Kit (available at http://download.microsoft.com/msdownload/adsi/2.5/sdk/x86/en/Sdk.zip). Alternatively, you
can use Platform SDK, which on one hand will give you the most recent information, but on the other hand, it will force you to go through a lengthy download process (the core SDK itself is 321.7 MB). You also have an option of ordering a CD; for details, refer to
Once you get the copy of ADsSecurity.dll, copy it to your %Windir%\System32 directory and register by running
REGSVR32.EXE ADsSecurity.DLL from the command prompt.
In order to fully understand the structure of a Security Descriptor (and ultimately to be able to write scripts that change it), you will need to
become familiar with a number of constants used in setting ACE masks (affecting permissions), ACE flags (affecting inheritance), and ACE types
(determining whether ACE mask is used for allowing or denying access).
The format of access masks and the listing of constants are available at msdn.microsoft.com but since you are risking an information overload by
accessing it, here is an abbreviated version:
The following are relevant constants that can be used to analyze the
granular permissions assigned to files and folders by setting appropriate
- '*** bit indicating permission to read data from file or list
contents of directory
'*** corresponds to List Folder / Read Data permissions in Windows UI
const FILE_READ_DATA = &h1 'bit number 0
const FILE_LIST_DIRECTORY = &h1 'bit number 0
- '*** bit indicating permission to write data to file or
create file in directory
'*** corresponds to Create Files / Write Data permissions in Windows UI
const FILE_WRITE_DATA = &h2 'bit number 1
const FILE_ADD_FILE = &h2 'bit number 1
- '*** bit indicating permission to append data to file or to
'*** corresponds to Create Folders / Append Data permissions in Windows
const FILE_APPEND_DATA = &h4 'bit number 2
const FILE_ADD_SUBDIRECTORY = &h4 'bit number 2
- '*** bit indicating permission to read extended attributes
'*** corresponds to Read Extended Attributes permissions in Windows UI
const FILE_READ_EA = &h8 'bit number 3
- '*** bit indicating permission to write extended attributes
'*** corresponds to Write Extended Attributes permissions in Windows UI
const FILE_WRITE_EA = &h10 'bit number 4
- '*** bit indicating permission to execute file or traverse
'*** corresponds to Traverse Folder / Execute File permissions in
const FILE_EXECUTE = &h20 'bit number 5
const FILE_TRAVERSE = &h20 'bit number 5
- '*** bit indicating permission to delete directory and all
files it contains
'*** corresponds to Delete Subfolders and Files permissions in Windows
const FILE_DELETE_CHILD = &h40 'bit number 6
- '*** bit indicating permission to read file or folder
'*** corresponds to Read Attributes permissions in Windows UI
const FILE_READ_ATTRIBUTES = &h80 'bit number 7
- '*** bit indicating permission to change file or folder
'*** corresponds to Write Attributes permissions in Windows UI
const FILE_WRITE_ATTRIBUTES = &h100 'bit number 8
- '*** bit indicating permission to delete file or folder
'*** corresponds to Delete permissions in Windows UI
const DELETE = &h10000 'bit number 16
- '*** bit indicating permission to read security descriptor
'*** corresponds to Read Permissions permissions in Windows UI
const READ_CONTROL = &h20000 'bit number 17
- '*** bit indicating permission to change discretionary ACL
'*** corresponds to Change Permissions permissions in Windows UI
const WRITE_DAC = &h40000 'bit number 18
- '*** bit indicating permission to assign owner
'*** corresponds to Take Ownership permissions in Windows UI
const WRITE_OWNER = &h80000 'bit number 19
- '*** bit indicating permission to perform synchronize
operation, used sometimes during file access
'*** this permission is automaticaly granted with read and write access
and revoked when read or write access is denied.
'*** it is not displayed in the list of permissions in Windows UI
const SYNCHRONIZE = &h100000 'bit number 20
Handling these individual permissions is typically not needed, since they tend to be assigned on a less granular level, at least when dealing with
file system permissions (controlling access to Active Directory objects is much more complex). Therefore, it might be more efficient (and easier)
to consider simply four types of basic access rights:
- Full Control
- No Access
Here's how these types of access rights translate into a combination of access mask bits. Each needs to be considered in combination with the value
of the ACE type:
- NTFS Full Control file permissions consist of the following access masks (111110000000111111111 in binary or 2032127 in decimal)
- NTFS Change file permissions consist of the following access masks (100110000000110111111 in binary or 1245631 in decimal)
- NTFS Read file permissions consist of the following access masks (100100000000010101001 in binary or 1179817 in decimal)
- The following listing illustrates access masks for NTFS deny read file permissions (000100000000010101001 in binary or 131241 in decimal)
Note that since this listing refers to ACCESS_DENIED Ace type, the SYNCHRONIZE permission is missing (comparing with the previous set of entries).
In my next article, I'll provide a script which will allow you to display the content of DACL (ACE entries) for arbitrarily chosen files or folders.