File: system\security\policy\policystatement.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
using System.Diagnostics.Contracts;
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
//  PolicyStatement.cs
// 
// <OWNER>Microsoft</OWNER>
//
//  Represents the policy associated with some piece of evidence
//
 
namespace System.Security.Policy {
    
    using System;
    using System.Security;
    using System.Security.Util;
    using Math = System.Math;
    using System.Collections;
    using System.Collections.Generic;
    using System.Security.Permissions;
    using System.Text;
    using System.Globalization;
[Serializable]
    [Flags]
[System.Runtime.InteropServices.ComVisible(true)]
    public enum PolicyStatementAttribute
    {
        Nothing = 0x0,
        Exclusive = 0x01,
        LevelFinal = 0x02,
        All = 0x03,
    }
    
    [Serializable]
    [System.Runtime.InteropServices.ComVisible(true)]
    sealed public class PolicyStatement : ISecurityPolicyEncodable, ISecurityEncodable
    {
        // The PermissionSet associated with this policy
        internal PermissionSet m_permSet;
 
#if FEATURE_CAS_POLICY
        // Evidence which was not verified but which was required to generate this policy statement.
        // This is not serialized, since once we serialize we lose the ability to verify the evidence,
        // meaning that restoring this state is meaningless.
        [NonSerialized]
        private List<IDelayEvaluatedEvidence> m_dependentEvidence;
#endif
 
        // The bitfield of inheritance properties associated with this policy
        internal PolicyStatementAttribute m_attributes;
 
        internal PolicyStatement()
        {
            m_permSet = null;
            m_attributes = PolicyStatementAttribute.Nothing;
        }
        
        public PolicyStatement( PermissionSet permSet )
            : this( permSet, PolicyStatementAttribute.Nothing )
        {
        }
        
        public PolicyStatement( PermissionSet permSet, PolicyStatementAttribute attributes )
        {
            if (permSet == null)
            {
                m_permSet = new PermissionSet( false );
            }
            else
            {
                m_permSet = permSet.Copy();
            }
            if (ValidProperties( attributes ))
            {
                m_attributes = attributes;
            }
        }
        
        private PolicyStatement( PermissionSet permSet, PolicyStatementAttribute attributes, bool copy )
        {
            if (permSet != null)
            {
                if (copy)
                    m_permSet = permSet.Copy();
                else
                    m_permSet = permSet;
            }
            else
            {
                m_permSet = new PermissionSet( false );
            }
                
            m_attributes = attributes;
        }
 
        public PermissionSet PermissionSet
        {
            get
            {
                lock (this)
                {
                    return m_permSet.Copy();
                }
            }
            
            set
            {
                lock (this)
                {
                    if (value == null)
                    {
                        m_permSet = new PermissionSet( false );
                    }
                    else
                    {
                        m_permSet = value.Copy();
                    }
                }
            }
        }
        
        internal void SetPermissionSetNoCopy( PermissionSet permSet )
        {
            m_permSet = permSet;
        }
        
        internal PermissionSet GetPermissionSetNoCopy()
        {
            lock (this)
            {
                return m_permSet;
            }
        }
        
        public PolicyStatementAttribute Attributes
        {
            get
            {
                return m_attributes;
            }
            
            set
            {
                if (ValidProperties( value ))
                {
                    m_attributes = value;
                }
            }
        }
        
        public PolicyStatement Copy()
        {
            PolicyStatement copy = new PolicyStatement(m_permSet, Attributes, true); // The PolicyStatement .ctor will copy the permission set
#if FEATURE_CAS_POLICY
            if (HasDependentEvidence)
            {
                copy.m_dependentEvidence = new List<IDelayEvaluatedEvidence>(m_dependentEvidence);
            }
#endif
 
            return copy;
        }
        
        public String AttributeString
        {
            get
            {
                StringBuilder sb = new StringBuilder();
            
                bool first = true;
            
                if (GetFlag((int) PolicyStatementAttribute.Exclusive ))
                {
                    sb.Append( "Exclusive" );
                    first = false;
                }
                if (GetFlag((int) PolicyStatementAttribute.LevelFinal ))
                {
                    if (!first)
                        sb.Append( " " );
                    sb.Append( "LevelFinal" );
                }
            
                return sb.ToString();
            }
        }
 
        private static bool ValidProperties( PolicyStatementAttribute attributes )
        {
            if ((attributes & ~(PolicyStatementAttribute.All)) == 0)
            {
                return true;
            }
            else
            {
                throw new ArgumentException( Environment.GetResourceString( "Argument_InvalidFlag" ) );
            }
        }
        
        private bool GetFlag( int flag )
        {
            return (flag & (int)m_attributes) != 0;
        }
 
#if FEATURE_CAS_POLICY
        /// <summary>
        ///     Gets all of the delay evaluated evidence which needs to be verified before this policy can
        ///     be used.
        /// </summary>
        internal IEnumerable<IDelayEvaluatedEvidence> DependentEvidence
        {
            get
            {
                BCLDebug.Assert(HasDependentEvidence, "HasDependentEvidence");
                return m_dependentEvidence.AsReadOnly();
            }
        }
 
        /// <summary>
        ///     Determine if this policy dependent upon the evaluation of any delay evaluated evidence
        /// </summary>
        internal bool HasDependentEvidence
        {
            get { return m_dependentEvidence != null && m_dependentEvidence.Count > 0; }
        }
 
        /// <summary>
        ///     Add evidence which this policy statement is depending upon being verified to be valid.
        /// </summary>
        internal void AddDependentEvidence(IDelayEvaluatedEvidence dependentEvidence)
        {
            BCLDebug.Assert(dependentEvidence != null, "dependentEvidence != null");
 
            if (m_dependentEvidence == null)
            {
                m_dependentEvidence = new List<IDelayEvaluatedEvidence>();
            }
 
            m_dependentEvidence.Add(dependentEvidence);
        }
#endif
 
        /// <summary>
        ///     Union a child policy statement into this policy statement
        /// </summary>
        internal void InplaceUnion(PolicyStatement childPolicy)
        {
            BCLDebug.Assert(childPolicy != null, "childPolicy != null");
 
            if (((Attributes & childPolicy.Attributes) & PolicyStatementAttribute.Exclusive) == PolicyStatementAttribute.Exclusive)
            {
                throw new PolicyException(Environment.GetResourceString( "Policy_MultipleExclusive" ));
            }
 
#if FEATURE_CAS_POLICY
            // If our code group generated a grant set based upon unverified evidence, or it generated a grant
            // set strictly less than that of a child group based upon unverified evidence, we need to keep
            // track of any unverified evidence our child group has.
            if (childPolicy.HasDependentEvidence)
            {
                bool childEvidenceNeedsVerification = m_permSet.IsSubsetOf(childPolicy.GetPermissionSetNoCopy()) &&
                                                      !childPolicy.GetPermissionSetNoCopy().IsSubsetOf(m_permSet);
 
                if (HasDependentEvidence || childEvidenceNeedsVerification)
                {
                    if (m_dependentEvidence == null)
                    {
                        m_dependentEvidence = new List<IDelayEvaluatedEvidence>();
                    }
 
                    m_dependentEvidence.AddRange(childPolicy.DependentEvidence);
                }
            }
#endif
 
            // We need to merge together our grant set and attributes.  The result of this merge is
            // dependent upon if we're merging a child marked exclusive or not.  If the child is not
            // exclusive, we need to union in its grant set and or in its attributes. However, if the child
            // is exclusive then it is the only code group which should have an effect on the resulting
            // grant set and therefore our grant should be ignored.
            if ((childPolicy.Attributes & PolicyStatementAttribute.Exclusive) == PolicyStatementAttribute.Exclusive)
            {
                m_permSet = childPolicy.GetPermissionSetNoCopy();
                Attributes = childPolicy.Attributes;
            }
            else
            {
                m_permSet.InplaceUnion(childPolicy.GetPermissionSetNoCopy());
                Attributes = Attributes | childPolicy.Attributes;
            }
        }
 
#if FEATURE_CAS_POLICY
 
        public SecurityElement ToXml()
        {
            return ToXml( null );
        }
 
        public void FromXml( SecurityElement et )
        {
            FromXml( et, null );
        }
 
        public SecurityElement ToXml( PolicyLevel level )
        {
            return ToXml( level, false );
        }
 
        internal SecurityElement ToXml( PolicyLevel level, bool useInternal )
        {
            SecurityElement e = new SecurityElement( "PolicyStatement" );
            e.AddAttribute( "version", "1" );
            if (m_attributes != PolicyStatementAttribute.Nothing)
                e.AddAttribute( "Attributes", XMLUtil.BitFieldEnumToString( typeof( PolicyStatementAttribute ), m_attributes ) );            
            
            lock (this)
            {
                if (m_permSet != null)
                {
                    if (m_permSet is NamedPermissionSet)
                    {
                        // If the named permission set exists in the parent level of this
                        // policy struct, then just save the name of the permission set.
                        // Otherwise, serialize it like normal.
                
                        NamedPermissionSet namedPermSet = (NamedPermissionSet)m_permSet;
                        if (level != null && level.GetNamedPermissionSet( namedPermSet.Name ) != null)
                        {
                            e.AddAttribute( "PermissionSetName", namedPermSet.Name );
                        }
                        else
                        {
                            if (useInternal)
                                e.AddChild( namedPermSet.InternalToXml() );
                            else
                                e.AddChild( namedPermSet.ToXml() );
                        }
                    }
                    else
                    {
                        if (useInternal)
                            e.AddChild( m_permSet.InternalToXml() );
                        else
                            e.AddChild( m_permSet.ToXml() );
                    }
                }
            }
            
            return e;
        }
        
        [System.Security.SecuritySafeCritical]  // auto-generated
        public void FromXml( SecurityElement et, PolicyLevel level )
        {
            FromXml( et, level, false );
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        internal void FromXml( SecurityElement et, PolicyLevel level, bool allowInternalOnly )
        {
            if (et == null)
                throw new ArgumentNullException( "et" );
 
            if (!et.Tag.Equals( "PolicyStatement" ))
                throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidXMLElement" ),  "PolicyStatement", this.GetType().FullName ) );
            Contract.EndContractBlock();
        
            m_attributes = (PolicyStatementAttribute) 0;
 
            String strAttributes = et.Attribute( "Attributes" );
 
            if (strAttributes != null)
                m_attributes = (PolicyStatementAttribute)Enum.Parse( typeof( PolicyStatementAttribute ), strAttributes );
 
            lock (this)
            {
                m_permSet = null;
 
                if (level != null)
                {
                    String permSetName = et.Attribute( "PermissionSetName" );
    
                    if (permSetName != null)
                    {
                        m_permSet = level.GetNamedPermissionSetInternal( permSetName );
 
                        if (m_permSet == null)
                            m_permSet = new PermissionSet( PermissionState.None );
                    }
                }
 
 
                if (m_permSet == null)
                {
                    // There is no provided level, it is not a named permission set, or
                    // the named permission set doesn't exist in the provided level,
                    // so just create the class through reflection and decode normally.
        
                    SecurityElement e = et.SearchForChildByTag( "PermissionSet" );
 
                    if (e != null)
                    {
                        String className = e.Attribute( "class" );
 
                        if (className != null && (className.Equals( "NamedPermissionSet" ) ||
                                                  className.Equals( "System.Security.NamedPermissionSet" )))
                            m_permSet = new NamedPermissionSet( "DefaultName", PermissionState.None );
                        else
                            m_permSet = new PermissionSet( PermissionState.None );
                
                        try
                        {
                            m_permSet.FromXml( e, allowInternalOnly, true );
                        }
                        catch
                        {
                            // ignore any exceptions from the decode process.
                            // Note: we go ahead and use the permission set anyway.  This should be safe since
                            // the decode process should never give permission beyond what a proper decode would have
                            // given.
                        }
                    }
                    else
                    {
                        throw new ArgumentException( Environment.GetResourceString( "Argument_InvalidXML" ) );
                    }
                }
 
                if (m_permSet == null) 
                    m_permSet = new PermissionSet( PermissionState.None );
            }    
        }
 
 
        [System.Security.SecurityCritical]  // auto-generated
        internal void FromXml( SecurityDocument doc, int position, PolicyLevel level, bool allowInternalOnly )
        {
            if (doc == null)
                throw new ArgumentNullException( "doc" );
            Contract.EndContractBlock();
 
            if (!doc.GetTagForElement( position ).Equals( "PolicyStatement" ))
                throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_InvalidXMLElement" ),  "PolicyStatement", this.GetType().FullName ) );
        
            m_attributes = (PolicyStatementAttribute) 0;
 
            String strAttributes = doc.GetAttributeForElement( position, "Attributes" );
 
            if (strAttributes != null)
                m_attributes = (PolicyStatementAttribute)Enum.Parse( typeof( PolicyStatementAttribute ), strAttributes );
 
            lock (this)
            {
                m_permSet = null;
 
                if (level != null)
                {
                    String permSetName = doc.GetAttributeForElement( position, "PermissionSetName" );
    
                    if (permSetName != null)
                    {
                        m_permSet = level.GetNamedPermissionSetInternal( permSetName );
 
                        if (m_permSet == null)
                            m_permSet = new PermissionSet( PermissionState.None );
                    }
                }
 
 
                if (m_permSet == null)
                {
                    // There is no provided level, it is not a named permission set, or
                    // the named permission set doesn't exist in the provided level,
                    // so just create the class through reflection and decode normally.
        
                    ArrayList childPositions = doc.GetChildrenPositionForElement( position );
                    int positionPermissionSet = -1;
 
                    for (int i = 0; i < childPositions.Count; ++i)
                    {
                        if (doc.GetTagForElement( (int)childPositions[i] ).Equals( "PermissionSet" ))
                        {
                            positionPermissionSet = (int)childPositions[i];
                        }
                    }
 
                    if (positionPermissionSet != -1)
                    {
                        String className = doc.GetAttributeForElement( positionPermissionSet, "class" );
 
                        if (className != null && (className.Equals( "NamedPermissionSet" ) ||
                                                  className.Equals( "System.Security.NamedPermissionSet" )))
                            m_permSet = new NamedPermissionSet( "DefaultName", PermissionState.None );
                        else
                            m_permSet = new PermissionSet( PermissionState.None );
                
                        m_permSet.FromXml( doc, positionPermissionSet, allowInternalOnly );
                    }
                    else
                    {
                        throw new ArgumentException( Environment.GetResourceString( "Argument_InvalidXML" ) );
                    }
                }
 
                if (m_permSet == null) 
                    m_permSet = new PermissionSet( PermissionState.None );
            }    
        }
#endif // FEATURE_CAS_POLICY
 
 
        [System.Runtime.InteropServices.ComVisible(false)]
        public override bool Equals( Object obj )
        {
            PolicyStatement other = obj as PolicyStatement;
 
            if (other == null)
                return false;
 
            if (this.m_attributes != other.m_attributes)
                return false;
 
            if (!Object.Equals( this.m_permSet, other.m_permSet ))
                return false;
 
            return true;
        }
 
        [System.Runtime.InteropServices.ComVisible(false)]
        public override int GetHashCode()
        {
            int accumulator = (int)this.m_attributes;
 
            if (m_permSet != null)
                accumulator = accumulator ^ m_permSet.GetHashCode();
 
            return accumulator;
        }
 
    }
}