// // Copyright © Nick Lowe 2009 // // Nick Lowe // nick@int-r.net // http://processprivileges.codeplex.com/ namespace ProcessPrivileges { using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Security.Permissions; /// Enables privileges on a process in a safe way, ensuring that they are returned to their original state when an operation that requires a privilege completes. /// /// /// using System; /// using System.Diagnostics; /// using ProcessPrivileges; /// /// internal static class PrivilegeEnablerExample /// { /// public static void Main() /// { /// Process process = Process.GetCurrentProcess(); /// /// using (new PrivilegeEnabler(process, Privilege.TakeOwnership)) /// { /// // Privilege is enabled within the using block. /// Console.WriteLine( /// "{0} => {1}", /// Privilege.TakeOwnership, /// process.GetPrivilegeState(Privilege.TakeOwnership)); /// } /// /// // Privilege is disabled outside the using block. /// Console.WriteLine( /// "{0} => {1}", /// Privilege.TakeOwnership, /// process.GetPrivilegeState(Privilege.TakeOwnership)); /// } /// } /// /// /// /// When disabled, privileges are enabled until the instance of the PrivilegeEnabler class is disposed. /// If the privilege specified is already enabled, it is not modified and will not be disabled when the instance of the PrivilegeEnabler class is disposed. /// If desired, multiple privileges can be specified in the constructor. /// If using multiple instances on the same process, do not dispose of them out-of-order. Making use of a using statement, the recommended method, enforces this. /// For more information on privileges, see: /// Privileges /// Privilege Constants /// public sealed class PrivilegeEnabler : IDisposable { private static readonly Dictionary sharedPrivileges = new Dictionary(); private static readonly Dictionary accessTokenHandles = new Dictionary(); private AccessTokenHandle accessTokenHandle; private bool disposed; private bool ownsHandle; private Process process; /// Initializes a new instance of the PrivilegeEnabler class. /// The for a on which privileges should be enabled. /// Thrown when another instance exists and has not been disposed. /// Requires the immediate caller to have FullTrust. [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")] public PrivilegeEnabler(AccessTokenHandle accessTokenHandle) { this.accessTokenHandle = accessTokenHandle; } /// Initializes a new instance of the PrivilegeEnabler class. /// The on which privileges should be enabled. /// Thrown when another instance exists and has not been disposed. /// Requires the immediate caller to have FullTrust. [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")] public PrivilegeEnabler(Process process) { lock (accessTokenHandles) { if (accessTokenHandles.ContainsKey(process)) { this.accessTokenHandle = accessTokenHandles[process]; } else { this.accessTokenHandle = process.GetAccessTokenHandle(TokenAccessRights.AdjustPrivileges | TokenAccessRights.Query); accessTokenHandles.Add(process, this.accessTokenHandle); this.ownsHandle = true; } } this.process = process; } /// Initializes a new instance of the PrivilegeEnabler class with the specified privileges to be enabled. /// The for a on which privileges should be enabled. /// The privileges to be enabled. /// Thrown when an underlying Win32 function call does not succeed. /// Requires the immediate caller to have FullTrust. [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")] public PrivilegeEnabler(AccessTokenHandle accessTokenHandle, params Privilege[] privileges) : this(accessTokenHandle) { foreach (Privilege privilege in privileges) { this.EnablePrivilege(privilege); } } /// Initializes a new instance of the PrivilegeEnabler class with the specified privileges to be enabled. /// The on which privileges should be enabled. /// The privileges to be enabled. /// Thrown when an underlying Win32 function call does not succeed. /// Requires the immediate caller to have FullTrust. [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")] public PrivilegeEnabler(Process process, params Privilege[] privileges) : this(process) { foreach (Privilege privilege in privileges) { this.EnablePrivilege(privilege); } } /// Finalizes an instance of the PrivilegeEnabler class. ~PrivilegeEnabler() { this.InternalDispose(); } /// Disposes of an instance of the PrivilegeEnabler class. /// Thrown when an underlying Win32 function call does not succeed. /// Requires the call stack to have FullTrust. [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] public void Dispose() { this.InternalDispose(); GC.SuppressFinalize(this); } /// Enables the specified . /// The to be enabled. /// /// Result from the privilege adjustment. /// If the is already enabled, is returned. /// If the is owned by another instance of the PrivilegeEnabler class, is returned. /// If a is removed from a process, it cannot be enabled. /// /// /// When disabled, privileges are enabled until the instance of the PrivilegeEnabler class is disposed. /// If the privilege specified is already enabled, it is not modified and will not be disabled when the instance of the PrivilegeEnabler class is disposed. /// /// Thrown when an underlying Win32 function call does not succeed. /// Requires the immediate caller to have FullTrust. [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")] public AdjustPrivilegeResult EnablePrivilege(Privilege privilege) { lock (sharedPrivileges) { if (!sharedPrivileges.ContainsKey(privilege) && this.accessTokenHandle.GetPrivilegeState(privilege) == PrivilegeState.Disabled && this.accessTokenHandle.EnablePrivilege(privilege) == AdjustPrivilegeResult.PrivilegeModified) { sharedPrivileges.Add(privilege, this); return AdjustPrivilegeResult.PrivilegeModified; } return AdjustPrivilegeResult.None; } } [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")] private void InternalDispose() { if (!this.disposed) { lock (sharedPrivileges) { Privilege[] privileges = sharedPrivileges .Where(keyValuePair => keyValuePair.Value == this) .Select(keyValuePair => keyValuePair.Key) .ToArray(); foreach (Privilege privilege in privileges) { this.accessTokenHandle.DisablePrivilege(privilege); sharedPrivileges.Remove(privilege); } if (this.ownsHandle) { this.accessTokenHandle.Dispose(); lock (this.accessTokenHandle) { accessTokenHandles.Remove(this.process); } } this.accessTokenHandle = null; this.ownsHandle = false; this.process = null; this.disposed = true; } } } } }