/* * 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) { using (MemoryAlloc data = new MemoryAlloc(0x100)) { int retLength; NtStatus status = Win32.NtQuerySecurityObject( handle, securityInformation, data, data.Size, out retLength ); if (status == NtStatus.BufferTooSmall) { data.ResizeNew(retLength); Win32.NtQuerySecurityObject( handle, securityInformation, data, data.Size, out retLength ).ThrowIf(); } status.ThrowIf(); 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.Throw(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) { Win32.NtSetSecurityObject( handle, securityInformation, securityDescriptor ).ThrowIf(); } /// /// 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.HasFlag(SecurityInformation.Dacl)) dacl = securityDescriptor.Dacl ?? IntPtr.Zero; if (securityInformation.HasFlag(SecurityInformation.Group)) group = securityDescriptor.Group; if (securityInformation.HasFlag(SecurityInformation.Owner)) owner = securityDescriptor.Owner; if (securityInformation.HasFlag(SecurityInformation.Sacl)) sacl = securityDescriptor.Sacl ?? IntPtr.Zero; if ((result = Win32.SetSecurityInfo( handle, objectType, securityInformation, owner, group, dacl, sacl )) != 0) Win32.Throw(result); } public static implicit operator IntPtr(SecurityDescriptor securityDescriptor) { return securityDescriptor.Memory; } private readonly 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 )).IsError()) { _memory.Dispose(); _memory = null; this.DisableOwnership(false); Win32.Throw(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 { SecurityDescriptorControlFlags control; int revision; Win32.RtlGetControlSecurityDescriptor( this, out control, out revision ).ThrowIf(); return control; } set { Win32.RtlSetControlSecurityDescriptor( this, value, value ).ThrowIf(); } } /// /// Gets or sets the DACL. /// public Acl Dacl { get { return _dacl; } set { Win32.RtlSetDaclSecurityDescriptor( this, value != null, value ?? IntPtr.Zero, false ).ThrowIf(); this.SwapDacl(value); } } /// /// Gets or sets whether the DACL has been defaulted. /// public bool DaclDefaulted { get { return this.ControlFlags.HasFlag(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 { Win32.RtlSetGroupSecurityDescriptor( this, value, false ).ThrowIf(); this.SwapGroup(value); } } /// /// Gets or sets whether the group has been defaulted. /// public bool GroupDefaulted { get { return this.ControlFlags.HasFlag(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 { Win32.RtlSetOwnerSecurityDescriptor( this, value, false ).ThrowIf(); 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 { Win32.RtlSetSaclSecurityDescriptor( this, value != null, value ?? IntPtr.Zero, false ).ThrowIf(); this.SwapSacl(value); } } /// /// Gets or sets whether the SACL has been defaulted. /// public bool SaclDefaulted { get { return this.ControlFlags.HasFlag(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.HasFlag(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 accessStatus; int privilegeSetLength = 0; Win32.NtAccessCheck( this, tokenHandle, desiredAccess, ref genericMapping, IntPtr.Zero, ref privilegeSetLength, out grantedAccess, out accessStatus ).ThrowIf(); return accessStatus; } /// /// Checks whether the security descriptor is valid. /// /// True if the security descriptor is valid, otherwise false. public bool IsValid { get { return Win32.RtlValidSecurityDescriptor(this); } } private void Read() { bool present, defaulted; IntPtr dacl, group, owner, sacl; // Read the DACL. Win32.RtlGetDaclSecurityDescriptor( this, out present, out dacl, out defaulted ).ThrowIf(); if (present && dacl != IntPtr.Zero) this.SwapDacl(new Acl(Acl.FromPointer(dacl))); else this.SwapDacl(null); // Read the SACL. Win32.RtlGetSaclSecurityDescriptor( this, out present, out sacl, out defaulted ).ThrowIf(); if (present && sacl != IntPtr.Zero) this.SwapSacl(new Acl(Acl.FromPointer(sacl))); else this.SwapSacl(null); // Read the group. Win32.RtlGetGroupSecurityDescriptor( this, out group, out defaulted ).ThrowIf(); if (group != IntPtr.Zero) this.SwapGroup(new Sid(group)); else this.SwapGroup(null); // Read the owner. Win32.RtlGetOwnerSecurityDescriptor( this, out owner, out defaulted ).ThrowIf(); 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() { using (MemoryAlloc data = new MemoryAlloc(Win32.SecurityDescriptorMinLength)) { int retLength = data.Size; NtStatus status = Win32.RtlMakeSelfRelativeSD(this, data, ref retLength); if (status == NtStatus.BufferTooSmall) { data.ResizeNew(retLength); status = Win32.RtlMakeSelfRelativeSD(this, data, ref retLength); } status.ThrowIf(); return new SecurityDescriptor(data); } } } }