3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>Microsoft</OWNER>
7 namespace System.Security {
9 using System.Security.Util;
10 using System.Security.Permissions;
11 using System.Reflection;
12 using System.Collections;
13 using System.Threading;
14 using System.Globalization;
15 using System.Runtime.CompilerServices;
16 using System.Diagnostics.Contracts;
19 internal enum PermissionTokenType
28 internal sealed class PermissionTokenKeyComparer : IEqualityComparer
30 private Comparer _caseSensitiveComparer;
31 private TextInfo _info;
33 public PermissionTokenKeyComparer()
35 _caseSensitiveComparer = new Comparer(CultureInfo.InvariantCulture);
36 _info = CultureInfo.InvariantCulture.TextInfo;
39 [System.Security.SecuritySafeCritical] // auto-generated
40 public int Compare(Object a, Object b)
42 String strA = a as String;
43 String strB = b as String;
45 // if it's not a string then we just call the object comparer
46 if (strA == null || strB == null)
47 return _caseSensitiveComparer.Compare(a, b);
49 int i = _caseSensitiveComparer.Compare(a,b);
53 if (SecurityManager.IsSameType(strA, strB))
59 public new bool Equals( Object a, Object b )
61 if (a == b) return true;
62 if (a == null || b == null) return false;
63 return Compare( a, b ) == 0;
66 // The data structure consuming this will be responsible for dealing with null objects as keys.
67 public int GetHashCode(Object obj)
69 if (obj == null) throw new ArgumentNullException("obj");
70 Contract.EndContractBlock();
72 String str = obj as String;
75 return obj.GetHashCode();
77 int iComma = str.IndexOf( ',' );
82 for (int i = 0; i < iComma; ++i)
84 accumulator = (accumulator << 7) ^ str[i] ^ (accumulator >> 25);
92 internal sealed class PermissionToken : ISecurityEncodable
94 private static readonly PermissionTokenFactory s_theTokenFactory;
95 #if FEATURE_CAS_POLICY
96 private static volatile ReflectionPermission s_reflectPerm = null;
97 #endif // FEATURE_CAS_POLICY
98 private const string c_mscorlibName = "mscorlib";
100 internal int m_index;
101 internal volatile PermissionTokenType m_type;
102 #if FEATURE_CAS_POLICY
103 internal String m_strTypeName;
104 #endif // FEATURE_CAS_POLICY
105 static internal TokenBasedSet s_tokenSet = new TokenBasedSet();
107 internal static bool IsMscorlibClassName (string className) {
108 Contract.Assert( c_mscorlibName == ((RuntimeAssembly)Assembly.GetExecutingAssembly()).GetSimpleName(),
109 "mscorlib name mismatch" );
111 // If the class name does not look like a fully qualified name, we cannot simply determine if it's
112 // an mscorlib.dll type so we should return true so the type can be matched with the
113 // right index in the TokenBasedSet.
114 int index = className.IndexOf(',');
118 index = className.LastIndexOf(']');
122 // 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.
123 for (int i = index; i < className.Length; i++) {
124 if (className[i] == 'm' || className[i] == 'M') {
125 if (String.Compare(className, i, c_mscorlibName, 0, c_mscorlibName.Length, StringComparison.OrdinalIgnoreCase) == 0)
132 static PermissionToken()
134 s_theTokenFactory = new PermissionTokenFactory( 4 );
137 internal PermissionToken()
141 internal PermissionToken(int index, PermissionTokenType type, String strTypeName)
145 #if FEATURE_CAS_POLICY
146 m_strTypeName = strTypeName;
147 #endif // FEATURE_CAS_POLICY
150 [System.Security.SecurityCritical] // auto-generated
151 public static PermissionToken GetToken(Type cls)
156 #if FEATURE_CAS_POLICY
157 if (cls.GetInterface( "System.Security.Permissions.IBuiltInPermission" ) != null)
159 if (s_reflectPerm == null)
160 s_reflectPerm = new ReflectionPermission(PermissionState.Unrestricted);
161 s_reflectPerm.Assert();
162 MethodInfo method = cls.GetMethod( "GetTokenIndex", BindingFlags.Static | BindingFlags.NonPublic );
163 Contract.Assert( method != null, "IBuiltInPermission types should have a static method called 'GetTokenIndex'" );
165 // GetTokenIndex needs to be invoked without any security checks, since doing a security check
166 // will involve a ReflectionTargetDemand which creates a CompressedStack and attempts to get the
168 RuntimeMethodInfo getTokenIndex = method as RuntimeMethodInfo;
169 Contract.Assert(getTokenIndex != null, "method is not a RuntimeMethodInfo");
170 int token = (int)getTokenIndex.UnsafeInvoke(null, BindingFlags.Default, null, null, null);
171 return s_theTokenFactory.BuiltInGetToken(token, null, cls);
174 #endif // FEATURE_CAS_POLICY
176 return s_theTokenFactory.GetToken(cls, null);
180 public static PermissionToken GetToken(IPermission perm)
185 IBuiltInPermission ibPerm = perm as IBuiltInPermission;
188 return s_theTokenFactory.BuiltInGetToken( ibPerm.GetTokenIndex(), perm, null );
190 return s_theTokenFactory.GetToken(perm.GetType(), perm);
193 #if FEATURE_CAS_POLICY
194 public static PermissionToken GetToken(String typeStr)
196 return GetToken( typeStr, false );
200 [System.Security.SecuritySafeCritical] // auto-generated
201 [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
202 private static void GetTokenHelper(String typeStr)
204 new PermissionSet(PermissionState.Unrestricted).Assert();
205 StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
206 Type type = RuntimeTypeHandle.GetTypeByName( typeStr.Trim().Replace( '\'', '\"' ), ref stackMark);
207 Contract.Assert( (type == null) || (type.Module.Assembly != System.Reflection.Assembly.GetExecutingAssembly()) || (typeStr.IndexOf("mscorlib", StringComparison.Ordinal) < 0),
208 "We should not go through this path for mscorlib based permissions" );
212 public static PermissionToken GetToken(String typeStr, bool bCreateMscorlib)
217 if (IsMscorlibClassName( typeStr ))
219 if (!bCreateMscorlib)
225 return FindToken( Type.GetType( typeStr ) );
230 PermissionToken token = s_theTokenFactory.GetToken(typeStr);
232 GetTokenHelper(typeStr);
238 [SecuritySafeCritical]
239 public static PermissionToken FindToken( Type cls )
244 #if FEATURE_CAS_POLICY
245 if (cls.GetInterface( "System.Security.Permissions.IBuiltInPermission" ) != null)
247 if (s_reflectPerm == null)
248 s_reflectPerm = new ReflectionPermission(PermissionState.Unrestricted);
249 s_reflectPerm.Assert();
250 MethodInfo method = cls.GetMethod( "GetTokenIndex", BindingFlags.Static | BindingFlags.NonPublic );
251 Contract.Assert( method != null, "IBuiltInPermission types should have a static method called 'GetTokenIndex'" );
253 // GetTokenIndex needs to be invoked without any security checks, since doing a security check
254 // will involve a ReflectionTargetDemand which creates a CompressedStack and attempts to get the
256 RuntimeMethodInfo getTokenIndex = method as RuntimeMethodInfo;
257 Contract.Assert(getTokenIndex != null, "method is not a RuntimeMethodInfo");
258 int token = (int)getTokenIndex.UnsafeInvoke(null, BindingFlags.Default, null, null, null);
259 return s_theTokenFactory.BuiltInGetToken(token, null, cls);
262 #endif // FEATURE_CAS_POLICY
264 return s_theTokenFactory.FindToken( cls );
267 #endif // FEATURE_CAS_POLICY
269 public static PermissionToken FindTokenByIndex( int i )
271 return s_theTokenFactory.FindTokenByIndex( i );
274 public static bool IsTokenProperlyAssigned( IPermission perm, PermissionToken token )
276 PermissionToken heldToken = GetToken( perm );
277 if (heldToken.m_index != token.m_index)
280 if (token.m_type != heldToken.m_type)
283 if (perm.GetType().Module.Assembly == Assembly.GetExecutingAssembly() &&
284 heldToken.m_index >= BuiltInPermissionIndex.NUM_BUILTIN_NORMAL + BuiltInPermissionIndex.NUM_BUILTIN_UNRESTRICTED)
290 #if FEATURE_CAS_POLICY
291 public SecurityElement ToXml()
293 Contract.Assert( (m_type & PermissionTokenType.DontKnow) == 0, "Should have valid token type when ToXml is called" );
294 SecurityElement elRoot = new SecurityElement( "PermissionToken" );
295 if ((m_type & PermissionTokenType.BuiltIn) != 0)
296 elRoot.AddAttribute( "Index", "" + this.m_index );
298 elRoot.AddAttribute( "Name", SecurityElement.Escape( m_strTypeName ) );
299 elRoot.AddAttribute("Type", m_type.ToString("F"));
303 public void FromXml(SecurityElement elRoot)
305 // For the most part there is no parameter checking here since this is an
306 // internal class and the serialization/deserialization path is controlled.
308 if (!elRoot.Tag.Equals( "PermissionToken" ))
309 Contract.Assert( false, "Tried to deserialize non-PermissionToken element here" );
311 String strName = elRoot.Attribute( "Name" );
312 PermissionToken realToken;
314 realToken = GetToken( strName, true );
316 realToken = FindTokenByIndex( Int32.Parse( elRoot.Attribute( "Index" ), CultureInfo.InvariantCulture ) );
318 this.m_index = realToken.m_index;
319 this.m_type = (PermissionTokenType) Enum.Parse(typeof(PermissionTokenType), elRoot.Attribute("Type"));
320 Contract.Assert((this.m_type & PermissionTokenType.DontKnow) == 0, "Should have valid token type when FromXml is called.");
321 this.m_strTypeName = realToken.m_strTypeName;
323 #endif // FEATURE_CAS_POLICY
326 // Package access only
327 internal class PermissionTokenFactory
329 private volatile int m_size;
330 private volatile int m_index;
331 private volatile Hashtable m_tokenTable; // Cache of tokens by class string name
332 private volatile Hashtable m_handleTable; // Cache of tokens by type handle (IntPtr)
333 private volatile Hashtable m_indexTable; // Cache of tokens by index
336 // We keep an array of tokens for our built-in permissions.
337 // This is ordered in terms of unrestricted perms first, normals
338 // second. Of course, all the ordering is based on the individual
339 // permissions sticking to the deal, so we do some simple boundary
340 // checking but mainly leave it to faith.
342 private volatile PermissionToken[] m_builtIn;
344 private const String s_unrestrictedPermissionInferfaceName = "System.Security.Permissions.IUnrestrictedPermission";
346 internal PermissionTokenFactory( int size )
348 m_builtIn = new PermissionToken[BuiltInPermissionIndex.NUM_BUILTIN_NORMAL + BuiltInPermissionIndex.NUM_BUILTIN_UNRESTRICTED];
351 m_index = BuiltInPermissionIndex.NUM_BUILTIN_NORMAL + BuiltInPermissionIndex.NUM_BUILTIN_UNRESTRICTED;
353 m_handleTable = new Hashtable(size);
354 m_indexTable = new Hashtable(size);
357 #if FEATURE_CAS_POLICY
358 [SecuritySafeCritical]
359 internal PermissionToken FindToken( Type cls )
361 IntPtr typePtr = cls.TypeHandle.Value;
362 PermissionToken tok = (PermissionToken)m_handleTable[typePtr];
367 if (m_tokenTable == null)
370 tok = (PermissionToken)m_tokenTable[cls.AssemblyQualifiedName];
376 m_handleTable.Add(typePtr, tok);
382 #endif // FEATURE_CAS_POLICY
384 internal PermissionToken FindTokenByIndex( int i )
386 PermissionToken token;
388 if (i < BuiltInPermissionIndex.NUM_BUILTIN_NORMAL + BuiltInPermissionIndex.NUM_BUILTIN_UNRESTRICTED)
390 token = BuiltInGetToken( i, null, null );
394 token = (PermissionToken)m_indexTable[i];
400 [SecuritySafeCritical]
401 internal PermissionToken GetToken(Type cls, IPermission perm)
403 Contract.Assert( cls != null, "Must pass in valid type" );
405 IntPtr typePtr = cls.TypeHandle.Value;
406 object tok = m_handleTable[typePtr];
409 String typeStr = cls.AssemblyQualifiedName;
410 tok = m_tokenTable != null ? m_tokenTable[typeStr] : null; // Assumes asynchronous lookups are safe
416 if (m_tokenTable != null)
418 tok = m_tokenTable[typeStr]; // Make sure it wasn't just added
421 m_tokenTable = new Hashtable(m_size, 1.0f, new PermissionTokenKeyComparer());
427 tok = new PermissionToken( m_index++, PermissionTokenType.IUnrestricted, typeStr );
431 if (cls.GetInterface(s_unrestrictedPermissionInferfaceName) != null)
432 tok = new PermissionToken( m_index++, PermissionTokenType.IUnrestricted, typeStr );
434 tok = new PermissionToken( m_index++, PermissionTokenType.Normal, typeStr );
436 m_tokenTable.Add(typeStr, tok);
437 m_indexTable.Add(m_index - 1, tok);
438 PermissionToken.s_tokenSet.SetItem( ((PermissionToken)tok).m_index, tok );
441 if (!m_handleTable.Contains(typePtr))
442 m_handleTable.Add( typePtr, tok );
449 if (!m_handleTable.Contains(typePtr))
450 m_handleTable.Add( typePtr, tok );
455 if ((((PermissionToken)tok).m_type & PermissionTokenType.DontKnow) != 0)
459 Contract.Assert( !(perm is IBuiltInPermission), "This should not be called for built-ins" );
460 ((PermissionToken)tok).m_type = PermissionTokenType.IUnrestricted;
461 #if FEATURE_CAS_POLICY
462 ((PermissionToken)tok).m_strTypeName = perm.GetType().AssemblyQualifiedName;
463 #endif // FEATURE_CAS_POLICY
467 Contract.Assert( cls.GetInterface( "System.Security.Permissions.IBuiltInPermission" ) == null, "This shoudl not be called for built-ins" );
468 if (cls.GetInterface(s_unrestrictedPermissionInferfaceName) != null)
469 ((PermissionToken)tok).m_type = PermissionTokenType.IUnrestricted;
471 ((PermissionToken)tok).m_type = PermissionTokenType.Normal;
472 #if FEATURE_CAS_POLICY
473 ((PermissionToken)tok).m_strTypeName = cls.AssemblyQualifiedName;
474 #endif // FEATURE_CAS_POLICY
478 return (PermissionToken)tok;
481 internal PermissionToken GetToken(String typeStr)
484 tok = m_tokenTable != null ? m_tokenTable[typeStr] : null; // Assumes asynchronous lookups are safe
489 if (m_tokenTable != null)
491 tok = m_tokenTable[typeStr]; // Make sure it wasn't just added
494 m_tokenTable = new Hashtable(m_size, 1.0f, new PermissionTokenKeyComparer());
498 tok = new PermissionToken( m_index++, PermissionTokenType.DontKnow, typeStr );
499 m_tokenTable.Add(typeStr, tok);
500 m_indexTable.Add(m_index - 1, tok);
501 PermissionToken.s_tokenSet.SetItem(((PermissionToken)tok).m_index, tok);
506 return (PermissionToken)tok;
509 internal PermissionToken BuiltInGetToken( int index, IPermission perm, Type cls )
511 PermissionToken token = Volatile.Read(ref m_builtIn[index]);
517 token = m_builtIn[index];
521 PermissionTokenType permType = PermissionTokenType.DontKnow;
525 permType = PermissionTokenType.IUnrestricted;
527 else if (cls != null)
529 permType = PermissionTokenType.IUnrestricted;
532 token = new PermissionToken( index, permType | PermissionTokenType.BuiltIn, null );
533 Volatile.Write(ref m_builtIn[index], token);
534 PermissionToken.s_tokenSet.SetItem( token.m_index, token );
539 if ((token.m_type & PermissionTokenType.DontKnow) != 0)
541 token.m_type = PermissionTokenType.BuiltIn;
545 token.m_type |= PermissionTokenType.IUnrestricted;
547 else if (cls != null)
549 token.m_type |= PermissionTokenType.IUnrestricted;
553 token.m_type |= PermissionTokenType.DontKnow;