Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Setting ACE/ACL permissions in .NET 2.0


:P
On this page:

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.


The Voices of Reason


 

Bob Shepherd
February 07, 2006

# re: Setting ACE/ACL permissions in .NET 2.0

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!

Joseph Bittman MVP - DPM
March 26, 2006

# re: Setting ACE/ACL permissions in .NET 2.0

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!!!

Michael Freidgeim
April 23, 2006

# re: Setting ACE/ACL permissions in .NET 2.0

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.

JoltinJoe
May 09, 2006

# re: Setting ACE/ACL permissions in .NET 2.0

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.

Paul Noeldner
August 17, 2006

# re: Setting ACE/ACL permissions in .NET 2.0

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

Paul Noeldner
August 22, 2006

# re: Setting ACE/ACL permissions in .NET 2.0

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

FritzDog
September 13, 2006

# re: Setting ACE/ACL permissions in .NET 2.0

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
September 25, 2006

# ScottGu's Blog : Programmatically configuring ACE/ACL Permissions using .NET 2.0

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


Pete
October 06, 2006

# re: Setting ACE/ACL permissions in .NET 2.0

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?
October 11, 2006

# What did you learn today? - Wednesday, 08 February 2006


Rick Strahl's Web Log
October 15, 2006

# Setting File or Directory permissions ACE entries with .NET using CACLS.EXE - Rick Strahl's Web Log

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
October 26, 2006

# ITpro Supportforum: [LØST] Problem med shell/cmd i VB

Informasjonsteknologi. Enkelt og greit.

What did you learn today?
November 17, 2006

# What did you learn today? - 70-551, 70-552, 70-553 Section I, Part VIII - Access Control


What did you learn today?
November 25, 2006

# What did you learn today? - Tuesday, 07 February 2006


Ryan
January 01, 2007

# re: Setting ACE/ACL permissions in .NET 2.0

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.

Sony
March 03, 2007

# re: Setting ACE/ACL permissions in .NET 2.0

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.


March 12, 2007

# eknowledger: Setting ACE/ACL permissions in .NET 2.0

eknowledger: Setting ACE/ACL permissions in .NET 2.0

# ntfs on deploy - microsoft.public.dotnet.framework.windowsforms | Google Groups


Jonathan
August 09, 2007

# re: Setting ACE/ACL permissions in .NET 2.0

This doesn't seem to work with Windows Vista. I get a "Could not load file or assembly Win32Security..." error message.

Sony
August 30, 2007

# re: Setting ACE/ACL permissions in .NET 2.0

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

Vlad
September 24, 2007

# re: Setting ACE/ACL permissions in .NET 2.0

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

Kunjan Modi
February 08, 2008

# re: Setting ACE/ACL permissions in .NET 2.0

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!!!!!!

Jerry Issa
February 15, 2008

# re: Setting ACE/ACL permissions in .NET 2.0

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);

Jerry Issa
February 18, 2008

# re: Setting ACE/ACL permissions in .NET 2.0

Sorry for the misspelling in the above post. In particular, PropagationFlags.Nonce should obviously have been PropagationFlags.None in the code snippet.

Alex Rouillard
August 26, 2008

# re: Setting ACE/ACL permissions in .NET 2.0

Your the man !!

Thanks a lot

crashSmoke
October 13, 2008

# re: Setting ACE/ACL permissions in .NET 2.0

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.

crashSmoke
October 13, 2008

# re: Setting ACE/ACL permissions in .NET 2.0

OK, fairly obvious I guess (no, actually, its very obvious):

Call File.SetAccessControl(fileName, m_fileSecurity)

Ta.

crash.

Kim
January 10, 2009

# re: Setting ACE/ACL permissions in .NET 2.0

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?)

Kunal Mehta
January 15, 2009

# re: Setting ACE/ACL permissions in .NET 2.0

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/

Fernando
March 05, 2009

# re: Setting ACE/ACL permissions in .NET 2.0

Thank you! Your script helped a lot!

JT
September 17, 2009

# re: Setting ACE/ACL permissions in .NET 2.0

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

Khornphanom Lakhummee
October 06, 2009

# re: Setting ACE/ACL permissions in .NET 2.0

Great article. I believe that many people are looking for this solution like me. :)
Thank you very much Rick.

Regards,
Khornphanom Lakhummee

Sara
October 14, 2009

# re: Setting ACE/ACL permissions in .NET 2.0

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

Steve Walton
March 18, 2010

# re: Setting ACE/ACL permissions in .NET 2.0

Thanks Rick.

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

Thanks again.

qa
March 23, 2010

# re: Setting ACE/ACL permissions in .NET 2.0

It did not help me solving the problem with certificates ACLs.

mahendra
November 09, 2011

# re: Setting ACE/ACL permissions in .NET 2.0

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 - 2024