This blog post is part of a series about Active Directory attributes with values or behaviors that can be easily and inadvertently misinterpreted and misused. This series will provide information about these attributes, including both their limitations and their valid usages with respect to the administration of Active Directory.
This post will discuss a special type of Active Directory attribute, the Active Directory linked attribute. Linked attributes generally exist in associated pairs; one of the associated attributes is known as the “forward link” and the other associated attribute is known as the “back link”. Active Directory uses these attributes to describe relationships between objects.
The funny thing about linked attributes is that they don’t necessarily work the way you’d expect. Or maybe they work exactly the way you’d expect. I don’t know. I guess you’re going to have to continue reading to find out.
What Makes an Attribute a Linked Attribute?
Every attribute in Active Directory is defined by an AttributeSchema object in the Active Directory schema partition. The AttributeSchema objects that describe linked attributes are unique in that they are the only schema objects that possess a populated LinkID attribute. Since this is a distinguishing feature, identifying all of the linked attributes in a domain is as easy as using PowerShell to search the schema for objects with a populated LinkID, like this:
Get-ADObject -SearchBase (Get-ADRootDSE).SchemaNamingContext -LDAPFilter "(LinkID=*)"
While the presence of a populated LinkID attribute designates an attribute as a linked attribute, the value of the LinkID attribute defines its type. The LinkID value of a forward link is always a positive even integer and the LinkID value of a back link is always a positive odd integer. This behavior further serves to facilitate the behavior that Active Directory uses to associate a pair of linked attributes: the LinkID value of a back link is always the value of its associated forward link’s LinkID plus one. While this information may seem superfluous, let’s apply it to the output of a modified version of my earlier PowerShell script that I ran in my lab:
My modifications sort and limit the output to return only the two attributes with the smallest LinkIDs, which happen to be the Member attribute and the MemberOf attribute. As you may know, Active Directory uses the Member and MemberOf attributes to track group membership in Active Directory. Using what we now know about LinkIDs, here’s what this output can tell us about these two attributes:
- The LinkID value of the Member attribute is “2”, which is an even integer. That means the Member attribute is a forward link.
- The LinkID value of the MemberOf attribute is “3”, which is an odd integer. That means the MemberOf attribute is a back link.
- The LinkID value of the back link MemberOf is the LinkID value of the forward link Member attribute plus one (i.e., 3 = 2 + 1). That means the Member attribute and the MemberOf attribute are associated linked attributes.
A slightly different PowerShell script can actually be used to directly retrieve the name of a linked attribute’s associated forward link or back link, though it doesn’t explicitly tell you whether the attribute is a forward link or a back link. You would need to look at the LinkID value and determine that for yourself:
How Do Active Directory Linked Attributes Work?
Now that we’ve established what a linked attribute is and how to identify them, it’s time to explore their behavior.
Linked attributes store information about a relationship between two objects, in contrast to conventional Active Directory attributes that store information about an object. This functional difference is reflected in the fact that Active Directory stores the values of linked attributes differently than it stores the values of other attributes. Active Directory data is stored in the ntds.dit database file. The values of conventional attributes are stored in a table called the “datatable”. Linked attributes have their own dedicated table, the appropriately named “link_table”. If we take a peek inside a snapshot of my lab’s ntds.dit database file, we can see how Active Directory stores linked attribute values:
Entries in the link_table contain a reference to a forward link object (the highlighted “link_DNT” field in the screenshot), a reference to the associated back link object (the highlighted “backlink_DNT” field in the screenshot), and a reference to the LinkID of the forward link attribute (the highlighted “link_base” field in the screenshot).
Object references in the link_table make use of an object’s distinguished name tag (“DNT”), which is actually the internal primary key of records in the ntds.dit datatable. This prevents changes to an object’s distinguished name from requiring an update to any associated link_table entries.
The link_base field uses the forward link’s LinkID value to identify the relationship that is being tracked between the two objects (though, as you can see in my screenshot, the values in the table are actually the LinkID value divided by 2).
While this storage approach may seem a little odd, it’s actually a really brilliant design. It also results in some important practical consequences:
- Forward link values are stored; back link values are constructed. This is easily the most important concept to take away from this discussion, so I’m going to say it again. Forward link values are stored in the Active Directory database, but back links are constructed attributes. Back links do not actually store information. Since an association between two objects is a single entity, Active Directory doesn’t need to store more than one copy of an association. When a forward link is queried, Active Directory can simply return the link_table entries where the queried object’s DNT matches the value in the link_DNT field and the forward link’s LinkID matches the value in the link_base field. When a back link is queried, Active Directory can calculate its values by returning the link_table entries where the queried object’s DNT matches the value in the backlink_DNT field and the LinkID of the associated forward link (remember, subtracting 1 from the back link LinkID yields the associated forward link LinkID) matches the value in the link_base field.
- Forward link values are writable; back link values are read-only. Once you learn Active Directory only stores the values of forward links, this probably seems obvious. However, there is an important consequence to this behavior. When a linked attribute is modified, Active Directory updates the forward link, which modifies the object possessing the forward link. The back link, possessing a constructed read-only value, cannot ever be modified, so the object possessing the back link isn’t modified either. To illustrate why this is important, let’s consider adding a user to a group. This update only modifies the group’s Member attribute; the user’s MemberOf attribute is not modified. Since the group object had a material change, the metadata fields that reflect such a change (e.g., the “ModifyTimeStamp” and “WhenChanged” attributes) are updated. Those same metadata fields are not updated on the user object because, even though its MemberOf attribute will now return a different value, the MemberOf attribute itself wasn’t actually modified.
- Forward links are mandatory; back links are optional. If you’ve read other information on linked attributes, they tend to state that linked attributes always consist of a forward link and a back link. While that is often true, the presence of a back link is not strictly necessary. In fact, if we use PowerShell to retrieve linked attribute pairs, we can see that not every forward link in my lab has an associated back link:
OK, those are the three things that I think are worth remembering about linked attributes, all of which are associated to some extent with how Active Directory stores linked attribute values. Speaking of which, do you remember how I mentioned that the way linked attributes are stored is kinda brilliant? Active Directory’s approach to storing linked attribute values actually yields two really consequential benefits.
The first benefit comes from the fact that Active Directory only stores forward link values. By only storing those relationships once and leveraging that information to calculate the associated back link values, Active Directory is able to reduce the necessary size of the Active Directory database.
The other benefit, which is slightly less obvious, stems from the fact that Active Directory stores each association individually. Since each of a forward link’s associations have their own entry in the link_table, each entry can maintain its own Update Sequence Number (“USN”). This behavior is called Linked Value Replication (“LVR”) and allows Active Directory to replicate each individual association independently (i.e., if you add a user to a group with 100 existing members, only the entry for newly added user is replicated). This can significantly reduce the volume of replication necessary to propagate changes to linked attributes.
Before I tie a bow on all of this, there’s one other behavior that is worth mentioning: linked attribute values are removed from deleted objects unless the AD Recycle Bin is enabled. When an object that has a linked attribute is deleted, even though Active Directory maintains the object itself for a time as a tombstone, the object’s associated link_table entries are also deleted. Enabling the Active Directory Recycle Bin changes this behavior and retains the associated link_table entries for the duration of the deleted object’s tombstone period.
So, we’ve come to the end of another post in my “misinterpreted and misused attributes” series. Do linked attributes work the way that you expected them to work? I mean, this is a blog post, so that was a rhetorical question. In any case, I hope you learned something new.
As I mentioned (repeatedly), Active Directory linked attributes are stored differently than other Active Directory attributes and, consequently, they behave differently. This is especially true of back link attributes. If you only take one thing away from having read this it needs to be the fact that back links are constructed attributes; their values are not stored directly and, as a result, they really don’t behave at all like other attributes, especially with respect to updates. Active Directory generally does a very good job of concealing its back-end behaviors for the sake of consistent user experience. However, understanding those differences and their resulting behaviors, like those of the other attributes involved in this series, will prevent problems that can arise from their misinterpretation.
Read the other blogs in my series here!
Michael Olig is a Technical Product Manager at STEALTHbits Technologies. He is currently responsible for the company’s StealthRECOVER platform and StealthAUDIT cloud and Exchange solutions.
Michael’s eclectic work history prior to joining the STEALTHbits team includes the titles “Product Manager, eDiscovery Solutions”, “Senior Manager of DevOps”, “Litigation Paralegal”, and “chef”.