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.

135 lines
4.6 KiB

10 years ago
using Alphaleonis.Win32.Filesystem;
using Security2;
using System;
using System.Management.Automation;
namespace NTFSSecurity
{
[Cmdlet(VerbsLifecycle.Enable, "NTFSAuditInheritance", DefaultParameterSetName = "Path")]
[OutputType(typeof(FileSystemInheritanceInfo))]
10 years ago
public class EnableAuditInheritance : BaseCmdletWithPrivControl
{
private bool removeExplicitAuditRules;
10 years ago
private bool passThru;
[Parameter(Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "Path")]
[ValidateNotNullOrEmpty]
[Alias("FullName")]
[FileSystemPathTransformation]
10 years ago
public string[] Path
{
get { return paths.ToArray(); }
set
{
paths.Clear();
paths.AddRange(value);
}
}
[Parameter(Mandatory = true, Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "SecurityDescriptor")]
[ValidateNotNullOrEmpty]
public FileSystemSecurity2[] SecurityDescriptor
{
get { return securityDescriptors.ToArray(); }
set
{
securityDescriptors.Clear();
securityDescriptors.AddRange(value);
}
}
[Parameter]
public SwitchParameter PassThru
{
get { return passThru; }
set { passThru = value; }
}
/// <summary>
/// Removes the explicit audit entries of the item. Before 5.0.0, the switch was named
/// RemoveExplicitAccessRules, which remains an alias.
/// </summary>
10 years ago
[Parameter]
[Alias("RemoveExplicitAccessRules")]
public SwitchParameter RemoveExplicitAuditRules
10 years ago
{
get { return removeExplicitAuditRules; }
set { removeExplicitAuditRules = value; }
10 years ago
}
protected override void BeginProcessing()
{
base.BeginProcessing();
}
protected override void ProcessRecord()
{
if (ParameterSetName == "Path")
{
foreach (var path in paths)
{
FileSystemInfo item = null;
try
{
item = GetFileSystemInfo2(path);
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "ReadFileError", ErrorCategory.OpenError, path));
continue;
}
try
{
FileSystemInheritanceInfo.EnableAuditInheritance(item, removeExplicitAuditRules);
10 years ago
}
catch (UnauthorizedAccessException)
{
try
{
InvokeAsOwner(item, path, () =>
{
FileSystemInheritanceInfo.EnableAuditInheritance(item, removeExplicitAuditRules);
});
10 years ago
}
catch (Exception ex2)
{
fix(owner): pass on what a later command raises at the RestoreOwnerError record InvokeAsOwner (and Set-NTFSSecurityDescriptor&#39;s WriteChangesAsOwner) take ownership of an item, run the action, and in a finally restore the previous owner, writing a non-terminating RestoreOwnerError through WriteError when that restore fails. WriteError runs the later commands of the pipeline while it writes, so in the rare case that a later command throws exactly when it sees that RestoreOwnerError record (for example `... 2&gt;&amp;1 | ForEach-Object { if ($_.FullyQualifiedErrorId -like &#39;RestoreOwnerError,*&#39;) { throw } else { $_ } }`), that exception used to leave InvokeAsOwner through the finally and reach the handler around the call, which reported it as the item&#39;s own error (AddAceError, ReadSecurityError, ModifySdError, and so on) and moved on to the next path. The caller never saw the exception. Thirteen handlers now check IsFromLaterCommand as the first statement of their catch, the same pattern SetSecurityDescriptor.cs already used in its second handler and GetSecurityDescriptor.cs already used: Add/Clear and Get-NTFSAccess, Get-NTFSOrphanedAccess, Get-NTFSEffectiveAccess, Clear-NTFSAudit, Get-FileHash2, the six inheritance cmdlets, and the owner-retry of Set-NTFSSecurityDescriptor. The four add/remove access and audit cmdlets have the same flaw and belong to another work item. Tests\PipelineControl.Tests.ps1 adds one table-driven It, elevated only, that denies the current user the right a cmdlet&#39;s action needs, gives the item an owner only the Restore privilege can set back (which the test turns off), and asserts that a later command&#39;s exception reaches the caller, no item-error record was written for it, and the next path is untouched. Six of the thirteen handlers are pinned this way (the other seven need the current user to both fail and succeed the same access check at once, which Windows does not allow; see the comment above the Describe block and the probes under ..\probes-wi2\ for the empirical evidence). The four add and remove cmdlets, which have the same flaw, follow in the next commit of this item. Get-NTFSInheritance, the one of the thirteen that writes its result in a finally, writes it after the try instead, so that the object does not go to the later command that has just thrown. Co-authored-by: Copilot &lt;223556219+Copilot@users.noreply.github.com&gt; Co-authored-by: AI Assistant &lt;ai@example.com&gt;
2 weeks ago
// Not what a later command raises, for example when it takes the RestoreOwnerError record.
if (IsFromLaterCommand(ex2))
{
throw;
}
10 years ago
WriteError(new ErrorRecord(ex2, "ModifySdError", ErrorCategory.WriteError, path));
continue;
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "ModifySdError", ErrorCategory.WriteError, path));
continue;
}
// Only after a successful change, so that a failure doesn't report the unchanged state
if (passThru)
10 years ago
{
WriteObject(FileSystemInheritanceInfo.GetFileSystemInheritanceInfo(item));
10 years ago
}
}
}
else
{
foreach (var sd in securityDescriptors)
{
FileSystemInheritanceInfo.EnableAuditInheritance(sd, removeExplicitAuditRules);
10 years ago
if (passThru)
{
8 years ago
WriteObject(FileSystemInheritanceInfo.GetFileSystemInheritanceInfo(sd));
10 years ago
}
}
}
}
}
}