Code:
/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / 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 );
}
}
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- AssemblyAttributesGoHere.cs
- InkPresenterAutomationPeer.cs
- DetailsViewInsertEventArgs.cs
- ManagedCodeMarkers.cs
- IUnknownConstantAttribute.cs
- KnownTypeAttribute.cs
- ReverseInheritProperty.cs
- EncodingInfo.cs
- ProxyGenerationError.cs
- ClosureBinding.cs
- ServiceErrorHandler.cs
- Keyboard.cs
- ParserContext.cs
- EntityKeyElement.cs
- BlockCollection.cs
- BitmapSourceSafeMILHandle.cs
- OutKeywords.cs
- FastPropertyAccessor.cs
- QueryOptionExpression.cs
- DataGridViewUtilities.cs
- TextCharacters.cs
- UrlMappingsModule.cs
- DispatcherSynchronizationContext.cs
- EventListener.cs
- KeyGesture.cs
- SerializationInfo.cs
- CustomUserNameSecurityTokenAuthenticator.cs
- SettingsPropertyValueCollection.cs
- NativeMethods.cs
- DecoderBestFitFallback.cs
- ParallelTimeline.cs
- ClientTargetSection.cs
- RoutedUICommand.cs
- DescendantQuery.cs
- AutoGeneratedFieldProperties.cs
- TableCellCollection.cs
- CaseInsensitiveComparer.cs
- GridViewDesigner.cs
- StrongNameKeyPair.cs
- SingleTagSectionHandler.cs
- ConfigXmlWhitespace.cs
- SchemaConstraints.cs
- AvTrace.cs
- IPCCacheManager.cs
- _NativeSSPI.cs
- SortKey.cs
- ColorBlend.cs
- InfoCardArgumentException.cs
- LinkArea.cs
- DeflateEmulationStream.cs
- TypeSource.cs
- WorkflowApplicationTerminatedException.cs
- SecureConversationServiceElement.cs
- SHA1Managed.cs
- RemoteHelper.cs
- RowParagraph.cs
- storepermission.cs
- AttributeAction.cs
- ClientSideQueueItem.cs
- SettingsProperty.cs
- SamlSubjectStatement.cs
- DesignTimeParseData.cs
- BitmapEffectDrawing.cs
- HtmlInputHidden.cs
- ExtensionWindowResizeGrip.cs
- ParserContext.cs
- Deflater.cs
- Command.cs
- BridgeDataReader.cs
- StringFreezingAttribute.cs
- QilCloneVisitor.cs
- IndependentAnimationStorage.cs
- HttpStreams.cs
- pingexception.cs
- RectangleConverter.cs
- MatrixAnimationUsingPath.cs
- SizeAnimationBase.cs
- WebPartTracker.cs
- ContextMarshalException.cs
- DLinqTableProvider.cs
- ImageAutomationPeer.cs
- SelectionService.cs
- UnauthorizedWebPart.cs
- CacheEntry.cs
- ProxyElement.cs
- TakeOrSkipWhileQueryOperator.cs
- ConfigXmlDocument.cs
- DbParameterCollection.cs
- ReturnValue.cs
- SrgsElementFactoryCompiler.cs
- Parser.cs
- ContainerParaClient.cs
- XmlUnspecifiedAttribute.cs
- ScrollItemPattern.cs
- CodeParameterDeclarationExpression.cs
- XPathDocumentNavigator.cs
- ToolStripButton.cs
- OdbcError.cs
- ADConnectionHelper.cs
- SectionInformation.cs