Privilege.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / clr / src / BCL / System / Security / AccessControl / Privilege.cs / 1 / Privilege.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
/*============================================================
** 
** Class:  Privilege 
**
** Purpose: Managed wrapper for NT privileges. 
**
** Date:  July 1, 2004
**
===========================================================*/ 

using Microsoft.Win32; 
using Microsoft.Win32.SafeHandles; 
using System.Collections;
using System.Runtime.CompilerServices; 
using System.Runtime.InteropServices;
using System.Runtime.ConstrainedExecution;
using System.Security.Permissions;
using System.Security.Principal; 
using System.Threading;
using System.Runtime.Versioning; 
 
namespace System.Security.AccessControl
{ 
    using CultureInfo = System.Globalization.CultureInfo;
    using FCall = System.Security.Principal.Win32;
    using Luid = Win32Native.LUID;
 
#if false
    internal delegate void PrivilegedHelper(); 
#endif 

    internal sealed class Privilege 
    {
        private static LocalDataStoreSlot tlsSlot = Thread.AllocateDataSlot();
        private static Hashtable privileges = new Hashtable();
        private static Hashtable luids = new Hashtable(); 
        private static ReaderWriterLock privilegeLock = new ReaderWriterLock();
 
        private bool needToRevert = false; 
        private bool initialState = false;
        private bool stateWasChanged = false; 
        private Luid luid;
        private readonly Thread currentThread = Thread.CurrentThread;
        private TlsContents tlsContents = null;
 
        public const string CreateToken                     = "SeCreateTokenPrivilege";
        public const string AssignPrimaryToken              = "SeAssignPrimaryTokenPrivilege"; 
        public const string LockMemory                      = "SeLockMemoryPrivilege"; 
        public const string IncreaseQuota                   = "SeIncreaseQuotaPrivilege";
        public const string UnsolicitedInput                = "SeUnsolicitedInputPrivilege"; 
        public const string MachineAccount                  = "SeMachineAccountPrivilege";
        public const string TrustedComputingBase            = "SeTcbPrivilege";
        public const string Security                        = "SeSecurityPrivilege";
        public const string TakeOwnership                   = "SeTakeOwnershipPrivilege"; 
        public const string LoadDriver                      = "SeLoadDriverPrivilege";
        public const string SystemProfile                   = "SeSystemProfilePrivilege"; 
        public const string SystemTime                      = "SeSystemtimePrivilege"; 
        public const string ProfileSingleProcess            = "SeProfileSingleProcessPrivilege";
        public const string IncreaseBasePriority            = "SeIncreaseBasePriorityPrivilege"; 
        public const string CreatePageFile                  = "SeCreatePagefilePrivilege";
        public const string CreatePermanent                 = "SeCreatePermanentPrivilege";
        public const string Backup                          = "SeBackupPrivilege";
        public const string Restore                         = "SeRestorePrivilege"; 
        public const string Shutdown                        = "SeShutdownPrivilege";
        public const string Debug                           = "SeDebugPrivilege"; 
        public const string Audit                           = "SeAuditPrivilege"; 
        public const string SystemEnvironment               = "SeSystemEnvironmentPrivilege";
        public const string ChangeNotify                    = "SeChangeNotifyPrivilege"; 
        public const string RemoteShutdown                  = "SeRemoteShutdownPrivilege";
        public const string Undock                          = "SeUndockPrivilege";
        public const string SyncAgent                       = "SeSyncAgentPrivilege";
        public const string EnableDelegation                = "SeEnableDelegationPrivilege"; 
        public const string ManageVolume                    = "SeManageVolumePrivilege";
        public const string Impersonate                     = "SeImpersonatePrivilege"; 
        public const string CreateGlobal                    = "SeCreateGlobalPrivilege"; 
        public const string TrustedCredentialManagerAccess  = "SeTrustedCredManAccessPrivilege";
        public const string ReserveProcessor                = "SeReserveProcessorPrivilege"; 

        //
        // This routine is a wrapper around a hashtable containing mappings
        // of privilege names to LUIDs 
        //
 
        [ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )] 
        private static Luid LuidFromPrivilege( string privilege )
        { 
            Luid luid;
            luid.LowPart = 0;
            luid.HighPart = 0;
 
            //
            // Look up the privilege LUID inside the cache 
            // 

            RuntimeHelpers.PrepareConstrainedRegions(); 

            try
            {
                privilegeLock.AcquireReaderLock( -1 ); 

                if ( luids.Contains( privilege )) 
                { 
                    luid = ( Luid )luids[ privilege ];
 
                    privilegeLock.ReleaseReaderLock();
                }
                else
                { 
                    privilegeLock.ReleaseReaderLock();
 
                    if ( false == Win32Native.LookupPrivilegeValue( null, privilege, ref luid )) 
                    {
                        int error = Marshal.GetLastWin32Error(); 

                        if ( error == Win32Native.ERROR_NOT_ENOUGH_MEMORY )
                        {
                            throw new OutOfMemoryException(); 
                        }
                        else if ( error == Win32Native.ERROR_ACCESS_DENIED ) 
                        { 
                            throw new UnauthorizedAccessException();
                        } 
                        else if ( error == Win32Native.ERROR_NO_SUCH_PRIVILEGE )
                        {
                            throw new ArgumentException(
                                Environment.GetResourceString( "Argument_InvalidPrivilegeName", 
                                privilege ));
                        } 
                        else 
                        {
                            BCLDebug.Assert( false, string.Format( CultureInfo.InvariantCulture, "LookupPrivilegeValue() failed with unrecognized error code {0}", error )); 
                            throw new InvalidOperationException();
                        }
                    }
 
                    privilegeLock.AcquireWriterLock( -1 );
                } 
            } 
            finally
            { 
                if ( privilegeLock.IsReaderLockHeld )
                {
                    privilegeLock.ReleaseReaderLock();
                } 

                if ( privilegeLock.IsWriterLockHeld ) 
                { 
                    if ( !luids.Contains( privilege ))
                    { 
                        luids[ privilege ] = luid;
                        privileges[ luid ] = privilege;
                    }
 
                    privilegeLock.ReleaseWriterLock();
                } 
            } 

            return luid; 
        }

        private sealed class TlsContents : IDisposable
        { 
            private bool disposed = false;
            private int referenceCount = 1; 
            private SafeTokenHandle threadHandle = new SafeTokenHandle( IntPtr.Zero ); 
            private bool isImpersonating = false;
 
            private static SafeTokenHandle processHandle = new SafeTokenHandle( IntPtr.Zero );
            private static readonly object syncRoot = new object();

#region Constructor and Finalizer 

            [ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )] 
            [ResourceExposure(ResourceScope.None)] 
            [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
            public TlsContents() 
            {
                int error = 0;
                int cachingError = 0;
                bool success = true; 

                if ( processHandle.IsInvalid) 
                { 
                    lock( syncRoot )
                    { 
                        if ( processHandle.IsInvalid)
                        {
                            if ( false == Win32Native.OpenProcessToken(
                                            Win32Native.GetCurrentProcess(), 
                                            TokenAccessLevels.Duplicate,
                                            ref processHandle)) 
                            { 
                                cachingError = Marshal.GetLastWin32Error();
                                success = false; 
                            }
                        }
                    }
                } 

                RuntimeHelpers.PrepareConstrainedRegions(); 
                try 
                {
                    // Make the sequence non-interruptible 
                }
                finally
                {
                    try 
                    {
                        // 
                        // Open the thread token; if there is no thread token, get one from 
                        // the process token by impersonating self.
                        // 

                        SafeTokenHandle threadHandleBefore = this.threadHandle;
                        error = FCall.OpenThreadToken(
                                      TokenAccessLevels.Query | TokenAccessLevels.AdjustPrivileges, 
                                      WinSecurityContext.Process,
                                      out this.threadHandle ); 
                        unchecked { error &= ~(int)0x80070000; } 

                        if ( error != 0 ) 
                        {
                            if ( success == true )
                            {
                                this.threadHandle = threadHandleBefore; 

                                if ( error != Win32Native.ERROR_NO_TOKEN ) 
                                { 
                                    success = false;
                                } 

                                BCLDebug.Assert( this.isImpersonating == false, "Incorrect isImpersonating state" );

                                if ( success == true ) 
                                {
                                    error = 0; 
                                    if ( false == Win32Native.DuplicateTokenEx( 
                                                    processHandle,
                                                    TokenAccessLevels.Impersonate | TokenAccessLevels.Query | TokenAccessLevels.AdjustPrivileges, 
                                                    IntPtr.Zero,
                                                    Win32Native.SECURITY_IMPERSONATION_LEVEL.Impersonation,
                                                    System.Security.Principal.TokenType.TokenImpersonation,
                                                    ref this.threadHandle )) 
                                    {
                                        error = Marshal.GetLastWin32Error(); 
                                        success = false; 
                                    }
                                } 

                                if ( success == true )
                                {
                                    error = FCall.SetThreadToken( this.threadHandle ); 
                                    unchecked { error &= ~(int)0x80070000; }
 
                                    if ( error != 0 ) 
                                    {
                                        success = false; 
                                    }
                                }

                                if ( success == true ) 
                                {
                                    this.isImpersonating = true; 
                                } 
                            }
                            else 
                            {
                                error = cachingError;
                            }
                        } 
                        else
                        { 
                            success = true; 
                        }
                    } 
                    finally
                    {
                        if ( !success )
                        { 
                            Dispose();
                        } 
                    } 
                }
 
                if ( error == Win32Native.ERROR_NOT_ENOUGH_MEMORY )
                {
                    throw new OutOfMemoryException();
                } 
                else if ( error == Win32Native.ERROR_ACCESS_DENIED ||
                    error == Win32Native.ERROR_CANT_OPEN_ANONYMOUS ) 
                { 
                    throw new UnauthorizedAccessException();
                } 
                else if ( error != 0 )
                {
                    BCLDebug.Assert( false, string.Format( CultureInfo.InvariantCulture, "WindowsIdentity.GetCurrentThreadToken() failed with unrecognized error code {0}", error ));
                    throw new InvalidOperationException(); 
                }
            } 
 
            ~TlsContents()
            { 
                if ( !this.disposed )
                {
                    Dispose( false );
                } 
            }
#endregion 
 
#region IDisposable implementation
 
            public void Dispose()
            {
                Dispose( true );
                GC.SuppressFinalize( this ); 
            }
 
            private void Dispose( bool disposing ) 
            {
                if ( this.disposed ) return; 

                if ( disposing )
                {
                    if ( this.threadHandle != null ) 
                    {
                        this.threadHandle.Dispose(); 
                        this.threadHandle = null; 
                    }
                } 

                if ( this.isImpersonating )
                {
                    FCall.RevertToSelf(); 
                }
 
                this.disposed = true; 
            }
#endregion 

#region Reference Counting

            public void IncrementReferenceCount() 
            {
                this.referenceCount++; 
            } 

            public int DecrementReferenceCount() 
            {
                int result = --this.referenceCount;

                if ( result == 0 ) 
                {
                    Dispose(); 
                } 

                return result; 
            }

            public int ReferenceCountValue
            { 
                get { return this.referenceCount; }
            } 
#endregion 

#region Properties 

            public SafeTokenHandle ThreadHandle
            {
                get { return this.threadHandle; } 
            }
 
            public bool IsImpersonating 
            {
                get { return this.isImpersonating; } 
            }
#endregion
        }
 
#region Constructors
 
        public Privilege( string privilegeName ) 
        {
            if ( !WindowsIdentity.RunningOnWin2K ) 
            {
                throw new NotSupportedException( Environment.GetResourceString( "PlatformNotSupported_RequiresNT" ));
            }
 
            if ( privilegeName == null )
            { 
                throw new ArgumentNullException( "privilegeName" ); 
            }
 
            this.luid = LuidFromPrivilege( privilegeName );
        }
#endregion
 
        //
        // Finalizer simply ensures that the privilege was not leaked 
        // 

        ~Privilege() 
        {
            BCLDebug.Assert( !this.needToRevert, "Must revert privileges that you alter!" );

            if ( this.needToRevert ) 
            {
                Revert(); 
            } 
        }
 
#region Public interface
        [ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
        public void Enable()
        { 
            this.ToggleState( true );
        } 
 
        public bool NeedToRevert
        { 
            get { return this.needToRevert; }
        }

#endregion 

//      [SecurityPermission( SecurityAction.Demand, TogglePrivileges=true )] 
        [ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )] 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain | ResourceScope.Assembly)] 
        private void ToggleState( bool enable )
        {
            int error = 0;
 
            //
            // All privilege operations must take place on the same thread 
            // 

            if ( !this.currentThread.Equals( Thread.CurrentThread )) 
            {
                throw new InvalidOperationException( Environment.GetResourceString( "InvalidOperation_MustBeSameThread" ));
            }
 
            //
            // This privilege was already altered and needs to be reverted before it can be altered again 
            // 

            if ( this.needToRevert ) 
            {
                throw new InvalidOperationException( Environment.GetResourceString( "InvalidOperation_MustRevertPrivilege" ));
            }
 
            //
            // Need to make this block of code non-interruptible so that it would preserve 
            // consistency of thread oken state even in the face of catastrophic exceptions 
            //
 
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                // 
                // The payload is entirely in the finally block
                // This is how we ensure that the code will not be 
                // interrupted by catastrophic exceptions 
                //
            } 
            finally
            {
                try
                { 
                    //
                    // Retrieve TLS state 
                    // 

                    this.tlsContents = Thread.GetData( tlsSlot ) as TlsContents; 

                    if ( this.tlsContents == null )
                    {
                        this.tlsContents = new TlsContents(); 
                        Thread.SetData( tlsSlot, this.tlsContents );
                    } 
                    else 
                    {
                        this.tlsContents.IncrementReferenceCount(); 
                    }

                    Win32Native.TOKEN_PRIVILEGE newState = new Win32Native.TOKEN_PRIVILEGE();
                    newState.PrivilegeCount = 1; 
                    newState.Privilege.Luid = this.luid;
                    newState.Privilege.Attributes = enable ? Win32Native.SE_PRIVILEGE_ENABLED : Win32Native.SE_PRIVILEGE_DISABLED; 
 
                    Win32Native.TOKEN_PRIVILEGE previousState = new Win32Native.TOKEN_PRIVILEGE();
                    uint previousSize = 0; 

                    //
                    // Place the new privilege on the thread token and remember the previous state.
                    // 

                    if ( false == Win32Native.AdjustTokenPrivileges( 
                                      this.tlsContents.ThreadHandle, 
                                      false,
                                      ref newState, 
                                      ( uint )Marshal.SizeOf( previousState ),
                                      ref previousState,
                                      ref previousSize ))
                    { 
                        error = Marshal.GetLastWin32Error();
                    } 
                    else if ( Win32Native.ERROR_NOT_ALL_ASSIGNED == Marshal.GetLastWin32Error()) 
                    {
                        error = Win32Native.ERROR_NOT_ALL_ASSIGNED; 
                    }
                    else
                    {
                        // 
                        // This is the initial state that revert will have to go back to
                        // 
 
                        this.initialState = (( previousState.Privilege.Attributes & Win32Native.SE_PRIVILEGE_ENABLED ) != 0 );
 
                        //
                        // Remember whether state has changed at all
                        //
 
                        this.stateWasChanged = ( this.initialState != enable );
 
                        // 
                        // If we had to impersonate, or if the privilege state changed we'll need to revert
                        // 

                        this.needToRevert = this.tlsContents.IsImpersonating || this.stateWasChanged;
                    }
                } 
                finally
                { 
                    if ( !this.needToRevert ) 
                    {
                        this.Reset(); 
                    }
                }
            }
 
            if ( error == Win32Native.ERROR_NOT_ALL_ASSIGNED )
            { 
                throw new PrivilegeNotHeldException( privileges[this.luid] as string ); 
            }
            if ( error == Win32Native.ERROR_NOT_ENOUGH_MEMORY ) 
            {
                throw new OutOfMemoryException();
            }
            else if ( error == Win32Native.ERROR_ACCESS_DENIED || 
                error == Win32Native.ERROR_CANT_OPEN_ANONYMOUS )
            { 
                throw new UnauthorizedAccessException(); 
            }
            else if ( error != 0 ) 
            {
                BCLDebug.Assert( false, string.Format( CultureInfo.InvariantCulture, "AdjustTokenPrivileges() failed with unrecognized error code {0}", error ));
                throw new InvalidOperationException();
            } 
        }
 
//      [SecurityPermission( SecurityAction.Demand, TogglePrivileges=true )] 
        [ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
        public void Revert() 
        {
            int error = 0;

            if ( !this.currentThread.Equals( Thread.CurrentThread )) 
            {
                throw new InvalidOperationException( Environment.GetResourceString( "InvalidOperation_MustBeSameThread" )); 
            } 

            if ( !this.NeedToRevert ) 
            {
                return;
            }
 
            //
            // This code must be eagerly prepared and non-interruptible. 
            // 

            RuntimeHelpers.PrepareConstrainedRegions(); 
            try
            {
                //
                // The payload is entirely in the finally block 
                // This is how we ensure that the code will not be
                // interrupted by catastrophic exceptions 
                // 
            }
            finally 
            {
                bool success = true;

                try 
                {
                    // 
                    // Only call AdjustTokenPrivileges if we're not going to be reverting to self, 
                    // on this Revert, since doing the latter obliterates the thread token anyway
                    // 

                    if ( this.stateWasChanged &&
                        ( this.tlsContents.ReferenceCountValue > 1 ||
                          !this.tlsContents.IsImpersonating )) 
                    {
                        Win32Native.TOKEN_PRIVILEGE newState = new Win32Native.TOKEN_PRIVILEGE(); 
                        newState.PrivilegeCount = 1; 
                        newState.Privilege.Luid = this.luid;
                        newState.Privilege.Attributes = ( this.initialState ? Win32Native.SE_PRIVILEGE_ENABLED : Win32Native.SE_PRIVILEGE_DISABLED ); 

                        Win32Native.TOKEN_PRIVILEGE previousState = new Win32Native.TOKEN_PRIVILEGE();
                        uint previousSize = 0;
 
                        if ( false == Win32Native.AdjustTokenPrivileges(
                                          this.tlsContents.ThreadHandle, 
                                          false, 
                                          ref newState,
                                          ( uint )Marshal.SizeOf( previousState ), 
                                          ref previousState,
                                          ref previousSize ))
                        {
                            error = Marshal.GetLastWin32Error(); 
                            success = false;
                        } 
                    } 
                }
                finally 
                {
                    if ( success )
                    {
                        this.Reset(); 
                    }
                } 
            } 

            if ( error == Win32Native.ERROR_NOT_ENOUGH_MEMORY ) 
            {
                throw new OutOfMemoryException();
            }
            else if ( error == Win32Native.ERROR_ACCESS_DENIED ) 
            {
                throw new UnauthorizedAccessException(); 
            } 
            else if ( error != 0 )
            { 
                BCLDebug.Assert( false, string.Format( CultureInfo.InvariantCulture, "AdjustTokenPrivileges() failed with unrecognized error code {0}", error ));
                throw new InvalidOperationException();
            }
        } 
#if false
        [ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )] 
        public static void RunWithPrivilege( string privilege, bool enabled, PrivilegedHelper helper ) 
        {
            if ( helper == null ) 
            {
                throw new ArgumentNullException( "helper" );
            }
 
            Privilege p = new Privilege( privilege );
 
            RuntimeHelpers.PrepareConstrainedRegions(); 

            try 
            {
                if (enabled)
                {
                    p.Enable(); 
                }
                else 
                { 
                    p.Disable();
                } 

                helper();
            }
            finally 
            {
                p.Revert(); 
            } 
        }
#endif 

        [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)] 
        private void Reset()
        { 
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try
            { 
            }
            finally
            {
                this.stateWasChanged = false; 
                this.initialState = false;
                this.needToRevert = false; 
 
                if ( this.tlsContents != null )
                { 
                    if ( 0 == this.tlsContents.DecrementReferenceCount())
                    {
                        this.tlsContents = null;
                        Thread.SetData( tlsSlot, null ); 
                    }
                } 
            } 
        }
    } 
}
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK