In my last post on creating your own AD/ADAM permissions editor I covered the basic terminology used with Active Directory and also introduced the DirectoryEntry class. In this post I will discuss how to read, filter and understand an ACL on a DirectoryEntry.
The first thing we need to decide is what part of the ACL we want to read. As mentioned in the glossary on my last post, an ACL actually contains TWO types of ACL record - those to do with reading/modifying the object itself (DACL) and those to do with reading/modifying the audit settings (SACL). For the purposes of what we are doing, we're only bothered about the DACL. Let's see how we identify in code what type of ACL records we want to see:
myDirectoryEntry.SecurityMasks = SecurityMasks.Dacl;
And it really is that easy. It feels a bit odd just setting this on the DirectoryEntry and then (for now) doing nothing with it, but the reason for this is that it is a mask which is applied when you do security-based operations on the DirectoryEntry. The SecurityMasks enumerator contains other values such as Group, Owner, Sacl or None (which shows all records in the ACL of every type... nice and confusing).
Setting the mask is all well and good, but now we actually need to get the ACL - or, strictly speaking, the DACL - and see what entries it contains. To do that we use the 'ObjectSecurity' property of the DirectoryEntry. This will return an ActiveDirectorySecurity object which is really a worker class to get and modify ACLs. An example of getting this is shown below:
ActiveDirectorySecurity securityWorker = myDirectoryEntry.ObjectSecurity;
As this point we are ready to start getting our ACLs, and this is where it starts to get a little more complex. You see, the type of 'user' to which an ACL entry refers is represented as an IdentityReference, as far as .NET is concerned. Only problem is that when you ask for the ACL, you don't ask for the entries by IdentityReference, but rather you have to ask for them by either NT Account or by SecurityIdentifier (SID). The reason for this is because the information for the account can be 'wrapped' in different ways. Sometimes you'll need one wrapper, sometimes another. Typically, the SID would be something you'd pass around as an ID, but the NT Account would be used when you want to display an account name. Things are a bit more complex than this, but I'll deal with that later.
For now, then, let's see how we get that all important DACL from the ObjectSecurity object that we assigned above. The rules themselves are put into a collection of type AuthorizationRuleCollection. First, lets get them as rules with SecurityIdentifier object (SID):
AuthorizationRuleCollection aclRules = securityWorker.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
And now lets see how we get them with NT Account details:
AuthorizationRuleCollection aclRules = securityWorker.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
The two boolean settings are for explicit rules and inherited rules. You can grab everything and then look at the access rule itself to see what object it refers to if you like, or you can decide what kind of rules to grab up front if you prefer. Techie note - When you have an inherited rule it's not always easy to find what object it orignated from. By stepping through the ACLs on the parent objects and asking for explicit rules you can determine what object an inherited ACL started from.
We are now at the point where we have a read an ACL - filtered to the DACL, in this case - and have a collection of rules ready for us to step through. We have understood that when asking for the rules we have had to choose how to represent the identities of the accounts for the rules. In my next post I will explain what an access rule itself consists of and what the various parts of it mean, and how to get that data out.