Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

ACLs for File and Directory Access

5.00/5 (1 vote)
19 Feb 2013CPOL2 min read 21.5K  
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)