|
|
|
|
using Alphaleonis.Win32.Filesystem;
|
|
|
|
|
using System.Security.AccessControl;
|
|
|
|
|
using System.Security.Principal;
|
|
|
|
|
|
|
|
|
|
namespace Security2
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
public class FileSystemInheritanceInfo
|
|
|
|
|
{
|
|
|
|
|
private enum InheritanceScope
|
|
|
|
|
{
|
|
|
|
|
Access,
|
|
|
|
|
Audit
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private FileSystemInfo item;
|
|
|
|
|
private bool? accessInheritanceEnabled;
|
|
|
|
|
private bool? auditInheritanceEnabled;
|
|
|
|
|
|
|
|
|
|
public FileSystemInfo Item
|
|
|
|
|
{
|
|
|
|
|
get { return item; }
|
|
|
|
|
set { item = value; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool? AccessInheritanceEnabled
|
|
|
|
|
{
|
|
|
|
|
get { return accessInheritanceEnabled; }
|
|
|
|
|
set { accessInheritanceEnabled = value; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool? AuditInheritanceEnabled
|
|
|
|
|
{
|
|
|
|
|
get { return auditInheritanceEnabled; }
|
|
|
|
|
set { auditInheritanceEnabled = value; }
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
// Null without an item, such as for a descriptor that a conversion from FileSecurity built directly, instead
|
|
|
|
|
// of a NullReferenceException.
|
|
|
|
|
public string FullName { get { return item != null ? item.FullName : 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
|
|
|
public string Name { get { return item != null ? Path.GetFileName(item.FullName) : null; } }
|
|
|
|
|
|
|
|
|
|
private FileSystemInheritanceInfo(FileSystemInfo item, bool? accessInheritanceEnabled, bool? auditInheritanceEnabled)
|
|
|
|
|
{
|
|
|
|
|
this.item = item;
|
|
|
|
|
this.accessInheritanceEnabled = accessInheritanceEnabled;
|
|
|
|
|
this.auditInheritanceEnabled = auditInheritanceEnabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region GetFileSystemInheritanceInfo
|
|
|
|
|
public static FileSystemInheritanceInfo GetFileSystemInheritanceInfo(string path)
|
|
|
|
|
{
|
|
|
|
|
var item = new FileInfo(path);
|
|
|
|
|
return GetFileSystemInheritanceInfo(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static FileSystemInheritanceInfo GetFileSystemInheritanceInfo(FileSystemInfo item)
|
|
|
|
|
{
|
fix: drive roots, audit descriptors, -WhatIf conflicts, and small items
- #41: for the root of a drive, the cmdlets read and changed the security
descriptor of the drive, a device object. FileSystemSecurity2 now routes
drive roots through the path-based AlphaFS methods, which keep the
trailing backslash; the removal and inheritance helpers use it too.
- #109: Add-, Remove-, and Clear-NTFSAudit report a security descriptor
without the audit entries like Get-NTFSAudit, through one helper, and
Get-NTFSEffectiveAccess names the cause that Windows reported instead
of a missing Security privilege.
- #108: Copy-Item2 and Move-Item2 check the destination only for an
operation that runs; with -WhatIf, a verbose message names the conflict.
- #111: Disable-Privileges skips the privileges that the token doesn't
hold, the privilege messages are spelled right, and Get-FileHash2
declares the type name of its objects; 05-Releasing.md documents the
release metadata tests.
- rc3 review leftovers: Remove-NTFSAudit writes nothing for an item
without a SACL, the owner retry of Set-NTFSSecurityDescriptor restores
the previous owner in a finally block and keeps an owner that the
descriptor sets, and FileSystemSecurity2.Write with another item writes
only the sections that were read.
Each fix has a test that failed first, in Windows PowerShell 5.1 and
PowerShell 7; writing a drive root was checked once on a temporary VHD.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
bool? areAuditRulesProtected = null;
|
|
|
|
|
|
fix: drive roots, audit descriptors, -WhatIf conflicts, and small items
- #41: for the root of a drive, the cmdlets read and changed the security
descriptor of the drive, a device object. FileSystemSecurity2 now routes
drive roots through the path-based AlphaFS methods, which keep the
trailing backslash; the removal and inheritance helpers use it too.
- #109: Add-, Remove-, and Clear-NTFSAudit report a security descriptor
without the audit entries like Get-NTFSAudit, through one helper, and
Get-NTFSEffectiveAccess names the cause that Windows reported instead
of a missing Security privilege.
- #108: Copy-Item2 and Move-Item2 check the destination only for an
operation that runs; with -WhatIf, a verbose message names the conflict.
- #111: Disable-Privileges skips the privileges that the token doesn't
hold, the privilege messages are spelled right, and Get-FileHash2
declares the type name of its objects; 05-Releasing.md documents the
release metadata tests.
- rc3 review leftovers: Remove-NTFSAudit writes nothing for an item
without a SACL, the owner retry of Set-NTFSSecurityDescriptor restores
the previous owner in a finally block and keeps an owner that the
descriptor sets, and FileSystemSecurity2.Write with another item writes
only the sections that were read.
Each fix has a test that failed first, in Windows PowerShell 5.1 and
PowerShell 7; writing a drive root was checked once on a temporary VHD.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
var areAccessRulesProtected = FileSystemSecurity2.GetSecurity(item, AccessControlSections.Access).AreAccessRulesProtected;
|
|
|
|
|
|
fix: drive roots, audit descriptors, -WhatIf conflicts, and small items
- #41: for the root of a drive, the cmdlets read and changed the security
descriptor of the drive, a device object. FileSystemSecurity2 now routes
drive roots through the path-based AlphaFS methods, which keep the
trailing backslash; the removal and inheritance helpers use it too.
- #109: Add-, Remove-, and Clear-NTFSAudit report a security descriptor
without the audit entries like Get-NTFSAudit, through one helper, and
Get-NTFSEffectiveAccess names the cause that Windows reported instead
of a missing Security privilege.
- #108: Copy-Item2 and Move-Item2 check the destination only for an
operation that runs; with -WhatIf, a verbose message names the conflict.
- #111: Disable-Privileges skips the privileges that the token doesn't
hold, the privilege messages are spelled right, and Get-FileHash2
declares the type name of its objects; 05-Releasing.md documents the
release metadata tests.
- rc3 review leftovers: Remove-NTFSAudit writes nothing for an item
without a SACL, the owner retry of Set-NTFSSecurityDescriptor restores
the previous owner in a finally block and keeps an owner that the
descriptor sets, and FileSystemSecurity2.Write with another item writes
only the sections that were read.
Each fix has a test that failed first, in Windows PowerShell 5.1 and
PowerShell 7; writing a drive root was checked once on a temporary VHD.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
areAuditRulesProtected = FileSystemSecurity2.GetSecurity(item, AccessControlSections.Audit).AreAuditRulesProtected;
|
|
|
|
|
}
|
fix: drive roots, audit descriptors, -WhatIf conflicts, and small items
- #41: for the root of a drive, the cmdlets read and changed the security
descriptor of the drive, a device object. FileSystemSecurity2 now routes
drive roots through the path-based AlphaFS methods, which keep the
trailing backslash; the removal and inheritance helpers use it too.
- #109: Add-, Remove-, and Clear-NTFSAudit report a security descriptor
without the audit entries like Get-NTFSAudit, through one helper, and
Get-NTFSEffectiveAccess names the cause that Windows reported instead
of a missing Security privilege.
- #108: Copy-Item2 and Move-Item2 check the destination only for an
operation that runs; with -WhatIf, a verbose message names the conflict.
- #111: Disable-Privileges skips the privileges that the token doesn't
hold, the privilege messages are spelled right, and Get-FileHash2
declares the type name of its objects; 05-Releasing.md documents the
release metadata tests.
- rc3 review leftovers: Remove-NTFSAudit writes nothing for an item
without a SACL, the owner retry of Set-NTFSSecurityDescriptor restores
the previous owner in a finally block and keeps an owner that the
descriptor sets, and FileSystemSecurity2.Write with another item writes
only the sections that were read.
Each fix has a test that failed first, in Windows PowerShell 5.1 and
PowerShell 7; writing a drive root was checked once on a temporary VHD.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
catch (System.IO.IOException)
|
|
|
|
|
{
|
fix: drive roots, audit descriptors, -WhatIf conflicts, and small items
- #41: for the root of a drive, the cmdlets read and changed the security
descriptor of the drive, a device object. FileSystemSecurity2 now routes
drive roots through the path-based AlphaFS methods, which keep the
trailing backslash; the removal and inheritance helpers use it too.
- #109: Add-, Remove-, and Clear-NTFSAudit report a security descriptor
without the audit entries like Get-NTFSAudit, through one helper, and
Get-NTFSEffectiveAccess names the cause that Windows reported instead
of a missing Security privilege.
- #108: Copy-Item2 and Move-Item2 check the destination only for an
operation that runs; with -WhatIf, a verbose message names the conflict.
- #111: Disable-Privileges skips the privileges that the token doesn't
hold, the privilege messages are spelled right, and Get-FileHash2
declares the type name of its objects; 05-Releasing.md documents the
release metadata tests.
- rc3 review leftovers: Remove-NTFSAudit writes nothing for an item
without a SACL, the owner retry of Set-NTFSSecurityDescriptor restores
the previous owner in a finally block and keeps an owner that the
descriptor sets, and FileSystemSecurity2.Write with another item writes
only the sections that were read.
Each fix has a test that failed first, in Windows PowerShell 5.1 and
PowerShell 7; writing a drive root was checked once on a temporary VHD.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
//log that the security privilege is missing
|
|
|
|
|
}
|
fix: drive roots, audit descriptors, -WhatIf conflicts, and small items
- #41: for the root of a drive, the cmdlets read and changed the security
descriptor of the drive, a device object. FileSystemSecurity2 now routes
drive roots through the path-based AlphaFS methods, which keep the
trailing backslash; the removal and inheritance helpers use it too.
- #109: Add-, Remove-, and Clear-NTFSAudit report a security descriptor
without the audit entries like Get-NTFSAudit, through one helper, and
Get-NTFSEffectiveAccess names the cause that Windows reported instead
of a missing Security privilege.
- #108: Copy-Item2 and Move-Item2 check the destination only for an
operation that runs; with -WhatIf, a verbose message names the conflict.
- #111: Disable-Privileges skips the privileges that the token doesn't
hold, the privilege messages are spelled right, and Get-FileHash2
declares the type name of its objects; 05-Releasing.md documents the
release metadata tests.
- rc3 review leftovers: Remove-NTFSAudit writes nothing for an item
without a SACL, the owner retry of Set-NTFSSecurityDescriptor restores
the previous owner in a finally block and keeps an owner that the
descriptor sets, and FileSystemSecurity2.Write with another item writes
only the sections that were read.
Each fix has a test that failed first, in Windows PowerShell 5.1 and
PowerShell 7; writing a drive root was checked once on a temporary VHD.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
|
|
|
|
|
return new FileSystemInheritanceInfo(item, !areAccessRulesProtected, !areAuditRulesProtected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static FileSystemInheritanceInfo GetFileSystemInheritanceInfo(FileSystemSecurity2 sd)
|
|
|
|
|
{
|
|
|
|
|
// Like for an item, the audit state is unknown when the SACL was not read.
|
|
|
|
|
bool? auditInheritanceEnabled = null;
|
|
|
|
|
if (sd.HasAuditSection)
|
|
|
|
|
{
|
|
|
|
|
auditInheritanceEnabled = !sd.SecurityDescriptor.AreAuditRulesProtected;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new FileSystemInheritanceInfo(sd.Item, !sd.SecurityDescriptor.AreAccessRulesProtected, auditInheritanceEnabled);
|
|
|
|
|
}
|
|
|
|
|
#endregion GetFileSystemInheritanceInfo
|
|
|
|
|
|
|
|
|
|
#region Enable / DisableInheritance internal
|
fix: change the audit inheritance of items without audit entries
Enable-NTFSAuditInheritance, Disable-NTFSAuditInheritance, and
Set-NTFSInheritance -AuditInheritanceEnabled failed with "(5) Access is
denied" for a file or folder without a SACL, also elevated with the
Security privilege. The cmdlets read only the audit section and changed
the flag that disables or enables audit inheritance. AlphaFS writes that
flag only together with a SACL, so it wrote no section at all, which
Windows denies; the retry as owner repeated the same write. An empty SACL
is now added first, but only to a descriptor that was read with its SACL.
The elevated CI runs of #100 to #106 showed this through the test of an
omitted -AccessInheritanceEnabled. From #104 on, the test that keeps the
inherited entries of a security descriptor failed as well: elevated,
Get-NTFSSecurityDescriptor reads the SACL, and Windows then returns a DACL
that isn't in the auto-inherit format, such as that of a file in the temp
folder of the user, without its inherited flags. The test now reads the
access section only and checks that the descriptor has inherited entries.
Tests: five cases for items without audit entries, red with "Access is
denied" before the fix; the test that keeps the explicit audit entries now
checks the errors and the inheritance state of both calls; a test checks
that a descriptor read without its audit entries gets no SACL, which would
replace the audit entries of the item when it is written.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
// An item without audit entries can have no SACL at all. AlphaFS writes the flag that disables or enables
|
|
|
|
|
// audit inheritance only together with a SACL, and a write without any section is denied: (5) Access is
|
|
|
|
|
// denied. The empty SACL is added only to a descriptor that was read with its SACL, so that writing it can't
|
|
|
|
|
// remove audit entries.
|
|
|
|
|
private static void AddMissingSystemAcl(FileSystemSecurity2 sd)
|
|
|
|
|
{
|
|
|
|
|
if (!sd.HasAuditSection)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rawDescriptor = new RawSecurityDescriptor(sd.SecurityDescriptor.GetSecurityDescriptorBinaryForm(), 0);
|
|
|
|
|
if (rawDescriptor.SystemAcl != null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rawDescriptor.SystemAcl = new RawAcl(GenericAcl.AclRevision, 0);
|
|
|
|
|
rawDescriptor.SetFlags(rawDescriptor.ControlFlags | ControlFlags.SystemAclPresent);
|
|
|
|
|
var binaryForm = new byte[rawDescriptor.BinaryLength];
|
|
|
|
|
rawDescriptor.GetBinaryForm(binaryForm, 0);
|
|
|
|
|
sd.SecurityDescriptor.SetSecurityDescriptorBinaryForm(binaryForm, AccessControlSections.Audit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void EnableInheritance(FileSystemSecurity2 sd, bool removeExplicitAccessRules, InheritanceScope scope)
|
|
|
|
|
{
|
fix: change the audit inheritance of items without audit entries
Enable-NTFSAuditInheritance, Disable-NTFSAuditInheritance, and
Set-NTFSInheritance -AuditInheritanceEnabled failed with "(5) Access is
denied" for a file or folder without a SACL, also elevated with the
Security privilege. The cmdlets read only the audit section and changed
the flag that disables or enables audit inheritance. AlphaFS writes that
flag only together with a SACL, so it wrote no section at all, which
Windows denies; the retry as owner repeated the same write. An empty SACL
is now added first, but only to a descriptor that was read with its SACL.
The elevated CI runs of #100 to #106 showed this through the test of an
omitted -AccessInheritanceEnabled. From #104 on, the test that keeps the
inherited entries of a security descriptor failed as well: elevated,
Get-NTFSSecurityDescriptor reads the SACL, and Windows then returns a DACL
that isn't in the auto-inherit format, such as that of a file in the temp
folder of the user, without its inherited flags. The test now reads the
access section only and checks that the descriptor has inherited entries.
Tests: five cases for items without audit entries, red with "Access is
denied" before the fix; the test that keeps the explicit audit entries now
checks the errors and the inheritance state of both calls; a test checks
that a descriptor read without its audit entries gets no SACL, which would
replace the audit entries of the item when it is written.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
if (scope == InheritanceScope.Audit)
|
|
|
|
|
{
|
|
|
|
|
AddMissingSystemAcl(sd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sd.IsFile)
|
|
|
|
|
{
|
|
|
|
|
if (scope == InheritanceScope.Access)
|
|
|
|
|
{
|
|
|
|
|
sd.SecurityDescriptor.SetAccessRuleProtection(false, false);
|
|
|
|
|
|
|
|
|
|
//if RemoveExplicitAccessRules is set
|
|
|
|
|
if (removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
//remove all explicitly set ACEs from the item
|
|
|
|
|
foreach (FileSystemAccessRule ace in ((FileSecurity)sd.SecurityDescriptor).GetAccessRules(true, false, typeof(SecurityIdentifier)))
|
|
|
|
|
{
|
|
|
|
|
((FileSecurity)sd.SecurityDescriptor).RemoveAccessRule(ace);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sd.SecurityDescriptor.SetAuditRuleProtection(false, false);
|
|
|
|
|
|
|
|
|
|
//if RemoveExplicitAccessRules is set
|
|
|
|
|
if (removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
//remove all explicitly set ACEs from the item
|
|
|
|
|
foreach (FileSystemAuditRule ace in ((FileSecurity)sd.SecurityDescriptor).GetAuditRules(true, false, typeof(SecurityIdentifier)))
|
|
|
|
|
{
|
|
|
|
|
((FileSecurity)sd.SecurityDescriptor).RemoveAuditRule(ace);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (scope == InheritanceScope.Access)
|
|
|
|
|
{
|
|
|
|
|
((DirectorySecurity)sd.SecurityDescriptor).SetAccessRuleProtection(false, false);
|
|
|
|
|
|
|
|
|
|
//if RemoveExplicitAccessRules is set
|
|
|
|
|
if (removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
//remove all explicitly set ACEs from the item
|
|
|
|
|
foreach (FileSystemAccessRule ace in ((DirectorySecurity)sd.SecurityDescriptor).GetAccessRules(true, false, typeof(SecurityIdentifier)))
|
|
|
|
|
{
|
|
|
|
|
((DirectorySecurity)sd.SecurityDescriptor).RemoveAccessRule(ace);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
((DirectorySecurity)sd.SecurityDescriptor).SetAuditRuleProtection(false, false);
|
|
|
|
|
|
|
|
|
|
//if RemoveExplicitAccessRules is set
|
|
|
|
|
if (removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
//remove all explicitly set ACEs from the item
|
|
|
|
|
foreach (FileSystemAuditRule ace in ((DirectorySecurity)sd.SecurityDescriptor).GetAuditRules(true, false, typeof(SecurityIdentifier)))
|
|
|
|
|
{
|
|
|
|
|
((DirectorySecurity)sd.SecurityDescriptor).RemoveAuditRule(ace);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void DisableInheritance(FileSystemSecurity2 sd, bool removeInheritedAccessRules, InheritanceScope scope)
|
|
|
|
|
{
|
fix: change the audit inheritance of items without audit entries
Enable-NTFSAuditInheritance, Disable-NTFSAuditInheritance, and
Set-NTFSInheritance -AuditInheritanceEnabled failed with "(5) Access is
denied" for a file or folder without a SACL, also elevated with the
Security privilege. The cmdlets read only the audit section and changed
the flag that disables or enables audit inheritance. AlphaFS writes that
flag only together with a SACL, so it wrote no section at all, which
Windows denies; the retry as owner repeated the same write. An empty SACL
is now added first, but only to a descriptor that was read with its SACL.
The elevated CI runs of #100 to #106 showed this through the test of an
omitted -AccessInheritanceEnabled. From #104 on, the test that keeps the
inherited entries of a security descriptor failed as well: elevated,
Get-NTFSSecurityDescriptor reads the SACL, and Windows then returns a DACL
that isn't in the auto-inherit format, such as that of a file in the temp
folder of the user, without its inherited flags. The test now reads the
access section only and checks that the descriptor has inherited entries.
Tests: five cases for items without audit entries, red with "Access is
denied" before the fix; the test that keeps the explicit audit entries now
checks the errors and the inheritance state of both calls; a test checks
that a descriptor read without its audit entries gets no SACL, which would
replace the audit entries of the item when it is written.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
if (scope == InheritanceScope.Audit)
|
|
|
|
|
{
|
|
|
|
|
AddMissingSystemAcl(sd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sd.IsFile)
|
|
|
|
|
{
|
|
|
|
|
if (scope == InheritanceScope.Access)
|
|
|
|
|
((FileSecurity)sd.SecurityDescriptor).SetAccessRuleProtection(true, !removeInheritedAccessRules);
|
|
|
|
|
else
|
|
|
|
|
((FileSecurity)sd.SecurityDescriptor).SetAuditRuleProtection(true, !removeInheritedAccessRules);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (scope == InheritanceScope.Access)
|
|
|
|
|
((DirectorySecurity)sd.SecurityDescriptor).SetAccessRuleProtection(true, !removeInheritedAccessRules);
|
|
|
|
|
else
|
|
|
|
|
((DirectorySecurity)sd.SecurityDescriptor).SetAuditRuleProtection(true, !removeInheritedAccessRules);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion Enable / DisableInheritance internal
|
|
|
|
|
|
|
|
|
|
#region Public Methods using SecurityDescriptor
|
|
|
|
|
public static void EnableAccessInheritance(FileSystemSecurity2 sd, bool removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
EnableInheritance(sd, removeExplicitAccessRules, InheritanceScope.Access);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void EnableAuditInheritance(FileSystemSecurity2 sd, bool removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
EnableInheritance(sd, removeExplicitAccessRules, InheritanceScope.Audit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void DisableAccessInheritance(FileSystemSecurity2 sd, bool removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
DisableInheritance(sd, removeExplicitAccessRules, InheritanceScope.Access);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void DisableAuditInheritance(FileSystemSecurity2 sd, bool removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
DisableInheritance(sd, removeExplicitAccessRules, InheritanceScope.Audit);
|
|
|
|
|
}
|
|
|
|
|
#endregion Public Methods using SecurityDescriptor
|
|
|
|
|
|
|
|
|
|
#region Public Methods using FileSystemInfo
|
|
|
|
|
public static void EnableAccessInheritance(FileSystemInfo item, bool removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
var sd = new FileSystemSecurity2(item, AccessControlSections.Access);
|
|
|
|
|
EnableAccessInheritance(sd, removeExplicitAccessRules);
|
|
|
|
|
sd.Write();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void DisableAccessInheritance(FileSystemInfo item, bool removeInheritedAccessRules)
|
|
|
|
|
{
|
|
|
|
|
var sd = new FileSystemSecurity2(item, AccessControlSections.Access);
|
|
|
|
|
DisableAccessInheritance(sd, removeInheritedAccessRules);
|
|
|
|
|
sd.Write();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void EnableAuditInheritance(FileSystemInfo item, bool removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
var sd = new FileSystemSecurity2(item, AccessControlSections.Audit);
|
|
|
|
|
EnableAuditInheritance(sd, removeExplicitAccessRules);
|
|
|
|
|
sd.Write();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void DisableAuditInheritance(FileSystemInfo item, bool removeInheritedAccessRules)
|
|
|
|
|
{
|
|
|
|
|
var sd = new FileSystemSecurity2(item, AccessControlSections.Audit);
|
|
|
|
|
DisableAuditInheritance(sd, removeInheritedAccessRules);
|
|
|
|
|
sd.Write();
|
|
|
|
|
}
|
|
|
|
|
#endregion Public Methods using FileSystemInfo
|
|
|
|
|
|
|
|
|
|
#region Public Methods using Path
|
|
|
|
|
public static void EnableAccessInheritance(string path, bool removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
EnableAccessInheritance(new FileInfo(path), removeExplicitAccessRules);
|
|
|
|
|
}
|
|
|
|
|
else if (Directory.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
EnableAccessInheritance(new DirectoryInfo(path), removeExplicitAccessRules);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void DisableAccessInheritance(string path, bool removeInheritedAccessRules)
|
|
|
|
|
{
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
DisableAccessInheritance(new FileInfo(path), removeInheritedAccessRules);
|
|
|
|
|
}
|
|
|
|
|
else if (Directory.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
DisableAccessInheritance(new DirectoryInfo(path), removeInheritedAccessRules);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void EnableAuditInheritance(string path, bool removeExplicitAccessRules)
|
|
|
|
|
{
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
EnableAuditInheritance(new FileInfo(path), removeExplicitAccessRules);
|
|
|
|
|
}
|
|
|
|
|
else if (Directory.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
EnableAuditInheritance(new DirectoryInfo(path), removeExplicitAccessRules);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void DisableAuditInheritance(string path, bool removeInheritedAccessRules)
|
|
|
|
|
{
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
DisableAuditInheritance(new FileInfo(path), removeInheritedAccessRules);
|
|
|
|
|
}
|
|
|
|
|
else if (Directory.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
DisableAuditInheritance(new DirectoryInfo(path), removeInheritedAccessRules);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion Public Methods using Path
|
|
|
|
|
}
|
|
|
|
|
}
|