2

I need to remove certain accounts (like the "Everyone" trustee or some global group that is giving everyone access to a folder) from an ACL on a particular subfolder of a share. I get a DirectorySecurity object, get and loop through the AuthorizationRuleCollection, remove the AccessRule in question from the ACL, and then I call SetAccessControl to apply the changes. Everything works fine if the target folder is small, but if it has a lot of child folders and files, it can take forever to apply the changes (much longer than to just do it manually). I only want to deal with the ACL on the target folder. Is there a way to do this using the .NET DirectorySecurity classes? Or do I have to resort to the Win32 API or some other solution?

Here is a snippet of code. The call to dirInfo.SetAccessControl(dirSec) is where it hangs when the folder size is very large.

DirectoryInfo dirInfo = new DirectoryInfo(path);
DirectorySecurity dirSec = dirInfo.GetAccessControl();
AuthorizationRuleCollection acl = dirSec.GetAccessRules(true, true,     
                                  typeof(System.Security.Principal.NTAccount));
foreach (FileSystemAccessRule ace in acl)
{
    if (groupsToRemove.Contains(ace.IdentityReference.Value))
    {
        dirSec.RemoveAccessRuleSpecific(ace);
        dirInfo.SetAccessControl(dirSec);
    }
}
riQQ
  • 9,878
  • 7
  • 49
  • 66
achaetes
  • 93
  • 1
  • 8

2 Answers2

2
DirectoryInfo dirInfo = new DirectoryInfo(path);
DirectorySecurity dirSec = dirInfo.GetAccessControl();
AuthorizationRuleCollection acl = dirSec.GetAccessRules(true, true,     
                                  typeof(System.Security.Principal.NTAccount));
foreach (FileSystemAccessRule ace in acl)
{
    if (groupsToRemove.Contains(ace.IdentityReference.Value))
    {
        dirSec.RemoveAccessRuleSpecific(ace);
        dirInfo.SetAccessControl(dirSec);
    }
}

In your code, you are applying the updates to the ACL every interation of your loop, this gets very expensive. Have you tried moving dirInfo.SetAccessControl(dirSec); outside the foreach ? This should invoke the SetAccessControl method on your DirectoryInfo object once, applying all the changes in one pass, like this:

foreach (FileSystemAccessRule ace in acl)
{
    if (groupsToRemove.Contains(ace.IdentityReference.Value))
    {
        dirSec.RemoveAccessRuleSpecific(ace);        
    }
}
dirInfo.SetAccessControl(dirSec);
sean_m
  • 1,564
  • 1
  • 12
  • 14
  • 1
    It's been a long time since I first posted this and I'm not working on that project anymore, so sorry I didn't see your answer until now. If I remember right, I wasn't removing a lot of groups (only 2 I believe), so I don't think applying the updates was causing the extreme delay. However, I do think your code is the better way to do it, especially if there were a lot of groups to remove. Thanks! – achaetes Aug 31 '12 at 18:03
1

You have to set the SE_DACL_PROTECTED flag in order to "prevent ACEs set on the DACL of the parent container, and any objects above the parent container in the directory hierarchy, from being applied to the object DACL." This would likely speed up your operation because it would not have to apply it all child objects. Also from MSDN,

Be aware that the SE_DACL_PRESENT flag must be present to set SE_DACL_PROTECTED and SE_SACL_PRESENT must be present to set SE_SACL_PROTECTED.

You then have to use the IADsSecurityDescriptor.Control property to control whether DACLs and SACLs are inherited by the object from its parent container.

More information is available at MSDN for the IADsSecurityDescriptor Interface.

  • Thanks 0A0D, but I don't think this is the answer for my specific issue. I'm using C#, so after reading your answer I added some code to do a check for DirectorySecurity.AreAccessRulesProtected, and I checked one of the folders having the issue. It was already protected, so it is not inheriting from the parent folder. (And if you look at the advanced security settings via the windows GUI, the checkbox "Allow inheritable permissions from the parent to propagate to this object and all child objects..." is not checked.) I really think my issue is due to the large folder size. Any other ideas? – achaetes Jul 21 '11 at 20:18
  • You mean a folder with a large number of files? –  Jul 21 '11 at 20:28
  • Yes, the folder I'm testing with has a total of 100 subfolders and 3672 files giving it a size of 1.87GB. But the folder is protected against inheritance and if I were to manually remove the ACE it only takes a second. – achaetes Jul 21 '11 at 20:44
  • I added the code snippet to my original question, so I could format it nicer. Thanks. – achaetes Jul 21 '11 at 22:08
  • Yes. The path is in the form `\\server\drive$\folder\subfolder`. Appreciate your continued help on this. – achaetes Jul 22 '11 at 15:37