Directory Services

Example Code for Setting an ACE on a Directory Object

Define the SetRight function

The following code example defines a SetRight function that adds an Access Control Entry (ACE) to the Discretionary Access Control List (DACL) of the security descriptor of a specified Active Directory object. The subroutine enables you to:

Following this code example are several code examples that show how to use the SetRight function to set different types of ACEs.
[Visual Basic]
Const ACL_REVISION_DS = &H4

Public Function SetRight(objectDN As String, _
						accessrights As Long, _
						accesstype As Long, _
						aceinheritflags As Long, _
						objectGUID As String, _
						inheritedObjectGUID As String, _
						trustee As String) As Boolean
			 
Dim dsobject As IADs
Dim sd As IADsSecurityDescriptor
Dim dacl As IADsAccessControlList
Dim newace As New AccessControlEntry
Dim lflags As Long

On Error GoTo Cleanup
 
' Bind to the specified object.
Set dsobject = GetObject(objectDN)
 
' Read the security descriptor on the object.
Set sd = dsobject.Get("ntSecurityDescriptor")
 
' Get the DACL from the security descriptor.
Set dacl = sd.DiscretionaryAcl
 
' Set the properties of the new ACE.
newace.AccessMask = accessrights
newace.AceType = accesstype
newace.AceFlags = aceinheritflags
newace.trustee = trustee
 
' Set the GUID for the object type or inherited object type.
lflags = 0

If Not objectGUID = vbNullString Then
   newace.ObjectType = objectGUID
   lflags = lflags Or &H1 'ADS_FLAG_OBJECT_TYPE_PRESENT
End If

If Not inheritedObjectGUID = vbNullString Then
   newace.InheritedObjectType = inheritedObjectGUID
   lflags = lflags Or &H2 'ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT
End If

If Not (lflags = 0) Then newace.Flags = lflags
 
' Set the ACL Revision
dacl.AclRevision = ACL_REVISION_DS

' Now add the ACE to the DACL and to the security descriptor.
dacl.AddAce newace
sd.DiscretionaryAcl = dacl
 
' Apply it to the object.
dsobject.Put "ntSecurityDescriptor", sd
dsobject.SetInfo
SetRight = True
Exit Function

Cleanup:
Set dsobject = Nothing
Set sd = Nothing
Set dacl = Nothing
Set newace = Nothing
SetRight = False

End Function
[C++]
HRESULT SetRight(
		IADs *pObject,
		long lAccessMask,
		long lAccessType,
		long lAccessInheritFlags,
		LPOLESTR szObjectGUID,
		LPOLESTR szInheritedObjectGUID,
		LPOLESTR szTrustee)
{
VARIANT varSD;
HRESULT hr = E_FAIL;
IADsAccessControlList *pACL = NULL;
IADsSecurityDescriptor *pSD = NULL;
IDispatch *pDispDACL = NULL;
IADsAccessControlEntry *pACE = NULL;
IDispatch *pDispACE = NULL;
long lFlags = 0L;
 
// This code example takes the szTrustee in an expected naming format 
// and assumes it is the name for the correct trustee.
// The application should validate the specified trustee.
if (!szTrustee || !pObject)
	return E_INVALIDARG;
 
VariantInit(&varSD);
 
// Get the nTSecurityDescriptor.
// Type should be VT_DISPATCH--an IDispatch ptr to the security descriptor object.
hr = pObject->Get(_bstr_t("nTSecurityDescriptor"), &varSD);
if ( FAILED(hr) || varSD.vt != VT_DISPATCH ) {
	wprintf(L"get nTSecurityDescriptor failed: 0x%x\n", hr);
	return hr;
}
 
hr = V_DISPATCH( &varSD )->QueryInterface(IID_IADsSecurityDescriptor,(void**)&pSD);
if ( FAILED(hr) ) {
	wprintf(L"QI for IADsSecurityDescriptor failed: 0x%x\n", hr);
	goto cleanup;
}
 
// Get the DACL.
hr = pSD->get_DiscretionaryAcl(&pDispDACL);
if (SUCCEEDED(hr)) 
	hr = pDispDACL->QueryInterface(IID_IADsAccessControlList,(void**)&pACL);
if ( FAILED(hr) ) {
	wprintf(L"Could not get DACL: 0x%x\n", hr);
	goto cleanup;
}
 
// Create the COM object for the new ACE.
hr  = CoCreateInstance( 
			 CLSID_AccessControlEntry,
			 NULL,
			 CLSCTX_INPROC_SERVER,
			 IID_IADsAccessControlEntry,
			 (void **)&pACE
			 );
if ( FAILED(hr) ) {
	wprintf(L"Could not create ACE object: 0x%x\n", hr);
	goto cleanup;
}
 
// Set the properties for the new ACE.
 
// Set the mask that specifies the access right.
hr = pACE->put_AccessMask( lAccessMask );
 
// Set the trustee.
hr = pACE->put_Trustee( szTrustee );
 
// Set AceType.
hr = pACE->put_AceType( lAccessType );
 
// Set AceFlags to specify whether other objects can inherit the ACE from the specified object.
hr = pACE->put_AceFlags( lAccessInheritFlags );
 
// If an szObjectGUID is specified, add ADS_FLAG_OBJECT_TYPE_PRESENT 
// to the lFlags mask and set the ObjectType.
if (szObjectGUID)
{
	lFlags |= ADS_FLAG_OBJECT_TYPE_PRESENT;
	hr = pACE->put_ObjectType( szObjectGUID );
}
 
// If an szInheritedObjectGUID is specified, add ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT 
// to the lFlags mask and set the InheritedObjectType.
if (szInheritedObjectGUID)
{
	lFlags |= ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT;
	hr = pACE->put_InheritedObjectType( szInheritedObjectGUID );
}
 
// Set flags if ObjectType or InheritedObjectType were set.
if (lFlags)
	hr = pACE->put_Flags(lFlags);
 
// Add the ACE to the ACL to the SD to the cache to the object.
// Need to QI for the IDispatch pointer to pass to the AddAce method.
hr = pACE->QueryInterface(IID_IDispatch, (void**)&pDispACE);
if (SUCCEEDED(hr))
{
	// Set the ACL revision.
	hr = pACL->put_AclRevision(ACL_REVISION_DS);

	// Add the ACE.
	hr = pACL->AddAce(pDispACE);
	if (SUCCEEDED(hr))
	{
		// Write the DACL.
		hr = pSD->put_DiscretionaryAcl(pDispDACL);
		if (SUCCEEDED(hr))
		{
			// Write the ntSecurityDescriptor property to the property cache.
			hr = pObject->Put(CComBSTR("nTSecurityDescriptor"), varSD);
			if (SUCCEEDED(hr))
			{
				// Call SetInfo to update the property on the object in the directory.
				hr = pObject->SetInfo();
		}
	}
}
}
 
cleanup:
if (pDispACE)
	pDispACE->Release();
if (pACE)
	pACE->Release();
if (pACL)
	pACL->Release();
if (pDispDACL)
	pDispDACL->Release();
if (pSD)
	pSD->Release();
 
VariantClear(&varSD);
return hr;
}

Grant or deny access to the entire object

The following code example builds a binding string for the Users container and then calls the SetRight function to set an ACE on the Users container. This example sets an ACE that grants the trustee permission to read or write any property on the object.

[Visual Basic]
Dim rootDSE As IADs
Dim objectDN As String
Dim bResult As Boolean
Const ADS_RIGHT_READ_PROP = &H10
Const ADS_RIGHT_WRITE_PROP = &H20
 
' Bind to the Users container in the local domain.
Set rootDSE = GetObject("LDAP://rootDSE")
objectDN = "LDAP://cn=users," & rootDSE.Get("defaultNamingContext")
 
' Grant trustee the right to read/write any property.
bResult = SetRight objectDN, _
				ADS_RIGHT_READ_PROP Or ADS_RIGHT_WRITE_PROP, _
				ADS_ACETYPE_ACCESS_ALLOWED, _
				0, _
				vbNullString, _
				vbNullString, _
				"someone@fabrikam.com" ' Trustee

If bResult = True Then
	MsgBox ("The trustee can read or write any property.")
Else
	MsgBox ("An error occurred.")
End If

The following code example calls the SetRight function to set an ACE that grants the trustee permission to read or write any property on the object. The code example assumes that pObject and szTrustee are set to valid values. For more information, see Setting Access Rights on an Object.

[C++]
HRESULT hr;
IADs *pObject;
LPWSTR szTrustee;
 
hr = SetRight(
		pObject,  // IADs pointer to the object
		ADS_RIGHT_READ_PROP | ADS_RIGHT_WRITE_PROP,
		ADS_ACETYPE_ACCESS_ALLOWED,
		0, 	// Not inheritable
		NULL,  // No object type GUID
		NULL,  // No inherited object type GUID
		szTrustee
		);

Grant or deny access to a specific property on the object

This code example calls the SetRight subroutine to grant the trustee permission to read or write a specific property on the object. Be aware that you must specify the schemIDGUID of the property and you must specify ADS_ACETYPE_ACCESS_ALLOWED_OBJECT to indicate that this is an object-specific ACE. This code example also specifies the ADS_ACEFLAG_INHERIT_ACE flag which means the ACE can be inherited by child objects.

[Visual Basic]
' Grant trustee the permission to read the Telephone-Number property
' of all child objects in the Users container. 
' {bf967a49-0de6-11d0-a285-00aa003049e2} is the schemaIDGUID of 
' the Telephone-Number property.

bResult = SetRight objectDN, _
				ADS_RIGHT_WRITE_PROP Or ADS_RIGHT_READ_PROP, _
				ADS_ACETYPE_ACCESS_ALLOWED_OBJECT, _
				ADS_ACEFLAG_INHERIT_ACE, _
				"{bf967a49-0de6-11d0-a285-00aa003049e2}", _
				vbNullString, _
				"someone@fabrikam.com" ' Trustee

If bResult = True Then
	MsgBox ("The trustee can read the telephone number property.")
Else
	MsgBox ("An error occurred.")
End If
[C++]
// Grant trustee permission to read the Telephone-Number property
// of all child objects in the Users container. 
// {bf967a49-0de6-11d0-a285-00aa003049e2} is the schemaIDGUID of 
// the Telephone-Number property.
hr = SetRight(
		pObject,  // IADs pointer to the object.
		ADS_RIGHT_READ_PROP | ADS_RIGHT_WRITE_PROP,
		ADS_ACETYPE_ACCESS_ALLOWED_OBJECT,
		ADS_ACEFLAG_INHERIT_ACE,
		L"{bf967a49-0de6-11d0-a285-00aa003049e2}",
		NULL,  // No inherited object type GUID.
		szTrustee
		);

Grant or deny access to a set of properties on the object

This code example calls the SetRight function to grant the trustee permission to read or write a specific set of properties on the object. Specify ADS_ACETYPE_ACCESS_ALLOWED_OBJECT to indicate that this is an object-specific ACE.

A property set is defined by a controlAccessRight object in the Extended Rights container of the Configuration partition. To identify the property set in the ACE, you must specify the rightsGUID property of a controlAccessRight object. Be aware that this property set GUID is also set in the attributeSecurityGUID property of every attributeSchema object included in the property set. For more information, see Control Access Rights.

This code example also specifies inheritance flags that make the ACE inheritable by child objects, but ineffective on the immediate object. In addition, the sample specifies the GUID of the User class, which means that the ACE can be inherited only by objects of that class.

[Visual Basic]
' Grant trustee permission to read or write a set of properties.
' {77B5B886-944A-11d1-AEBD-0000F80367C1} is a GUID that identifies 
' a property set.
' {bf967aba-0de6-11d0-a285-00aa003049e2} is a GUID that identifies the
' User class, so this ACE is inherited only by objects of that class.

bResult = SetRight objectDN, _
				ADS_RIGHT_READ_PROP Or ADS_RIGHT_WRITE_PROP, _
						ADS_ACETYPE_ACCESS_ALLOWED_OBJECT, _
						ADS_ACEFLAG_INHERIT_ACE Or ADS_ACEFLAG_INHERIT_ONLY_ACE, _
						"{77B5B886-944A-11d1-AEBD-0000F80367C1}", _
						"{bf967aba-0de6-11d0-a285-00aa003049e2}", _
						"someone@fabrikam.com" ' Trustee

If bResult = True Then
	MsgBox ("The trustee can read or write a set of properties.")
Else
	MsgBox ("An error occurred.")
End If
[C++]
// Grant trustee permission to read or write a set of properties.
// {77B5B886-944A-11d1-AEBD-0000F80367C1} is a GUID that identifies 
// a property set (rightsGUID of a controlAccessRight object).
// {bf967aba-0de6-11d0-a285-00aa003049e2} is the schemaIDGUID of the
// User class, so this ACE is inherited only by objects of that class.
hr = SetRight(
		pObject,  // IADs pointer to the object.
		ADS_RIGHT_READ_PROP | ADS_RIGHT_WRITE_PROP,
		ADS_ACETYPE_ACCESS_ALLOWED_OBJECT,
		ADS_ACEFLAG_INHERIT_ACE | ADS_ACEFLAG_INHERIT_ONLY_ACE,
		L"{77B5B886-944A-11d1-AEBD-0000F80367C1}",
		L"{bf967aba-0de6-11d0-a285-00aa003049e2}",
		szTrustee
		);

Grant or deny permission to create a specific type of child object

This code example calls the SetRight function to grant a specified trustee permission to create and delete User objects in the subtree under the specified object. Be aware that the sample specifies the GUID of the User class, which means that the ACE allows only the trustee to create User objects, not objects of other classes. Specify ADS_ACETYPE_ACCESS_ALLOWED_OBJECT to indicate that this is an object-specific ACE.

[Visual Basic]
' Grant trustee permission to create or delete User objects 
' in the specified object. 
' {bf967aba-0de6-11d0-a285-00aa003049e2} is a GUID that identifies the
' User class.

bResult = SetRight objectDN, _
						ADS_RIGHT_DS_CREATE_CHILD Or ADS_RIGHT_DS_DELETE_CHILD, _
						ADS_ACETYPE_ACCESS_ALLOWED_OBJECT, _
						0, _
						"{bf967aba-0de6-11d0-a285-00aa003049e2}", _
						vbNullString, _
						"jeffsmith@fabrikam.com" 'trustee

If bResult = True Then
	MsgBox ("The trustee can create or delete User objects.")
Else
	MsgBox ("An error occurred.")
End If
[C++]
// Grant trustee permission to create or delete User objects 
// in the specified object. 
// {bf967aba-0de6-11d0-a285-00aa003049e2} is the schemaIDGUID of the
// User class.
hr = SetRight(
		pObject,  // IADs pointer to the object.
		ADS_RIGHT_DS_CREATE_CHILD | ADS_RIGHT_DS_DELETE_CHILD,
		ADS_ACETYPE_ACCESS_ALLOWED_OBJECT,
		0, 	// Not inheritable.
		L"{bf967aba-0de6-11d0-a285-00aa003049e2}",
		NULL,  // No inherited object type GUID.
		szTrustee
		);

For more information, and the schemaIDGUID of a predefined attribute or class, see the attribute or class reference page in the Active Directory Schema reference. For more information, and a code example that can be used to obtain a schemaIDGUID programmatically, see Reading attributeSchema and classSchema Objects.