【问题标题】:compare windows file (or folder) permissions比较windows文件(或文件夹)权限
【发布时间】:2013-06-06 10:46:02
【问题描述】:

我偶尔会将一些网站从一台网络服务器迁移到另一台。

将所有文件从旧服务器复制到新服务器后,我需要很长时间才能(重新)了解哪些文件夹或文件需要由 IIS 写入。 (顺便说一句,听起来很熟悉?:))

我编写了一个允许我选择起始目录的 WinForms 应用程序。应用程序应该(递归地)比较每个文件/目录的安全权限是否等于其父目录的安全权限。

我想在旧服务器上使用这个应用程序来扫描具有不同权限的目录。

示例: C:\MySites\Uploads does not have the same permissions set as its parent directory.(此文件夹对 IIS 用户“IUSR”是可写的,而其父文件夹只能读取。)

在我设法遍历所有目录和文件的意义上,该应用程序几乎完成我只需要比较他们的权限

你能帮忙吗?这是我需要你帮助的部分摘录。

string results = "";

string parentFolderPath = "c:\\someParentDir";
string childItemPath = "c:\\someParentDir\\SomeChildDir.ext";

DirectorySecurity parentFolderAccessControl = Directory.GetAccessControl(parentFolderPath);
DirectorySecurity childItemAccessControl = Directory.GetAccessControl(childItemPath);

if (!parentFolderAccessControl.Equals(childItemAccessControl)) // <-- D'oh here
{
    results += childItemPath + " does not have the same permissions set as its parent directory.\n";
}

if 始终为真,因为 DirectorySecurity 永远不会相等。 (我明白为什么会这样:引用不同的内存分配......等等等等。)但是比较 DirectorySecurities 的最佳方法是什么?

【问题讨论】:

  • 我认为这个答案可能会对您有所帮助。 stackoverflow.com/a/1281638/1181408 本质上,您需要在 DirectorySecurity 对象上调用 GetAccessRules,然后遍历生成的集合。
  • @cgotberg 这听起来相当昂贵。获取两个集合。检查 collection1 中的用户是否存在于 collection2 和其他方式中。然后 foreach 用户检查访问是否相等。这正是我的出发点,但我希望这里有人有更好的解决方案。
  • 我认为它很昂贵,但在这个偶尔需要迁移代码的概念中,它可能并不重要。您可以使用这个通用的 .net 比较对象代码来进行深度比较,这可能与以往一样昂贵。 comparenetobjects.codeplex.com
  • @cgotberg 我最终只是这样做了。也许您对我在下面自己的答案中粘贴的代码有一些反馈

标签: c# windows file-permissions


【解决方案1】:

在我解决这个问题时,这实际上变得更加复杂,因为 Windows 权限可以:

  • 分为允许和拒绝
  • 分散在多个条目上(每个用户每个允许/拒绝多个条目)

最终,这就是我做出来的:

private bool compareAccessControls(
    DirectorySecurity parentAccessControl,
    DirectorySecurity childAccessControl,
    out Dictionary<IdentityReference, FileSystemRights> accessAllowRulesGainedByChild,
    out Dictionary<IdentityReference, FileSystemRights> accessDenyRulesGainedByChild,
    out Dictionary<IdentityReference, FileSystemRights> accessAllowRulesGainedByParent,
    out Dictionary<IdentityReference, FileSystemRights> accessDenyRulesGainedByParent
)
{
    // combine parent access rules

    Dictionary<IdentityReference, FileSystemRights> combinedParentAccessAllowRules = new Dictionary<IdentityReference, FileSystemRights>();
    Dictionary<IdentityReference, FileSystemRights> combinedParentAccessDenyRules = new Dictionary<IdentityReference, FileSystemRights>();
    foreach (FileSystemAccessRule parentAccessRule in parentAccessControl.GetAccessRules(true, true, typeof(NTAccount)))
    {
        if (parentAccessRule.AccessControlType == AccessControlType.Allow)
            if (combinedParentAccessAllowRules.ContainsKey(parentAccessRule.IdentityReference))
                combinedParentAccessAllowRules[parentAccessRule.IdentityReference] = combinedParentAccessAllowRules[parentAccessRule.IdentityReference] | parentAccessRule.FileSystemRights;
            else
                combinedParentAccessAllowRules.Add(parentAccessRule.IdentityReference, parentAccessRule.FileSystemRights);
        else
            if (combinedParentAccessDenyRules.ContainsKey(parentAccessRule.IdentityReference))
                combinedParentAccessDenyRules[parentAccessRule.IdentityReference] = combinedParentAccessDenyRules[parentAccessRule.IdentityReference] | parentAccessRule.FileSystemRights;
            else
                combinedParentAccessDenyRules.Add(parentAccessRule.IdentityReference, parentAccessRule.FileSystemRights);
    }

    // combine child access rules

    Dictionary<IdentityReference, FileSystemRights> combinedChildAccessAllowRules = new Dictionary<IdentityReference, FileSystemRights>();
    Dictionary<IdentityReference, FileSystemRights> combinedChildAccessDenyRules = new Dictionary<IdentityReference, FileSystemRights>();
    foreach (FileSystemAccessRule childAccessRule in childAccessControl.GetAccessRules(true, true, typeof(NTAccount)))
    {
        if (childAccessRule.AccessControlType == AccessControlType.Allow)
            if (combinedChildAccessAllowRules.ContainsKey(childAccessRule.IdentityReference))
                combinedChildAccessAllowRules[childAccessRule.IdentityReference] = combinedChildAccessAllowRules[childAccessRule.IdentityReference] | childAccessRule.FileSystemRights;
            else
                combinedChildAccessAllowRules.Add(childAccessRule.IdentityReference, childAccessRule.FileSystemRights);
        else
            if (combinedChildAccessDenyRules.ContainsKey(childAccessRule.IdentityReference))
                combinedChildAccessDenyRules[childAccessRule.IdentityReference] = combinedChildAccessDenyRules[childAccessRule.IdentityReference] | childAccessRule.FileSystemRights;
            else
                combinedChildAccessDenyRules.Add(childAccessRule.IdentityReference, childAccessRule.FileSystemRights);
    }

    // compare combined rules

    accessAllowRulesGainedByChild = new Dictionary<IdentityReference, FileSystemRights>();
    foreach (KeyValuePair<IdentityReference, FileSystemRights> combinedChildAccessAllowRule in combinedChildAccessAllowRules)
    {
        if (combinedParentAccessAllowRules.ContainsKey(combinedChildAccessAllowRule.Key))
        {
            FileSystemRights accessAllowRuleGainedByChild = combinedChildAccessAllowRule.Value & ~combinedParentAccessAllowRules[combinedChildAccessAllowRule.Key];
            if (accessAllowRuleGainedByChild != default(FileSystemRights))
                accessAllowRulesGainedByChild.Add(combinedChildAccessAllowRule.Key, accessAllowRuleGainedByChild);
        }
        else
        {
            accessAllowRulesGainedByChild.Add(combinedChildAccessAllowRule.Key, combinedChildAccessAllowRule.Value);
        }
    }

    accessDenyRulesGainedByChild = new Dictionary<IdentityReference, FileSystemRights>();
    foreach (KeyValuePair<IdentityReference, FileSystemRights> combinedChildAccessDenyRule in combinedChildAccessDenyRules)
    {
        if (combinedParentAccessDenyRules.ContainsKey(combinedChildAccessDenyRule.Key))
        {
            FileSystemRights accessDenyRuleGainedByChild = combinedChildAccessDenyRule.Value & ~combinedParentAccessDenyRules[combinedChildAccessDenyRule.Key];
            if (accessDenyRuleGainedByChild != default(FileSystemRights))
                accessDenyRulesGainedByChild.Add(combinedChildAccessDenyRule.Key, accessDenyRuleGainedByChild);
        }
        else
        {
            accessDenyRulesGainedByChild.Add(combinedChildAccessDenyRule.Key, combinedChildAccessDenyRule.Value);
        }
    }

    accessAllowRulesGainedByParent = new Dictionary<IdentityReference, FileSystemRights>();
    foreach (KeyValuePair<IdentityReference, FileSystemRights> combinedParentAccessAllowRule in combinedParentAccessAllowRules)
    {
        if (combinedChildAccessAllowRules.ContainsKey(combinedParentAccessAllowRule.Key))
        {
            FileSystemRights accessAllowRuleGainedByParent = combinedParentAccessAllowRule.Value & ~combinedChildAccessAllowRules[combinedParentAccessAllowRule.Key];
            if (accessAllowRuleGainedByParent != default(FileSystemRights))
                accessAllowRulesGainedByParent.Add(combinedParentAccessAllowRule.Key, accessAllowRuleGainedByParent);
        }
        else
        {
            accessAllowRulesGainedByParent.Add(combinedParentAccessAllowRule.Key, combinedParentAccessAllowRule.Value);
        }
    }

    accessDenyRulesGainedByParent = new Dictionary<IdentityReference, FileSystemRights>();
    foreach (KeyValuePair<IdentityReference, FileSystemRights> combinedParentAccessDenyRule in combinedParentAccessDenyRules)
    {
        if (combinedChildAccessDenyRules.ContainsKey(combinedParentAccessDenyRule.Key))
        {
            FileSystemRights accessDenyRuleGainedByParent = combinedParentAccessDenyRule.Value & ~combinedChildAccessDenyRules[combinedParentAccessDenyRule.Key];
            if (accessDenyRuleGainedByParent != default(FileSystemRights))
                accessDenyRulesGainedByParent.Add(combinedParentAccessDenyRule.Key, accessDenyRuleGainedByParent);
        }
        else
        {
            accessDenyRulesGainedByParent.Add(combinedParentAccessDenyRule.Key, combinedParentAccessDenyRule.Value);
        }
    }

    if (accessAllowRulesGainedByChild.Count > 0 || accessDenyRulesGainedByChild.Count > 0 || accessAllowRulesGainedByParent.Count > 0 || accessDenyRulesGainedByParent.Count > 0)
        return false;
    else
        return true;
}

【讨论】:

  • 一开始我觉得这似乎有点荒谬,但我最终还是使用了它。谢谢!
  • 顺便说一句,我将它作为 FileSystemSecurity 的扩展方法,以便它可以用于文件和目录。我还添加了参数,以便可以更改 GetAccessRules 调用的 includeExplicit 和 includeInherited 参数。 public static bool IsEqual(this FileSystemSecurity sourceAccessControl, FileSystemSecurity destAccessControl, bool includeExplicit, bool includeInherited)
【解决方案2】:

你不能使用 Equals() 因为这个方法是从 Object 继承的。 您需要在该 DirectorySecurity 类上找到一个标识属性。我想 字符串 GetSecurityDescriptorSddlForm()

应该做你的工作。你可以调用 Equals() 。

编辑:对不起,这个方法需要一个参数来调用。尝试在 DirectorySecurity 上找到另一个更便于比较的属性。

Edit2:我不熟悉 .NET 安全框架和权限管理,但您应该采用类似的方法。您可以在 FileSystemAccessRule.FileSystemRights 上执行 != resp: == 因为该属性是一个枚举(内部是一个 int)。

ArrayList notIdenticalList = new ArrayList(); 

        DirectorySecurity parentFolderAccessControl = Directory.GetAccessControl(null);
        DirectorySecurity childItemAccessControl = Directory.GetAccessControl(null);
        foreach (FileSystemAccessRule parentRule in parentFolderAccessControl.GetAccessRules(true, true, typeof(NTAccount)))
        {
            foreach (FileSystemAccessRule childRule in childItemAccessControl.GetAccessRules(true, true, typeof(NTAccount)))
            {
                if (parentRule.FileSystemRights != childRule.FileSystemRights)
                {
                    // add to not identical-list
                    notIdenticalList.Add(fileToAdd...);
                    break;
                }
            }
        }

【讨论】:

  • 该功能是否对列出具有特定访问权限的用户帐户的顺序敏感?还是它总是首先对用户帐户进行排序?示例:假设系统帐户和 IUSR 帐户都具有对目录及其父目录的写入权限。但是对于第一个目录,首先列出系统帐户,对于父目录,首先列出 IUSR...?
  • 你的意思是Equals()还是什么函数?
  • 没有。我的意思是你建议的功能。在有效权限相同的情况下,字符串是否可以不同(不同的用户帐户顺序)。
  • 对不起,我请假了 :) ... 感谢您的帮助!有趣的是,在看到您的编辑之前,我开始使用 SecurityIdentifier 而不是 NTAccount。你知道最大的不同吗?两者都应该在任何 Windows-XP 和更新的机器上工作吗?
  • 顺便说一下,如果所有用户都拥有相同的权限,您当前的代码现在会检查这两个文件。例如。用户“System”拥有文件夹“A”的所有权限,而用户“Somebody”仅拥有文件夹“B”的读取权限。 ==> notIdenticalList ...但我可以解决这个问题。
猜你喜欢
  • 1970-01-01
  • 2011-12-27
  • 1970-01-01
  • 2014-08-24
  • 2016-03-20
  • 1970-01-01
  • 2011-08-12
相关资源
最近更新 更多