|
|
|
|
using Alphaleonis.Win32.Filesystem;
|
|
|
|
|
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;
|
|
|
|
|
|
fix(security2): keep a descriptor without an item usable by the cmdlets that take a security descriptor
PowerShell's parameter binder uses the conversion that 3.1 fixed for
every -SecurityDescriptor parameter, so a descriptor that Get-Acl
returns, never meant for these cmdlets, now binds where it used to be
a binding error. Two more consequences of that surfaced:
With the default module setting GetInheritedFrom ($true), Get-NTFSAccess,
Get-NTFSAudit, Get-NTFSOrphanedAccess, and Get-NTFSOrphanedAudit stopped
with the InvalidOperationException that a previous fix added for a
descriptor without an item; a cmdlet user has no parameter to avoid it.
GetFileSystemAccessRules and GetFileSystemAuditRules now treat
getInheritedFrom as false for such a descriptor instead of throwing: the
entries come back with no source, the same as an entry whose source
Windows cannot name.
The private constructor that wraps a descriptor directly marked every
section, including Audit, as read; Get-Acl never reads Audit unless
-Audit is given. This made HasAuditSection wrongly report true, so the
existing #109 check let Get-NTFSAudit go on with no audit data instead
of reporting that the descriptor has none, and let Get-NTFSInheritance
report AuditInheritanceEnabled as a real value instead of null
(unknown). The constructor now includes Audit in the sections only when
the descriptor's binary form actually carries a SACL, the same test
HasSystemAcl already uses.
Get-NTFSOwner, Get-NTFSSimpleAccess, Get-NTFSOrphanedAccess,
Get-NTFSEffectiveAccess, and Add-/Remove-NTFSAccess with such a
descriptor already worked; Set-NTFSSecurityDescriptor already reported
a clear, non-terminating error. A review finding on the earlier fix is
also addressed: two assertions read a property through reflection
instead of a plain PowerShell property access, which silently turns a
throwing getter into $null without a trace and so could not tell a
getter that throws from one that legitimately returns null.
Every existing behavior for an item that is not null is unchanged.
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
|
|
|
// 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. Such an
|
|
|
|
|
// entry gets no source, the same as one whose source Windows could not name: a cmdlet caller has no
|
|
|
|
|
// parameter to turn getInheritedFrom off (the module setting GetInheritedFrom is true by default), so an
|
|
|
|
|
// exception here would stop a cmdlet that a descriptor without an item was never meant to reach.
|
|
|
|
|
var findInheritedFrom = getInheritedFrom && sd.Item != null;
|
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
|
|
|
|
fix(security2): keep a descriptor without an item usable by the cmdlets that take a security descriptor
PowerShell's parameter binder uses the conversion that 3.1 fixed for
every -SecurityDescriptor parameter, so a descriptor that Get-Acl
returns, never meant for these cmdlets, now binds where it used to be
a binding error. Two more consequences of that surfaced:
With the default module setting GetInheritedFrom ($true), Get-NTFSAccess,
Get-NTFSAudit, Get-NTFSOrphanedAccess, and Get-NTFSOrphanedAudit stopped
with the InvalidOperationException that a previous fix added for a
descriptor without an item; a cmdlet user has no parameter to avoid it.
GetFileSystemAccessRules and GetFileSystemAuditRules now treat
getInheritedFrom as false for such a descriptor instead of throwing: the
entries come back with no source, the same as an entry whose source
Windows cannot name.
The private constructor that wraps a descriptor directly marked every
section, including Audit, as read; Get-Acl never reads Audit unless
-Audit is given. This made HasAuditSection wrongly report true, so the
existing #109 check let Get-NTFSAudit go on with no audit data instead
of reporting that the descriptor has none, and let Get-NTFSInheritance
report AuditInheritanceEnabled as a real value instead of null
(unknown). The constructor now includes Audit in the sections only when
the descriptor's binary form actually carries a SACL, the same test
HasSystemAcl already uses.
Get-NTFSOwner, Get-NTFSSimpleAccess, Get-NTFSOrphanedAccess,
Get-NTFSEffectiveAccess, and Add-/Remove-NTFSAccess with such a
descriptor already worked; Set-NTFSSecurityDescriptor already reported
a clear, non-terminating error. A review finding on the earlier fix is
also addressed: two assertions read a property through reflection
instead of a plain PowerShell property access, which silently turns a
throwing getter into $null without a trace and so could not tell a
getter that throws from one that legitimately returns null.
Every existing behavior for an item that is not null is unchanged.
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
|
|
|
if (findInheritedFrom)
|
|
|
|
|
{
|
fix: compare output objects and report InheritedFrom correctly
Equals of FileSystemAccessRule2, FileSystemAuditRule2, and
FileSystemSecurity2 cast its argument to the .NET type, which throws for
the wrapper types themselves: -eq and -contains, and in PowerShell 7 also
Select-Object -Unique and Compare-Object, stopped with an
InvalidCastException. GetHashCode of FileSystemSecurity2 read a field
that is never set and threw a NullReferenceException. Two objects are now
equal when they hold the same entry or descriptor, like the .NET types.
InheritedFrom: Win32.GetInheritedFrom returned the sources of the SACL
whenever the descriptor had one, also for the access entries, and the
callers gave the filtered entries of -ExcludeExplicit the sources of the
first entries of the ACL. Get-NTFSAccess -SecurityDescriptor stopped with
an ArgumentOutOfRangeException for a descriptor with audit entries, as
Get-NTFSSecurityDescriptor reads them in an elevated session. The method
now takes the ACL of the entries, and the callers map the sources before
they filter.
The coverage report of rc6 pointed at both; each test fails without its
fix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
3 weeks ago
|
|
|
inheritedFrom = Win32.GetInheritedFrom(sd.Item, sd.SecurityDescriptor, true);
|
|
|
|
|
}
|
|
|
|
|
|
fix: compare output objects and report InheritedFrom correctly
Equals of FileSystemAccessRule2, FileSystemAuditRule2, and
FileSystemSecurity2 cast its argument to the .NET type, which throws for
the wrapper types themselves: -eq and -contains, and in PowerShell 7 also
Select-Object -Unique and Compare-Object, stopped with an
InvalidCastException. GetHashCode of FileSystemSecurity2 read a field
that is never set and threw a NullReferenceException. Two objects are now
equal when they hold the same entry or descriptor, like the .NET types.
InheritedFrom: Win32.GetInheritedFrom returned the sources of the SACL
whenever the descriptor had one, also for the access entries, and the
callers gave the filtered entries of -ExcludeExplicit the sources of the
first entries of the ACL. Get-NTFSAccess -SecurityDescriptor stopped with
an ArgumentOutOfRangeException for a descriptor with audit entries, as
Get-NTFSSecurityDescriptor reads them in an elevated session. The method
now takes the ACL of the entries, and the callers map the sources before
they filter.
The coverage report of rc6 pointed at both; each test fails without its
fix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
3 weeks 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.
|
|
|
|
|
var aceCounter = 0;
|
|
|
|
|
var acl = !sd.IsFile ?
|
fix: compare output objects and report InheritedFrom correctly
Equals of FileSystemAccessRule2, FileSystemAuditRule2, and
FileSystemSecurity2 cast its argument to the .NET type, which throws for
the wrapper types themselves: -eq and -contains, and in PowerShell 7 also
Select-Object -Unique and Compare-Object, stopped with an
InvalidCastException. GetHashCode of FileSystemSecurity2 read a field
that is never set and threw a NullReferenceException. Two objects are now
equal when they hold the same entry or descriptor, like the .NET types.
InheritedFrom: Win32.GetInheritedFrom returned the sources of the SACL
whenever the descriptor had one, also for the access entries, and the
callers gave the filtered entries of -ExcludeExplicit the sources of the
first entries of the ACL. Get-NTFSAccess -SecurityDescriptor stopped with
an ArgumentOutOfRangeException for a descriptor with audit entries, as
Get-NTFSSecurityDescriptor reads them in an elevated session. The method
now takes the ACL of the entries, and the callers map the sources before
they filter.
The coverage report of rc6 pointed at both; each test fails without its
fix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
3 weeks ago
|
|
|
((DirectorySecurity)sd.SecurityDescriptor).GetAuditRules(true, true, typeof(SecurityIdentifier)) :
|
|
|
|
|
((FileSecurity)sd.SecurityDescriptor).GetAuditRules(true, true, typeof(SecurityIdentifier));
|
|
|
|
|
|
|
|
|
|
foreach (FileSystemAuditRule ace in acl)
|
|
|
|
|
{
|
fix(security2): keep a descriptor without an item usable by the cmdlets that take a security descriptor
PowerShell's parameter binder uses the conversion that 3.1 fixed for
every -SecurityDescriptor parameter, so a descriptor that Get-Acl
returns, never meant for these cmdlets, now binds where it used to be
a binding error. Two more consequences of that surfaced:
With the default module setting GetInheritedFrom ($true), Get-NTFSAccess,
Get-NTFSAudit, Get-NTFSOrphanedAccess, and Get-NTFSOrphanedAudit stopped
with the InvalidOperationException that a previous fix added for a
descriptor without an item; a cmdlet user has no parameter to avoid it.
GetFileSystemAccessRules and GetFileSystemAuditRules now treat
getInheritedFrom as false for such a descriptor instead of throwing: the
entries come back with no source, the same as an entry whose source
Windows cannot name.
The private constructor that wraps a descriptor directly marked every
section, including Audit, as read; Get-Acl never reads Audit unless
-Audit is given. This made HasAuditSection wrongly report true, so the
existing #109 check let Get-NTFSAudit go on with no audit data instead
of reporting that the descriptor has none, and let Get-NTFSInheritance
report AuditInheritanceEnabled as a real value instead of null
(unknown). The constructor now includes Audit in the sections only when
the descriptor's binary form actually carries a SACL, the same test
HasSystemAcl already uses.
Get-NTFSOwner, Get-NTFSSimpleAccess, Get-NTFSOrphanedAccess,
Get-NTFSEffectiveAccess, and Add-/Remove-NTFSAccess with such a
descriptor already worked; Set-NTFSSecurityDescriptor already reported
a clear, non-terminating error. A review finding on the earlier fix is
also addressed: two assertions read a property through reflection
instead of a plain PowerShell property access, which silently turns a
throwing getter into $null without a trace and so could not tell a
getter that throws from one that legitimately returns null.
Every existing behavior for an item that is not null is unchanged.
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
|
|
|
var source = findInheritedFrom && aceCounter < inheritedFrom.Count ? inheritedFrom[aceCounter] : null;
|
fix: compare output objects and report InheritedFrom correctly
Equals of FileSystemAccessRule2, FileSystemAuditRule2, and
FileSystemSecurity2 cast its argument to the .NET type, which throws for
the wrapper types themselves: -eq and -contains, and in PowerShell 7 also
Select-Object -Unique and Compare-Object, stopped with an
InvalidCastException. GetHashCode of FileSystemSecurity2 read a field
that is never set and threw a NullReferenceException. Two objects are now
equal when they hold the same entry or descriptor, like the .NET types.
InheritedFrom: Win32.GetInheritedFrom returned the sources of the SACL
whenever the descriptor had one, also for the access entries, and the
callers gave the filtered entries of -ExcludeExplicit the sources of the
first entries of the ACL. Get-NTFSAccess -SecurityDescriptor stopped with
an ArgumentOutOfRangeException for a descriptor with audit entries, as
Get-NTFSSecurityDescriptor reads them in an elevated session. The method
now takes the ACL of the entries, and the callers map the sources before
they filter.
The coverage report of rc6 pointed at both; each test fails without its
fix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
3 weeks ago
|
|
|
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 <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
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 };
|
fix(security2): keep a descriptor without an item usable by the cmdlets that take a security descriptor
PowerShell's parameter binder uses the conversion that 3.1 fixed for
every -SecurityDescriptor parameter, so a descriptor that Get-Acl
returns, never meant for these cmdlets, now binds where it used to be
a binding error. Two more consequences of that surfaced:
With the default module setting GetInheritedFrom ($true), Get-NTFSAccess,
Get-NTFSAudit, Get-NTFSOrphanedAccess, and Get-NTFSOrphanedAudit stopped
with the InvalidOperationException that a previous fix added for a
descriptor without an item; a cmdlet user has no parameter to avoid it.
GetFileSystemAccessRules and GetFileSystemAuditRules now treat
getInheritedFrom as false for such a descriptor instead of throwing: the
entries come back with no source, the same as an entry whose source
Windows cannot name.
The private constructor that wraps a descriptor directly marked every
section, including Audit, as read; Get-Acl never reads Audit unless
-Audit is given. This made HasAuditSection wrongly report true, so the
existing #109 check let Get-NTFSAudit go on with no audit data instead
of reporting that the descriptor has none, and let Get-NTFSInheritance
report AuditInheritanceEnabled as a real value instead of null
(unknown). The constructor now includes Audit in the sections only when
the descriptor's binary form actually carries a SACL, the same test
HasSystemAcl already uses.
Get-NTFSOwner, Get-NTFSSimpleAccess, Get-NTFSOrphanedAccess,
Get-NTFSEffectiveAccess, and Add-/Remove-NTFSAccess with such a
descriptor already worked; Set-NTFSSecurityDescriptor already reported
a clear, non-terminating error. A review finding on the earlier fix is
also addressed: two assertions read a property through reflection
instead of a plain PowerShell property access, which silently turns a
throwing getter into $null without a trace and so could not tell a
getter that throws from one that legitimately returns null.
Every existing behavior for an item that is not null is unchanged.
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
|
|
|
if (findInheritedFrom && inheritedFrom.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
// Windows names a folder with a trailing backslash; the text for an unknown parent has none.
|
|
|
|
|
ace2.inheritedFrom = string.IsNullOrEmpty(source) ? "" : source.TrimEnd('\\');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|