Contact   •   Products   •   Search

Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs

Setting ACE/ACL permissions in .NET 2.0


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.

Make Donation


Feedback for this Post

 
# re: Setting ACE/ACL permissions in .NET 2.0
by Bob Shepherd February 07, 2006 @ 3:02am
Thank you so much Rick. You solved several puzzlers that I was struggling with. The MSDN documentation is really inadequate. You have done a great service!
# re: Setting ACE/ACL permissions in .NET 2.0
by Joseph Bittman MVP - DPM March 26, 2006 @ 8:32am
I'm really stuck on this... I need a directory to have ACE entries which have the equivilent of Windows Explorer's "Applies To: This Folder, Sub-Folders, and File" type of thing. It appears you are having to add the extra inheritance flags to the earlier "This Folder" FileSystemAccessRule object... through the ModifyAccessRule method.

But you are passing another FileSysAccessRule to the ModifyAccessRule method... and in that FileSysAccessRule, you have specified IFlags... which looks like it represents BOTH ObjectInherit and ContainerInherit enum values??? How did you do that? lol I'm stuck on how you added those two values together into one IFlags? ......... I'm in VB and it doesn't look like the '|' operator is supported.

Any ideas? It appears though.... that if I can't combine the two enum values into one Iflags, that I could split them into two seperate accessrules and call ModifyAccessRule twice for each one? Thanks!!!
# re: Setting ACE/ACL permissions in .NET 2.0
by Michael Freidgeim April 23, 2006 @ 4:27pm
I beleive that
if (this.UserRights == "C")
Rights = FileSystemRights.ChangePermissions | FileSystemRights.Modify ;

FileSystemRights.ChangePermissions specifies the right to change the security and audit rules associated with a file or folder.
But common sence "change" permission corresponds to FileSystemRights.Modify value.
# re: Setting ACE/ACL permissions in .NET 2.0
by JoltinJoe May 09, 2006 @ 6:30am
Thank you, thank you, thank you. I was also getting very frustrated by the poor documentation on some of the .NET 2.0 functions. I really learned a lot from this page.
# re: Setting ACE/ACL permissions in .NET 2.0
by Paul Noeldner August 17, 2006 @ 10:39am
Super - I dug for 3 days and finally found your example re setting directory ACLs with inheritance and propagation. Haven't tried it yet but from feedback this looks good. The MSDN VB101 ACLChange example does a file ok, but when I simply change it to touch a directory instead. Also fyi the ACLChange output LOOKED LIKE it was working, but (1) it didn't propagate inherited rights and (2) the changes never committed (close the program, reopen, they're lost, and they never show up in Explorer).
# re: Setting ACE/ACL permissions in .NET 2.0
by Paul Noeldner August 22, 2006 @ 8:01pm
The following code modification makes the VB101 ACLChange example work correctly for directories including the option to touch subdirectories that do not inherit rights. Changes: 1) Setting both ContainerInherit and ObjectInherit makes it work like doing a checkbox in Explorer. 2) A call to Directory.SetAccessControl is required to actually commit the change and trigger propagation to subdirs and files that inherit rights. 3) Add a Checkbox to optionally recurse all subdirs and touch any that do not automatically inherit rights. Here's the modified AddToFileACE function:
------------------------------------------
Private Function AddToFileACE(ByVal sDirName As String, ByVal userName As String, ByVal rights As FileSystemRights, ByVal accessControl As AccessControlType)
Dim bAdded As Boolean
Try
If ((sDirName = DirectoryName.Text) Or (Directory.GetAccessControl(sDirName).AreAccessRulesProtected)) Then
m_DirectorySecurity = Directory.GetAccessControl(sDirName)
Dim ace As FileSystemAccessRule = New FileSystemAccessRule(New NTAccount(userName), rights, (InheritanceFlags.ContainerInherit Or InheritanceFlags.ObjectInherit), PropagationFlags.None, accessControl)
m_DirectorySecurity.AddAccessRule(ace)
Directory.SetAccessControl(sDirName, m_DirectorySecurity)
bAdded = True
sDirsTouched = sDirsTouched + sDirName + vbCrLf
End If
If CheckApplyToSubDirs.Checked Then
For Each sSubDir In Directory.GetDirectories(sDirName)
AddToFileACE(sSubDir, userName, rights, accessControl)
Next
End If
Catch ex As System.Security.Principal.IdentityNotMappedException
MessageBox.Show("Failed to add rule - does username exist?", "ACL Sample", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Try
Return bAdded
End Function
------------------------------------------
# re: Setting ACE/ACL permissions in .NET 2.0
by FritzDog September 13, 2006 @ 7:07pm
Ok here's a scenario....
I have a workgroup with multiple machines, on which new User Accounts can be added at any time and without my knowledge. This is ok.

I have a set of directories which should only be modified by 1 NTAccount out of all of those. I can set access to a folder for this one account very easily:

AccessRule = new FileSystemAccessRule(this.Username, Rights,iFlags,PropagationFlags.InheritOnly, AccessControlType.Allow);

HOWEVER, I would like to set another rule that restricts the World's access. If I try this:

AccessRule = new FileSystemAccessRule("Everyone", Rights,iFlags,PropagationFlags.InheritOnly, AccessControlType.Allow);

the "Everyone" group's access changes, including the name I am trying to set explicitly.

Is there a way I can restrict "Everyone"'s access EXCEPT this.user? So far, every time I give "Everyone" limited access, it overrides my user's access rights. And unfortunately, I cannot explicitly deny other users access because as I stated they are added at any time. Please help! :)
# ScottGu's Blog : Programmatically configuring ACE/ACL Permissions using .NET 2.0
by ScottGu's Blog September 25, 2006 @ 7:16am
Rick Strahl has posted a good example on his blog about how to programmatically configureACLs and permissions for things like files and directories using the new .NET 2.0 filesystemaccess APIs. Worth taking a look if you are looking to automate the setup
# DotNetSlackers: Setting ACE/ACL permissions in .NET 2.0
by DotNetSlackers Latest ASP.NET News September 27, 2006 @ 9:32pm
# re: Setting ACE/ACL permissions in .NET 2.0
by Pete October 06, 2006 @ 8:41am
Good snippets. Good rant. .NET2 is still very immature as a technology, but to be honest documentation has always been an issue with Microsoft's newest technologies as far back as I can remember (Windows 386!) - there is always a lag. At least these days there are decent blogs such as yours - we're not forced to rely entirely on the msdn!
# What did you learn today? - Wednesday, 08 February 2006
by What did you learn today? October 11, 2006 @ 1:35pm
# Setting File or Directory permissions ACE entries with .NET using CACLS.EXE - Rick Strahl's Web Log
by Rick Strahl's Web Log October 15, 2006 @ 6:46am
Ever need to find a quick way to set access permissions to a directory or file in .NET. Here's a class that wrappers the tried and true CACLS.EXE Windows utility so you can programmatically assign ACEs to a path.
# ITpro Supportforum: [LØST] Problem med shell/cmd i VB
by ITpro October 26, 2006 @ 2:13am
Informasjonsteknologi. Enkelt og greit.
# What did you learn today? - 70-551, 70-552, 70-553 Section I, Part VIII - Access Control
by What did you learn today? November 17, 2006 @ 2:28am
# What did you learn today? - Tuesday, 07 February 2006
by What did you learn today? November 25, 2006 @ 2:31pm
# re: Setting ACE/ACL permissions in .NET 2.0
by Ryan January 01, 2007 @ 11:44am
Thanks Rick!

After a nasty encounter with a rootkit, I finally decided to get religion about security and stop running as admin on XP Pro. This, of course, is a constant source of frustration. Being denied access to files and directories I created as admin was making me livid. Thank you for educating us and helping me solve an immediate problem.
# re: Setting ACE/ACL permissions in .NET 2.0
by Sony March 03, 2007 @ 5:12am
Hi I think its really great, but can you tell me how to give full trust?, I am using ASP.NET 2.0 to call.
# eknowledger: Setting ACE/ACL permissions in .NET 2.0
by March 12, 2007 @ 12:20pm
eknowledger: Setting ACE/ACL permissions in .NET 2.0
# ntfs on deploy - microsoft.public.dotnet.framework.windowsforms | Google Groups
by microsoft.public.dotnet.framework.windowsforms Google Group March 21, 2007 @ 4:20am
# re: Setting ACE/ACL permissions in .NET 2.0
by Jonathan August 09, 2007 @ 11:21am
This doesn't seem to work with Windows Vista. I get a "Could not load file or assembly Win32Security..." error message.
# re: Setting ACE/ACL permissions in .NET 2.0
by Sony August 30, 2007 @ 2:48am
I implemented it, it worked very well in my test lab, but failed in production, throws exception, no registry access, no full trust etc, I impersonated in ASP.NET with a Domain Admin account, can you help me, I will give more details if necessary
# re: Setting ACE/ACL permissions in .NET 2.0
by Vlad September 24, 2007 @ 2:03am
Hi,
Please help me with small issue (actually it is huge!!!).
The code works fine when I have explicit rights on the directory, but if I don't have it (I'm still an administrator, but have no explicit entry in ACL on the directory) this line:

<code lang="c#">
DirectorySecurity Security = Info.GetAccessControl(AccessControlSections.Access);
</code lang="c#">

Throws an exception: Attempted to perform an unauthorized operation.

This app used CACLS.EXE until now (and it worked great!), but I would like to use this code...

Please help
# re: Setting ACE/ACL permissions in .NET 2.0
by Kunjan Modi February 08, 2008 @ 12:06pm
Hi,

This is an excellent piece of code snippet. I was looking for something like this for the last 2 months. Finally, I feel my prayers have been answered.

I just have one small issue. When I implemented this code in my asp.net 2.0 web application, i get unauthorizedaccessexception on

Info.SetAccessControl(Security);

From security aspect, it is running under currently logged on user's identity. Also, I m running this on IIS 6.0 and there is a dedicated app pool for the website running under a special account in the same domain as the currently logged in user.

Please Help!!!!!!
# re: Setting ACE/ACL permissions in .NET 2.0
by Jerry Issa February 15, 2008 @ 11:59am
Rick,

Good primer, and I agree with many of your complaints (especially about the level of detail on MSDN). However, there's one problem (I haven't looked around your blog, so I apologize if you've already realized the issue and posted about it). It relates to this snippet:

"...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..."

That's not true, but I could see how someone might come to that that conclusion because of the PropagationFlags enumeration. I know that I was confused by them when I first tried to set permissions programattically and I couldn't find an adequate explanation anywhere online. So here's my attempt to save someone else similar frustration:

* InheritanceFlags.None - No inheritance, plain and simple. The ACE will not be inherited by any children of this object.
* InheritanceFlags.ContainerInherit - The ACE will be inherited by child containers (eg, folders) of this object.
* InheritanceFlags.ObjectInherit - The ACE will be inherited by child leafs (eg, files) of this object.

* PropagationFlags.None - If InheritanceFlags.None is used, this flag should be used as well (though this example seems to work fine violating this rule). If any other InheritanceFlags are used, the ACE will apply to this object AND all descendants specified by InheritanceFlags.
* PropagationFlags.NoPropagateInherit - The ACE will be passed on to children as specified by the InheritanceFlags, but not to the children of the child container objects. Only children, not grandchildren or other descendants, will inherit.
* PropagationFlags.InheritOnly - The ACE will be inherited, but will NOT apply to this object. Here's where the confusion lies. You don't have to specifcy InheritOnly to inherit, PropagationFlags.None will work just fine.

Two notes:
* You can combine the PropagationFlags just like the InheritanceFlags. So just like InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit (using C-style syntax) means that the ACE is inherited by leafs and containers, PropagationFlags.NoPropagateInherit | PropagationFlags.InheritOnly means that the ACE would apply to children of the current object but not to the object itself or to grandchildren or other descendants of the object.
* Should go without saying, but since both None flags are the other flags set to zero, combining a flag with the None flag has no effect. Hence, InheritanceFlags.ObjectInherit | InheritanceFlags.None is still InheritanceFlags.ObjectInherit and PropagationFlags.InheritOnly | PropagationFlags.None is still PropagationFlags.InheritOnly.

In conclusion, to do what you wanted to do could be accomplished by

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

                                iFlags,

                                PropagationFlags.Nonce,

                                AccessControlType.Allow);
# re: Setting ACE/ACL permissions in .NET 2.0
by Jerry Issa February 18, 2008 @ 11:54am
Sorry for the misspelling in the above post. In particular, PropagationFlags.Nonce should obviously have been PropagationFlags.None in the code snippet.
# re: Setting ACE/ACL permissions in .NET 2.0
by Alex Rouillard August 26, 2008 @ 6:20am
Your the man !!

Thanks a lot
# re: Setting ACE/ACL permissions in .NET 2.0
by crashSmoke October 13, 2008 @ 3:19am
Good post! However,

I downloaded the Microsoft example for changing ACLs on a file (which is my ultimate goal):
http://download.microsoft.com/download/c/2/3/c2318968-80aa-43de-a755-9c0763a2dca8/VB101SamplesBCL.msi

As someone has already commented, this does not commit the changes to the file. There is a post underneath that refers to commiting changes to a dir, not to a file, and says that an additional Directory.SetAccessControl call is required. What is the equivilant for a file? And why do Microsoft not publish this info with their example. Apart from showing you what you could do, this example is usless without that info! And very annoying seeing as they do not refresh their GUI properly and just manually add the new rule to the tree node giving the impression it worked, and is commited. Personally, I would call that cheating :)

Any help is much appreciated!

crash.
# re: Setting ACE/ACL permissions in .NET 2.0
by crashSmoke October 13, 2008 @ 3:24am
OK, fairly obvious I guess (no, actually, its very obvious):

Call File.SetAccessControl(fileName, m_fileSecurity)

Ta.

crash.
# re: Setting ACE/ACL permissions in .NET 2.0
by Kim January 10, 2009 @ 10:32am
Thanks! Very helpful! How can I programatically "Replace all existing inheritable permissions on all descendants with inheritable permissions from this object"? (How can I programatically "check" this option?)
# re: Setting ACE/ACL permissions in .NET 2.0
by Kunal Mehta January 15, 2009 @ 4:18am
Hello,

I am using BlogEngin.NET open source application. Afer transfering to New Hosting Provider. I getting error of access denied. Which is basically the problem of permission of "App_Data" Folder.

I told to my hosting provider. They told me that we have set the permission. After that I will getting this error ocasionally means some times. I will refersh the page again and again then sudenly error comes. If you go through all page one by one then suddenly error appears.

If you want to check my website is http://elevatesoftsolutions.in/default.aspx

Please let me any other way to set the permission to existing folder.

Thanks
Kunal Mehta
--
http://360by2.blogspot.com/
# re: Setting ACE/ACL permissions in .NET 2.0
by Fernando March 05, 2009 @ 1:29pm
Thank you! Your script helped a lot!
# re: Setting ACE/ACL permissions in .NET 2.0
by JT September 17, 2009 @ 2:21am
Hi Rick,

Great example, and still useful 3 years after :) However as Jerry Issa states, I'm pretty sure the Propagation should be set to PropagationFlags.None.

Counterintuitively, this means that the newly added access control will apply to this folder, subfolders and files, which is the most common use case. The current example will only apply the ACL to children, which is (in my experience) much less common.

Regards,
James
# re: Setting ACE/ACL permissions in .NET 2.0
by Khornphanom Lakhummee October 06, 2009 @ 12:55am
Great article. I believe that many people are looking for this solution like me. :)
Thank you very much Rick.

Regards,
Khornphanom Lakhummee
# re: Setting ACE/ACL permissions in .NET 2.0
by Sara October 14, 2009 @ 5:51pm
Hi I'm trying to set the ACL's of a certificate private key which is located under
C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys

The code runs in the cmd having admin permissions. Still I get the error:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.UnauthorizedAccessException: Attempted to perform an unauthorized operation.
at System.Security.AccessControl.Win32.SetSecurityInfo(ResourceType type, String name, SafeHandle handle, SecurityInfos securityInformation, SecurityIdentifier owner, SecurityIdentifier group, GenericAcl sacl, GenericAcl dacl)
at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, SafeHandle handle, AccessControlSections includeSections, Object exceptionContext)
at System.Security.AccessControl.NativeObjectSecurity.Persist(SafeHandle handle, AccessControlSections includeSections, Object exceptionContext)
at System.Security.AccessControl.FileSystemSecurity.Persist(SafeFileHandle handle, String fullPath)

I can manually set this ACL's using the same account
# re: Setting ACE/ACL permissions in .NET 2.0
by Steve Walton March 18, 2010 @ 6:14am
Thanks Rick.

Great article. Solved my problems when the MSDN documentation was not helping at all.

Thanks again.
# re: Setting ACE/ACL permissions in .NET 2.0
by qa March 23, 2010 @ 7:04am
It did not help me solving the problem with certificates ACLs.
# re: Setting ACE/ACL permissions in .NET 2.0
by mahendra November 09, 2011 @ 3:37am
I have subfolder and files only permission set at parent folder.
now i added one child folder inside the parent folder and need to set this folder, subfolders and files permission to child folder

Please guide me
 


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2014