Printout Header
RSS Feed

AD Permissions : The AdminSDHolder Mechanism

The adminCount Attribute
Protected Objects
How to access a protected object?
DSPROP - Trigger manually or change frequency
Script: Find users and groups where the permission inheritance is blocked
Tool: Find objects where the permission inheritance is blocked


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:

AD Users and Computers: Benutzer kann Kennwort nicht ändern

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:

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 Open Specification
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:

  1. 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.

  2. 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:

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

Groups Account Operators
Backup Operators
Cert Publishers                            (only 'til Windows 2000)
Domain Admins
Domain Controllers
Enterprise Admins
Read-only Domain Controllers     (only since Windows Server 2008)
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 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:

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

AD Users and Computers: Benutzer kann Kennwort nicht ändern

... 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):

AD Users and Computers: Benutzer kann Kennwort nicht ändern

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 dsHeuristics in the Microsoft Open Specification
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:

  1. 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.

  2. 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.

  3. 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).

    AD Users and Computers: Benutzer kann Kennwort nicht ändern

    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.

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

AD Users and Computers: Benutzer kann Kennwort nicht ändern

...and authenticate yourself with user name and password (menu option Connection - Bind) ...

AD Users and Computers: Benutzer kann Kennwort nicht ändern

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

AD Users and Computers: Benutzer kann Kennwort nicht ändern

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.

serverName = "" 'insert the name of your own DC baseStr = "ou=funktionen,dc=iv,dc=bwl,dc=net" 'insert the LDAP path of the domain or OU... ' which the search should be performed Const SE_DACL_PROTECTED = &H1000 filterStr = "(|(objectclass=group)(objectclass=user))" Set dso = GetObject("LDAP:") Set ado = CreateObject("ADODB.Connection") 'creation of the ADO connection ado.Provider = "ADSDSOObject" 'use the ADSI interface ado.Properties("User ID") = "administrator" 'pass credentials - omit these 2 lines to use your current credentials! ado.Properties("Password") = "secret" ado.Properties("Encrypt Password") = True 'only needed if you set "User ID" and "Password" ado.Open "AD-Search" 'this is a arbitrarily chosen name Set adoCmd = CreateObject("ADODB.Command") 'create new ADO command adoCmd.ActiveConnection = ado 'assignment to an existing ADO connection adoCmd.Properties("Page Size") = 1000 'set the Paged Results value to 1000 (AD standard) adoCmd.Properties("Cache Results") = True adoCmd.CommandText = "<LDAP://" & serverName & "/" & baseStr & ">;" & filterStr & ";ADsPath;subtree" Set objectList = adoCmd.Execute 'perform search While Not objectList.EOF Set obj = dso.OpenDSObject(objectList.Fields("ADsPath"), userName, userPass, 1) Set objSecDesc = obj.get("nTSecurityDescriptor") If ((objSecDesc.Control And SE_DACL_PROTECTED) <> 0) Then WScript.Echo adminCount & " " & obj.distinguishedname End If objectList.MoveNext 'jump to the next search result entry Wend

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:

AD Users and Computers: Benutzer kann Kennwort nicht ändern