ACLs for File and Directory Access





5.00/5 (1 vote)
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.
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:
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:
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