# 5.1.3.3.3 Checking Object-Specific Access

This section describes how object-specific access rights on Active Directory objects are evaluated, with the exception of access rights representing control access rights and validated write rights. That is the subject of the subsequent sections.

When evaluating object-specific access rights specified in
object-specific ACEs for
an Active Directory object, the security descriptor of the
object (or its parent) is used along with a three-level "object type
tree" associated with that object. For an object O that is the subject of
an access check, the
object type tree T(V, E) consists of nodes V={v_{1}, v_{2},
...}, edges E={e_{1}, e_{2}, ...}, and a GUID-valued label for
each node in V indicated by *Guid(v)*, and is constructed as follows:

Let O be an object of class c, and let A={a

_{1}, a_{2}, ...} be the set of attributes that instances of class c can contain. For each attribute a_{i}that is an element of A, if a_{i}.attributeSecurityGUID ≠ NULL, then let p_{i}denote the property set of which a_{i}is a member and let Guid(p_{i}) = a_{i}.attributeSecurityGUID (see Property Set in section 3.1.1.2). Let P be the union of all such sets {p_{i}}.Add c to V as the root node of the tree and set Guid(c) to c!schemaIDGUID.

For every property set p

_{i}that is an element of P, add a node p_{i}to V and Guid(p_{i}) is as specified earlier.For every attribute a

_{i}that is an element of A, add a node a_{i}to V and set Guid(a_{i}) to a_{i}!schemaIDGUID.For every property set p

_{i}that is an element of P, add an edge (c, p_{i}) to E such that p_{i}is a child of c.For every attribute a

_{i}that is an element of A, if there exists a property set p_{i}that is an element of P of which a_{i}is a member then add an edge (p_{i}, a_{i}) to E such that a_{i}is a child of p_{i}; otherwise add an edge (c, a_{i}) to E such that a_{i}is a child of c.

**Note** The object type tree used during an
access check can include only a subset of the property set (see Property Set in
section 3.1.1.2.3.3)
nodes and a subset of the attribute nodes that the requester is interested in.
An object type tree for an object is illustrated by the following figure.

**Figure 4: An object type tree**

Let r be the root node of the object type tree T. Further, label each node v that is an element of V with two additional labels called Grant(v) and Deny(v) indicating the access rights that are granted and denied, respectively, at that node. Set both labels to a value 0 initially for every node.

The following rules are used to determine the authorization for the requester's security context:

If the security descriptor of object O has no DACL or its "DACL Present" (DP) bit is not set, then grant the requester all possible access rights on the object.

If the DACL does not have any ACE, then grant the requester no access rights on the object.

Evaluate the DACL by examining each ACE in sequence, starting with the first ACE. Perform the following sequence of actions for each ACE in the order as shown. Let the ACCESS_MASK field of the ACE have a value M.

If the "Inherit Only" (IO) flag is set in the ACE, skip the ACE.

If the SID in the ACE does not match any SID in the requester's security context, skip the ACE.

If the ACE type is "Access Allowed" and the access rights in M are not in Deny(r), then add the rights in M to Grant(r) (where r denotes the root node of object type tree T as stated above). For every descendant node u of r, if the rights in M are not in Deny(u), then add the rights in M to Grant(u).

If the ACE type is "Object Access Allowed" and the ObjectType field in the ACE is not present, then treat the ACE type as "Access Allowed" and perform the action in 3.3.

If the ACE type is "Object Access Allowed" and the ObjectType field in the ACE contains a GUID value g:

If there exists no node v that is an element of V such that Guid(v) = g, then skip the ACE.

Otherwise, let v that is an element of V be the unique node such that Guid(v) = g. If the rights in M are not in Deny(v), then add the rights in M to Grant(v). For every descendant node u of v, if the rights in M are not in Deny(u), then add the rights in M to Grant(u).

If v = r, then proceed to the next ACE.

If Grant(v) = Grant(s) for every sibling s of node v, then add the rights in Grant(v) to Grant(p) where p is the parent of node v. Otherwise, proceed to the next ACE.

Set v to p, and repeat these three steps.

If the ACE type is "Access Denied" and the access rights in M are not in Grant(r), then add the rights in M to Deny(r). For every descendant node u below the root node, if the rights in M are not in Grant(u), then add the rights in M to Deny(u).

If the ACE type is "Object Access Denied" and the ObjectType field in the ACE is not present, then treat the ACE type as "Access Denied" and perform the action in 3.6.

If the ACE type is "Object Access Denied" and the ObjectType field in the ACE contains a GUID value g:

If there exists no node v that is an element of V such that Guid(v) = g, then skip the ACE.

Otherwise, let v be the unique node in P such that Guid(v) = g if any such node exists. If no such node exists, let v be the unique node in A such that Guid(v) = g. If the rights in M are not in Grant(v), then add the rights in M to Deny(v). For every descendant node u of v, if the rights in M are not in Grant(u), then add the rights in M to Deny(u). For every ancestor node w of v, add the rights in M to Deny(w).

When the end of the DACL is reached, the access rights in Grant(r) at the root node of tree T is the maximum access available to the requester on the object. For each node u below the root node r, the access rights in Grant(u) is the maximum access available to the requester for that node.

If the requested access is for the entire object, check the requested access mask against the access rights granted in Grant(r). If the requested access is for specific properties on the object, check the requested access mask against the rights granted in Grant(u) where u is the attribute node in tree T that is the target of the request.