File: system\security\util\xmlutil.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
/*============================================================
**
** CLASS:    XMLUtil
** 
** <OWNER>Microsoft</OWNER>
**
** PURPOSE:  Helpers for XML input & output
**
===========================================================*/
namespace System.Security.Util  {
    
    using System;
    using System.Security;
    using System.Security.Permissions;
    using System.Security.Policy;
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.IO;
    using System.Text;
    using System.Runtime.CompilerServices;
    using PermissionState = System.Security.Permissions.PermissionState;
    using BindingFlags = System.Reflection.BindingFlags;
    using Assembly = System.Reflection.Assembly;
    using System.Threading;
    using System.Globalization;
    using System.Reflection;
    using System.Diagnostics.Contracts;
 
    internal static class XMLUtil
    {
        //
        // Warning: Element constructors have side-effects on their
        //          third argument.
        //
        
        private const String BuiltInPermission = "System.Security.Permissions.";
#if FEATURE_CAS_POLICY        
        private const String BuiltInMembershipCondition = "System.Security.Policy.";
        private const String BuiltInCodeGroup = "System.Security.Policy.";
        private const String BuiltInApplicationSecurityManager = "System.Security.Policy.";
        private static readonly char[] sepChar =  {',', ' '};
#endif        
        public static SecurityElement
        NewPermissionElement (IPermission ip)
        {
            return NewPermissionElement (ip.GetType ().FullName) ;
        }
        
        public static SecurityElement
        NewPermissionElement (String name)
        {
            SecurityElement ecr = new SecurityElement( "Permission" );
            ecr.AddAttribute( "class", name );
            return ecr;
        }
        
        public static void
        AddClassAttribute( SecurityElement element, Type type, String typename )
        {
            // Replace any quotes with apostrophes so that we can include quoted materials
            // within classnames.  Notably the assembly name member 'loc' uses a quoted string.
        
            // NOTE: this makes assumptions as to what reflection is expecting for a type string
            // it will need to be updated if reflection changes what it wants.
        
            if ( typename == null )
                typename = type.FullName;
            Contract.Assert( type.FullName.Equals( typename ), "Incorrect class name passed! Was : " + typename + " Shoule be: " + type.FullName);
            element.AddAttribute( "class", typename + ", " + type.Module.Assembly.FullName.Replace( '\"', '\'' ) );
        }
        
        internal static bool ParseElementForAssemblyIdentification(SecurityElement el,
                                                                   out String className,
                                                                   out String assemblyName, // for example "WindowsBase"
                                                                   out String assemblyVersion)
        {
 
            className = null;
            assemblyName = null;
            assemblyVersion = null;
            
            String fullClassName = el.Attribute( "class" );
            
            if (fullClassName == null)
            {
                return false;
            }
            if (fullClassName.IndexOf('\'') >= 0)
            {
                fullClassName = fullClassName.Replace( '\'', '\"' );
            }
 
            int commaIndex = fullClassName.IndexOf( ',' );
            int namespaceClassNameLength;
            
            // If the classname is tagged with assembly information, find where
            // the assembly information begins.
            
            if (commaIndex == -1)
            {
                return false;
            }
 
            namespaceClassNameLength = commaIndex;
            className = fullClassName.Substring(0, namespaceClassNameLength);
            String assemblyFullName = fullClassName.Substring(commaIndex + 1);
            AssemblyName an = new AssemblyName(assemblyFullName);
            assemblyName = an.Name;
            assemblyVersion = an.Version.ToString();
            return true;
        }
        [System.Security.SecurityCritical]  // auto-generated
        private static bool
        ParseElementForObjectCreation( SecurityElement el,
                                       String requiredNamespace,
                                       out String className,
                                       out int classNameStart,
                                       out int classNameLength )
        {
            className = null;
            classNameStart = 0;
            classNameLength = 0;
            
            int requiredNamespaceLength = requiredNamespace.Length;
 
            String fullClassName = el.Attribute( "class" );
            
            if (fullClassName == null)
            {
                throw new ArgumentException( Environment.GetResourceString( "Argument_NoClass" ) );
            }
            
            if (fullClassName.IndexOf('\'') >= 0)
            {
                fullClassName = fullClassName.Replace( '\'', '\"' );
            }
            
            if (!PermissionToken.IsMscorlibClassName( fullClassName ))
            {
                return false;
            }
 
            int commaIndex = fullClassName.IndexOf( ',' );
            int namespaceClassNameLength;
            
            // If the classname is tagged with assembly information, find where
            // the assembly information begins.
            
            if (commaIndex == -1)
            {
                namespaceClassNameLength = fullClassName.Length;
            }
            else
            {
                namespaceClassNameLength = commaIndex;
            }
 
            // Only if the length of the class name is greater than the namespace info
            // on our requiredNamespace do we continue
            // with our check.
            
            if (namespaceClassNameLength > requiredNamespaceLength)
            {
                // Make sure we are in the required namespace.
                if (fullClassName.StartsWith(requiredNamespace, StringComparison.Ordinal))
                {
                    className = fullClassName;
                    classNameLength = namespaceClassNameLength - requiredNamespaceLength;
                    classNameStart = requiredNamespaceLength;
                    return true;
                }
            }
            
            return false;
        }
 
#if FEATURE_CAS_POLICY
        public static String SecurityObjectToXmlString(Object ob)
        {
            if(ob == null)
                return "";
            PermissionSet pset = ob as PermissionSet;
            if(pset != null)
                return pset.ToXml().ToString();
            return ((IPermission)ob).ToXml().ToString();
        }
 
        [System.Security.SecurityCritical]  // auto-generated
        public static Object XmlStringToSecurityObject(String s)
        {
            if(s == null)
                return null;
            if(s.Length < 1)
                return null;
            return SecurityElement.FromString(s).ToSecurityObject();
        }
#endif // FEATURE_CAS_POLICY
 
        [SecuritySafeCritical]
        public static IPermission
        CreatePermission (SecurityElement el, PermissionState permState, bool ignoreTypeLoadFailures)
        {
            if (el == null || !(el.Tag.Equals("Permission") || el.Tag.Equals("IPermission")) )
                throw new ArgumentException( String.Format( null, Environment.GetResourceString( "Argument_WrongElementType" ), "<Permission>" ) ) ;
            Contract.EndContractBlock();
    
            String className;
            int classNameLength;
            int classNameStart;
            
            if (!ParseElementForObjectCreation( el,
                                                BuiltInPermission,
                                                out className,
                                                out classNameStart,
                                                out classNameLength ))
            {
                goto USEREFLECTION;
            }
                                              
            // We have a built in permission, figure out which it is.
                    
            // UIPermission
            // FileIOPermission
            // SecurityPermission
            // PrincipalPermission
            // ReflectionPermission
            // FileDialogPermission
            // EnvironmentPermission
            // GacIdentityPermission
            // UrlIdentityPermission
            // SiteIdentityPermission
            // ZoneIdentityPermission
            // KeyContainerPermission
            // UnsafeForHostPermission
            // HostProtectionPermission
            // StrongNameIdentityPermission
#if !FEATURE_CORECLR                              
            // IsolatedStorageFilePermission
#endif
#if !FEATURE_PAL
            // RegistryPermission
            // PublisherIdentityPermission
#endif // !FEATURE_PAL
 
            switch (classNameLength)
            {
                case 12:
                    // UIPermission
                    if (String.Compare(className, classNameStart, "UIPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new UIPermission( permState );
                    else
                        goto USEREFLECTION;
                                
                case 16:
                    // FileIOPermission
                    if (String.Compare(className, classNameStart, "FileIOPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new FileIOPermission( permState );
                    else
                        goto USEREFLECTION;
                            
                case 18:
#if !FEATURE_PAL
                    // RegistryPermission
                    // SecurityPermission
                    if (className[classNameStart] == 'R')
                    {
                        if (String.Compare(className, classNameStart, "RegistryPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new RegistryPermission( permState );
                        else
                            goto USEREFLECTION;
                    }
                    else
                    {
                        if (String.Compare(className, classNameStart, "SecurityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new SecurityPermission( permState );
                        else
                            goto USEREFLECTION;
                    }
#else // !FEATURE_PAL
                    if (String.Compare(className, classNameStart, "SecurityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new SecurityPermission( permState );
                    else
                        goto USEREFLECTION;
#endif // !FEATURE_PAL
                  
#if !FEATURE_CORECLR              
                case 19:
                    // PrincipalPermission
                    if (String.Compare(className, classNameStart, "PrincipalPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new PrincipalPermission( permState );
                    else
                        goto USEREFLECTION;
#endif // !FEATURE_CORECLR
                case 20:
                    // ReflectionPermission
                    // FileDialogPermission
                    if (className[classNameStart] == 'R')
                    {
                        if (String.Compare(className, classNameStart, "ReflectionPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new ReflectionPermission( permState );
                        else
                            goto USEREFLECTION;
                    }
                    else
                    {
                        if (String.Compare(className, classNameStart, "FileDialogPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new FileDialogPermission( permState );
                        else
                            goto USEREFLECTION;
                    }
 
                case 21:
                    // EnvironmentPermission
                    // UrlIdentityPermission
                    // GacIdentityPermission
                    if (className[classNameStart] == 'E')
                    {
                        if (String.Compare(className, classNameStart, "EnvironmentPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new EnvironmentPermission( permState );
                        else
                            goto USEREFLECTION;
                    }
                    else if (className[classNameStart] == 'U')
                    {
                        if (String.Compare(className, classNameStart, "UrlIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new UrlIdentityPermission( permState );
                        else
                            goto USEREFLECTION;
                    }
                    else
                    {
                        if (String.Compare(className, classNameStart, "GacIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new GacIdentityPermission( permState );
                        else
                            goto USEREFLECTION;
                    }
 
                            
                case 22:
                    // SiteIdentityPermission
                    // ZoneIdentityPermission
                    // KeyContainerPermission
                    if (className[classNameStart] == 'S')
                    {
                        if (String.Compare(className, classNameStart, "SiteIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new SiteIdentityPermission( permState );
                        else
                            goto USEREFLECTION;
                    }
                    else if (className[classNameStart] == 'Z')
                    {
                        if (String.Compare(className, classNameStart, "ZoneIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new ZoneIdentityPermission( permState );
                        else
                            goto USEREFLECTION;
                    }
                    else
                    {
#if !FEATURE_PAL
                        if (String.Compare(className, classNameStart, "KeyContainerPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new KeyContainerPermission( permState );
                        else
#endif // !FEATURE_PAL
                            goto USEREFLECTION;
                    }
 
 
                case 24:
                    // HostProtectionPermission
                    if (String.Compare(className, classNameStart, "HostProtectionPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new HostProtectionPermission( permState );
                    else
                        goto USEREFLECTION;
 
#if FEATURE_X509 && FEATURE_CAS_POLICY
                case 27:
                    // PublisherIdentityPermission
                    if (String.Compare(className, classNameStart, "PublisherIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new PublisherIdentityPermission( permState );
                    else
                        goto USEREFLECTION;
#endif // FEATURE_X509 && FEATURE_CAS_POLICY
 
                case 28:
                    // StrongNameIdentityPermission
                    if (String.Compare(className, classNameStart, "StrongNameIdentityPermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new StrongNameIdentityPermission( permState );
                    else
                        goto USEREFLECTION;
#if !FEATURE_CORECLR                                                          
                case 29:
                    // IsolatedStorageFilePermission
                    if (String.Compare(className, classNameStart, "IsolatedStorageFilePermission", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new IsolatedStorageFilePermission( permState );
                    else
                        goto USEREFLECTION;
#endif                            
                default:
                    goto USEREFLECTION;
            }
    
USEREFLECTION:
 
            Object[] objs = new Object[1];
            objs[0] = permState;
 
            Type permClass = null;
            IPermission perm = null;
 
            new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
            permClass = GetClassFromElement(el, ignoreTypeLoadFailures);
            if (permClass == null)
                return null;
            if (!(typeof(IPermission).IsAssignableFrom(permClass)))
                throw new ArgumentException( Environment.GetResourceString("Argument_NotAPermissionType") );
 
            perm = (IPermission) Activator.CreateInstance(permClass, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public, null, objs, null );
 
            return perm;
        }
 
#if FEATURE_CAS_POLICY
#pragma warning disable 618 // CodeGroups are obsolete
        [System.Security.SecuritySafeCritical]  // auto-generated
        public static CodeGroup
        CreateCodeGroup (SecurityElement el)
        {
            if (el == null || !el.Tag.Equals("CodeGroup"))
                throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_WrongElementType" ), "<CodeGroup>" ) ) ;
            Contract.EndContractBlock();
    
            String className;
            int classNameLength;
            int classNameStart;
 
            if (!ParseElementForObjectCreation( el,
                                                BuiltInCodeGroup,
                                                out className,
                                                out classNameStart,
                                                out classNameLength ))
            {
                goto USEREFLECTION;
            }
    
            switch (classNameLength)
            {
                case 12:
                    // NetCodeGroup
                    if (String.Compare(className, classNameStart, "NetCodeGroup", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new NetCodeGroup();
                    else
                        goto USEREFLECTION;
 
                case 13:
                    // FileCodeGroup
                    if (String.Compare(className, classNameStart, "FileCodeGroup", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new FileCodeGroup();
                    else
                        goto USEREFLECTION;
                case 14:
                    // UnionCodeGroup
                    if (String.Compare(className, classNameStart, "UnionCodeGroup", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new UnionCodeGroup();
                    else
                        goto USEREFLECTION;
                                
                case 19:
                    // FirstMatchCodeGroup
                    if (String.Compare(className, classNameStart, "FirstMatchCodeGroup", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new FirstMatchCodeGroup();
                    else
                        goto USEREFLECTION;
 
                default:
                    goto USEREFLECTION;
            }
 
USEREFLECTION: 
            Type groupClass = null;
            CodeGroup group = null;
 
            new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
            groupClass = GetClassFromElement(el, true);
            if (groupClass == null)
                return null;
            if (!(typeof(CodeGroup).IsAssignableFrom(groupClass)))
                throw new ArgumentException( Environment.GetResourceString("Argument_NotACodeGroupType") );
 
            group = (CodeGroup) Activator.CreateInstance(groupClass, true);
 
            Contract.Assert( groupClass.Module.Assembly != Assembly.GetExecutingAssembly(),
                "This path should not get called for mscorlib based classes" );
 
            return group;
        }
#pragma warning restore 618
        
        [System.Security.SecurityCritical]  // auto-generated
        internal static IMembershipCondition
        CreateMembershipCondition( SecurityElement el )
        {
            if (el == null || !el.Tag.Equals("IMembershipCondition"))
                throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, Environment.GetResourceString( "Argument_WrongElementType" ), "<IMembershipCondition>" ) ) ;
            Contract.EndContractBlock();
    
            String className;
            int classNameStart;
            int classNameLength;
            
            if (!ParseElementForObjectCreation( el,
                                                BuiltInMembershipCondition,
                                                out className,
                                                out classNameStart,
                                                out classNameLength ))
            {
                goto USEREFLECTION;
            }
 
            // We have a built in membership condition, figure out which it is.
                    
            // Here's the list of built in membership conditions as of 9/17/2002
            // System.Security.Policy.AllMembershipCondition
            // System.Security.Policy.URLMembershipCondition
            // System.Security.Policy.SHA1MembershipCondition
            // System.Security.Policy.SiteMembershipCondition
            // System.Security.Policy.ZoneMembershipCondition                                                                                                                                                              
            // System.Security.Policy.PublisherMembershipCondition
            // System.Security.Policy.StrongNameMembershipCondition
            // System.Security.Policy.ApplicationMembershipCondition
            // System.Security.Policy.DomainApplicationMembershipCondition
            // System.Security.Policy.ApplicationDirectoryMembershipCondition
                    
            switch (classNameLength)
            {
                case 22:
                    // AllMembershipCondition
                    // URLMembershipCondition
                    if (className[classNameStart] == 'A')
                    {
                        if (String.Compare(className, classNameStart, "AllMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new AllMembershipCondition();
                        else
                            goto USEREFLECTION;
                    }
                    else
                    {
                        if (String.Compare(className, classNameStart, "UrlMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new UrlMembershipCondition();
                        else
                            goto USEREFLECTION;
                    }
                                
                case 23:
#if !FEATURE_PAL                
                    // HashMembershipCondition
                    // SiteMembershipCondition
                    // ZoneMembershipCondition                                                                                                                                                              
                    if (className[classNameStart] == 'H')
                    {
                        if (String.Compare(className, classNameStart, "HashMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new HashMembershipCondition();
                        else
                            goto USEREFLECTION;
                    }
                    else if (className[classNameStart] == 'S')
#else
                    // SiteMembershipCondition
                    // ZoneMembershipCondition                                                                                                                                                              
                    if (className[classNameStart] == 'S')
#endif // !FEATURE_PAL
                    {
                        if (String.Compare(className, classNameStart, "SiteMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new SiteMembershipCondition();
                        else
                            goto USEREFLECTION;
                    }
                    else
                    {
                        if (String.Compare(className, classNameStart, "ZoneMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
                            return new ZoneMembershipCondition();
                        else
                            goto USEREFLECTION;
                    }
 
                case 28:
#if !FEATURE_PAL
                    // PublisherMembershipCondition
                    if (String.Compare(className, classNameStart, "PublisherMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new PublisherMembershipCondition();
                    else
#endif // !FEATURE_PAL
                        goto USEREFLECTION;
 
                case 29:
                    // StrongNameMembershipCondition
                    if (String.Compare(className, classNameStart, "StrongNameMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new StrongNameMembershipCondition();
                    else
                        goto USEREFLECTION;
 
                case 39:
                    // ApplicationDirectoryMembershipCondition
                    if (String.Compare(className, classNameStart, "ApplicationDirectoryMembershipCondition", 0, classNameLength, StringComparison.Ordinal) == 0)
                        return new ApplicationDirectoryMembershipCondition();
                    else
                        goto USEREFLECTION;
 
                default:
                    goto USEREFLECTION;
            }
 
USEREFLECTION:
            Type condClass = null;
            IMembershipCondition cond = null;
    
            new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
            condClass = GetClassFromElement(el, true);
            if (condClass == null)
                return null;
            if (!(typeof(IMembershipCondition).IsAssignableFrom(condClass)))
                throw new ArgumentException( Environment.GetResourceString("Argument_NotAMembershipCondition") );
 
            cond = (IMembershipCondition) Activator.CreateInstance(condClass, true);
 
            return cond;
        }
#endif //#if FEATURE_CAS_POLICY
        internal static Type
        GetClassFromElement (SecurityElement el, bool ignoreTypeLoadFailures)
        {
            String className = el.Attribute( "class" );
 
            if (className == null)
            {
                if (ignoreTypeLoadFailures)
                    return null;
                else
                    throw new ArgumentException( String.Format( null, Environment.GetResourceString("Argument_InvalidXMLMissingAttr"), "class") );
            }
 
            if (ignoreTypeLoadFailures)
            {
                try
                {
                    return Type.GetType(className, false, false);               
                }
                catch (SecurityException)
                {
                    return null;
                }
            }
            else
                return Type.GetType(className, true, false);               
        }
 
        public static bool
        IsPermissionElement (IPermission ip,
                             SecurityElement el)
        {
            if (!el.Tag.Equals ("Permission") && !el.Tag.Equals ("IPermission"))
                return false;
                
            return true;
        }
        
        public static bool
        IsUnrestricted (SecurityElement el)
        {
            String sUnrestricted = el.Attribute( "Unrestricted" );
            
            if (sUnrestricted == null)
                return false;
 
            return sUnrestricted.Equals( "true" ) || sUnrestricted.Equals( "TRUE" ) || sUnrestricted.Equals( "True" );
        }
 
 
        public static String BitFieldEnumToString( Type type, Object value )
        {
            int iValue = (int)value;
 
            if (iValue == 0)
                return Enum.GetName( type, 0 );
 
            StringBuilder result = StringBuilderCache.Acquire();
            bool first = true;
            int flag = 0x1;
 
            for (int i = 1; i < 32; ++i)
            {
                if ((flag & iValue) != 0)
                {
                    String sFlag = Enum.GetName( type, flag );
 
                    if (sFlag == null)
                        continue;
 
                    if (!first)
                    {
                        result.Append( ", " );
                    }
 
                    result.Append( sFlag );
                    first = false;
                }
 
                flag = flag << 1;
            }
            
            return StringBuilderCache.GetStringAndRelease(result);
        } 
    }
}