Problems accessing the ntSecurityDescriptor property by using the ADSI LDAP provider (323749)



The information in this article applies to:

  • Microsoft Active Directory Services Interface, Microsoft Active Directory Client
  • Microsoft Active Directory Services Interface, System Component

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("LDAP://OU=Trash Me,dc=br549,dc=nttest,dc=microsoft,dc=com")
set oSD = obj.Get("ntSecurityDescriptor")<BR/>
'
' Work with the Security Descriptor.
'
obj.put "ntsecuritydescriptor",oSD 
obj.SetOption ADS_OPTION_SECURITY_MASK, ADS_SECURITY_INFO_DACL<BR/>
obj.SetInfo
WScript.Echo "Done"
				

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 <IADsObjectOptions, &IID_IADsObjectOptions> 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("LDAP://cn=My Group,cn=users,
                                           dc=dsdom,dc=extest,dc=microsoft,dc=com");
 IADsSecurityDescriptor sd = (IADsSecurityDescriptor)entry.Properties["ntSecurityDescriptor"].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["ntSecurityDescriptor"].Value = sd; 
try 
{ 
entry.CommitChanges(); 
Console.WriteLine("Success");
 }
 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

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

REFERENCES

For more information about Platform SDK Directory Services documentation, visit the following Microsoft Developer Network (MSDN) Web sites:

Modification Type:MajorLast Reviewed:1/6/2005
Keywords:kbDSWADSI2003Swept kbprb KB323749 kbAudDeveloper