In response to critical analysis regarding the granularity of the administrative model implemented in Windows NT, Microsoft's efforts with the Active Directory are sure to please administrators eager to break free of the chains binding them to the most mundane administrative tasks . This newfound freedom comes at the cost of additional complexity to the design and programmatic manipulation of the entries in the directory. However, most will agree that such complexity is a worthwhile compromise to gain the additional features and benefits derived from having such fine granularity to the administrative model.
Warning
Programmatic administration of the security descriptors for Active Directory objects is not a topic that should be tackled by those new to the Active Directory or Visual Basic. To successfully achieve a working security model, you often must pass a properly formatted schemaIDGuid for either an object class or attribute definition.
To perform this task, you can use a custom DLL included with the sample code associated with this text, found at http://www.newriders.com/adsi .
Security administration of objects in the directory uses the following basic flow to assign establish permissions on an object:
Bind to an object in the directory.
Open the object's security descriptor.
Obtain the discretionary access control list (DACL) from the security descriptor.
Create a new access control entry (ACE.)
Assign the appropriate constants to the fields in the ACE.
Assign a trustee to the ACE.
Write the ACE to the DACL.
Write the DACL to the Security Descriptor.
Write the update back to the Active Directory.
Based on the constants assigned within the properties of the access control entry, you can determine whether child objects should inherit the permissions assigned to the parent object. You can also specify whether the permissions will be inherited by all objects or will affect just a single object class or attribute definition.
After you understand how the security descriptors are manipulated programmatically, you can manipulate the most powerful security feature of the Active Directory: the delegation of administrative authority.
By managing security down to the attribute level, you can create an administrative model in which specific groups of users can manage a very small subset of properties for all users in a particular container. Imagine how much you would reduce administrative burden if you could create a Web page wherein users could manage their own user information, such as department, telephone extension, address, and so on. The number of solutions you can implement by taking advantage of attribute-level security descriptors is limited only by the design of your directory and by your own creativity.
To configure the ACE for an object in the Active Directory, you must reference the proper constant representing the right you wish to grant, the type of access control entry, and the inheritance scope for the ACE.
To specify the rights for an object in the Active Directory, you can assign any of the constants found in Table 12.2 to the AccessMask ACE field.
Constant | Value | Description |
---|---|---|
Full Control Access | -1 | To specify full control, set the value of the s AccessMask ACE field to “1. |
ADS_RIGHT_DS_CREATE_CHILD | 0x1 | Grants the ability to create child objects. All objects can be created unless the ObjectType field in the ACE contains a valid schemaIDGuid for an object class. |
ADS_RIGHT_DS_DELETE_CHILD | 0x2 | Grants the ability to delete child objects of all classes, unless the ObjectType contains a valid schemaIDGuid for an object class. |
ADS_RIGHT_ACTRL_DS_LIST | 0x4 | Grants the ability to list all child objects. |
ADS_RIGHT_DS_SELF | 0x8 | Grants the ability to list the object itself. |
ADS_RIGHT_DS_READ_PROP | 0x10 | Grants the ability to read object properties. Setting the ObjectType to a valid property or property set GUID restricts the grant to a specific property or property set. |
ADS_RIGHT_DS_WRITE_PROP | 0x20 | Grants the ability to write object properties. Can be restricted using the ObjectType ACE member. Setting the ObjectType to a valid property or property set GUID restricts the grant to a specific property or property set. |
ADS_RIGHT_DS_DELETE_TREE | 0x40 | Grants the ability to delete the object and all associated child objects. |
ADS_RIGHT_DS_LIST_OBJECT | 0x80 | Can be used to show or hide an object from user view. |
ADS_RIGHT_DS_CONTROL_ACCESS | 0x100 | Grants the ability to perform an operation restricted by an extended access right. Must specify a rights GUID identifying a controlAccessRight object in the Extended-Rights container in the configuration partition (naming context). |
ADS_RIGHT_DELETE | 0x10000 | Grants the right to delete the object. |
ADS_RIGHT_READ_CONTROL | 0x20000 | Grants the right to read the object's security descriptor. |
ADS_RIGHT_WRITE_DAC | 0x40000 | Grants the right to modify the discretionary access control list. |
ADS_RIGHT_OWNER | 0x80000 | Grants the right to take ownership of an object. |
ADS_RIGHT_SYNCHRONIZE | 0x100000 | Enables the object to be used for synchronization. |
ADS_RIGHT_ACCESS_SYSTEM_SECURITY | 0x1000000 | Grants the right to manipulate the object's SACL. |
ADS_RIGHT_GENERIC_ALL | 0x10000000 | Grants the right to create or delete child objects and subtrees, read and write all properties, and add or remove the object from the directory. |
ADS_RIGHT_GENERIC_EXECUTE | 0x20000000 | Grants the ability to list the object's children. |
ADS_RIGHT_GENERIC_WRITE | 0x40000000 | Grants the right to write to the DACL and all properties, as well as to remove the object from the directory. |
ADS_RIGHT_GENERIC_READ | 0x80000000 | Grants the right to read the security descriptor, all properties, and any children of the object. |
To specify the type of ACE used in an Active Directory object access control list (ACL), assign one of the constants in Table 12.3 to the AceType ACE field.
Constant | Value | Description |
---|---|---|
ADS_ACETYPE_ACCESS_ALLOWED | Access allowed, no object class discrimination | |
ADS_ACETYPE_ACCESS_DENIED | 0x1 | Access denied , no object class discrimination |
ADS_ACETYPE_SYSTEM_AUDIT | 0x2 | System type ACE, no object class discrimination |
ADS_ACETYPE_ACCESS_ALLOWED_OBJECT | 0x5 | Access allowed for objects defined by ObjectType or InheritedObjectType |
ADS_ACETYPE_ACCESS_DENIED_OBJECT | 0x6 | Access denied for objects defined by ObjectType or InheritedObjectType |
ADS_ACETYPE_SYSTEM_AUDIT_OBJECT | 0x7 | System type ACE, applied only to objects defined by ObjectType or InheritedObjectType |
To define the scope of inheritance and the use of system audit messages, assign one of the constants in Table 12.4 to an ACE's AceFlags field.
Constant | Value | Description |
---|---|---|
ADS_ACEFLAG_INHERIT_ACE | 0x2 | Child objects inherit the ACE unless the ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE flag has been set. |
ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE | 0x4 | The ACEs for all child objects will not contain this ACE. |
ADS_ACEFLAG_INHERIT_ONLY_ACE | 0x8 | Specifies the ACE to be inherited for child objects, but is not subject to the ACE itself. |
ADS_ACEFLAG_INHERITED_ACE | 0x10 | System controlled bit to determine whether the ACE was derived from the parent object. |
ADS_ACEFLAG_VALID_INHERIT_FLAGS | 0x1f | System controlled bit to determine whether inherit flags are valid. |
ADS_ACEFLAG_SUCCESSFUL_ACCESS | 0x40 | Used with SACL ACEs to generate a successful audit message. |
ADS_ACEFLAG_FAILED_ACCESS | 0x80 | Used with SACL ACEs to generate a failed audit message. |
To restrict an ACE to a particular class of objects (or even an individual object class attribute) assign the schemaIDGuid associated with the object class to the ACE's ObjectType field and then assign one of the constants in Table 12.5 to the Flags field in the ACE.
Constant | Value | Description |
---|---|---|
ADS_FLAG_OBJECT_TYPE_PRESENT | 0x1 | Indicates that the ObjectType field has been populated with a schemaIDGuid and that the ObjectType GUID should be used. |
ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT | 0x2 | Indicates that the InheritedObjectType field has been populated with a schemaIDGuid and that the InheritedObjectType GUID should be used. |
Every object in the Active Directory maintains a security descriptor that can be manipulated programmatically using Visual Basic. In this section, we'll explore basic manipulation of an object's security descriptor, including enumeration of the defined access control entries in an access control list, addition of an access control entry that only applies to the bound object's ACL, and removal of ACEs.
To enumerate the ACEs within the ACL of an object's security descriptor, use the following Visual Basic code:
Dim Obj As IADs Dim ACE As AccessControlEntry Dim DiscretionaryACL As AccessControlList Dim SecurityDescriptor As IADsSecurityDescripter Dim ObjectDistinguishedName As String ObjectDistinguishedName = "ou=Admins,dc=eCommerce2000,dc=com" Set Obj = GetObject("LDAP:// " & ObjectDistinguishedName) Set SecurityDescriptor = Obj.Get("ntSecurityDescriptor") Set DiscretionaryACL = SecurityDescriptor.DiscretionaryACL For Each ACE In DiscretionaryACL Debug.Print ACE.Trustee If (ACE.AccessMask And ADS_RIGHT_DELETE) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_DELETE" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_DELETE for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_DELETE for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_READ_CONTROL) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_READ_CONTROL" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_READ_CONTROL for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_READ_CONTROL for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_WRITE_DAC) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_WRITE_DAC" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_WRITE_DAC for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_WRITE_DAC for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_WRITE_OWNER) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_WRITE_OWNER" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_WRITE_OWNER for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_WRITE_OWNER for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_SYNCHRONIZE) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_SYNCHRONIZE" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_SYNCHRONIZE for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_SYNCHRONIZE for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_ACCESS_SYSTEM_SECURITY) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_ACCESS_SYSTEM_SECURITY" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_ACCESS_SYSTEM_SECURITY for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_ACCESS_SYSTEM_SECURITY for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_GENERIC_READ) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_GENERIC_READ" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & ///"ADS_RIGHT_GENERIC_READ for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_GENERIC_READ for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_GENERIC_WRITE) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_GENERIC_WRITE" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_GENERIC_WRITE for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_GENERIC_WRITE for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_GENERIC_EXECUTE) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_GENERIC_EXECUTE" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_GENERIC_EXECUTE for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_GENERIC_EXECUTE for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_GENERIC_ALL) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_GENERIC_ALL" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_GENERIC_ALL for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_GENERIC_ALL for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_DS_CREATE_CHILD) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_DS_CREATE_CHILD" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_DS_CREATE_CHILD for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_DS_CREATE_CHILD for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_DS_DELETE_CHILD) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_DS_DELETE_CHILD" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_DS_DELETE_CHILD for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_DS_DELETE_CHILD for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_ACTRL_DS_LIST) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_ACTRL_DS_LIST" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_ACTRL_DS_LIST for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_ACTRL_DS_LIST for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_DS_SELF) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_DS_SELF" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_DS_SELF for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_DS_SELF for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_DS_READ_PROP) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_DS_READ_PROP" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_DS_READ_PROP for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_DS_READ_PROP for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_DS_WRITE_PROP) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_DS_WRITE_PROP" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_DS_WRITE_PROP for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_DS_WRITE_PROP for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_DS_DELETE_TREE) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_DS_DELETE_TREE" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_DS_DELETE_TREE for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_DS_DELETE_TREE for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_DS_LIST_OBJECT) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_DS_LIST_OBJECT" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_DS_LIST_OBJECT for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_DS_LIST_OBJECT for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If If (ACE.AccessMask And ADS_RIGHT_DS_CONTROL_ACCESS) <> 0 Then If (ACE.ObjectType = "" And ACE.InheritedObjectType = "") Then Debug.Print vbTab & "ADS_RIGHT_DS_CONTROL_ACCESS" Else If ACE.InheritedObjectType = "" Then Debug.Print vbTab & "ADS_RIGHT_DS_CONTROL_ACCESS for SchemaIDGuid: " & ACE.ObjectType Else Debug.Print vbTab & "Inherited ADS_RIGHT_DS_CONTROL_ACCESS for SchemaIDGuid: " & ACE.InheritedObjectType End If End If End If Next
To add a new ACE to the ACL of an object's security descriptor, use the following Visual Basic code and the tables used for ACE field flag values (refer to the section "Constants Used in ACEs") as a guide:
Dim Obj As IADs Dim SecurityDescriptor As IADsSecurityDescriptor Dim ACE As AccessControlEntry Dim DACL As AccessControlList Set Obj = GetObject("LDAP://ou=Admins,dc=eCommerce2000,dc=com") Set SecurityDescriptor = Obj.Get("ntSecurityDescriptor") Set DACL = SecurityDescriptor.DiscretionaryACL Set ACE = CreateObject("AccessControlEntry") ACE.AccessMask = ADS_RIGHT_DELETE Or ADS_RIGHT_GENERIC_READ Or ADS_RIGHT_GENERIC_WRITE ACE.AceFlags = ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE ACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED ACE.Trustee = "eCommerce2000\DMZAdmin" DACL.AddAce ACE SecurityDescriptor.DiscretionaryACL = DACL Obj.Put "ntSecurityDescriptor", Array(SecurityDescriptor) Obj.SetInfo
Use the following Visual Basic code to remove all ACEs for a particular trustee:
Dim Obj As IADs Dim ACE As AccessControlEntry Dim DACL As AccessControlList Dim SecurityDescriptor As IADsSecurityDescriptor Set Obj = GetObject("LDAP://cn=Guest,ou=users, dc=eCommerce2000,dc=com") Set SecurityDescriptor = Obj.Get("ntSecurityDescriptor") Set DACL = SecurityDescriptor.DiscretionaryACL For Each ACE In DACL If UCase(ACE.Trustee) = "ECOMMERCE2000\GUEST" Then DACL.RemoveAce ACE End If Next SecurityDescriptor.DiscretionaryACL = DACL Obj.Put "ntSecurityDescriptor", Array(SecurityDescriptor) Obj.SetInfo
Tip
Although the previous code example indiscriminately removes an ACE based on the trustee's name , you can design a conditional to remove an ACE based on ObjectType or AccessMask constants .
The true power of the Active Directory is found in the Directory's ability to create ACLs for security descriptors at the attribute level, and its ability to delegate administrative privileges for objects in the directory.
A key element to creating a delegation model for the Active Directory is based on the concept of inheritance . Just as you can propagate an ACL throughout the entire file structure in the file system, the Active Directory allows you to specify permissions for a parent object and allow child objects to inherit the ACL.
By assigning the ADS_ACEFLAG_INHERIT_ACE constant to the AceFlags field in the ACE, you can allow or disallow the ability for child objects to inherit the permissions assigned to the parent object.
To establish a delegation model, you can assign trustees the ability to create and remove child objects, or even create and remove specific types of objects. To make this work effectively, you typically assign permissions to a container object (such as an OU) to establish the ability to manage child entities in the directory.
To take this a step further, because Windows 2000's Active Directory allows attribute-level permissions to be assigned, you can even specify specific object attributes that trustees can manipulate.
As shown in the following Visual Basic code, by simply changing the AceFlags field value assignment, you can allow child objects to inherit the permissions assigned to parent objects in the directory:
Dim Obj As IADs Dim SecurityDescriptor As IADsSecurityDescriptor Dim ACE As AccessControlEntry Dim DACL As AccessControlList Set Obj = GetObject("LDAP://ou=Admins,dc=eCommerce2000,dc=com") Set SecurityDescriptor = Obj.Get("ntSecurityDescriptor") Set DACL = SecurityDescriptor.DiscretionaryACL Set ACE = CreateObject("AccessControlEntry") ACE.AccessMask = ADS_RIGHT_GENERIC_READ ACE.AceFlags = ADS_ACEFLAG_INHERIT_ACE ACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED ACE.Trustee = "eCommerce2000\DMZAdmin" DACL.AddAce ACE SecurityDescriptor.DiscretionaryACL = DACL Obj.Put "ntSecurityDescriptor", Array(SecurityDescriptor) Obj.SetInfo
To allow a user to manipulate a subset of object classes, you can specify the allowed (or denied) object class in an ACE within the ACL assigned to the security descriptor for the OU.
For example, creating an access control entry based on an object class definition can be useful if you want a user to be able to create and delete objects belonging only to the Group object class. In this scenario, this user can create and remove groups within the particular OU, but cannot create any other type of object in the container.
Assigning the schemaIDGuid of the desired object class to the ObjectType field in the ACE and assigning the ACE's Flags field to ADS_FLAG_OBJECT_TYPE_PRESENT perform specification of a particular object class.
The schemaIDGuid is defined in the schema container of the directory; however, to use the GUID in the ObjectType field, a string must be created and assigned in the form {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} .
After obtaining and formatting the proper GUID for the object class (usually done in combination with the StringFromGUID2 API call), you can use the following Visual Basic code to guide your efforts to create an application that will restrict object manipulation to a single object class:
Dim Obj As IADs Dim SecurityDescriptor As IADsSecurityDescriptor Dim ACE As AccessControlEntry Dim DACL As AccessControlList Set Obj = GetObject("LDAP://ou=Admins,dc=eCommerce2000,dc=com") Set SecurityDescriptor = Obj.Get("ntSecurityDescriptor") Set DACL = SecurityDescriptor.DiscretionaryACL Set ACE = CreateObject("AccessControlEntry") ACE.AccessMask = ADS_RIGHT_DS_DELETE_TREE ACE.AceFlags = ADS_ACEFLAG_INHERIT_ACE ACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT ACE.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT ACE.ObjectType = "{BF967A9C-0DE6-11D0-A285-00AA003049E2}" ACE.Trustee = "eCommerce2000\DMZAdmin" DACL.AddAce ACE SecurityDescriptor.DiscretionaryACL = DACL Obj.Put "ntSecurityDescriptor", Array(SecurityDescriptor) Obj.SetInfo
Note
The GUID used in the previous example was for group objects.
If you prefer not to hard-code GUIDs into your application, you can download the COM-based GetSchemaIDGuid.DLL from http://www.newriders.com/adsi to programmatically derive the GUID for a particular object class.
To remove an ACE that has been assigned to restrict object manipulation to a specific class, simply use a conditional to match the ObjectType and Trustee fields during the enumeration process, as shown in the following Visual Basic code segment:
Dim Obj As IADs Dim ACE As AccessControlEntry Dim DACL As AccessControlList Dim SecurityDescriptor As Variant Set Obj = GetObject("LDAP://ou=Admins,dc=eCommerce2000,dc=com") Set SecurityDescriptor = Obj.Get("ntSecurityDescriptor") Set DACL = SecurityDescriptor.DiscretionaryACL For Each ACE In DACL If ((UCase(ACE.Trustee) = "ECOMMERCE2000\DMZADMIN") and (ACE.ObjectType = "{BF967A9C-0DE6-11D0-A285-00AA003049E2}")) Then DACL.RemoveAce ACE End If Next SecurityDescriptor.DiscretionaryACL = DACL Obj.Put "ntSecurityDescriptor", Array(SecurityDescriptor) Obj.SetInfo
Just as you can restrict manipulation of objects based on object class, you can also specify which attributes a user has the right to read and modify. Once again, you simply need to assign the schemaIDGuid for the desired property to the ObjectType field and set the AccessMask field to ADS_RIGHT_DS_READ_PROP or ADS_RIGHT_DS_WRITE_PROP .
The following Visual Code segment allows users to write their own telephoneNumber attribute for objects in the Users container:
Dim Obj As IADs Dim SecurityDescriptor As IADsSecurityDescriptor Dim ACE As AccessControlEntry Dim DACL As AccessControlList Set Obj = GetObject("LDAP://ou=Admins,dc=eCommerce2000,dc=com") Set SecurityDescriptor = Obj.Get("ntSecurityDescriptor") Set DACL = SecurityDescriptor.DiscretionaryACL Set ACE = CreateObject("AccessControlEntry") ACE.AccessMask = ADS_RIGHT_DS_READ_PROP Or ADS_RIGHT_DS_WRITE_PROP ACE.AceFlags = ADS_ACEFLAG_INHERIT_ACE ACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT ACE.ObjectType = "{BF967A49-0DE6-11D0-A285-00AA003049E2}" ACE.Trustee = "NT AUTHORITY\SELF" DACL.AddAce ACE SecurityDescriptor.DiscretionaryACL = DACL Obj.Put "ntSecurityDescriptor", Array(SecurityDescriptor) Obj.SetInfo
Top |