using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Security.AccessControl; using System.Security.Principal; using Vanara.InteropServices; using Vanara.PInvoke; using static Vanara.PInvoke.AdvApi32; namespace Vanara.Security.AccessControl { /// Enables access to managed as unmanaged . /// public class PinnedSid : PinnedObject { private readonly byte[] bytes; public PinnedSid(SecurityIdentifier sid) { bytes = new byte[sid.BinaryLength]; sid.GetBinaryForm(bytes, 0); SetObject(bytes); } public PSID PSID => (IntPtr)this; } /// Enables access to managed as unmanaged . public class PinnedAcl : PinnedObject { private readonly byte[] bytes; public PinnedAcl(RawAcl acl) { bytes = new byte[acl.BinaryLength]; acl.GetBinaryForm(bytes, 0); SetObject(bytes); } public PACL PACL => (IntPtr)this; } /// Enables access to managed as unmanaged . public class PinnedSecurityDescriptor : PinnedObject { private readonly byte[] bytes; public PinnedSecurityDescriptor(ObjectSecurity sd) { bytes = sd.GetSecurityDescriptorBinaryForm(); SetObject(bytes); } public PSECURITY_DESCRIPTOR PSECURITY_DESCRIPTOR => (IntPtr)this; } /// Helper methods for working with Access Control structures. public static class AccessControlHelper { public static ACCESS_ALLOWED_ACE GetAce(PACL pAcl, int aceIndex) { if (AdvApi32.GetAce(pAcl, aceIndex, out var acePtr)) return (ACCESS_ALLOWED_ACE)Marshal.PtrToStructure((IntPtr)acePtr, typeof(ACCESS_ALLOWED_ACE)); throw new System.ComponentModel.Win32Exception(); } public static uint GetAceCount(PACL pAcl) => GetAclInfo(pAcl).AceCount; public static ACL_SIZE_INFORMATION GetAclInfo(PACL pAcl) { var si = new ACL_SIZE_INFORMATION(); if (!GetAclInformation(pAcl, ref si, (uint)Marshal.SizeOf(si), ACL_INFORMATION_CLASS.AclSizeInformation)) throw new System.ComponentModel.Win32Exception(); return si; } public static uint GetAclSize(PACL pAcl) => GetAclInfo(pAcl).AclBytesInUse; public static uint GetEffectiveRights(this PSID pSid, PSECURITY_DESCRIPTOR pSD) { BuildTrusteeWithSid(out var t, pSid); GetSecurityDescriptorDacl(pSD, out var daclPresent, out var pDacl, out var daclDefaulted); GetEffectiveRightsFromAcl(pDacl, t, out var access); return access; } public static uint GetEffectiveRights(this RawSecurityDescriptor sd, SecurityIdentifier sid) { BuildTrusteeWithSid(out var t, GetPSID(sid)); using (var pDacl = new PinnedAcl(sd.DiscretionaryAcl)) { GetEffectiveRightsFromAcl(pDacl.PACL, t, out var access); return access; } } public static IEnumerable GetInheritanceSource(string objectName, System.Security.AccessControl.ResourceType objectType, SECURITY_INFORMATION securityInfo, bool container, PACL pAcl, ref GENERIC_MAPPING pGenericMapping) { var objSize = Marshal.SizeOf(typeof(INHERITED_FROM)); var aceCount = GetAceCount(pAcl); using (var pInherit = new SafeInheritedFromArray((ushort)aceCount)) { AdvApi32.GetInheritanceSource(objectName, (SE_OBJECT_TYPE)objectType, securityInfo, container, null, 0, pAcl, IntPtr.Zero, pGenericMapping, pInherit).ThrowIfFailed(); return pInherit.Results; } } public static PSID GetPSID(this SecurityIdentifier sid) { using (var ps = new PinnedSid(sid)) return ps.PSID; } public static SafeSecurityDescriptor GetPrivateObjectSecurity(this PSECURITY_DESCRIPTOR pSD, SECURITY_INFORMATION si) { var pResSD = SafeSecurityDescriptor.Null; AdvApi32.GetPrivateObjectSecurity(pSD, si, pResSD, 0, out var ret); if (ret > 0) { pResSD = new SafeSecurityDescriptor((int)ret); if (!pResSD.IsInvalid && !AdvApi32.GetPrivateObjectSecurity(pSD, si, pResSD, ret, out ret)) Win32Error.GetLastError().ThrowIfFailed(); } return pResSD; } public static SafeSecurityDescriptor GetPrivateObjectSecurity(this SafeSecurityDescriptor pSD, SECURITY_INFORMATION si) => GetPrivateObjectSecurity((PSECURITY_DESCRIPTOR)pSD, si); public static RawAcl RawAclFromPtr(PACL pAcl) { var len = GetAclSize(pAcl); var dest = new byte[len]; Marshal.Copy((IntPtr)pAcl, dest, 0, (int)len); return new RawAcl(dest, 0); } public static string ToSddl(this PSECURITY_DESCRIPTOR pSD, SECURITY_INFORMATION si) => ConvertSecurityDescriptorToStringSecurityDescriptor(pSD, si); public static string ToSddl(this SafeSecurityDescriptor pSD, SECURITY_INFORMATION si) => ConvertSecurityDescriptorToStringSecurityDescriptor(pSD, si); } }