summaryrefslogtreecommitdiff
path: root/src/Agent.Windows/Security/TaskAclManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Agent.Windows/Security/TaskAclManager.cs')
-rw-r--r--src/Agent.Windows/Security/TaskAclManager.cs27
1 files changed, 26 insertions, 1 deletions
diff --git a/src/Agent.Windows/Security/TaskAclManager.cs b/src/Agent.Windows/Security/TaskAclManager.cs
index be0080d..6534e5a 100644
--- a/src/Agent.Windows/Security/TaskAclManager.cs
+++ b/src/Agent.Windows/Security/TaskAclManager.cs
@@ -1,13 +1,34 @@
+using System.ComponentModel;
+using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
using Agent.Windows.Recovery;
+using Microsoft.Win32.SafeHandles;
namespace Agent.Windows.Security;
public sealed record AclSnapshot(string Path, byte[] SecurityDescriptor, Guid? JournalEntryId = null);
-public sealed class TaskAclManager(SecurityIdentifier appContainerSid, ISecurityAuditSink audit, TaskResourceJournal? journal = null)
+public sealed partial class TaskAclManager(SecurityIdentifier appContainerSid, ISecurityAuditSink audit, TaskResourceJournal? journal = null)
{
+ private const uint WriteDac = 0x00040000;
+ private const uint ShareReadWriteDelete = 0x00000007;
+ private const uint OpenExisting = 3;
+ private const uint BackupSemantics = 0x02000000;
+
+ public static void DemandWriteDac(string path)
+ {
+ string canonical = ResolvedPath.Resolve(path);
+ uint flags = Directory.Exists(canonical) ? BackupSemantics : 0;
+ using SafeFileHandle handle = CreateFile(canonical, WriteDac, ShareReadWriteDelete, 0, OpenExisting, flags, 0);
+ if (!handle.IsInvalid) return;
+ int error = Marshal.GetLastPInvokeError();
+ throw new SandboxPolicyException("sandbox.access_denied",
+ $"The current user cannot open '{canonical}' with WRITE_DAC ({new Win32Exception(error).Message}).",
+ "acl", canonical, "WRITE_DAC",
+ "Use a root owned by the current user or grant that user WRITE_DAC; elevation does not bypass this requirement.");
+ }
+
public AclSnapshot Grant(Guid taskId, string path, FileCapability capabilities)
{
string canonical = ResolvedPath.Resolve(path);
@@ -112,4 +133,8 @@ public sealed class TaskAclManager(SecurityIdentifier appContainerSid, ISecurity
if ((capabilities & FileCapability.Delete) != 0) rights |= FileSystemRights.Delete | FileSystemRights.DeleteSubdirectoriesAndFiles;
return rights;
}
+
+ [LibraryImport("kernel32.dll", EntryPoint = "CreateFileW", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
+ private static partial SafeFileHandle CreateFile(string fileName, uint desiredAccess, uint shareMode,
+ nint securityAttributes, uint creationDisposition, uint flagsAndAttributes, nint templateFile);
}