AD Permissions : The AdminSDHolder Mechanism
AdminSDHolder
When dealing with Active Directory object permissions, AD administrators often notice a strange effect: Permissions that have been set at the level of a specific OU suddenly don't apply any more to certain users or groups which are stored in that OU. Maybe a help desk staff or user object admin can no longer reset a password of a particular user, or can not change any telephone number or email address for accounts, or can not add new members to a specific group. Always with the same the error message: Access Denied / Insufficient permissions.
Examining the phenomenon in more detail, we find that here the inheritance of permissions is disabled on the those objects: Permissions set on a parent OU do not apply to the object any more:
Even stranger: If you want to correct this and activate the permission inheritance again (check the "Include inheritable permissions from the object's parent" option), then the permissions are normal for a while, but after about an hour, the inheritance is deactivated again!
What is going on here? Quite simply, the AdminSDHolder mechanism is the reason:
- A process called SDPROP (Security Descriptor Propagation ) is automatically activated every 60 minutes on the PDC emulator of the Active Directory domain. See topic below on how to influence the frequency of 60 minutes.
- The process looks for so-called protected objects. These are highly privileged objects which are vital for AD, such as members of the group 'Domain Admins' or 'Schema Admins' . A detailed list of Protected Objects follows below.
- For each Protected object the rights inheritance is disabled and for its permission ACL, a copy of the AdminSDHolder container is applied as the new permission entries. The adminSDHolder container located in each domain in the 'System' container and contains the blueprint. Its permission ACL is the blueprint for object objects special permissions.
- If permissions of protected objects are manipulated by the AdminSDHolder mechanism, then at the same time the attribute 'adminCount' is created and set to 1.
- If SDPROP detects that a protected object already has the rights inheritance disabled and has a copy of adminSDHolder rights, then it doesn't touch the object. Also the admincount attribute is NOT set to 1 in this case!
This is the reason for the mysterious manipulation of the permissions of the affected accounts. Active Directory protects users here that are considered important because they are a member of a important system groups. You could say tha AD want to ensure that a domain admin may not be altered or deleted by another domain admin, nor by an employee of the normal helpdesk.
Description of the AdminSDHolder mechanism in the Microsoft Knowledge Base
The annoying thing on AdminSDHolder mechanism: It is bad in 'cleaning up'. Because if a user is removed from one of the highly privileged system groups and no Protected Object's more, the deactivation of inheritance remains the same! Also, the attribute adminCount remains unchanged at the value of 1.
The adminCount attribute
When the AdminSDHolder mechanism modifies the access control list of an object, then the adminCount attribute is set to 1. There is a common misconceptionn that this is a reliable indicator or even a criterion for the selection of protected objects. This is not the case. Please note the following facts:
- Not all objects that have an adminCount value of 1 are subject to the AdminSDHolder mechanism. If a user account, for example, is removed from the Enterprise Admins and thus no longer protected Ooject, there will be still 1 as the adminCount value.
- Not all protected objects with disabled inheritance have an adminCount value of 1. Indeed, if you clear this attribute manually or set to 0, then the system will therefore NOT enable inheritance again and the ACL of the object wont be reverted to normal state! Rather, the process SDPROP recognizes that these protected object has the permissions set as the AdminSDHolder object, and that the inheritance is blocked: The object is not touched, and the value of adminCount remains as it is.
Why adminCount exists at all then? Good question. This is probably a holdover from Windows 2000 times when it should speed up the SDPROP process. Meanwhile, it is nothing else than than a quick check:
- Who is - or who was in the past - in a highly privileged group? - However, with no guarantee of completeness of the result.
The search for objects with an appropriate adminCount value would be possible with the simple LDAP filter (admin count=1). As I said: It would be a deceptive result. Better you look right after protected objects on their group memberships, or even better on their ACLs.
Protected Objects
The following objects are protected objects according to the AdminSDHolder mechanism:
User | Administrator Krbtgt |
Groups | Account Operators Administrators Backup Operators Cert Publishers (only 'til Windows 2000) Domain Admins Domain Controllers Enterprise Admins Read-only Domain Controllers (only since Windows Server 2008) Replicator Schema Admins Server Operators |
For the groups, the rule is that each direct and indirect member of these groups is an protected object! For example, if there is a group 'G_HelpDesk' contained in the account operators, this group becomes a protected object - along with all users contained in it. And the AdminSDHolder mechanism will change the permissions of the group and it's members accordingly.
You can configure Active Directory so that some of these groups no longer belong to the protected objects. For this, however, the global bit field dsHeuristics must be changed. This is an AD configuration value that is globally stored as an attribute in the config partition of Active Directory.
Please be always careful when you want to change the dsHeuristics value - he always has far-reaching effects! Best practice is to save the old value BEFORE changing this attribute.
To change dsHeuristics, you open the object CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=example,DC=com (of course you replace example.com with your own Active Directory forest root domain name). In this object there is either already an attribute called dsHeuristics, or you create it. The attribute is an ordinary string. However, there is a bit field encoded, ie each letter stands for one bit that can have the values 0-1 or a-f. The bits are then simply counted from left to right (starting with 1), the length of dsHeuristics may be different, for bits in high places that are not needed, the string is simply cut off.
You can now determine within the dsHeuristics field that one or more of the following groups will NOT Protected Objects and are to be considered no longer in the adminSDHolder mechanism:
- Account Operators
- Server Operators
- Print Operators
- Backup Operators
For this we need to change the 16th Bit (as already mentioned, the bits are counted from left to right starting with 1) in dsHeuristics. This bit is called dwAdminSDExMask. These are the possible values:
Value | Groups which wont be protected objects any more: |
0 | No group - this ie the default value |
1 | Account Operators |
2 | Server Operators |
3 | Server Operators + Account Operators |
4 | Print Operators |
5 | Print Operators + Account Operators |
6 | Print Operators + Server Operators |
7 | Print Operators + Server Operators + Account Operators |
8 | Backup Operatos |
9 | Backup Operators + Account Operators |
a | Backup Operators + Server Operators |
b | Backup Operators + Server Operators + Account Operators |
c | Backup Operatos + Print Operators |
d | Backup Operatos + Print Operators + Account Operators |
e | Backup Operatos + Print Operators + Server Operators |
f | Backup Operatos + Print Operators + Server Operators + Account Operators |
If the dsHeuristics attribute is not present, then set it to the value 000000000100000x - where x is then the desired value of dwAdminSDExMask from the table. So, for example, 000000000100000a if you want to exclude Backup Operators, and Server Operators of the Protected Objects. By the way: The 10th Bit must always be set to 1 if dsHeuristics is longer than 10 bits.
If the attribute already exists, you should leave the other bits alone - change only the 16th location - if the previous value was less than 10 digits, you have fill all the bits up to 16 with 0, whereas the 10th Bit is set to 1 - it signals that sdHeuristics is more than 10 digits long.
You could set the dsHeuristics value with the admin tool ADSIEdit...
... or with every normal LDAP editor (my own commercial LDAP Browser 'LEX - The LDAP Explorer' even comes with a confortable attribut editor for the dsHeuristics attribute):
The editing of the dsHeuristics attribute should however always be done very carefully and in no case without thorough consideration, because with dsHeuristics you influence the configuration of the entire AD forest! If you accidentally set another bit in this attribute, because you miscounted the character offset, then you probably change the behavior of the domain controllers in important, safety-relevant areas! Additional information:
Description of the dwAdminSDExMask bits in the Microsoft Open Specification
How to access a protected object?
In our scenario, the AdminSDHolder mechanism was the reason for, for example, a low-privileged user admin could not be change a protected object (eg to reset the password). Maybe you want to change this system behavior. There are now three variants to achieve this:
- Make sure that the object no longer belongs to the protected objects by removing it from the regarding highly privileged groups (list of protected objects). But once the membership is canceled, we must not forget to activate the rights inheritance on the object itself again. If you are very careful, you could set the attribute adminCount to 0 on the object (or delete it). Thus, the original state is restored.
- Configure your Active Directory so that the relevant high privileged group is not a protected object any more. But this approach has a global effect on all domains in your Active Directory forest, so it is a change that should be carefully considered!
In order to determine which are the pre-defined groups are considered as protected objects, and which are not, the attribute dsHeuristics is used. This process is described in detail in the preceding section. After this configuration is implemented, we must not forget to activate the rights inheritance on the object itself again. If you are very careful, you could set the attribute adminCount to 0 on the object (or delete it). Thus, the original state is restored.
- If the concerned object should remain a protected object and the user admin should for example, still be able to change the passwords, then add the user admin (or the group of users admins) directly into the permission template on AdminSDHolder object. AdminSDHolder is located in the System container of the domain (and is only visible when you activate the advanced view within AD Users and Computers).
Once these permission template has been changed, the SDPROP process ensures within the next 60 minutes that the new permission is active on all protected objects. However, you should be aware that these permissions applies actually for ALL protected objects - eg then also for the predefined administrative system groups - and in the entire domain. So be careful with the assignment of rights on the AdminSDHolder OU. In our case, for example, you should never grant our user admins (from the example) full permissions on the AdminSDHolder permissions, because then they would have full control over the domain admin groups. Instead, you would add the right to make password resets only for user objects.
SDPROP - Trigger manually or change frequency
The DSPROP process that searches for protected objects and changes their permission ACLs normally runs every 60 minutes. You can change this interval by setting or create the following value in the registry of the domain controller with the PDC Emulator role:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Parameters\AdminSDProtectFrequency (REG_DWORD)
You can enter values between 60 (= 1 minute) and 7200 (= 2 hours) here. However, Microsoft recommends that the SDPROP frequency should be changed for testing purposes and only for a short period of time, since the CPU load by the executing LSASS (Local Security Authority SubSystem) may have a severe impact on the domain controller performance.
You can trigger the DSPROP process and thus the adminSDHolder mechanism manually by sending a special signal to the PDC emulator of the domain via the LDAP protocol. This is a so-called RootDSE modify operation: A value is written to a particular attribute of the topmost root object of the directory service, the RootDSE (Directory Service Entry). In reality, this attribute does not exist, but the write operation gives the domain controller the signal to perform a specific operation, in our case just the trigger of the adminSDHolder mechanism.
- All Windows Server versions: Set RootDSE attribute fixupInheritance to 1. For this action, you need the extended right 'Recalculate Security Inheritance' (Extended Rights GUID 62dd28a8-7f46-11d2-b9ad-00c04f79f805).
- Starting with Windows 2008 R2: Set RootDSE attribute runProtectAdminGroupsTask to 1. For this action, you need the extended right 'Run-Protect-Admin-Groups-Task' (Extended Rights GUID 7726b9d5-a4b4-4288-a6b2-dce952e80a7f). In modern versions of Windows, the adminSDHolder mechanism runs faster (because fixupinheritance solves other checks for AD permissions that may take longer).
The write operation with Windows Server standard utility LDP.EXE: You have to connect to the domain controller with the PDC Emulator role. Use the menu option Connection - Connect for this...
...and authenticate yourself with user name and password (menu option Connection - Bind) ...
...finally open the dialog for submitting write requests with Browse - Modify. Leave the DN field blank, that means that you adress the rootDSE entry. You write the value 1 in the shadow 'attibute' fixupInheritance. The AdminSdHolder mechanism is triggered internally - you have to be patient anyway, since it takes a while for the investigation of the properties for all objects in the directory.
With the same procedure you could trigger the AdminSDHolder mechanism on a domain controller starting with Windows Server 2008 R2. Instead of fixupInheritance, just use the identifier runProtectAdminGroupsTask here - the value to be written is also 1.
Script: Find users and groups where the permission inheritance is blocked
Here is a script which can be used to search for users and groups in a domain or OU for which is the permission inheritance is blocked. This may be configured intentionally for some reasons - but it could also be a side effect of the AdminSDHOlder mechanism.
Tool: Find objects where the permission inheritance is blocked
There is a free admin utility, which helps you to evaluate easily which objects of the domain have a broken permission inheritance: LIZA - Active Directory Analysis for Security, permissions and ACLs. Use the option Search blocked Inheritance here. The result is displayed for the entire domain: