Microsoft KB Archive/323749

= Problems accessing the ntSecurityDescriptor property by using the ADSI LDAP provider =

Article ID: 323749

Article Last Modified on 1/6/2005

-

APPLIES TO


 * Microsoft Active Directory Service Interfaces 2.5
 * Microsoft Active Directory Service Interfaces 2.5

-



This article was previously published under Q323749



SYMPTOMS
A user who is not a member of the Administrators group is granted full control of an Active Directory object. Even though the user has full control, the user cannot add Access Control Entries (ACEs) to the Discretionary Access Control List (DACL) without taking ownership of the object.



CAUSE
By default, when accessing the ntSecurityDescriptor property, the ADSI LDAP provider writes the whole security descriptor back to the object. If a non-administrative user tries to write the ownership information of a security descriptor, and the user does not own the object, the NT security system generates an error.

A user who is not an administrator or a member of the administrators group is not permitted to give ownership of any object to any other user. The user can only take ownership of objects. If the user does not already own the object, the NT security system assumes that the user is trying to give ownership of the object to another user or group.



RESOLUTION
To resolve this issue, change the default behavior of the ADSI LDAP provider to instruct the directory service to write only the Discretionary Access Control List (DACL) information portion of the security descriptor back to the object. The IADsObjectOptions interface is designed to let the programmer change the behavior of the LDAP security control.



WORKAROUND
By using the IADsObjectOptions interface on an object, you can override the default behavior of the ADSI LDAP provider so that the ADSI property cache can write specific parts of the security descriptor. The following code samples demonstrate how to write only the DACL back to the object.

Visual Basic sample code
The following code uses the IADsObjectOptions interface to instruct the ADSI LDAP provider to write only the DACL back to the object. const ADS_OPTION_SECURITY_MASK = 3 const ADS_SECURITY_INFO_DACL = 4 dim obj set obj = GetObject(&quot;LDAP://OU=Trash Me,dc=br549,dc=nttest,dc=microsoft,dc=com&quot;) set oSD = obj.Get(&quot;ntSecurityDescriptor&quot;) ' ' Work with the Security Descriptor. ' obj.put &quot;ntsecuritydescriptor&quot;,oSD obj.SetOption ADS_OPTION_SECURITY_MASK, ADS_SECURITY_INFO_DACL obj.SetInfo WScript.Echo &quot;Done&quot;

Visual C++ sample code
The following code uses the IADsObjectOptions interface to instruct the LDAP security control to write only the DACL back to the object. //

// Obtain an IADsObjectOptions interface from the object whose

// DACL you want to modify.

//

CComQIPtr  pObjOptions( m_pIADs );

if( pObjOptions )

{

VARIANT OptionsVar;

VariantInit(&OptionsVar);

//

// Set the option mask that you want to change. In this case,

// you want to change the object's security information.

// Use the ADS_OPTION_SECURITY_MASK mask. Because you want to modify the

// DACL, set the variant to the ADS_SEDCURITY_INFO_DACL flag.

//

V_I4(&OptionsVar)=ADS_SECURITY_INFO_DACL ;

V_VT(&OptionsVar)=VT_I4;

hr = pObjOptions->SetOption(ADS_OPTION_SECURITY_MASK, OptionsVar);

}

//

// The smart pointer that is declared for pObjOptions can be released, or it

// will be destroyed and then released after the pointer goes out of scope.

//

Visual C# sample code
DirectoryEntry entry = new DirectoryEntry(&quot;LDAP://cn=My Group,cn=users,                                          dc=dsdom,dc=extest,dc=microsoft,dc=com&quot;); IADsSecurityDescriptor sd = (IADsSecurityDescriptor)entry.Properties[&quot;ntSecurityDescriptor&quot;].Value; IADsAccessControlList dacl = (IADsAccessControlList)sd.DiscretionaryAcl; //Just reset the same DACL. sd.DiscretionaryAcl = dacl; IADsObjectOptions options = (IADsObjectOptions)entry.NativeObject; options.SetOption((int)ADS_OPTION_ENUM.ADS_OPTION_SECURITY_MASK,                  ADS_SECURITY_INFO_ENUM.ADS_SECURITY_INFO_DACL); entry.Properties[&quot;ntSecurityDescriptor&quot;].Value = sd; try { entry.CommitChanges; Console.WriteLine(&quot;Success&quot;); } catch(Exception e) { Console.WriteLine(e); } //Wait for the user to read the print out. Console.ReadLine;



STATUS
This behavior is by design.



MORE INFORMATION
An NT Security Descriptor (SD) includes 3 major types of information:
 * Ownership: divided into two areas, Group and individual user.
 * User Access: stored in the form of an Access Control List (ACL). Frequently referred to as the Discretionary Access Control List (DACL).
 * System Auditing: a different ACL, generally referred to as the System Access Control List (SACL). Although the ACEs take on the same general form, the constants that make up an ACE in the SACL are very different.

The default behavior of the ADSI LDAP provider is to retrieve everything and write everything that is in the security descriptor.

Generally, in the context of Windows security, an ordinary user can take ownership of an object. However, an ordinary user cannot give ownership of the object to another trustee. Only an Administrator or a member of the Administrators group can take and give ownership of objects.

When an ordinary user tries to write a modified security descriptor back to an object that the user does not own, the default behavior is to write the whole security descriptor, including ownership information. The NT security system verifies the ownership information of the security descriptor against the user who is performing the action on it. If the information does not match, the writing of the Security Descriptor is not permitted. Therefore, an error occurs.

You may receive an error message that is similar to the following:

ERROR: A Constraint violation occurred

CODE: 8007202F

Steps to reproduce the behavior
 Create an organizational unit (OU) off the root domain node. Name it SD Test. Create a new user. Modify the security descriptor of the new OU to delegate full control of the OU to the new user.</li> Log on as the new user.</li>  Create a simple VBScript file that contains the following code. dim oRoot dim oOU dim oSD set oRoot = GetObject(&quot;LDAP://RootDSE&quot;) set oOU = GetObject(&quot;LDAP://ou=SD Test,&quot;&oRoot.Get(&quot;defaultNamingContext&quot;)) set oSD = oOU.Get(&quot;ntSecurityDescriptor&quot;) oOU.Put &quot;ntSecurityDescriptor&quot;, oSD oOU.SetInfo </li> Save the file. Then, run the code. The code generates a constraint violation.</li></ol>

<div class="references_section">