Code:
/ DotNET / DotNET / 8.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
- Vector3DAnimationUsingKeyFrames.cs
- UserControlBuildProvider.cs
- PointAnimationUsingPath.cs
- EncodingNLS.cs
- FaultHandlingFilter.cs
- DecoderNLS.cs
- HtmlFormAdapter.cs
- PeerResolverBindingElement.cs
- ExtenderControl.cs
- SendActivityDesignerTheme.cs
- GroupQuery.cs
- LockCookie.cs
- WindowsProgressbar.cs
- JsonWriter.cs
- DataContractJsonSerializerOperationBehavior.cs
- RuntimeHelpers.cs
- HatchBrush.cs
- IntermediatePolicyValidator.cs
- SQLDecimal.cs
- FamilyMapCollection.cs
- Button.cs
- ReadOnlyHierarchicalDataSourceView.cs
- SspiSafeHandles.cs
- ConfigXmlReader.cs
- ClipboardProcessor.cs
- TableItemPattern.cs
- NoPersistProperty.cs
- DataGridViewToolTip.cs
- DependentList.cs
- XPathAxisIterator.cs
- SqlDependencyListener.cs
- ChineseLunisolarCalendar.cs
- SqlErrorCollection.cs
- XPathSelectionIterator.cs
- ZoneButton.cs
- SafeProcessHandle.cs
- ADRoleFactory.cs
- OutputCacheModule.cs
- PerformanceCounterCategory.cs
- DBConnection.cs
- Win32KeyboardDevice.cs
- ConfigurationStrings.cs
- CounterSample.cs
- SafeBitVector32.cs
- DataGridViewSelectedColumnCollection.cs
- DescendentsWalkerBase.cs
- Dictionary.cs
- APCustomTypeDescriptor.cs
- XamlClipboardData.cs
- SmiTypedGetterSetter.cs
- InvalidProgramException.cs
- ImageSourceValueSerializer.cs
- DictionaryEntry.cs
- XhtmlBasicLabelAdapter.cs
- AnnouncementInnerClientCD1.cs
- BitmapVisualManager.cs
- Brush.cs
- ExpressionQuoter.cs
- ProcessThreadDesigner.cs
- InkCanvasSelection.cs
- ScriptReferenceEventArgs.cs
- Grant.cs
- SettingsPropertyValue.cs
- Vector3DCollectionValueSerializer.cs
- Parallel.cs
- PrimitiveRenderer.cs
- DictionaryEntry.cs
- XmlFormatExtensionPrefixAttribute.cs
- AsyncContentLoadedEventArgs.cs
- NumberFormatter.cs
- SingleAnimation.cs
- Win32Exception.cs
- EncryptedKeyIdentifierClause.cs
- QueryOutputWriterV1.cs
- UIElementParagraph.cs
- OracleEncoding.cs
- PrintController.cs
- DataRelationCollection.cs
- XhtmlConformanceSection.cs
- LocalizableResourceBuilder.cs
- TranslateTransform3D.cs
- InvalidProgramException.cs
- Rijndael.cs
- DataGridBoundColumn.cs
- XComponentModel.cs
- DataBindingValueUIHandler.cs
- CryptoConfig.cs
- xsdvalidator.cs
- StateDesigner.CommentLayoutGlyph.cs
- ServiceProviders.cs
- ProfileBuildProvider.cs
- VirtualPathData.cs
- ActiveXHelper.cs
- Timer.cs
- MdImport.cs
- TrustExchangeException.cs
- ApplicationProxyInternal.cs
- AccessViolationException.cs
- WorkflowOperationBehavior.cs
- ThaiBuddhistCalendar.cs