diff options
Diffstat (limited to 'src/mscorlib/src/System/Security/PermissionToken.cs')
-rw-r--r-- | src/mscorlib/src/System/Security/PermissionToken.cs | 557 |
1 files changed, 557 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Security/PermissionToken.cs b/src/mscorlib/src/System/Security/PermissionToken.cs new file mode 100644 index 0000000000..1b57e6ddf6 --- /dev/null +++ b/src/mscorlib/src/System/Security/PermissionToken.cs @@ -0,0 +1,557 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Security { + using System; + using System.Security.Util; + using System.Security.Permissions; + using System.Reflection; + using System.Collections; + using System.Threading; + using System.Globalization; + using System.Runtime.CompilerServices; + using System.Diagnostics.Contracts; + + [Flags] + internal enum PermissionTokenType + { + Normal = 0x1, + IUnrestricted = 0x2, + DontKnow = 0x4, + BuiltIn = 0x8 + } + + [Serializable] + internal sealed class PermissionTokenKeyComparer : IEqualityComparer + { + private Comparer _caseSensitiveComparer; + private TextInfo _info; + + public PermissionTokenKeyComparer() + { + _caseSensitiveComparer = new Comparer(CultureInfo.InvariantCulture); + _info = CultureInfo.InvariantCulture.TextInfo; + } + + [System.Security.SecuritySafeCritical] // auto-generated + public int Compare(Object a, Object b) + { + String strA = a as String; + String strB = b as String; + + // if it's not a string then we just call the object comparer + if (strA == null || strB == null) + return _caseSensitiveComparer.Compare(a, b); + + int i = _caseSensitiveComparer.Compare(a,b); + if (i == 0) + return 0; + + if (SecurityManager.IsSameType(strA, strB)) + return 0; + + return i; + } + + public new bool Equals( Object a, Object b ) + { + if (a == b) return true; + if (a == null || b == null) return false; + return Compare( a, b ) == 0; + } + + // The data structure consuming this will be responsible for dealing with null objects as keys. + public int GetHashCode(Object obj) + { + if (obj == null) throw new ArgumentNullException("obj"); + Contract.EndContractBlock(); + + String str = obj as String; + + if (str == null) + return obj.GetHashCode(); + + int iComma = str.IndexOf( ',' ); + if (iComma == -1) + iComma = str.Length; + + int accumulator = 0; + for (int i = 0; i < iComma; ++i) + { + accumulator = (accumulator << 7) ^ str[i] ^ (accumulator >> 25); + } + + return accumulator; + } + } + + [Serializable] + internal sealed class PermissionToken : ISecurityEncodable + { + private static readonly PermissionTokenFactory s_theTokenFactory; +#if FEATURE_CAS_POLICY + private static volatile ReflectionPermission s_reflectPerm = null; +#endif // FEATURE_CAS_POLICY + private const string c_mscorlibName = "mscorlib"; + + internal int m_index; + internal volatile PermissionTokenType m_type; +#if FEATURE_CAS_POLICY + internal String m_strTypeName; +#endif // FEATURE_CAS_POLICY + static internal TokenBasedSet s_tokenSet = new TokenBasedSet(); + + internal static bool IsMscorlibClassName (string className) { + Contract.Assert( c_mscorlibName == ((RuntimeAssembly)Assembly.GetExecutingAssembly()).GetSimpleName(), + "mscorlib name mismatch" ); + + // If the class name does not look like a fully qualified name, we cannot simply determine if it's + // an mscorlib.dll type so we should return true so the type can be matched with the + // right index in the TokenBasedSet. + int index = className.IndexOf(','); + if (index == -1) + return true; + + index = className.LastIndexOf(']'); + if (index == -1) + index = 0; + + // Search for the string 'mscorlib' in the classname. If we find it, we will conservatively assume it's an mscorlib.dll type and load it. + for (int i = index; i < className.Length; i++) { + if (className[i] == 'm' || className[i] == 'M') { + if (String.Compare(className, i, c_mscorlibName, 0, c_mscorlibName.Length, StringComparison.OrdinalIgnoreCase) == 0) + return true; + } + } + return false; + } + + static PermissionToken() + { + s_theTokenFactory = new PermissionTokenFactory( 4 ); + } + + internal PermissionToken() + { + } + + internal PermissionToken(int index, PermissionTokenType type, String strTypeName) + { + m_index = index; + m_type = type; +#if FEATURE_CAS_POLICY + m_strTypeName = strTypeName; +#endif // FEATURE_CAS_POLICY + } + + [System.Security.SecurityCritical] // auto-generated + public static PermissionToken GetToken(Type cls) + { + if (cls == null) + return null; + +#if FEATURE_CAS_POLICY + if (cls.GetInterface( "System.Security.Permissions.IBuiltInPermission" ) != null) + { + if (s_reflectPerm == null) + s_reflectPerm = new ReflectionPermission(PermissionState.Unrestricted); + s_reflectPerm.Assert(); + MethodInfo method = cls.GetMethod( "GetTokenIndex", BindingFlags.Static | BindingFlags.NonPublic ); + Contract.Assert( method != null, "IBuiltInPermission types should have a static method called 'GetTokenIndex'" ); + + // GetTokenIndex needs to be invoked without any security checks, since doing a security check + // will involve a ReflectionTargetDemand which creates a CompressedStack and attempts to get the + // token. + RuntimeMethodInfo getTokenIndex = method as RuntimeMethodInfo; + Contract.Assert(getTokenIndex != null, "method is not a RuntimeMethodInfo"); + int token = (int)getTokenIndex.UnsafeInvoke(null, BindingFlags.Default, null, null, null); + return s_theTokenFactory.BuiltInGetToken(token, null, cls); + } + else +#endif // FEATURE_CAS_POLICY + { + return s_theTokenFactory.GetToken(cls, null); + } + } + + public static PermissionToken GetToken(IPermission perm) + { + if (perm == null) + return null; + + IBuiltInPermission ibPerm = perm as IBuiltInPermission; + + if (ibPerm != null) + return s_theTokenFactory.BuiltInGetToken( ibPerm.GetTokenIndex(), perm, null ); + else + return s_theTokenFactory.GetToken(perm.GetType(), perm); + } + +#if FEATURE_CAS_POLICY + public static PermissionToken GetToken(String typeStr) + { + return GetToken( typeStr, false ); + } + +#if _DEBUG + [System.Security.SecuritySafeCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable + private static void GetTokenHelper(String typeStr) + { + new PermissionSet(PermissionState.Unrestricted).Assert(); + StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; + Type type = RuntimeTypeHandle.GetTypeByName( typeStr.Trim().Replace( '\'', '\"' ), ref stackMark); + Contract.Assert( (type == null) || (type.Module.Assembly != System.Reflection.Assembly.GetExecutingAssembly()) || (typeStr.IndexOf("mscorlib", StringComparison.Ordinal) < 0), + "We should not go through this path for mscorlib based permissions" ); + } +#endif + + public static PermissionToken GetToken(String typeStr, bool bCreateMscorlib) + { + if (typeStr == null) + return null; + + if (IsMscorlibClassName( typeStr )) + { + if (!bCreateMscorlib) + { + return null; + } + else + { + return FindToken( Type.GetType( typeStr ) ); + } + } + else + { + PermissionToken token = s_theTokenFactory.GetToken(typeStr); +#if _DEBUG + GetTokenHelper(typeStr); +#endif + return token; + } + } + + [SecuritySafeCritical] + public static PermissionToken FindToken( Type cls ) + { + if (cls == null) + return null; + +#if FEATURE_CAS_POLICY + if (cls.GetInterface( "System.Security.Permissions.IBuiltInPermission" ) != null) + { + if (s_reflectPerm == null) + s_reflectPerm = new ReflectionPermission(PermissionState.Unrestricted); + s_reflectPerm.Assert(); + MethodInfo method = cls.GetMethod( "GetTokenIndex", BindingFlags.Static | BindingFlags.NonPublic ); + Contract.Assert( method != null, "IBuiltInPermission types should have a static method called 'GetTokenIndex'" ); + + // GetTokenIndex needs to be invoked without any security checks, since doing a security check + // will involve a ReflectionTargetDemand which creates a CompressedStack and attempts to get the + // token. + RuntimeMethodInfo getTokenIndex = method as RuntimeMethodInfo; + Contract.Assert(getTokenIndex != null, "method is not a RuntimeMethodInfo"); + int token = (int)getTokenIndex.UnsafeInvoke(null, BindingFlags.Default, null, null, null); + return s_theTokenFactory.BuiltInGetToken(token, null, cls); + } + else +#endif // FEATURE_CAS_POLICY + { + return s_theTokenFactory.FindToken( cls ); + } + } +#endif // FEATURE_CAS_POLICY + + public static PermissionToken FindTokenByIndex( int i ) + { + return s_theTokenFactory.FindTokenByIndex( i ); + } + + public static bool IsTokenProperlyAssigned( IPermission perm, PermissionToken token ) + { + PermissionToken heldToken = GetToken( perm ); + if (heldToken.m_index != token.m_index) + return false; + + if (token.m_type != heldToken.m_type) + return false; + + if (perm.GetType().Module.Assembly == Assembly.GetExecutingAssembly() && + heldToken.m_index >= BuiltInPermissionIndex.NUM_BUILTIN_NORMAL + BuiltInPermissionIndex.NUM_BUILTIN_UNRESTRICTED) + return false; + + return true; + } + +#if FEATURE_CAS_POLICY + public SecurityElement ToXml() + { + Contract.Assert( (m_type & PermissionTokenType.DontKnow) == 0, "Should have valid token type when ToXml is called" ); + SecurityElement elRoot = new SecurityElement( "PermissionToken" ); + if ((m_type & PermissionTokenType.BuiltIn) != 0) + elRoot.AddAttribute( "Index", "" + this.m_index ); + else + elRoot.AddAttribute( "Name", SecurityElement.Escape( m_strTypeName ) ); + elRoot.AddAttribute("Type", m_type.ToString("F")); + return elRoot; + } + + public void FromXml(SecurityElement elRoot) + { + // For the most part there is no parameter checking here since this is an + // internal class and the serialization/deserialization path is controlled. + + if (!elRoot.Tag.Equals( "PermissionToken" )) + Contract.Assert( false, "Tried to deserialize non-PermissionToken element here" ); + + String strName = elRoot.Attribute( "Name" ); + PermissionToken realToken; + if (strName != null) + realToken = GetToken( strName, true ); + else + realToken = FindTokenByIndex( Int32.Parse( elRoot.Attribute( "Index" ), CultureInfo.InvariantCulture ) ); + + this.m_index = realToken.m_index; + this.m_type = (PermissionTokenType) Enum.Parse(typeof(PermissionTokenType), elRoot.Attribute("Type")); + Contract.Assert((this.m_type & PermissionTokenType.DontKnow) == 0, "Should have valid token type when FromXml is called."); + this.m_strTypeName = realToken.m_strTypeName; + } +#endif // FEATURE_CAS_POLICY + } + + // Package access only + internal class PermissionTokenFactory + { + private volatile int m_size; + private volatile int m_index; + private volatile Hashtable m_tokenTable; // Cache of tokens by class string name + private volatile Hashtable m_handleTable; // Cache of tokens by type handle (IntPtr) + private volatile Hashtable m_indexTable; // Cache of tokens by index + + + // We keep an array of tokens for our built-in permissions. + // This is ordered in terms of unrestricted perms first, normals + // second. Of course, all the ordering is based on the individual + // permissions sticking to the deal, so we do some simple boundary + // checking but mainly leave it to faith. + + private volatile PermissionToken[] m_builtIn; + + private const String s_unrestrictedPermissionInferfaceName = "System.Security.Permissions.IUnrestrictedPermission"; + + internal PermissionTokenFactory( int size ) + { + m_builtIn = new PermissionToken[BuiltInPermissionIndex.NUM_BUILTIN_NORMAL + BuiltInPermissionIndex.NUM_BUILTIN_UNRESTRICTED]; + + m_size = size; + m_index = BuiltInPermissionIndex.NUM_BUILTIN_NORMAL + BuiltInPermissionIndex.NUM_BUILTIN_UNRESTRICTED; + m_tokenTable = null; + m_handleTable = new Hashtable(size); + m_indexTable = new Hashtable(size); + } + +#if FEATURE_CAS_POLICY + [SecuritySafeCritical] + internal PermissionToken FindToken( Type cls ) + { + IntPtr typePtr = cls.TypeHandle.Value; + PermissionToken tok = (PermissionToken)m_handleTable[typePtr]; + + if (tok != null) + return tok; + + if (m_tokenTable == null) + return null; + + tok = (PermissionToken)m_tokenTable[cls.AssemblyQualifiedName]; + + if (tok != null) + { + lock (this) + { + m_handleTable.Add(typePtr, tok); + } + } + + return tok; + } +#endif // FEATURE_CAS_POLICY + + internal PermissionToken FindTokenByIndex( int i ) + { + PermissionToken token; + + if (i < BuiltInPermissionIndex.NUM_BUILTIN_NORMAL + BuiltInPermissionIndex.NUM_BUILTIN_UNRESTRICTED) + { + token = BuiltInGetToken( i, null, null ); + } + else + { + token = (PermissionToken)m_indexTable[i]; + } + + return token; + } + + [SecuritySafeCritical] + internal PermissionToken GetToken(Type cls, IPermission perm) + { + Contract.Assert( cls != null, "Must pass in valid type" ); + + IntPtr typePtr = cls.TypeHandle.Value; + object tok = m_handleTable[typePtr]; + if (tok == null) + { + String typeStr = cls.AssemblyQualifiedName; + tok = m_tokenTable != null ? m_tokenTable[typeStr] : null; // Assumes asynchronous lookups are safe + + if (tok == null) + { + lock (this) + { + if (m_tokenTable != null) + { + tok = m_tokenTable[typeStr]; // Make sure it wasn't just added + } + else + m_tokenTable = new Hashtable(m_size, 1.0f, new PermissionTokenKeyComparer()); + + if (tok == null) + { + if (perm != null) + { + tok = new PermissionToken( m_index++, PermissionTokenType.IUnrestricted, typeStr ); + } + else + { + if (cls.GetInterface(s_unrestrictedPermissionInferfaceName) != null) + tok = new PermissionToken( m_index++, PermissionTokenType.IUnrestricted, typeStr ); + else + tok = new PermissionToken( m_index++, PermissionTokenType.Normal, typeStr ); + } + m_tokenTable.Add(typeStr, tok); + m_indexTable.Add(m_index - 1, tok); + PermissionToken.s_tokenSet.SetItem( ((PermissionToken)tok).m_index, tok ); + } + + if (!m_handleTable.Contains(typePtr)) + m_handleTable.Add( typePtr, tok ); + } + } + else + { + lock (this) + { + if (!m_handleTable.Contains(typePtr)) + m_handleTable.Add( typePtr, tok ); + } + } + } + + if ((((PermissionToken)tok).m_type & PermissionTokenType.DontKnow) != 0) + { + if (perm != null) + { + Contract.Assert( !(perm is IBuiltInPermission), "This should not be called for built-ins" ); + ((PermissionToken)tok).m_type = PermissionTokenType.IUnrestricted; +#if FEATURE_CAS_POLICY + ((PermissionToken)tok).m_strTypeName = perm.GetType().AssemblyQualifiedName; +#endif // FEATURE_CAS_POLICY + } + else + { + Contract.Assert( cls.GetInterface( "System.Security.Permissions.IBuiltInPermission" ) == null, "This shoudl not be called for built-ins" ); + if (cls.GetInterface(s_unrestrictedPermissionInferfaceName) != null) + ((PermissionToken)tok).m_type = PermissionTokenType.IUnrestricted; + else + ((PermissionToken)tok).m_type = PermissionTokenType.Normal; +#if FEATURE_CAS_POLICY + ((PermissionToken)tok).m_strTypeName = cls.AssemblyQualifiedName; +#endif // FEATURE_CAS_POLICY + } + } + + return (PermissionToken)tok; + } + + internal PermissionToken GetToken(String typeStr) + { + Object tok = null; + tok = m_tokenTable != null ? m_tokenTable[typeStr] : null; // Assumes asynchronous lookups are safe + if (tok == null) + { + lock (this) + { + if (m_tokenTable != null) + { + tok = m_tokenTable[typeStr]; // Make sure it wasn't just added + } + else + m_tokenTable = new Hashtable(m_size, 1.0f, new PermissionTokenKeyComparer()); + + if (tok == null) + { + tok = new PermissionToken( m_index++, PermissionTokenType.DontKnow, typeStr ); + m_tokenTable.Add(typeStr, tok); + m_indexTable.Add(m_index - 1, tok); + PermissionToken.s_tokenSet.SetItem(((PermissionToken)tok).m_index, tok); + } + } + } + + return (PermissionToken)tok; + } + + internal PermissionToken BuiltInGetToken( int index, IPermission perm, Type cls ) + { + PermissionToken token = Volatile.Read(ref m_builtIn[index]); + + if (token == null) + { + lock (this) + { + token = m_builtIn[index]; + + if (token == null) + { + PermissionTokenType permType = PermissionTokenType.DontKnow; + + if (perm != null) + { + permType = PermissionTokenType.IUnrestricted; + } + else if (cls != null) + { + permType = PermissionTokenType.IUnrestricted; + } + + token = new PermissionToken( index, permType | PermissionTokenType.BuiltIn, null ); + Volatile.Write(ref m_builtIn[index], token); + PermissionToken.s_tokenSet.SetItem( token.m_index, token ); + } + } + } + + if ((token.m_type & PermissionTokenType.DontKnow) != 0) + { + token.m_type = PermissionTokenType.BuiltIn; + + if (perm != null) + { + token.m_type |= PermissionTokenType.IUnrestricted; + } + else if (cls != null) + { + token.m_type |= PermissionTokenType.IUnrestricted; + } + else + { + token.m_type |= PermissionTokenType.DontKnow; + } + } + + return token; + } + } +} |