Now that we’ve seen some of the things you can do with SIDs when you use them in the way they were intended to be used, now let’s see what you can do with SIDs when you’re willing to work outside the box.
For Exchange 2000, we had a product requirement that we implement a feature called “Roles”. A simple example of a “Role” in the NT base security system is the CREATOR_OWNER SID (S-1-3-0). If you put the creator-owner SID in an ACL, it has no effect on the access check for that object, but when the ACL is inherited by a new object, the creator-owner ACE is replaced with the owner SID of the user who created the new object.
So a role is essentially a macro that’s expanded at some point in the lifetime of the object. For CREATOR_OWNER, it’s expanded at ACL inheritance time, for an Exchange role SID, it’s expanded at the access check time, and allows you to define a single ACE that acts as a per-object group – essentially when Exchange performs its access checks, the role SID is expanded to contain the set of people in a property on the message that’s described by the role SID.
We couldn’t use NT security groups for roles, because of the requirement that roles be expanded on a per-object basis – you couldn’t define a separate security group for each message in a folder, for example, since that wouldn’t scale (or be manageable). In addition, you need to have some form of administrative rights to modify the active directory, and we knew that most IT departments wouldn’t allow random users to be creating groups in the active directory.
One of the other criteria that we had for role ACEs was that ACLs containing role ACEs had to be valid NT ACLs. So we needed to find a way of representing roles in an ACE without breaking NT’s IsValidSecurityDescriptor() API.
So how did we do this?
The first thing that needs to be explained is the concept of a “resource manager”. What’s a “resource manager”? The term “resource manager” is sort-of like the term “policy” – each person uses it in a different fashion, which means that it can be quite confusing. To the NT security infrastructure, a resource manager is a component that is using NT security to protect some asset. The NT filesystem is a resource manager, as is the NT registry, the NT Active Directory, etc. Well, Exchange is also a resource manager. I’ve written about the Exchange resource manager before here, here, and here on the Microsoft Exchange blog. The key thing to keep in mind about a resource manager is that it completely defines the security descriptors that are contained in its store. The ACL for a registry key will never appear in the active directory as an ACL. Exchange’s ACLs will never appear in the NT registry, or on the NT filesystem (ok, I lied on that last one).
Well, if we’re writing our own resource manager, we can take advantage of that hierarchy in ways that the designers of the NT security infrastructure never imagined. And that’s where the psychotropic drugs come into play.
In my first SID post, I talked about the fact that SIDs are essentially hierarchical. The Revision determines the structure of what follows the Revision in the SID, the IdentifierAuthority determines the structure of what follows the IdentifierAuthority in the SID.
So if we could define our own identifier authority, then we could define whatever we wanted to in the portion of the SID after the identifier authority. This is EXACTLY what the SECURITY_RESOURCE_MANAGER_AUTHORITY exists for. Essentially, if you define a SID in the SECURITY_RESOURCE_MANAGER_AUTHORITY SID authority, you get to have SECURITY_MAX_SID-FIELD_OFFSET(SID, SubAuthority) (about 30-ish) bytes of data that you can set to be anything you want them to be. The NT security infrastructure will completely ignore the data after the resource manager identifier authority. All of the APIs that check for validity of SIDs will stop looking as soon as they see that the SID is owned by the resource manager authority.
Since security descriptors don’t bleed from one resource manager to another, you only need a single resource manager identifier authority.
So for Exchange Roles, we encoded the information needed to expand the role (the role scope and the role property) into the role SID. When Exchange performed an access check, it took the role membership, retrieved the role property from the folder (or object) specified by the role scope, and replaced the ACE containing the role SID in the ACL with the contents of that property (of course we cached the result of this expansion, so it was performed at most once per message).