You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

82 lines
3.7 KiB

10 years ago
using Alphaleonis.Win32.Filesystem;
fix(security2): let the readers handle a descriptor that has no item 3.1 made a FileSystemSecurity2 without an item reachable from a .NET caller (the conversions from FileSecurity and DirectorySecurity), but six sibling call sites still dereferenced the item without checking it first, so a caller who converted a FileSecurity or DirectorySecurity and then read its entries, owner, inheritance, or effective access met a NullReferenceException instead of a usable result. GetFileSystemAccessRules and GetFileSystemAuditRules (the FileSystemSecurity2 overload) now give each returned entry the same null FullName that the descriptor itself reports; asking for the source of an inherited entry (getInheritedFrom) needs the path of the item, so it now throws one clear InvalidOperationException instead, naming the reason, when the descriptor has none. FileSystemOwner and FileSystemInheritanceInfo give a null FullName (and Name) the same way; FileSystemOwner.ToString, which must never return null, gives an empty string instead, since there is no other representation to fall back to. The FileSystemAccessRule2(rule, item) constructor, which EffectiveAccess.GetEffectiveAccess uses to build its result, now accepts a null item the same way, so effective access can be calculated for such a descriptor and the result names no path. Every existing behavior for an item that is not null is unchanged; only a .NET caller that reads such a descriptor can notice the difference, and only for the better: a usable result or a clear error instead of an unrelated NullReferenceException. Public signatures are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com>
1 week ago
using System;
10 years ago
using System.Collections.Generic;
using System.Security.AccessControl;
using System.Security.Principal;
namespace Security2
{
public partial class FileSystemAuditRule2
{
public static IEnumerable<FileSystemAuditRule2> GetFileSystemAuditRules(FileSystemInfo item, bool includeExplicit, bool includeInherited, bool getInheritedFrom = false)
{
var sd = new FileSystemSecurity2(item);
return GetFileSystemAuditRules(sd, includeExplicit, includeInherited, getInheritedFrom);
}
public static IEnumerable<FileSystemAuditRule2> GetFileSystemAuditRules(FileSystemSecurity2 sd, bool includeExplicit, bool includeInherited, bool getInheritedFrom = false)
{
List<FileSystemAuditRule2> aceList = new List<FileSystemAuditRule2>();
List<string> inheritedFrom = null;
if (getInheritedFrom)
{
fix(security2): let the readers handle a descriptor that has no item 3.1 made a FileSystemSecurity2 without an item reachable from a .NET caller (the conversions from FileSecurity and DirectorySecurity), but six sibling call sites still dereferenced the item without checking it first, so a caller who converted a FileSecurity or DirectorySecurity and then read its entries, owner, inheritance, or effective access met a NullReferenceException instead of a usable result. GetFileSystemAccessRules and GetFileSystemAuditRules (the FileSystemSecurity2 overload) now give each returned entry the same null FullName that the descriptor itself reports; asking for the source of an inherited entry (getInheritedFrom) needs the path of the item, so it now throws one clear InvalidOperationException instead, naming the reason, when the descriptor has none. FileSystemOwner and FileSystemInheritanceInfo give a null FullName (and Name) the same way; FileSystemOwner.ToString, which must never return null, gives an empty string instead, since there is no other representation to fall back to. The FileSystemAccessRule2(rule, item) constructor, which EffectiveAccess.GetEffectiveAccess uses to build its result, now accepts a null item the same way, so effective access can be calculated for such a descriptor and the result names no path. Every existing behavior for an item that is not null is unchanged; only a .NET caller that reads such a descriptor can notice the difference, and only for the better: a usable result or a clear error instead of an unrelated NullReferenceException. Public signatures are unchanged. Co-authored-by: Copilot &lt;223556219+Copilot@users.noreply.github.com&gt; Co-authored-by: AI Assistant &lt;ai@example.com&gt;
1 week ago
// The source of an inherited entry is found from the path of the item that the descriptor was read
// from; a descriptor that a caller built directly, such as the conversion from FileSecurity, has none.
if (sd.Item == null)
{
throw new InvalidOperationException(
"Cannot find the source of an inherited entry: this security descriptor has no item, so there " +
"is no path to search from. Pass getInheritedFrom as false, or read the entries from an item.");
}
inheritedFrom = Win32.GetInheritedFrom(sd.Item, sd.SecurityDescriptor, true);
10 years ago
}
// All entries, so that each entry gets the source at its index in the SACL; before 5.0.0-rc6, the entries of
// -ExcludeExplicit got the sources of other entries. The filter follows.
10 years ago
var aceCounter = 0;
var acl = !sd.IsFile ?
((DirectorySecurity)sd.SecurityDescriptor).GetAuditRules(true, true, typeof(SecurityIdentifier)) :
((FileSecurity)sd.SecurityDescriptor).GetAuditRules(true, true, typeof(SecurityIdentifier));
10 years ago
foreach (FileSystemAuditRule ace in acl)
{
var source = getInheritedFrom && aceCounter < inheritedFrom.Count ? inheritedFrom[aceCounter] : null;
aceCounter++;
if (ace.IsInherited ? !includeInherited : !includeExplicit)
{
continue;
}
fix(security2): let the readers handle a descriptor that has no item 3.1 made a FileSystemSecurity2 without an item reachable from a .NET caller (the conversions from FileSecurity and DirectorySecurity), but six sibling call sites still dereferenced the item without checking it first, so a caller who converted a FileSecurity or DirectorySecurity and then read its entries, owner, inheritance, or effective access met a NullReferenceException instead of a usable result. GetFileSystemAccessRules and GetFileSystemAuditRules (the FileSystemSecurity2 overload) now give each returned entry the same null FullName that the descriptor itself reports; asking for the source of an inherited entry (getInheritedFrom) needs the path of the item, so it now throws one clear InvalidOperationException instead, naming the reason, when the descriptor has none. FileSystemOwner and FileSystemInheritanceInfo give a null FullName (and Name) the same way; FileSystemOwner.ToString, which must never return null, gives an empty string instead, since there is no other representation to fall back to. The FileSystemAccessRule2(rule, item) constructor, which EffectiveAccess.GetEffectiveAccess uses to build its result, now accepts a null item the same way, so effective access can be calculated for such a descriptor and the result names no path. Every existing behavior for an item that is not null is unchanged; only a .NET caller that reads such a descriptor can notice the difference, and only for the better: a usable result or a clear error instead of an unrelated NullReferenceException. Public signatures are unchanged. Co-authored-by: Copilot &lt;223556219+Copilot@users.noreply.github.com&gt; Co-authored-by: AI Assistant &lt;ai@example.com&gt;
1 week ago
// sd.FullName, not sd.Item.FullName: null without an item instead of a NullReferenceException.
var ace2 = new FileSystemAuditRule2(ace) { FullName = sd.FullName, InheritanceEnabled = !sd.SecurityDescriptor.AreAuditRulesProtected };
if (getInheritedFrom && inheritedFrom.Count > 0)
10 years ago
{
// Windows names a folder with a trailing backslash; the text for an unknown parent has none.
ace2.inheritedFrom = string.IsNullOrEmpty(source) ? "" : source.TrimEnd('\\');
10 years ago
}
aceList.Add(ace2);
}
return aceList;
}
public static IEnumerable<FileSystemAuditRule2> GetFileSystemAuditRules(string path, bool includeExplicit, bool includeInherited)
{
if (File.Exists(path))
{
var item = new FileInfo(path);
return GetFileSystemAuditRules(item, includeExplicit, includeInherited);
}
else
{
var item = new DirectoryInfo(path);
return GetFileSystemAuditRules(item, includeExplicit, includeInherited);
}
}
}
}