Setting ACE/ACL Permissions is getting a bit more – uh, organized in .NET 2.0 with a set of classes that allow reading and assigning of the security descriptors. I’m no expert in this complex topic, but I do have frequent needs to set directory and file level ACE/ACL permissions.

 

I had previously posted on how to do this using CACLS.EXE and that actually works well. In fact, all things considered it looks like it’s actually easier to do that than what I’ll show below. <g> Still, the new Security classes are a welcome addition because they provide a common API for all sorts of Security Descriptor manipulation including for things like Registry keys and other OS objects. So there’s a common, consistent if somewhat complex API in place that you can use for most of these.

 

The following is an example of setting the ACL on a directory including inherited permissions for child directories and files. This maps the code that I showed in the earlier CACLS example.

 

public bool SetAcl()

{

    if ( this.Pathname == null || this.Pathname == "")

    {

        ErrorMessage +=  "Path cannot be empty.";

        return false;

    }

 

    // *** Strip off trailing backslash which isn't supported

    this.Pathname = this.Pathname.TrimEnd('\\');

 

    FileSystemRights Rights = (FileSystemRights) 0;

 

    if (this.UserRights == "R")

        Rights = FileSystemRights.ReadAndExecute;

    else if (this.UserRights == "C")

        Rights = FileSystemRights.ChangePermissions;

    else if (this.UserRights == "F")

        Rights = FileSystemRights.FullControl;

 

    // *** Add Access Rule to the actual directory itself

    FileSystemAccessRule AccessRule = new FileSystemAccessRule(this.Username, Rights,

                                InheritanceFlags.None,

                                PropagationFlags.NoPropagateInherit,

                                AccessControlType.Allow);

 

    DirectoryInfo Info = new DirectoryInfo(this.Pathname);

    DirectorySecurity Security = Info.GetAccessControl(AccessControlSections.Access);

 

    bool Result = false;

    Security.ModifyAccessRule(AccessControlModification.Set, AccessRule, out Result);

 

    if (!Result)

        return false;

 

    // *** Always allow objects to inherit on a directory

    InheritanceFlags iFlags = InheritanceFlags.ObjectInherit;

    if (this.InheritSubDirectories)

        iFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;

 

    // *** Add Access rule for the inheritance

    AccessRule = new FileSystemAccessRule(this.Username, Rights,

                                iFlags,

                                PropagationFlags.InheritOnly,

                                AccessControlType.Allow);

    Result = false;

    Security.ModifyAccessRule(AccessControlModification.Add, AccessRule, out Result);

 

    if (!Result)

        return false;

 

    Info.SetAccessControl(Security);

 

   

    return true;           

}

 

 As you can see there are a number of different objects involved. It starts with the DirectorySecurity class. This class is a directory specific security class, but there are others for files, Registry keys etc. that map a common interface. On this security object you can then set permissions. The first thing to do is create a FileSystemAccessRule which determines which rights and inheritance rules you want to set. There are a lot of options here and some of the options are a bit difficult to figure out.

 

First the Inheritance and Propagation flags can only be set in the constructor! You can look at the values later, but once the instance is created they become ReadOnly. It took some help from a fellow MVP to realize I had to set these values in the constructor.

 

Further the Inheritance and Propagation rights very closely follow the actual API structures, rather than providing a more intuitive API. So instead of providing options for downlevel delegation as well as setting permissions on the current object (which is in effect two sets of permissions) you have to set and assign each one individually. So if you set the propagation flags to inherit you’ll find the actual directory doesn’t get the rights. If you look in the Windows Security dialog for a directory and look at an ‘inherited’ permission set you will indeed see that there’s one set for this folder only and one for inherit subfolders and files. It seems silly that this API doesn’t have an option to set both of these with a single Propagation Flag. Again, totally non-intuitive.

 

So in the above code I create the FileSystemAccess rule, then first assign the rule with a Set operation (which overrides the permissions for this object and user completely), and then does the whole thing again with the inheritable rights, Adding the permissions.

 

<rant>

It works, and isn’t too complex once you know how it works, but it’s not easy to figure out without an example. The examples on MSDN don’t really go into any detail and show an overly simplistic scenario of a single file. The APIs pretty much assume you understand how ACE/ACLs work from an API perspective which is silly given that this is a new API for .NET 2.0 and especially since there was a lot of crying out to get this functionality into the framework. This is a frequent requirement for applications.

 

It just seems silly to implement a new API and not really address the common use case scenario with a couple of lines of code. Most developers have specific needs – I need to set user X and give him these permissions on this directory or file and propagate these changes. Instead there are a whole set of APIs; I have to use 4 classes to make this work!

</rant>

 

BTW, this code still requires Full Trust just like the CACLS solution for obvious reasons.