File: system\security\framesecuritydescriptor.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
// <OWNER>Microsoft</OWNER>
namespace System.Security {
    using System.Text;
    using System.Runtime.CompilerServices;
    using System.Threading;
    using System;
    using System.Collections;
    using System.Security.Permissions;
    using System.Globalization;
    using System.Runtime.ConstrainedExecution;
    using System.Runtime.Versioning;
    using System.Diagnostics.Contracts;
#if !FEATURE_PAL
    using Microsoft.Win32.SafeHandles;
    using System.Security.Principal;
#endif    
     //FrameSecurityDescriptor.cs
    //
    // Internal use only.
    // DO NOT DOCUMENT
    //
 
    [Serializable]
    internal class FrameSecurityDescriptor
    {
    
        /*    EE has native FrameSecurityDescriptorObject definition in object.h
                Make sure to update that structure as well, if you make any changes here.
        */
        private PermissionSet       m_assertions;    // imperative asserts
        private PermissionSet       m_denials;      // imperative denials
        private PermissionSet       m_restriction;      // imperative permitonlys
        private PermissionSet       m_DeclarativeAssertions;
        private PermissionSet       m_DeclarativeDenials;
        private PermissionSet       m_DeclarativeRestrictions;
 
#if !FEATURE_PAL
        // if this frame contains a call to any WindowsIdentity.Impersonate(), 
        // we save the previous SafeTokenHandles here (in the next two fields)
        // Used during exceptionstackwalks to revert impersonation before calling filters        
        [System.Security.SecurityCritical] // auto-generated
        [NonSerialized]
        private SafeAccessTokenHandle     m_callerToken; 
        [System.Security.SecurityCritical] // auto-generated
        [NonSerialized]
        private SafeAccessTokenHandle     m_impToken;                               
#endif
 
        private bool                m_AssertFT;
        private bool                m_assertAllPossible;
#pragma warning disable 169 
        private bool                m_declSecComputed; // set from the VM to indicate that the declarative A/PO/D on this frame has been populated
#pragma warning restore 169
 
 
 
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern void IncrementOverridesCount();
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern void DecrementOverridesCount();
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern void IncrementAssertCount();
        [System.Security.SecurityCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern void DecrementAssertCount();
 
 
        // Default constructor.
        internal FrameSecurityDescriptor()
        {
            //m_flags = 0;
        }
        //-----------------------------------------------------------+
        // H E L P E R
        //-----------------------------------------------------------+
        
        private PermissionSet CreateSingletonSet(IPermission perm)
        {
            PermissionSet permSet = new PermissionSet(false);
            permSet.AddPermission(perm.Copy());
            return permSet;
        }
    
        //-----------------------------------------------------------+
        // A S S E R T
        //-----------------------------------------------------------+
 
        internal bool HasImperativeAsserts() 
        {
            // we store declarative actions in both fields, so check if they are different
            return (m_assertions != null);
        }
        internal bool HasImperativeDenials() 
        {
            // we store declarative actions in both fields, so check if they are different
            return (m_denials != null);
        }
        internal bool HasImperativeRestrictions() 
        {
            // we store declarative actions in both fields, so check if they are different
            return (m_restriction != null);
        }
        [System.Security.SecurityCritical]  // auto-generated
        internal void SetAssert(IPermission perm)
        {            
            m_assertions = CreateSingletonSet(perm);
            IncrementAssertCount();
        }
        
        [System.Security.SecurityCritical]  // auto-generated
        internal void SetAssert(PermissionSet permSet)
        {            
            m_assertions = permSet.Copy();
            m_AssertFT = m_AssertFT || m_assertions.IsUnrestricted();
            IncrementAssertCount();
        }
        
        internal PermissionSet GetAssertions(bool fDeclarative)
        {
            return (fDeclarative) ? m_DeclarativeAssertions : m_assertions;
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal void SetAssertAllPossible()
        {
            m_assertAllPossible = true;
            IncrementAssertCount();
        }
 
        internal bool GetAssertAllPossible()
        {
            return m_assertAllPossible;
        }
        
        //-----------------------------------------------------------+
        // D E N Y
        //-----------------------------------------------------------+
    
        [System.Security.SecurityCritical]  // auto-generated
        internal void SetDeny(IPermission perm)
        {
#if FEATURE_CAS_POLICY
            BCLDebug.Assert(AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled, "Deny is only valid in legacy CAS mode");
#endif // FEATURE_CAS_POLICY
 
            m_denials = CreateSingletonSet(perm);
            IncrementOverridesCount();
 
        }
        
        [System.Security.SecurityCritical]  // auto-generated
        internal void SetDeny(PermissionSet permSet)
        {
            m_denials = permSet.Copy();
            IncrementOverridesCount();
        }
    
        internal PermissionSet GetDenials(bool fDeclarative)
        {
            return (fDeclarative) ? m_DeclarativeDenials: m_denials;
        }
 
        //-----------------------------------------------------------+
        // R E S T R I C T
        //-----------------------------------------------------------+
    
        [System.Security.SecurityCritical]  // auto-generated
        internal void SetPermitOnly(IPermission perm)
        {
            m_restriction  = CreateSingletonSet(perm);
            IncrementOverridesCount();
        }
        
        [System.Security.SecurityCritical]  // auto-generated
        internal void SetPermitOnly(PermissionSet permSet)
        {
            // permSet must not be null
            m_restriction  = permSet.Copy();
            IncrementOverridesCount();
        }
        
        internal PermissionSet GetPermitOnly(bool fDeclarative)
        {
            
            return (fDeclarative) ? m_DeclarativeRestrictions : m_restriction;
        }
#if !FEATURE_PAL        
        //-----------------------------------------------------------+
        // SafeAccessTokenHandle (Impersonation + EH purposes)
        //-----------------------------------------------------------+
        [System.Security.SecurityCritical]  // auto-generated
        internal void SetTokenHandles (SafeAccessTokenHandle callerToken, SafeAccessTokenHandle impToken)
        {
            if (m_callerToken != null && !m_callerToken.IsInvalid)
            {
                m_callerToken.Dispose();
            }
            m_callerToken = callerToken;
            m_impToken = impToken;
        }
#endif
        //-----------------------------------------------------------+
        // R E V E R T
        //-----------------------------------------------------------+
    
        [System.Security.SecurityCritical]  // auto-generated
        internal void RevertAssert()
        {
            if (m_assertions != null)
            {
                m_assertions = null;
                DecrementAssertCount();
            }
 
 
            if (m_DeclarativeAssertions != null)
            {
                m_AssertFT = m_DeclarativeAssertions.IsUnrestricted();
            }
            else
            {
                m_AssertFT = false;
            }
        }
        
        [System.Security.SecurityCritical]  // auto-generated
        internal void RevertAssertAllPossible()
        {
            if (m_assertAllPossible)
            {
            m_assertAllPossible = false;
                DecrementAssertCount();
            }
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal void RevertDeny()
        {
            if (HasImperativeDenials())
            {
                DecrementOverridesCount();
                m_denials = null;
            }
        }
        
        [System.Security.SecurityCritical]  // auto-generated
        internal void RevertPermitOnly()
        {
            if (HasImperativeRestrictions())
            {
                DecrementOverridesCount();
                m_restriction= null;;
            }
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal void RevertAll()
        {
            RevertAssert();
            RevertAssertAllPossible();
            RevertDeny();
            RevertPermitOnly();
        }
 
 
        //-----------------------------------------------------------+
        // Demand Evaluation
        //-----------------------------------------------------------+
 
 
        // This will get called when we hit a FSD while evaluating a demand on the call stack or compressedstack
        [System.Security.SecurityCritical]  // auto-generated
        internal bool CheckDemand(CodeAccessPermission demand, PermissionToken permToken, RuntimeMethodHandleInternal rmh)
        {
            // imperative security
            bool fContinue = CheckDemand2(demand, permToken, rmh, false); 
            if (fContinue == SecurityRuntime.StackContinue)
            {
                // declarative security
                fContinue = CheckDemand2(demand, permToken, rmh, true);
            }
            return fContinue;
        }
        
        [System.Security.SecurityCritical]  // auto-generated
        internal bool CheckDemand2(CodeAccessPermission demand, PermissionToken permToken, RuntimeMethodHandleInternal rmh, bool fDeclarative)
        {
            PermissionSet permSet;
            
            // If the demand is null, there is no need to continue
            Contract.Assert(demand != null && !demand.CheckDemand(null), "Empty demands should have been filtered out by this point");
 
            // decode imperative
            if (GetPermitOnly(fDeclarative) != null)
                GetPermitOnly(fDeclarative).CheckDecoded(demand, permToken);
    
            if (GetDenials(fDeclarative) != null)
                GetDenials(fDeclarative).CheckDecoded(demand, permToken);
    
            if (GetAssertions(fDeclarative) != null)
                GetAssertions(fDeclarative).CheckDecoded(demand, permToken);
            
            // NOTE: See notes about exceptions and exception handling in FrameDescSetHelper 
    
            bool bThreadSecurity = SecurityManager._SetThreadSecurity(false);
    
            // Check Reduction
            
            try
            {
                permSet = GetPermitOnly(fDeclarative);
                if (permSet != null)
                {
                    CodeAccessPermission perm = (CodeAccessPermission)permSet.GetPermission(demand);
            
                    // If the permit only set does not contain the demanded permission, throw a security exception
                    if (perm == null)
                    {
                        if (!permSet.IsUnrestricted())
                            throw new SecurityException(String.Format(CultureInfo.InvariantCulture, Environment.GetResourceString("Security_Generic"), demand.GetType().AssemblyQualifiedName), null, permSet, SecurityRuntime.GetMethodInfo(rmh), demand, demand);
                    }
                    else
                    {
                        bool bNeedToThrow = true;
    
                        try
                        {
                            bNeedToThrow = !demand.CheckPermitOnly(perm);
                        }
                        catch (ArgumentException)
                        {
                        }
    
                        if (bNeedToThrow)
                            throw new SecurityException(String.Format(CultureInfo.InvariantCulture, Environment.GetResourceString("Security_Generic"), demand.GetType().AssemblyQualifiedName), null, permSet, SecurityRuntime.GetMethodInfo(rmh), demand, demand);
                    }
                }
            
                // Check Denials
            
                permSet = GetDenials(fDeclarative);
                if (permSet != null)
                {
                    CodeAccessPermission perm = (CodeAccessPermission)permSet.GetPermission(demand);
                    
                    // If an unrestricted set was denied and the demand implements IUnrestricted
                    if (permSet.IsUnrestricted())
                        throw new SecurityException(String.Format(CultureInfo.InvariantCulture, Environment.GetResourceString("Security_Generic"), demand.GetType().AssemblyQualifiedName), permSet, null, SecurityRuntime.GetMethodInfo(rmh), demand, demand);
    
                    // If the deny set does contain the demanded permission, throw a security exception
                    bool bNeedToThrow = true;
                    try
                    {
                        bNeedToThrow = !demand.CheckDeny(perm);
                    }
                    catch (ArgumentException)
                    {
                    }
                    if (bNeedToThrow)
                        throw new SecurityException(String.Format(CultureInfo.InvariantCulture, Environment.GetResourceString("Security_Generic"), demand.GetType().AssemblyQualifiedName), permSet, null, SecurityRuntime.GetMethodInfo(rmh), demand, demand);
                }
    
                if (GetAssertAllPossible())
                {
                    return SecurityRuntime.StackHalt;
                }        
    
                permSet = GetAssertions(fDeclarative);
                // Check Assertions
                if (permSet != null)
                {
            
                    CodeAccessPermission perm = (CodeAccessPermission)permSet.GetPermission(demand);
                
                    // If the assert set does contain the demanded permission, halt the stackwalk
            
                    try
                    {
                        if (permSet.IsUnrestricted() || demand.CheckAssert(perm))
                        {
                            return SecurityRuntime.StackHalt;
                        }
                    }
                    catch (ArgumentException)
                    {
                    }
                }
                
            }
            finally
            {
                if (bThreadSecurity)
                    SecurityManager._SetThreadSecurity(true);
            }
            
            return SecurityRuntime.StackContinue;
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal bool CheckSetDemand(PermissionSet demandSet,
                                                                   out PermissionSet alteredDemandSet,
                                                                   RuntimeMethodHandleInternal rmh)
        {
            // imperative security
            PermissionSet altPset1 = null, altPset2 = null;
            bool fContinue = CheckSetDemand2(demandSet, out altPset1, rmh, false); 
            if (altPset1 != null)
            {
                demandSet = altPset1;
            }
                
            if (fContinue == SecurityRuntime.StackContinue)
            {
                // declarative security
                fContinue = CheckSetDemand2(demandSet, out altPset2, rmh, true);
            }
            // Return the most recent altered set
            // If both declarative and imperative asserts modified the demand set: return altPset2
            // Else if imperative asserts modified the demand set: return altPset1
            // else no alteration: return null
            if (altPset2 != null)
                alteredDemandSet = altPset2;
            else if (altPset1 != null)
                alteredDemandSet = altPset1;
            else
                alteredDemandSet = null;                
            
            return fContinue;
        }
        
        [System.Security.SecurityCritical]  // auto-generated
        internal bool CheckSetDemand2(PermissionSet demandSet,
                                                                   out PermissionSet alteredDemandSet,
                                                                   RuntimeMethodHandleInternal rmh, bool fDeclarative)
        {
            PermissionSet permSet;
    
            // In the common case we are not going to alter the demand set, so just to
            // be safe we'll set it to null up front.
            alteredDemandSet = null;
    
            // There's some oddness in here to deal with exceptions.  The general idea behind
            // this is that we need some way of dealing with custom permissions that may not
            // handle all possible scenarios of Union(), Intersect(), and IsSubsetOf() properly
            // (they don't support it, throw null reference exceptions, etc.).
            
            // An empty demand always succeeds.
            if (demandSet == null || demandSet.IsEmpty())
                return SecurityRuntime.StackHalt;
 
            if (GetPermitOnly(fDeclarative) != null)
                GetPermitOnly(fDeclarative).CheckDecoded( demandSet );
            if (GetDenials(fDeclarative) != null)
                GetDenials(fDeclarative).CheckDecoded( demandSet );
            if (GetAssertions(fDeclarative) != null)
                GetAssertions(fDeclarative).CheckDecoded( demandSet );
            
         
            bool bThreadSecurity = SecurityManager._SetThreadSecurity(false);
    
            try
            {
                // In the case of permit only, we define an exception to be failure of the check
                // and therefore we throw a security exception.
                
                permSet = GetPermitOnly(fDeclarative);
                if (permSet != null)
                {
                    IPermission permFailed = null;
                    bool bNeedToThrow = true;
    
                    try
                    {
                        bNeedToThrow = !demandSet.CheckPermitOnly(permSet, out permFailed);
                    }
                    catch (ArgumentException)
                    {
                    }
                    if (bNeedToThrow)
                        throw new SecurityException(Environment.GetResourceString("Security_GenericNoType"), null, permSet, SecurityRuntime.GetMethodInfo(rmh), demandSet, permFailed);
                }
                
                // In the case of denial, we define an exception to be failure of the check
                // and therefore we throw a security exception.
                
                permSet = GetDenials(fDeclarative);
    
    
                if (permSet != null)
                {
                    IPermission permFailed = null;
    
                    bool bNeedToThrow = true;
    
                    try
                    {
                        bNeedToThrow = !demandSet.CheckDeny(permSet, out permFailed);
                    }
                    catch (ArgumentException)
                    {
                    }
    
                    if (bNeedToThrow)
                        throw new SecurityException(Environment.GetResourceString("Security_GenericNoType"), permSet, null, SecurityRuntime.GetMethodInfo(rmh), demandSet, permFailed);
                }
            
                // The assert case is more complex.  Since asserts have the ability to "bleed through"
                // (where part of a demand is handled by an assertion, but the rest is passed on to
                // continue the stackwalk), we need to be more careful in handling the "failure" case.
                // Therefore, if an exception is thrown in performing any operation, we make sure to keep
                // that permission in the demand set thereby continuing the demand for that permission
                // walking down the stack.
                
                if (GetAssertAllPossible())
                {
                    return SecurityRuntime.StackHalt;
                }        
            
                permSet = GetAssertions(fDeclarative);
                if (permSet != null)
                {
                    // If this frame asserts a superset of the demand set we're done
                    
                    if (demandSet.CheckAssertion( permSet ))
                        return SecurityRuntime.StackHalt;
                
                    // Determine whether any of the demand set asserted.  We do this by
                    // copying the demand set and removing anything in it that is asserted.
                        
                    if (!permSet.IsUnrestricted())
                    {
                        PermissionSet.RemoveAssertedPermissionSet(demandSet, permSet, out alteredDemandSet);
                    }
                }
    
                        }
            finally
            {
                if (bThreadSecurity)
                    SecurityManager._SetThreadSecurity(true);
            }
 
            return SecurityRuntime.StackContinue;
        }
    }
 
#if FEATURE_COMPRESSEDSTACK
    // Used by the stack compressor to communicate a DynamicResolver to managed code during a stackwalk.
    // The JIT will not actually place these on frames.
    internal class FrameSecurityDescriptorWithResolver : FrameSecurityDescriptor
    {
        private System.Reflection.Emit.DynamicResolver m_resolver;
 
        public System.Reflection.Emit.DynamicResolver Resolver
        {
            get
            {
                return m_resolver;
            }
        }
    }
#endif // FEATURE_COMPRESSEDSTACK
}