Click here to Skip to main content
15,892,072 members
Articles / Programming Languages / Visual Basic
Technical Blog

ACLs for File and Directory Access

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
19 Feb 2013CPOL2 min read 21K   8   3
Sometimes you have a need to modify file or directory permissions (e.g., limiting issues with UAC).

Sometimes you have a need to modify file or directory permissions (e.g., limiting issues with UAC). Finding the information on how to set the permissions for a directory or file can be difficult. I was looking to add BUILTIN\Users to a directory with Modify permissions to a subdirectory in my application's Program Files directory.

VB
Dim sLogFile As String
sLogFile = IO.Path.Combine(IO.Path.GetDirectoryName(Application.ExecutablePath()), "Data", "Log", "Example.log")

If Not My.Computer.FileSystem.DirectoryExists(IO.Path.GetDirectoryName(sLogFile)) Then
  ' Create the directory
  Dim sDataDir As String = IO.Path.Combine(IO.Path.GetDirectoryName(Application.ExecutablePath()), "Data")

  ' The VB.NET runtime will create any intermediary directories as necessary
  My.Computer.FileSystem.CreateDirectory(IO.Path.GetDirectoryName(sLogFile))

  ' Get the ACL for the directory just created
  Dim oACL As Security.AccessControl.DirectorySecurity = IO.Directory.GetAccessControl(IO.Path.GetDirectoryName(sDataDir), Security.AccessControl.AccessControlSections.Access)

  ' Create a security Identifier for the BuiltinUsers Group to be passed to the new access rule
  Dim oBuiltInUsersSid As New Security.Principal.SecurityIdentifier(Security.Principal.WellKnownSidType.BuiltinUsersSid, Nothing)

  ' Create the rule that needs to be added to the ACL
  Dim oRule As New Security.AccessControl.FileSystemAccessRule(oBuiltInUsersSid,
                                                               Security.AccessControl.FileSystemRights.Modify Or Security.AccessControl.FileSystemRights.Synchronize,
                                                               Security.AccessControl.InheritanceFlags.ContainerInherit Or Security.AccessControl.InheritanceFlags.ObjectInherit,
                                                               Security.AccessControl.PropagationFlags.None,
                                                               Security.AccessControl.AccessControlType.Allow)

  ' Add the new rule to our ACL
  oACL.AddAccessRule(oRule)

  ' Update the directory to include the new rules created
  System.IO.Directory.SetAccessControl(sDataDir, oACL)
End If

Here's what is going on in the above code. First, I am putting together the full path and filename for the file I want to use for logging. Second, I am checking to see if the directory exists (because I don't want to throw an error for something when I don't have to).

If the directory doesn't exist, create the directory and any intermediary directories as required. Get the ACLs for the directory as it exists. Create a new FileSystemAccessRule for the role/rule combination desired. That rule gets added to the existing rules. The existing rules get replaced by the modified rules created.

I wanted to use the well known SIDs for a couple of reasons. They are defined and will not change. I don't have to worry with localized names for the roles as my application has a globalized scope.

Using Security.Principal.SecurityIdentifier with a SID requires a Domain SID be used. Since I only want to use the well known SID for BUILTIN\Users, I can specify just the Security.Principal.WellKnownSidType.BuiltinUsersSid enumeration and Nothing for the domain SID.

At first, I used only Security.AccessControl.FileSystemRights.Modify to set the Modify permissions on the directory. I found out that this resulted in specialized permissions being applied. This was not what I wanted. So, I manually created the directory and applied the permissions I wanted. Using the ListDirectoryACLs function to see what roles/rules were in place, I found that I needed to add the Security.AccessControl.FileSystemRights.Synchronize permission.

I also had set Security.AccessControl.InheritanceFlags to

InheritanceFlags.ContainerInherit
and Security.AccessControl.PropagationFlags to PropagationFlags.None based on some other articles I found on the web. These properties also needed some tweaking to get to the permissions set by Windows 7.

Here is a helper function to show what ACL permissions you have for a directory:

VB
Public Function ListDirectoryACLs(ByVal Directory As String) As String
  Dim oDirACLs As New Security.AccessControl.DirectorySecurity(Directory, Security.AccessControl.AccessControlSections.Access)
  Dim sbAccess As New System.Text.StringBuilder()

  For Each oAccessRule As System.Security.AccessControl.FileSystemAccessRule In oDirACLs.GetAccessRules(True, True, GetType(System.Security.Principal.NTAccount))
    sbAccess.AppendFormat("Account:     {0}", oAccessRule.IdentityReference.Value).AppendLine()
    sbAccess.AppendFormat("Type:        {0}", oAccessRule.AccessControlType).AppendLine()
    sbAccess.AppendFormat("Rights:      {0}", oAccessRule.FileSystemRights).AppendLine()
    sbAccess.AppendFormat("Inherited:   {0}", oAccessRule.IsInherited).AppendLine()
    sbAccess.AppendFormat("Inheritance: {0}", oAccessRule.InheritanceFlags).AppendLine()
    sbAccess.AppendFormat("Propagation: {0}", oAccessRule.PropagationFlags).AppendLine()
    sbAccess.AppendLine(New String("-"c, 25))
  Next

  Return sbAccess.ToString()
End Function

Output from the ListDirectoryACLs() function:

Account: BUILTIN\Users
Type: Allow
Rights: Modify, Synchronize
Inherited: False
Inheritance: ContainerInherit, ObjectInherit
Propagation: None
-------------------------
Account: BUILTIN\Users
Type: Allow
Rights: Modify, Synchronize
Inherited: False
Inheritance: ContainerInherit, ObjectInherit
Propagation: None
-------------------------
Account: NT AUTHORITY\SYSTEM
Type: Allow
Rights: FullControl
Inherited: True
Inheritance: ContainerInherit, ObjectInherit
Propagation: None
-------------------------
Account: BUILTIN\Users
Type: Allow
Rights: Modify, Synchronize
Inherited: False
Inheritance: ContainerInherit, ObjectInherit
Propagation: None
-------------------------
Account: NT AUTHORITY\SYSTEM
Type: Allow
Rights: FullControl
Inherited: True
Inheritance: ContainerInherit, ObjectInherit
Propagation: None
-------------------------
Account: BUILTIN\Administrators
Type: Allow
Rights: FullControl
Inherited: True
Inheritance: ContainerInherit, ObjectInherit
Propagation: None
-------------------------
Account: BUILTIN\Users
Type: Allow
Rights: Modify, Synchronize
Inherited: False
Inheritance: ContainerInherit, ObjectInherit
Propagation: None
-------------------------
Account: NT AUTHORITY\SYSTEM
Type: Allow
Rights: FullControl
Inherited: True
Inheritance: ContainerInherit, ObjectInherit
Propagation: None
-------------------------
Account: BUILTIN\Administrators
Type: Allow
Rights: FullControl
Inherited: True
Inheritance: ContainerInherit, ObjectInherit
Propagation: None
-------------------------
Account: MyDomain\myusername
Type: Allow
Rights: FullControl
Inherited: True
Inheritance: ContainerInherit, ObjectInherit
Propagation: None
-------------------------

And its equivalent for a file:

VB
Public Function ListFileACLs(ByVal Filename As String) As String
  Dim oFileACLs As New Security.AccessControl.FileSecurity(Filename, Security.AccessControl.AccessControlSections.Access)
  Dim sbAccess As New System.Text.StringBuilder()

  For Each oAccessRule As System.Security.AccessControl.FileSystemAccessRule In oFileACLs.GetAccessRules(True, True, GetType(System.Security.Principal.NTAccount))
    sbAccess.AppendFormat("Account:     {0}", oAccessRule.IdentityReference.Value).AppendLine()
    sbAccess.AppendFormat("Type:        {0}", oAccessRule.AccessControlType).AppendLine()
    sbAccess.AppendFormat("Rights:      {0}", oAccessRule.FileSystemRights).AppendLine()
    sbAccess.AppendFormat("Inherited:   {0}", oAccessRule.IsInherited).AppendLine()
    sbAccess.AppendFormat("Inheritance: {0}", oAccessRule.InheritanceFlags).AppendLine()
    sbAccess.AppendFormat("Propagation: {0}", oAccessRule.PropagationFlags).AppendLine()
    sbAccess.AppendLine(New String("-"c, 25))
  Next

  Return sbAccess.ToString()
End Function

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
Long time software engineer who rambles occasionally about coding, best practices, and other random things.

Comments and Discussions

 
QuestionThanks for the nice demo and one question Pin
Member 22835959-Jan-15 7:21
Member 22835959-Jan-15 7:21 
AnswerRe: Thanks for the nice demo and one question Pin
Adam Zuckerman9-Jan-15 9:40
Adam Zuckerman9-Jan-15 9:40 
GeneralThanks Pin
ledtech325-Feb-13 8:16
ledtech325-Feb-13 8:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.