/* * Process Hacker - * security descriptor * * Copyright (C) 2009 wj32 * * This file is part of Process Hacker. * * Process Hacker is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Process Hacker is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Process Hacker. If not, see . */ using System; using ProcessHacker.Common.Objects; using ProcessHacker.Native.Api; using ProcessHacker.Native.Objects; namespace ProcessHacker.Native.Security.AccessControl { /// /// Represents a security descriptor. /// public sealed class SecurityDescriptor : BaseObject { /// /// Gets the security descriptor of a kernel object. /// /// A handle to a kernel object. /// The information to retrieve. /// A security descriptor. public static SecurityDescriptor GetSecurity(IntPtr handle, SecurityInformation securityInformation) { NtStatus status; int retLength; using (var data = new MemoryAlloc(0x100)) { status = Win32.NtQuerySecurityObject( handle, securityInformation, data, data.Size, out retLength ); if (status == NtStatus.BufferTooSmall) { data.Resize(retLength); status = Win32.NtQuerySecurityObject( handle, securityInformation, data, data.Size, out retLength ); } if (status >= NtStatus.Error) Win32.ThrowLastError(status); return new SecurityDescriptor(data); } } /// /// Gets the security descriptor of an object. /// /// A handle to an object. /// The type of the object. /// The information to retrieve. /// A security descriptor. public static SecurityDescriptor GetSecurity(IntPtr handle, SeObjectType objectType, SecurityInformation securityInformation) { Win32Error result; IntPtr dummy, securityDescriptor; if ((result = Win32.GetSecurityInfo( handle, objectType, securityInformation, out dummy, out dummy, out dummy, out dummy, out securityDescriptor )) != 0) Win32.ThrowLastError(result); return new SecurityDescriptor(new LocalMemoryAlloc(securityDescriptor)); } /// /// Sets the security descriptor of a kernel object. /// /// A handle to a kernel object. /// The information to modify. /// The security descriptor. public static void SetSecurity(IntPtr handle, SecurityInformation securityInformation, SecurityDescriptor securityDescriptor) { NtStatus status; if ((status = Win32.NtSetSecurityObject( handle, securityInformation, securityDescriptor )) >= NtStatus.Error) Win32.ThrowLastError(status); } /// /// Sets the security descriptor of an object. /// /// A handle to an object. /// The type of the object. /// The information to modify. /// The security descriptor. public static void SetSecurity(IntPtr handle, SeObjectType objectType, SecurityInformation securityInformation, SecurityDescriptor securityDescriptor) { Win32Error result; IntPtr dacl = IntPtr.Zero; IntPtr group = IntPtr.Zero; IntPtr owner = IntPtr.Zero; IntPtr sacl = IntPtr.Zero; if ((securityInformation & SecurityInformation.Dacl) == SecurityInformation.Dacl) dacl = securityDescriptor.Dacl ?? IntPtr.Zero; if ((securityInformation & SecurityInformation.Group) == SecurityInformation.Group) group = securityDescriptor.Group; if ((securityInformation & SecurityInformation.Owner) == SecurityInformation.Owner) owner = securityDescriptor.Owner; if ((securityInformation & SecurityInformation.Sacl) == SecurityInformation.Sacl) sacl = securityDescriptor.Sacl ?? IntPtr.Zero; if ((result = Win32.SetSecurityInfo( handle, objectType, securityInformation, owner, group, dacl, sacl )) != 0) Win32.ThrowLastError(result); } public static implicit operator IntPtr(SecurityDescriptor securityDescriptor) { return securityDescriptor.Memory; } private MemoryRegion _memory; private Acl _dacl; private Acl _sacl; private Sid _owner; private Sid _group; /// /// Creates an empty security descriptor. /// public SecurityDescriptor() { NtStatus status; _memory = new MemoryAlloc(Win32.SecurityDescriptorMinLength); if ((status = Win32.RtlCreateSecurityDescriptor( _memory, Win32.SecurityDescriptorRevision )) >= NtStatus.Error) { _memory.Dispose(); _memory = null; this.DisableOwnership(false); Win32.ThrowLastError(status); } _memory.Reference(); _memory.Dispose(); } /// /// Creates a security descriptor with the specified components. /// /// A SID representing an owner. /// A SID representing a group. /// The discretionary access control list. /// The system access control list. public SecurityDescriptor(Sid owner, Sid group, Acl dacl, Acl sacl) : this() { this.Owner = owner; this.Group = group; this.Dacl = dacl; this.Sacl = sacl; } /// /// Creates a security descriptor from memory. /// /// The memory region to use. This object will be referenced. public SecurityDescriptor(MemoryRegion memory) { _memory = memory; _memory.Reference(); this.Read(); } protected override void DisposeObject(bool disposing) { if (_dacl != null) _dacl.Dereference(disposing); if (_sacl != null) _sacl.Dereference(disposing); if (_owner != null) _owner.Dereference(disposing); if (_group != null) _group.Dereference(disposing); if (_memory != null) _memory.Dereference(disposing); } /// /// Gets or sets the control flags. /// public SecurityDescriptorControlFlags ControlFlags { get { NtStatus status; SecurityDescriptorControlFlags control; int revision; if ((status = Win32.RtlGetControlSecurityDescriptor( this, out control, out revision )) >= NtStatus.Error) Win32.ThrowLastError(status); return control; } set { NtStatus status; if ((status = Win32.RtlSetControlSecurityDescriptor( this, value, value )) >= NtStatus.Error) Win32.ThrowLastError(status); } } /// /// Gets or sets the DACL. /// public Acl Dacl { get { return _dacl; } set { NtStatus status; if ((status = Win32.RtlSetDaclSecurityDescriptor( this, value != null, value ?? IntPtr.Zero, false )) >= NtStatus.Error) Win32.ThrowLastError(status); this.SwapDacl(value); } } /// /// Gets or sets whether the DACL has been defaulted. /// public bool DaclDefaulted { get { return (this.ControlFlags & SecurityDescriptorControlFlags.DaclDefaulted) == SecurityDescriptorControlFlags.DaclDefaulted; } set { if (value) this.ControlFlags |= SecurityDescriptorControlFlags.DaclDefaulted; else this.ControlFlags &= ~SecurityDescriptorControlFlags.DaclDefaulted; } } /// /// Gets or sets the group. /// public Sid Group { get { return _group; } set { NtStatus status; if ((status = Win32.RtlSetGroupSecurityDescriptor( this, value, false )) >= NtStatus.Error) Win32.ThrowLastError(status); this.SwapGroup(value); } } /// /// Gets or sets whether the group has been defaulted. /// public bool GroupDefaulted { get { return (this.ControlFlags & SecurityDescriptorControlFlags.GroupDefaulted) == SecurityDescriptorControlFlags.GroupDefaulted; } set { if (value) this.ControlFlags |= SecurityDescriptorControlFlags.GroupDefaulted; else this.ControlFlags &= ~SecurityDescriptorControlFlags.GroupDefaulted; } } /// /// Gets the size of the security descriptor, in bytes. /// public int Length { get { return Win32.RtlLengthSecurityDescriptor(this); } } /// /// Gets a pointer to the associated memory of the security descriptor. /// public IntPtr Memory { get { return _memory; } } /// /// Gets or sets the owner. /// public Sid Owner { get { return _owner; } set { NtStatus status; if ((status = Win32.RtlSetOwnerSecurityDescriptor( this, value, false )) >= NtStatus.Error) Win32.ThrowLastError(status); this.SwapOwner(value); } } /// /// Gets or sets whether the owner has been defaulted. /// public bool OwnerDefaulted { get { return (this.ControlFlags & SecurityDescriptorControlFlags.OwnerDefaulted) == SecurityDescriptorControlFlags.OwnerDefaulted; } set { if (value) this.ControlFlags |= SecurityDescriptorControlFlags.OwnerDefaulted; else this.ControlFlags &= ~SecurityDescriptorControlFlags.OwnerDefaulted; } } /// /// Gets or sets the SACL. /// public Acl Sacl { get { return _sacl; } set { NtStatus status; if ((status = Win32.RtlSetSaclSecurityDescriptor( this, value != null, value ?? IntPtr.Zero, false )) >= NtStatus.Error) Win32.ThrowLastError(status); this.SwapSacl(value); } } /// /// Gets or sets whether the SACL has been defaulted. /// public bool SaclDefaulted { get { return (this.ControlFlags & SecurityDescriptorControlFlags.SaclDefaulted) == SecurityDescriptorControlFlags.SaclDefaulted; } set { if (value) this.ControlFlags |= SecurityDescriptorControlFlags.SaclDefaulted; else this.ControlFlags &= ~SecurityDescriptorControlFlags.SaclDefaulted; } } /// /// Gets whether the security descriptor is in self-relative form. /// public bool SelfRelative { get { return (this.ControlFlags & SecurityDescriptorControlFlags.SelfRelative) == SecurityDescriptorControlFlags.SelfRelative; } } /// /// Checks whether the security descriptor grants a set of access rights to a client. /// /// A handle to a token which represents the client. /// The access rights requested by the client. /// A structure which defines how generic access rights are to be mapped. /// A variable which receives the granted access rights. /// Success if access was granted, otherwise another NT status value. public NtStatus CheckAccess(TokenHandle tokenHandle, int desiredAccess, GenericMapping genericMapping, out int grantedAccess) { NtStatus status; NtStatus accessStatus; int privilegeSetLength = 0; if ((status = Win32.NtAccessCheck( this, tokenHandle, desiredAccess, ref genericMapping, IntPtr.Zero, ref privilegeSetLength, out grantedAccess, out accessStatus )) >= NtStatus.Error) Win32.ThrowLastError(status); return accessStatus; } /// /// Checks whether the security descriptor is valid. /// /// True if the security descriptor is valid, otherwise false. public bool IsValid() { return Win32.RtlValidSecurityDescriptor(this); } private void Read() { NtStatus status; bool present, defaulted; IntPtr dacl, group, owner, sacl; // Read the DACL. if ((status = Win32.RtlGetDaclSecurityDescriptor( this, out present, out dacl, out defaulted )) >= NtStatus.Error) Win32.ThrowLastError(status); if (present) this.SwapDacl(new Acl(Acl.FromPointer(dacl))); else this.SwapDacl(null); // Read the SACL. if ((status = Win32.RtlGetSaclSecurityDescriptor( this, out present, out sacl, out defaulted )) >= NtStatus.Error) Win32.ThrowLastError(status); if (present) this.SwapSacl(new Acl(Acl.FromPointer(sacl))); else this.SwapSacl(null); // Read the group. if ((status = Win32.RtlGetGroupSecurityDescriptor( this, out group, out defaulted )) >= NtStatus.Error) Win32.ThrowLastError(status); if (group != IntPtr.Zero) this.SwapGroup(new Sid(group)); else this.SwapGroup(null); // Read the owner. if ((status = Win32.RtlGetOwnerSecurityDescriptor( this, out owner, out defaulted )) >= NtStatus.Error) Win32.ThrowLastError(status); if (owner != IntPtr.Zero) this.SwapOwner(new Sid(owner)); else this.SwapOwner(null); } private void SwapDacl(Acl dacl) { BaseObject.SwapRef(ref _dacl, dacl); } private void SwapGroup(Sid group) { BaseObject.SwapRef(ref _group, group); } private void SwapOwner(Sid owner) { BaseObject.SwapRef(ref _owner, owner); } private void SwapSacl(Acl sacl) { BaseObject.SwapRef(ref _sacl, sacl); } /// /// Creates a copy of the security descriptor in self-relative form. /// /// A new self-relative security descriptor. public SecurityDescriptor ToSelfRelative() { NtStatus status; int retLength; using (var data = new MemoryAlloc(Win32.SecurityDescriptorMinLength)) { retLength = data.Size; status = Win32.RtlMakeSelfRelativeSD(this, data, ref retLength); if (status == NtStatus.BufferTooSmall) { data.Resize(retLength); status = Win32.RtlMakeSelfRelativeSD(this, data, ref retLength); } if (status >= NtStatus.Error) Win32.ThrowLastError(status); return new SecurityDescriptor(data); } } } }