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
Dim sDataDir As String = IO.Path.Combine(IO.Path.GetDirectoryName(Application.ExecutablePath()), "Data")
My.Computer.FileSystem.CreateDirectory(IO.Path.GetDirectoryName(sLogFile))
Dim oACL As Security.AccessControl.DirectorySecurity = IO.Directory.GetAccessControl(IO.Path.GetDirectoryName(sDataDir), Security.AccessControl.AccessControlSections.Access)
Dim oBuiltInUsersSid As New Security.Principal.SecurityIdentifier(Security.Principal.WellKnownSidType.BuiltinUsersSid, Nothing)
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)
oACL.AddAccessRule(oRule)
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