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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TypeLoadException.cs
- MatrixUtil.cs
- _IPv6Address.cs
- File.cs
- Typography.cs
- PropertyMappingExceptionEventArgs.cs
- DebugTraceHelper.cs
- TimeSpanParse.cs
- ToolStripDropDownItem.cs
- DemultiplexingClientMessageFormatter.cs
- PauseStoryboard.cs
- ConfigurationManagerInternal.cs
- SmtpTransport.cs
- ManifestResourceInfo.cs
- StringInfo.cs
- FileEnumerator.cs
- CustomError.cs
- ToolStripPanelRenderEventArgs.cs
- LogicalExpr.cs
- StringArrayConverter.cs
- ErrorHandler.cs
- VirtualizedItemProviderWrapper.cs
- TextRunCache.cs
- DataSourceView.cs
- IIS7WorkerRequest.cs
- SvcMapFileSerializer.cs
- SystemGatewayIPAddressInformation.cs
- XPathScanner.cs
- ZipIOEndOfCentralDirectoryBlock.cs
- WsatAdminException.cs
- InstanceDataCollectionCollection.cs
- SerializerWriterEventHandlers.cs
- X509Chain.cs
- WebDisplayNameAttribute.cs
- CorrelationActionMessageFilter.cs
- ReflectTypeDescriptionProvider.cs
- HttpValueCollection.cs
- StreamReader.cs
- CryptoStream.cs
- mediapermission.cs
- TreeNodeBindingDepthConverter.cs
- SqlMethodCallConverter.cs
- DoubleAnimationUsingPath.cs
- PermissionSetTriple.cs
- TypeTypeConverter.cs
- TreeView.cs
- HttpResponseHeader.cs
- Size3DConverter.cs
- RectAnimationBase.cs
- TransportSecurityProtocol.cs
- BaseValidator.cs
- TextElementCollection.cs
- MouseGestureConverter.cs
- UniqueConstraint.cs
- ITextView.cs
- ErrorProvider.cs
- NamespaceMapping.cs
- ActivityMarkupSerializationProvider.cs
- AdjustableArrowCap.cs
- XPathSelectionIterator.cs
- ActiveDesignSurfaceEvent.cs
- _NegoState.cs
- PackagePart.cs
- DecoderFallback.cs
- MergeFailedEvent.cs
- KerberosReceiverSecurityToken.cs
- MachineKeyConverter.cs
- WmlCommandAdapter.cs
- Win32KeyboardDevice.cs
- FontFamilyValueSerializer.cs
- FrameAutomationPeer.cs
- PrimitiveType.cs
- TextParaLineResult.cs
- PermissionAttributes.cs
- RadioButton.cs
- Translator.cs
- ClientTargetCollection.cs
- MessageQueuePermission.cs
- EdmType.cs
- FactoryMaker.cs
- XamlReader.cs
- WmpBitmapEncoder.cs
- MarshalByValueComponent.cs
- FormsAuthenticationModule.cs
- WeakEventManager.cs
- BlobPersonalizationState.cs
- AuthorizationBehavior.cs
- Padding.cs
- Cell.cs
- IisTraceListener.cs
- WinEventQueueItem.cs
- XXXInfos.cs
- Dictionary.cs
- ConfigurationSectionGroup.cs
- EventListener.cs
- Quaternion.cs
- Rect3DValueSerializer.cs
- OracleConnectionStringBuilder.cs
- TextCompositionEventArgs.cs
- PropertyDescriptorComparer.cs