Question Problem with applying NTFS permissions through DirectorySecurity.

Herman

Well-known member
Joined
Oct 18, 2011
Messages
883
Location
Montreal, QC, CA
Programming Experience
10+
I have been tasked with writing a small tool to automate the creation of TS profiles on our server. After creating the users, groups, and UPN suffix through the domain controller's AD, I have to create a skeleton folder structure for the user, with appropriate permissions. I have the following code, please let me know if you spot the solution... The problem is explained in the comments:

    Public Sub CreateFolders(ByVal domain As String)
        Dim diHosted As New DirectoryInfo("\\" & ServerAddress & "\Hosted")

        Dim diCompany = diHosted.CreateSubdirectory(domain)
        Dim diCommon = diCompany.CreateSubdirectory("Common")
        Dim diProfiles = diCompany.CreateSubdirectory("Profiles")
        Dim diUsers = diCompany.CreateSubdirectory("Users")

        Dim de = GroupPrincipal.FindByIdentity(GetPrincipalContext("OU=Groups,OU=" & domain & ",OU=Hosted,DC=mydomain,DC=com"), domain & "-Security-Group")

        ' This part works fine. The correct permissions are applied and the correct permissions are inherited.
        Dim acl As DirectorySecurity = diCompany.GetAccessControl()
        With acl
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.AppendData, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.CreateDirectories, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.CreateFiles, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.Delete, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.ExecuteFile, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.ListDirectory, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.Modify, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.Read, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.ReadAndExecute, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.ReadAttributes, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.ReadData, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.ReadExtendedAttributes, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.ReadPermissions, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.Synchronize, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.Traverse, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.Write, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.WriteAttributes, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.WriteData, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.WriteExtendedAttributes, AccessControlType.Allow))
        End With
        diCompany.SetAccessControl(acl)

        ' For these subfolders, I need to have only the three permissions listed here for the group. The rest
        ' of the permissions applied above should NOT be inherited here. However I DO need the other inherited
        ' permissions (from the parent`s parent). I know I can protect this ACL from inheriting through
        ' .SetAccessRuleProtection(True, False), but that is no good as I need to keep the inherited permissions
        ' from everyone else except the group represented by de.Sid.
        acl = diProfiles.GetAccessControl()
        With acl
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.AppendData, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.CreateDirectories, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.Traverse, AccessControlType.Allow))
        End With
        diProfiles.SetAccessControl(acl)

        acl = diUsers.GetAccessControl()
        With acl
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.AppendData, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.CreateDirectories, AccessControlType.Allow))
            .AddAccessRule(GetFileSystemAccessRule(de.Sid, FileSystemRights.Traverse, AccessControlType.Allow))
        End With
        diUsers.SetAccessControl(acl)

    End Sub

    Private Function GetFileSystemAccessRule(ByVal sid As Security.Principal.SecurityIdentifier, ByVal right As FileSystemRights, ByVal access As AccessControlType) As FileSystemAccessRule
        Return New FileSystemAccessRule(sid, right, InheritanceFlags.ContainerInherit Or InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)
    End Function
 
Remove InheritanceFlags.ContainerInherit to avoid subfolders from inheriting this rule.
 
That would work, except there are three subfolders under the root, and one of them needs to inherit... I think I found my answer while sifting through some MSDN docs. You cannot inherit only some access rules and not others, it's either all or nothing. What happens when you manually modify the permissions in the properties pane of a folder, and remove an inherited permission, is that ALL the other inherited permissions are recreated on the folder. This is basically what I will have to do through code, I am halfway done correcting it now.

I wish those APIs would have better documentation, between this and the DirectoryServices API I have had a hard time in the last few days just because of lacking docs.
 
There a table of the flags and how they apply here: ACL Propagation Rules
and a graphical view (figure 5) here: Manage Access to Windows Objects with ACLs and the .NET Framework
What happens when you manually modify the permissions in the properties pane of a folder, and remove an inherited permission, is that ALL the other inherited permissions are recreated on the folder.
Think I've seen that, I have not worked much with access permissions myself, only by limited testing.
 
Another thing, you have a lot of overlapping rules there, For example Read includes all the other Read... rules, see FileSystemRights Enumeration (System.Security.AccessControl)
You also missed that it is a flags enumeration, where each flag can be combined to form a single value, so you only need to set one rule with one combined rights value.

As for the "problem", you can solve that by adding a no-inheritance rule to diCompany, adding the same as full inheritance rule to diCommon, and the other limited rule to diProfiles and diUsers.
 
Thanks John. This is the first time I need to play with permissions this deep programmatically, and to be honest I wasn't sure if I could just OR the flags together like I would normally. I did see that some of the flag values overlapped, but I was more concerned with getting a result than refactoring. In any case the issue is already solved. In the end I added .SetAccessRuleProtection(True, False) to diProfile and diUsers, and manually added to them the remaining rules that would have otherwise been inherited. That did the trick and everything is working nicely. I will certainly take your advice when the time for refactoring comes. Now I am up against yet another poorly documented API, to create, link and edit group policies. I think I just figured it out now though, so that should be done by tomorrow morning.

About that, do you know if there is a way to add a RunOnce script to a group policy, kind of like the Logon/Logoff scripts? I need to install a SQL instance automagically the first time any user of a particular UPN suffix logs on to his session.... Got the SQL unattended install script, just need to find some place to run it from... Maybe I'll just add it in as a logon script and have it delete itself when it's done.
 
In the end I added .SetAccessRuleProtection(True, False) to diProfile and diUsers, and manually added to them the remaining rules that would have otherwise been inherited.
That means from now on you will have to micromanage the rules that would otherwise be inherited and controlled from higher level. It is easy to avoid that trouble.
 
Meh the other permissions are really just for owner, local admins, and domain admins. I don't think I'll have to micromanage that much... Besides, that is already how it was ending up when the guy was creating them manually.
 
Back
Top