File: system\security\securitycontext.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
/*============================================================
**
** Class:  SecurityContext
** 
** <OWNER>Microsoft</OWNER>
**
**
** Purpose: Capture security  context for a thread
**
** 
===========================================================*/
namespace System.Security
{    
    using Microsoft.Win32;
    using Microsoft.Win32.SafeHandles;
    using System.Threading;
    using System.Runtime.Remoting;
    using System.Security.Principal;
    using System.Collections;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
    using System.Runtime.InteropServices;
    using System.Runtime.CompilerServices;
#if FEATURE_CORRUPTING_EXCEPTIONS
    using System.Runtime.ExceptionServices;
#endif // FEATURE_CORRUPTING_EXCEPTIONS
    using System.Runtime.ConstrainedExecution;
    using System.Runtime.Versioning;
    using System.Diagnostics.Contracts;
    using System.Diagnostics.CodeAnalysis;
 
    // This enum must be kept in sync with the SecurityContextSource enum in the VM
    public enum SecurityContextSource
    {
        CurrentAppDomain = 0,
        CurrentAssembly
    }
 
    internal enum SecurityContextDisableFlow
    {
        Nothing = 0,
        WI = 0x1,
        All = 0x3FFF
    }
 
#if !FEATURE_PAL && FEATURE_IMPERSONATION
    internal enum WindowsImpersonationFlowMode { 
    IMP_FASTFLOW = 0,
       IMP_NOFLOW = 1,
       IMP_ALWAYSFLOW = 2,
       IMP_DEFAULT = IMP_FASTFLOW 
    }
#endif
 
#if FEATURE_COMPRESSEDSTACK
    internal struct SecurityContextSwitcher: IDisposable
    {
        internal SecurityContext.Reader prevSC; // prev SC that we restore on an Undo
        internal SecurityContext currSC; //current SC  - SetSecurityContext that created the switcher set this on the Thread
        internal ExecutionContext currEC; // current ExecutionContext on Thread
        internal CompressedStackSwitcher cssw;
#if !FEATURE_PAL && FEATURE_IMPERSONATION
        internal WindowsImpersonationContext wic;
#endif
 
        [System.Security.SecuritySafeCritical] // overrides public transparent member
        public void Dispose()
        {
            Undo();
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
#if FEATURE_CORRUPTING_EXCEPTIONS
        [HandleProcessCorruptedStateExceptions] // 
        [SuppressMessage("Microsoft.Security", "CA2153:DoNotCatchCorruptedStateExceptionsInGeneralHandlers", Justification = "Reviewed for security")]
#endif // FEATURE_CORRUPTING_EXCEPTIONS
        internal bool UndoNoThrow()
        {
            try
            {
                Undo();
            }
            catch (Exception ex)
            {
                if (!AppContextSwitches.UseLegacyExecutionContextBehaviorUponUndoFailure)
                {
                    // Fail fast since we can't continue safely
                    Environment.FailFast(Environment.GetResourceString("ExecutionContext_UndoFailed"), ex);
                }
                return false;
            }
            return true;
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]  // FailFast
#if FEATURE_CORRUPTING_EXCEPTIONS
        [HandleProcessCorruptedStateExceptions] // 
        [SuppressMessage("Microsoft.Security", "CA2153:DoNotCatchCorruptedStateExceptionsInGeneralHandlers", Justification = "Reviewed for security")]
#endif // FEATURE_CORRUPTING_EXCEPTIONS
        public void Undo()
        {        
            if (currSC == null) 
            {
                return; // mutiple Undo()s called on this switcher object
            }  
 
            if (currEC != null)
            {
                Contract.Assert(currEC == Thread.CurrentThread.GetMutableExecutionContext(), "SecurityContextSwitcher used from another thread");
                Contract.Assert(currSC == currEC.SecurityContext, "SecurityContextSwitcher context mismatch");
            
                // restore the saved security context 
                currEC.SecurityContext = prevSC.DangerousGetRawSecurityContext();
            }
            else
            {
                // caller must have already restored the ExecutionContext
                Contract.Assert(Thread.CurrentThread.GetExecutionContextReader().SecurityContext.IsSame(prevSC));
            }
 
            currSC = null; // this will prevent the switcher object being used again        
 
            bool bNoException = true;
#if !FEATURE_PAL && FEATURE_IMPERSONATION
            try 
            {
                if (wic != null)
                    bNoException &= wic.UndoNoThrow();
            }
            catch
            {
                // Failfast since we can't continue safely...
                bNoException &= cssw.UndoNoThrow();
                System.Environment.FailFast(Environment.GetResourceString("ExecutionContext_UndoFailed"));
                
            }
#endif
            bNoException &= cssw.UndoNoThrow();
 
 
            if (!bNoException)
            {
                // Failfast since we can't continue safely...
                System.Environment.FailFast(Environment.GetResourceString("ExecutionContext_UndoFailed"));                
            }
 
        }
    }
    
 
    public sealed class SecurityContext : IDisposable 
    {
#if !FEATURE_PAL && FEATURE_IMPERSONATION
        // Note that only one of the following variables will be true. The way we set up the flow mode in the g_pConfig guarantees this.
        static bool _LegacyImpersonationPolicy = (GetImpersonationFlowMode() == WindowsImpersonationFlowMode.IMP_NOFLOW);
        static bool _alwaysFlowImpersonationPolicy = (GetImpersonationFlowMode() == WindowsImpersonationFlowMode.IMP_ALWAYSFLOW);
#endif
        /*=========================================================================
        ** Data accessed from managed code that needs to be defined in 
        ** SecurityContextObject  to maintain alignment between the two classes.
        ** DON'T CHANGE THESE UNLESS YOU MODIFY SecurityContextObject in vm\object.h
        =========================================================================*/
        
        private ExecutionContext            _executionContext;
#if !FEATURE_PAL && FEATURE_IMPERSONATION
        private volatile WindowsIdentity             _windowsIdentity;
#endif
        private volatile CompressedStack          _compressedStack;
        static private volatile SecurityContext _fullTrustSC;
        
        internal volatile bool isNewCapture = false;
        internal volatile SecurityContextDisableFlow _disableFlow = SecurityContextDisableFlow.Nothing;
                
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        internal SecurityContext()
        {
        }
 
        internal struct Reader
        {
            SecurityContext m_sc;
 
            public Reader(SecurityContext sc) { m_sc = sc; }
 
            public SecurityContext DangerousGetRawSecurityContext() { return m_sc; }
 
            public bool IsNull { get { return m_sc == null; } }
            public bool IsSame(SecurityContext sc) { return m_sc == sc; }
            public bool IsSame(SecurityContext.Reader sc) { return m_sc == sc.m_sc; }
 
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public bool IsFlowSuppressed(SecurityContextDisableFlow flags)
            {           
                return (m_sc == null) ? false : ((m_sc._disableFlow & flags) == flags);
            }
        
            public CompressedStack CompressedStack { get { return IsNull ? null : m_sc.CompressedStack; } }
 
            public WindowsIdentity WindowsIdentity 
            { 
                [MethodImpl(MethodImplOptions.AggressiveInlining)]
                get { return IsNull ? null : m_sc.WindowsIdentity; } 
            }
        }
        
            
        static internal SecurityContext FullTrustSecurityContext
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (_fullTrustSC == null)
                    _fullTrustSC = CreateFullTrustSecurityContext();
                return _fullTrustSC;
            }
        }
 
        // link the security context to an ExecutionContext
        internal ExecutionContext ExecutionContext
        {
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            set
            {
                _executionContext = value;
            }
        }
                
#if !FEATURE_PAL && FEATURE_IMPERSONATION
 
 
        internal WindowsIdentity WindowsIdentity 
        {
            get 
            {
                return _windowsIdentity;
            }
            set
            {
                // Note, we do not dispose of the existing windows identity, since some code such as remoting
                // relies on reusing that identity.  If you are not going to reuse the existing identity, then
                // you should dispose of the existing identity before resetting it.
                    _windowsIdentity = value;
            }
        }
#endif // !FEATURE_PAL && FEATURE_IMPERSONATION
 
              
        internal CompressedStack CompressedStack
        {
            get
            {
                return _compressedStack; 
            }
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            set
            {
                _compressedStack =  value;                    
            }
        }
 
        public void Dispose()
        {
#if !FEATURE_PAL && FEATURE_IMPERSONATION
            if (_windowsIdentity != null)
                _windowsIdentity.Dispose();
#endif // !FEATURE_PAL
        }
 
        [System.Security.SecurityCritical]  // auto-generated_required
        public static AsyncFlowControl SuppressFlow()
        {
            return SuppressFlow(SecurityContextDisableFlow.All);
        }
        
        [System.Security.SecurityCritical]  // auto-generated_required
        public static AsyncFlowControl SuppressFlowWindowsIdentity()
        {
            return SuppressFlow(SecurityContextDisableFlow.WI);
        }
 
        [SecurityCritical]
        internal static AsyncFlowControl SuppressFlow(SecurityContextDisableFlow flags)
        {
            if (IsFlowSuppressed(flags))
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotSupressFlowMultipleTimes"));
            }
 
            ExecutionContext ec = Thread.CurrentThread.GetMutableExecutionContext();
            if (ec.SecurityContext == null)
                ec.SecurityContext = new SecurityContext();
            AsyncFlowControl afc = new AsyncFlowControl();
            afc.Setup(flags);
            return afc;
        }
 
        [SecuritySafeCritical]
        public static void RestoreFlow()
        {
            SecurityContext sc = Thread.CurrentThread.GetMutableExecutionContext().SecurityContext;
            if (sc == null || sc._disableFlow == SecurityContextDisableFlow.Nothing)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_CannotRestoreUnsupressedFlow"));
            }
            sc._disableFlow = SecurityContextDisableFlow.Nothing;        
        }
 
        public static bool IsFlowSuppressed()
        {
            return SecurityContext.IsFlowSuppressed(SecurityContextDisableFlow.All);
        }
#if !FEATURE_PAL && FEATURE_IMPERSONATION
        public static bool IsWindowsIdentityFlowSuppressed()
        {
            return (_LegacyImpersonationPolicy|| SecurityContext.IsFlowSuppressed(SecurityContextDisableFlow.WI));
        }
#endif        
        [SecuritySafeCritical]
        internal static bool IsFlowSuppressed(SecurityContextDisableFlow flags)
        {           
            return Thread.CurrentThread.GetExecutionContextReader().SecurityContext.IsFlowSuppressed(flags);
        }
 
        // This method is special from a security perspective - the VM will not allow a stack walk to
        // continue past the call to SecurityContext.Run.  If you change the signature to this method, or
        // provide an alternate way to do a SecurityContext.Run make sure to update
        // SecurityStackWalk::IsSpecialRunFrame in the VM to search for the new method.
        [System.Security.SecurityCritical]  // auto-generated_required
        [DynamicSecurityMethodAttribute()]
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        public static void Run(SecurityContext securityContext, ContextCallback callback, Object state)
        {
            if (securityContext == null )
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NullContext"));
            }
            Contract.EndContractBlock();
 
            StackCrawlMark stackMark = StackCrawlMark.LookForMe;
 
            if (!securityContext.isNewCapture)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotNewCaptureContext"));
            }
 
            securityContext.isNewCapture = false;
 
            ExecutionContext.Reader ec = Thread.CurrentThread.GetExecutionContextReader();
            
            // Optimization: do the callback directly if both the current and target contexts are equal to the
            // default full-trust security context
            if ( SecurityContext.CurrentlyInDefaultFTSecurityContext(ec)
                && securityContext.IsDefaultFTSecurityContext())
            {
                callback(state);
                
                if (GetCurrentWI(Thread.CurrentThread.GetExecutionContextReader()) != null) 
                {
                    // If we enter here it means the callback did an impersonation
                    // that we need to revert.
                    // We don't need to revert any other security state since it is stack-based 
                    // and automatically goes away when the callback returns.
                    WindowsIdentity.SafeRevertToSelf(ref stackMark);
                    // Ensure we have reverted to the state we entered in.
                    Contract.Assert(GetCurrentWI(Thread.CurrentThread.GetExecutionContextReader()) == null);
                }
            }
            else
            {
                RunInternal(securityContext, callback, state);
            }
 
        }
        [System.Security.SecurityCritical]  // auto-generated
        internal static void RunInternal(SecurityContext securityContext, ContextCallback callBack, Object state)
        {
            if (cleanupCode == null)
            {
                tryCode = new RuntimeHelpers.TryCode(runTryCode);
                cleanupCode = new RuntimeHelpers.CleanupCode(runFinallyCode);
            }
            SecurityContextRunData runData = new SecurityContextRunData(securityContext, callBack, state);
            RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(tryCode, cleanupCode, runData);
 
        }
        
        internal class SecurityContextRunData
        {
            internal SecurityContext sc;
            internal ContextCallback callBack;
            internal Object state;
            internal SecurityContextSwitcher scsw;
            internal SecurityContextRunData(SecurityContext securityContext, ContextCallback cb, Object state)
            {
                this.sc = securityContext;
                this.callBack = cb;
                this.state = state;
                this.scsw = new SecurityContextSwitcher();
            }
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        static internal void runTryCode(Object userData)
        {
            SecurityContextRunData rData = (SecurityContextRunData) userData;
            rData.scsw = SetSecurityContext(rData.sc, Thread.CurrentThread.GetExecutionContextReader().SecurityContext, modifyCurrentExecutionContext: true);
            rData.callBack(rData.state);
            
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        [PrePrepareMethod]
        static internal void runFinallyCode(Object userData, bool exceptionThrown)
        {
            SecurityContextRunData rData = (SecurityContextRunData) userData;
            rData.scsw.Undo();
        }
                    
        static volatile internal RuntimeHelpers.TryCode tryCode;
        static volatile internal RuntimeHelpers.CleanupCode cleanupCode;
 
 
 
        // Internal API that gets called from public SetSecurityContext and from SetExecutionContext
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.Process)]
        [ResourceConsumption(ResourceScope.Process)]
        [DynamicSecurityMethodAttribute()]
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        internal static SecurityContextSwitcher SetSecurityContext(SecurityContext sc, SecurityContext.Reader prevSecurityContext, bool modifyCurrentExecutionContext)
        {
            StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
            return SetSecurityContext(sc, prevSecurityContext, modifyCurrentExecutionContext, ref stackMark);
        }
 
        [System.Security.SecurityCritical]  // auto-generated
#if FEATURE_CORRUPTING_EXCEPTIONS
        [HandleProcessCorruptedStateExceptions] // 
        [SuppressMessage("Microsoft.Security", "CA2153:DoNotCatchCorruptedStateExceptionsInGeneralHandlers", Justification = "Reviewed for security")]
#endif // FEATURE_CORRUPTING_EXCEPTIONS
        internal static SecurityContextSwitcher SetSecurityContext(SecurityContext sc, SecurityContext.Reader prevSecurityContext, bool modifyCurrentExecutionContext, ref StackCrawlMark stackMark)
        {
            // Save the flow state at capture and reset it in the SC.
            SecurityContextDisableFlow _capturedFlowState = sc._disableFlow;
            sc._disableFlow = SecurityContextDisableFlow.Nothing;
            
            //Set up the switcher object
            SecurityContextSwitcher scsw = new SecurityContextSwitcher();
            scsw.currSC = sc;   
            scsw.prevSC = prevSecurityContext;
 
            if (modifyCurrentExecutionContext)
            {
                // save the current Execution Context
                ExecutionContext currEC = Thread.CurrentThread.GetMutableExecutionContext();
                scsw.currEC = currEC;
                currEC.SecurityContext = sc;
            }
 
            if (sc != null)
            {
                RuntimeHelpers.PrepareConstrainedRegions();
                try
                {
#if !FEATURE_PAL && FEATURE_IMPERSONATION
                    scsw.wic = null;
                    if (!_LegacyImpersonationPolicy)
                    {
                        if (sc.WindowsIdentity != null)
                        {
                            scsw.wic = sc.WindowsIdentity.Impersonate(ref stackMark);
                        }
                        else if ( ((_capturedFlowState & SecurityContextDisableFlow.WI) == 0) 
                            && prevSecurityContext.WindowsIdentity != null)
                        {
                            // revert impersonation if there was no WI flow supression at capture and we're currently impersonating
                            scsw.wic = WindowsIdentity.SafeRevertToSelf(ref stackMark); 
                        }
                    }
#endif
                    scsw.cssw = CompressedStack.SetCompressedStack(sc.CompressedStack, prevSecurityContext.CompressedStack);
                }
                catch
                {
                    scsw.UndoNoThrow();
                    throw;
                }
            }
            return scsw;
        }
 
        /// <internalonly/>
        [System.Security.SecuritySafeCritical]  // auto-generated
        public SecurityContext CreateCopy()
        {
            if (!isNewCapture)
            {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotNewCaptureContext"));
            }                                
 
            SecurityContext sc = new SecurityContext();
            sc.isNewCapture = true;
            sc._disableFlow = _disableFlow;
 
#if !FEATURE_PAL && FEATURE_IMPERSONATION
            if (WindowsIdentity != null)
                sc._windowsIdentity = new WindowsIdentity(WindowsIdentity.AccessToken);
#endif //!FEATURE_PAL && FEATURE_IMPERSONATION
 
            if (_compressedStack != null)
                sc._compressedStack = _compressedStack.CreateCopy();
 
            return sc;
        }
 
        /// <internalonly/>
        [System.Security.SecuritySafeCritical]  // auto-generated
        internal SecurityContext CreateMutableCopy()
        {
            Contract.Assert(!this.isNewCapture);
 
            SecurityContext sc = new SecurityContext();
            sc._disableFlow = this._disableFlow;
 
#if !FEATURE_PAL && FEATURE_IMPERSONATION
            if (this.WindowsIdentity != null)
                sc._windowsIdentity = new WindowsIdentity(this.WindowsIdentity.AccessToken);
#endif //!FEATURE_PAL && FEATURE_IMPERSONATION
 
            // 
            if (this._compressedStack != null)
                sc._compressedStack = this._compressedStack.CreateCopy();
 
            return sc;
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
        public static SecurityContext Capture( )
        {
            // check to see if Flow is suppressed
            if (IsFlowSuppressed()) 
                return null;
 
            StackCrawlMark stackMark= StackCrawlMark.LookForMyCaller;
            SecurityContext sc = SecurityContext.Capture(Thread.CurrentThread.GetExecutionContextReader(), ref stackMark);
            if (sc == null)
                sc = CreateFullTrustSecurityContext();
            return sc;
         }
 
        // create a clone from a non-existing SecurityContext
        [System.Security.SecurityCritical]  // auto-generated
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static internal SecurityContext Capture(ExecutionContext.Reader currThreadEC, ref StackCrawlMark stackMark)
        {
            // check to see if Flow is suppressed
            if (currThreadEC.SecurityContext.IsFlowSuppressed(SecurityContextDisableFlow.All)) 
                return null;
        
            // If we're in FT right now, return null
            if (CurrentlyInDefaultFTSecurityContext(currThreadEC))
                return null;
 
            return CaptureCore(currThreadEC, ref stackMark);
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        static private SecurityContext CaptureCore(ExecutionContext.Reader currThreadEC, ref StackCrawlMark stackMark)
        {
            SecurityContext sc = new SecurityContext();
            sc.isNewCapture = true;
 
    #if !FEATURE_PAL && FEATURE_IMPERSONATION
                // Force create WindowsIdentity
            if (!IsWindowsIdentityFlowSuppressed())
            {
                WindowsIdentity currentIdentity = GetCurrentWI(currThreadEC);
                if (currentIdentity != null)
                    sc._windowsIdentity = new WindowsIdentity(currentIdentity.AccessToken);
            }
            else
            {
                sc._disableFlow = SecurityContextDisableFlow.WI;
            }
    #endif // !FEATURE_PAL && FEATURE_IMPERSONATION
 
            // Force create CompressedStack
            sc.CompressedStack = CompressedStack.GetCompressedStack(ref stackMark);
            return sc;
        }
        [System.Security.SecurityCritical]  // auto-generated
        static internal SecurityContext CreateFullTrustSecurityContext()
        {
            SecurityContext sc = new SecurityContext();
            sc.isNewCapture = true;
        
    #if !FEATURE_PAL && FEATURE_IMPERSONATION
            if (IsWindowsIdentityFlowSuppressed())
            {
                sc._disableFlow = SecurityContextDisableFlow.WI;
            }
    #endif // !FEATURE_PAL && FEATURE_IMPERSONATION
        
 
            // Force create CompressedStack
            sc.CompressedStack = new CompressedStack(null);
            return sc;
        }
 
#if !FEATURE_PAL && FEATURE_IMPERSONATION
 
    static internal bool AlwaysFlowImpersonationPolicy { get { return _alwaysFlowImpersonationPolicy; } }
 
        // Check to see if we have a WI on the thread and return if we do
    [System.Security.SecurityCritical]  // auto-generated
    [ResourceExposure(ResourceScope.None)]
    [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    static internal WindowsIdentity GetCurrentWI(ExecutionContext.Reader threadEC)
    {
        return GetCurrentWI(threadEC, _alwaysFlowImpersonationPolicy);
    }
 
    [System.Security.SecurityCritical]  // auto-generated
    [ResourceExposure(ResourceScope.None)]
    [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    static internal WindowsIdentity GetCurrentWI(ExecutionContext.Reader threadEC, bool cachedAlwaysFlowImpersonationPolicy)
    {
        Contract.Assert(cachedAlwaysFlowImpersonationPolicy == _alwaysFlowImpersonationPolicy);
        if (cachedAlwaysFlowImpersonationPolicy)
        {
            // Examine the threadtoken at the cost of a kernel call if the user has set the IMP_ALWAYSFLOW mode
            return WindowsIdentity.GetCurrentInternal(TokenAccessLevels.MaximumAllowed, true);
        }
 
        return threadEC.SecurityContext.WindowsIdentity;
    }
 
    [System.Security.SecurityCritical]
    [ResourceExposure(ResourceScope.None)]
    [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
    static internal void RestoreCurrentWI(ExecutionContext.Reader currentEC, ExecutionContext.Reader prevEC, WindowsIdentity targetWI, bool cachedAlwaysFlowImpersonationPolicy)
    {
        Contract.Assert(currentEC.IsSame(Thread.CurrentThread.GetExecutionContextReader()));
        Contract.Assert(cachedAlwaysFlowImpersonationPolicy == _alwaysFlowImpersonationPolicy);
 
        // NOTE: cachedAlwaysFlowImpersonationPolicy is a perf optimization to avoid always having to access a static variable here.
        if (cachedAlwaysFlowImpersonationPolicy || prevEC.SecurityContext.WindowsIdentity != targetWI)
        {
            //
            // Either we're always flowing, or the target WI was obtained from the current EC in the first place.
            //
            Contract.Assert(_alwaysFlowImpersonationPolicy || currentEC.SecurityContext.WindowsIdentity == targetWI);
 
            RestoreCurrentWIInternal(targetWI);
        }
    }
 
    [System.Security.SecurityCritical]
    [ResourceExposure(ResourceScope.None)]
    [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
    static private void RestoreCurrentWIInternal(WindowsIdentity targetWI)
    {
        int hr = Win32.RevertToSelf();
        if (hr < 0)
            Environment.FailFast(Win32Native.GetMessage(hr));
 
        if (targetWI != null)
        {   
            SafeAccessTokenHandle tokenHandle = targetWI.AccessToken;
            if (tokenHandle != null && !tokenHandle.IsInvalid)
            {
                hr = Win32.ImpersonateLoggedOnUser(tokenHandle);
                if (hr < 0)
                    Environment.FailFast(Win32Native.GetMessage(hr));
            }                
        }
    }
 
    [System.Security.SecurityCritical]  // auto-generated
    internal bool IsDefaultFTSecurityContext()
    {
        return (WindowsIdentity == null && (CompressedStack == null || CompressedStack.CompressedStackHandle == null));
    }
    [System.Security.SecurityCritical]  // auto-generated
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    static internal bool CurrentlyInDefaultFTSecurityContext(ExecutionContext.Reader threadEC)
    {
        return (IsDefaultThreadSecurityInfo() && GetCurrentWI(threadEC) == null);
    }
#else
        
        internal bool IsDefaultFTSecurityContext()
        {
            return (CompressedStack == null || CompressedStack.CompressedStackHandle == null);
        }
        static internal bool CurrentlyInDefaultFTSecurityContext(ExecutionContext threadEC)
        {
            return (IsDefaultThreadSecurityInfo());
        }
#endif
#if !FEATURE_PAL && FEATURE_IMPERSONATION
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        internal extern static WindowsImpersonationFlowMode GetImpersonationFlowMode();
#endif
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        internal extern static bool IsDefaultThreadSecurityInfo();
        
    }
#endif // FEATURE_COMPRESSEDSTACK
}