问题
I occasionally migrate some website from one web server to another.
After copying all files from the old server to the new server, it takes me quite some time to get (re)acquainted with which folders or files need to be writable by IIS. (Sounds familiar, by the way ? :) )
I have written a WinForms application that allows me to select a starting directory. The application should (recursively) compare if the security permissions of each file/directory are equal to that of its parent directory.
I want to use this application on the old server to scan for directories with different permissions.
Example: C:\MySites\Uploads does not have the same permissions set as its parent directory.
(This folder was writable for the IIS user 'IUSR', while its parent folder was only readable.)
The application is almost complete in the sense that I manage to traverse all directories and files. I just need to compare their permissions!
Can you please help? Here is an excerpt of where I need your help.
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";
}
The if
is always true, because the DirectorySecurities are never equal. (I understand why that is: reference to different memory allocations ... blah blah.) But what would be the best way to compare the DirectorySecurities?
回答1:
This actually became much more complex while I was working it out, because Windows rights can:
- split up into Allow and Deny
- Fragmented over multiple entries (multiple entries per user per Allow/Deny)
Eventually, this is what I made out of it:
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;
}
回答2:
You cannot use Equals() since this method is inherited from Object. You need to find a identifying attribute on that DirectorySecurity class. I think String GetSecurityDescriptorSddlForm()
should do your job. You can invoke Equals() on that.
Edit: Well sorry, this method needs a parameter for invocation. Try finding another attribute on the DirectorySecurity which is better for comparison.
Edit2: I'm not familar with .NET Security Framework and Right-Management, but something like this should be your approach. You can do != resp: == on FileSystemAccessRule.FileSystemRights because that attribute is an enum (internally an 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;
}
}
}
来源:https://stackoverflow.com/questions/17029638/compare-windows-file-or-folder-permissions