2009-09-09 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / corlib / System.Security / SecurityManager.cs
1 //
2 // System.Security.SecurityManager.cs
3 //
4 // Authors:
5 //      Nick Drochak(ndrochak@gol.com)
6 //      Sebastien Pouliot  <sebastien@ximian.com>
7 //
8 // (C) Nick Drochak
9 // Portions (C) 2004 Motus Technologies Inc. (http://www.motus.com)
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 #if !NET_2_1
33
34 using System.Collections;
35 using System.Globalization;
36 using System.IO;
37 using System.Reflection;
38 using System.Runtime.CompilerServices;
39 using System.Runtime.InteropServices;
40 using System.Security.Permissions;
41 using System.Security.Policy;
42 using System.Text;
43
44 using Mono.Xml;
45
46 namespace System.Security {
47
48         // Must match MonoDeclSecurityActions in /mono/metadata/reflection.h
49         internal struct RuntimeDeclSecurityActions {
50                 public RuntimeDeclSecurityEntry cas;
51                 public RuntimeDeclSecurityEntry noncas;
52                 public RuntimeDeclSecurityEntry choice;
53         }
54
55 #if NET_2_0
56         [ComVisible (true)]
57         public static class SecurityManager {
58 #else
59         public sealed class SecurityManager {
60
61                 private SecurityManager ()
62                 {
63                 }
64 #endif
65                 private static object _lockObject;
66                 private static ArrayList _hierarchy;
67                 private static IPermission _unmanagedCode;
68                 private static Hashtable _declsecCache;
69                 private static PolicyLevel _level;
70
71                 static SecurityManager () 
72                 {
73                         // lock(this) is bad
74                         // http://msdn.microsoft.com/library/en-us/dnaskdr/html/askgui06032003.asp?frame=true
75                         _lockObject = new object ();
76                 }
77
78                 // properties
79
80                 extern public static bool CheckExecutionRights {
81                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
82                         get;
83
84                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
85                         [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
86                         set;
87                 }
88
89 #if NET_2_0
90                 [Obsolete ("The security manager cannot be turned off on MS runtime")]
91 #endif
92                 extern public static bool SecurityEnabled {
93                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
94                         get;
95
96                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
97                         [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
98                         set;
99                 }
100
101                 // methods
102
103 #if NET_1_1
104                 // NOTE: This method doesn't show in the class library status page because
105                 // it cannot be "found" with the StrongNameIdentityPermission for ECMA key.
106                 // But it's there!
107                 // FIXME works for fulltrust (empty), documentation doesn't really make sense, type wise
108                 [MonoTODO ("CAS support is experimental (and unsupported). This method only works in FullTrust.")]
109                 [StrongNameIdentityPermission (SecurityAction.LinkDemand, PublicKey = "0x00000000000000000400000000000000")]
110                 public static void GetZoneAndOrigin (out ArrayList zone, out ArrayList origin) 
111                 {
112                         zone = new ArrayList ();
113                         origin = new ArrayList ();
114                 }
115 #endif
116
117                 public static bool IsGranted (IPermission perm)
118                 {
119                         if (perm == null)
120                                 return true;
121                         if (!SecurityEnabled)
122                                 return true;
123
124                         // - Policy driven
125                         // - Only check the caller (no stack walk required)
126                         // - Not affected by overrides (like Assert, Deny and PermitOnly)
127                         // - calls IsSubsetOf even for non CAS permissions
128                         //   (i.e. it does call Demand so any code there won't be executed)
129 #if NET_2_0
130                         // with 2.0 identity permission are unrestrictable
131                         return IsGranted (Assembly.GetCallingAssembly (), perm);
132 #else
133                         if (perm is IUnrestrictedPermission)
134                                 return IsGranted (Assembly.GetCallingAssembly (), perm);
135                         else
136                                 return IsGrantedRestricted (Assembly.GetCallingAssembly (), perm);
137 #endif
138                 }
139
140 #if !NET_2_0
141                 // only for permissions that do not implement IUnrestrictedPermission
142                 internal static bool IsGrantedRestricted (Assembly a, IPermission perm)
143                 {
144                         PermissionSet granted = a.GrantedPermissionSet;\r
145                         if (granted != null) {\r
146                                 CodeAccessPermission grant = (CodeAccessPermission) granted.GetPermission (perm.GetType ());
147                                 if (!perm.IsSubsetOf (grant)) {
148                                         return false;
149                                 }
150                         }
151
152                         PermissionSet denied = a.DeniedPermissionSet;
153                         if (denied != null) {\r
154                                 CodeAccessPermission refuse = (CodeAccessPermission) a.DeniedPermissionSet.GetPermission (perm.GetType ());
155                                 if ((refuse != null) && perm.IsSubsetOf (refuse))
156                                         return false;
157                         }
158                         return true;
159                 }
160 #endif
161                 // note: in 2.0 *all* permissions (including identity permissions) support unrestricted
162                 internal static bool IsGranted (Assembly a, IPermission perm)
163                 {
164                         PermissionSet granted = a.GrantedPermissionSet;\r
165                         if ((granted != null) && !granted.IsUnrestricted ()) {\r
166                                 CodeAccessPermission grant = (CodeAccessPermission) granted.GetPermission (perm.GetType ());\r
167                                 if (!perm.IsSubsetOf (grant)) {\r
168                                         return false;\r
169                                 }\r
170                         }\r
171 \r
172                         PermissionSet denied = a.DeniedPermissionSet;\r
173                         if ((denied != null) && !denied.IsEmpty ()) {\r
174                                 if (denied.IsUnrestricted ())\r
175                                         return false;\r
176                                 CodeAccessPermission refuse = (CodeAccessPermission) a.DeniedPermissionSet.GetPermission (perm.GetType ());\r
177                                 if ((refuse != null) && perm.IsSubsetOf (refuse))\r
178                                         return false;\r
179                         }\r
180                         return true;\r
181                 }
182
183                 internal static IPermission CheckPermissionSet (Assembly a, PermissionSet ps, bool noncas)
184                 {
185                         if (ps.IsEmpty ())
186                                 return null;
187
188                         foreach (IPermission p in ps) {
189                                 // note: this may contains non CAS permissions
190                                 if ((!noncas) && (p is CodeAccessPermission)) {
191 #if NET_2_0
192                                         if (!IsGranted (a, p))
193                                                 return p;
194 #else
195                                         if (p is IUnrestrictedPermission) {
196                                                 if (!IsGranted (a, p))
197                                                         return p;
198                                         } else {
199                                                 if (!IsGrantedRestricted (a, p))
200                                                         return p;
201                                         }
202 #endif
203                                 } else {
204                                         // but non-CAS will throw on failure...
205                                         try {
206                                                 p.Demand ();
207                                         }
208                                         catch (SecurityException) {
209                                                 // ... so we catch
210                                                 return p;
211                                         }
212                                 }
213                         }
214                         return null;
215                 }
216
217                 internal static IPermission CheckPermissionSet (AppDomain ad, PermissionSet ps)
218                 {
219                         if ((ps == null) || ps.IsEmpty ())
220                                 return null;
221
222                         PermissionSet granted = ad.GrantedPermissionSet;
223                         if (granted == null)
224                                 return null;
225 #if NET_2_0
226                         if (granted.IsUnrestricted ())
227                                 return null;
228 #else
229                         if ((granted.Count == 0) && granted.IsUnrestricted ())
230                                 return null;
231 #endif
232                         if (ps.IsUnrestricted ())
233                                 return new SecurityPermission (SecurityPermissionFlag.NoFlags);
234
235                         foreach (IPermission p in ps) {
236                                 if (p is CodeAccessPermission) {
237                                         CodeAccessPermission grant = (CodeAccessPermission) granted.GetPermission (p.GetType ());
238                                         if (grant == null) {
239                                                 if (!granted.IsUnrestricted () || !(p is IUnrestrictedPermission)) {
240                                                         if (!p.IsSubsetOf (null))
241                                                                 return p;
242                                                 }
243                                         } else if (!p.IsSubsetOf (grant)) {
244                                                 return p;
245                                         }
246                                 } else {
247                                         // but non-CAS will throw on failure...
248                                         try {
249                                                 p.Demand ();
250                                         }
251                                         catch (SecurityException) {
252                                                 // ... so we catch
253                                                 return p;
254                                         }
255                                 }
256                         }
257                         return null;
258                 }
259
260                 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
261                 public static PolicyLevel LoadPolicyLevelFromFile (string path, PolicyLevelType type)
262                 {
263                         if (path == null)
264                                 throw new ArgumentNullException ("path");
265
266                         PolicyLevel pl = null;
267                         try {
268                                 pl = new PolicyLevel (type.ToString (), type);
269                                 pl.LoadFromFile (path);
270                         }
271                         catch (Exception e) {
272                                 throw new ArgumentException (Locale.GetText ("Invalid policy XML"), e);
273                         }
274                         return pl;
275                 }
276
277                 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
278                 public static PolicyLevel LoadPolicyLevelFromString (string str, PolicyLevelType type)
279                 {
280                         if (null == str)
281                                 throw new ArgumentNullException ("str");
282
283                         PolicyLevel pl = null;
284                         try {
285                                 pl = new PolicyLevel (type.ToString (), type);
286                                 pl.LoadFromString (str);
287                         }
288                         catch (Exception e) {
289                                 throw new ArgumentException (Locale.GetText ("Invalid policy XML"), e);
290                         }
291                         return pl;
292                 }
293
294                 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
295                 public static IEnumerator PolicyHierarchy ()
296                 {
297                         return Hierarchy;
298                 }
299
300                 public static PermissionSet ResolvePolicy (Evidence evidence)
301                 {
302                         // no evidence, no permission
303                         if (evidence == null)
304                                 return new PermissionSet (PermissionState.None);
305
306                         PermissionSet ps = null;
307                         // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
308                         IEnumerator ple = Hierarchy;
309                         while (ple.MoveNext ()) {
310                                 PolicyLevel pl = (PolicyLevel) ple.Current;
311                                 if (ResolvePolicyLevel (ref ps, pl, evidence)) {
312                                         break;  // i.e. PolicyStatementAttribute.LevelFinal
313                                 }
314                         }
315
316                         ResolveIdentityPermissions (ps, evidence);
317
318                         return ps;
319                 }
320
321 #if NET_2_0
322                 [MonoTODO ("(2.0) more tests are needed")]
323                 public static PermissionSet ResolvePolicy (Evidence[] evidences)
324                 {
325                         if ((evidences == null) || (evidences.Length == 0) ||
326                                 ((evidences.Length == 1) && (evidences [0].Count == 0))) {
327                                 return new PermissionSet (PermissionState.None);
328                         }
329
330                         // probably not optimal
331                         PermissionSet ps = ResolvePolicy (evidences [0]);
332                         for (int i=1; i < evidences.Length; i++) {
333                                 ps = ps.Intersect (ResolvePolicy (evidences [i]));
334                         }
335                         return ps;
336                 }
337
338                 public static PermissionSet ResolveSystemPolicy (Evidence evidence)
339                 {
340                         // no evidence, no permission
341                         if (evidence == null)
342                                 return new PermissionSet (PermissionState.None);
343
344                         // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
345                         PermissionSet ps = null;
346                         IEnumerator ple = Hierarchy;
347                         while (ple.MoveNext ()) {
348                                 PolicyLevel pl = (PolicyLevel) ple.Current;
349                                 if (pl.Type == PolicyLevelType.AppDomain)
350                                         break;
351                                 if (ResolvePolicyLevel (ref ps, pl, evidence))
352                                         break;  // i.e. PolicyStatementAttribute.LevelFinal
353                         }
354
355                         ResolveIdentityPermissions (ps, evidence);
356                         return ps;
357                 }
358 #endif
359
360                 static private SecurityPermission _execution = new SecurityPermission (SecurityPermissionFlag.Execution);
361
362                 public static PermissionSet ResolvePolicy (Evidence evidence, PermissionSet reqdPset, PermissionSet optPset, PermissionSet denyPset, out PermissionSet denied)
363                 {
364                         PermissionSet resolved = ResolvePolicy (evidence);
365                         // do we have the minimal permission requested by the assembly ?
366                         if ((reqdPset != null) && !reqdPset.IsSubsetOf (resolved)) {
367                                 throw new PolicyException (Locale.GetText (
368                                         "Policy doesn't grant the minimal permissions required to execute the assembly."));
369                         }
370
371                         // do we check for execution rights ?
372                         if (CheckExecutionRights) {
373                                 bool execute = false;
374                                 // an empty permissionset doesn't include Execution
375                                 if (resolved != null) {
376                                         // unless we have "Full Trust"...
377                                         if (resolved.IsUnrestricted ()) {
378                                                 execute = true;
379                                         } else {
380                                                 // ... we need to find a SecurityPermission
381                                                 IPermission security = resolved.GetPermission (typeof (SecurityPermission));
382                                                 execute = _execution.IsSubsetOf (security);
383                                         }
384                                 }
385
386                                 if (!execute) {
387                                         throw new PolicyException (Locale.GetText (
388                                                 "Policy doesn't grant the right to execute the assembly."));
389                                 }
390                         }
391
392                         denied = denyPset;
393                         return resolved;
394                 }
395
396                 public static IEnumerator ResolvePolicyGroups (Evidence evidence)
397                 {
398                         if (evidence == null)
399                                 throw new ArgumentNullException ("evidence");
400
401                         ArrayList al = new ArrayList ();
402                         // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
403                         IEnumerator ple = Hierarchy;
404                         while (ple.MoveNext ()) {
405                                 PolicyLevel pl = (PolicyLevel) ple.Current;
406                                 CodeGroup cg = pl.ResolveMatchingCodeGroups (evidence);
407                                 al.Add (cg);
408                         }
409                         return al.GetEnumerator ();
410                 }
411
412                 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
413                 public static void SavePolicy () 
414                 {
415                         IEnumerator e = Hierarchy;
416                         while (e.MoveNext ()) {
417                                 PolicyLevel level = (e.Current as PolicyLevel);
418                                 level.Save ();
419                         }
420                 }
421
422                 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
423                 public static void SavePolicyLevel (PolicyLevel level) 
424                 {
425                         // Yes this will throw a NullReferenceException, just like MS (see FDBK13121)
426                         level.Save ();
427                 }
428
429                 // private/internal stuff
430
431                 private static IEnumerator Hierarchy {
432                         get {
433                                 lock (_lockObject) {
434                                         if (_hierarchy == null)
435                                                 InitializePolicyHierarchy ();
436                                 }
437                                 return _hierarchy.GetEnumerator ();
438                         }
439                 }
440
441                 private static void InitializePolicyHierarchy ()
442                 {
443                         string machinePolicyPath = Path.GetDirectoryName (Environment.GetMachineConfigPath ());
444                         // note: use InternalGetFolderPath to avoid recursive policy initialization
445                         string userPolicyPath = Path.Combine (Environment.InternalGetFolderPath (Environment.SpecialFolder.ApplicationData), "mono");
446
447                         PolicyLevel enterprise = new PolicyLevel ("Enterprise", PolicyLevelType.Enterprise);
448                         _level = enterprise;
449                         enterprise.LoadFromFile (Path.Combine (machinePolicyPath, "enterprisesec.config"));
450
451                         PolicyLevel machine = new PolicyLevel ("Machine", PolicyLevelType.Machine);
452                         _level = machine;
453                         machine.LoadFromFile (Path.Combine (machinePolicyPath, "security.config"));
454
455                         PolicyLevel user = new PolicyLevel ("User", PolicyLevelType.User);
456                         _level = user;
457                         user.LoadFromFile (Path.Combine (userPolicyPath, "security.config"));
458
459                         ArrayList al = new ArrayList ();
460                         al.Add (enterprise);
461                         al.Add (machine);
462                         al.Add (user);
463
464                         _hierarchy = ArrayList.Synchronized (al);
465                         _level = null;
466                 }
467
468                 internal static bool ResolvePolicyLevel (ref PermissionSet ps, PolicyLevel pl, Evidence evidence)
469                 {
470                         PolicyStatement pst = pl.Resolve (evidence);
471                         if (pst != null) {
472                                 if (ps == null) {
473                                         // only for initial (first) policy level processed
474                                         ps = pst.PermissionSet;
475                                 } else {
476                                         ps = ps.Intersect (pst.PermissionSet);
477                                         if (ps == null) {
478                                                 // null is equals to None - exist that null can throw NullReferenceException ;-)
479                                                 ps = new PermissionSet (PermissionState.None);
480                                         }
481                                 }
482
483                                 if ((pst.Attributes & PolicyStatementAttribute.LevelFinal) == PolicyStatementAttribute.LevelFinal)
484                                         return true;
485                         }
486                         return false;
487                 }
488
489                 internal static void ResolveIdentityPermissions (PermissionSet ps, Evidence evidence)
490                 {
491 #if NET_2_0
492                         // in 2.0 identity permissions can now be unrestricted
493                         if (ps.IsUnrestricted ())
494                                 return;
495 #endif
496                         // Only host evidence are used for policy resolution
497                         IEnumerator ee = evidence.GetHostEnumerator ();
498                         while (ee.MoveNext ()) {
499                                 IIdentityPermissionFactory ipf = (ee.Current as IIdentityPermissionFactory);
500                                 if (ipf != null) {
501                                         IPermission p = ipf.CreateIdentityPermission (evidence);
502                                         ps.AddPermission (p);
503                                 }
504                         }
505                 }
506
507                 internal static PolicyLevel ResolvingPolicyLevel {
508                         get { return _level; }
509                         set { _level = value; }
510                 }
511
512                 internal static PermissionSet Decode (IntPtr permissions, int length)
513                 {
514                         // Permission sets from the runtime (declarative security) can be cached
515                         // for performance as they can never change (i.e. they are read-only).
516                         PermissionSet ps = null;
517
518                         lock (_lockObject) {
519                                 if (_declsecCache == null) {
520                                         _declsecCache = new Hashtable ();
521                                 }
522
523                                 object key = (object) (int) permissions;
524                                 ps = (PermissionSet) _declsecCache [key];
525                                 if (ps == null) {
526                                         // create permissionset and add it to the cache
527                                         byte[] data = new byte [length];
528                                         Marshal.Copy (permissions, data, 0, length);
529                                         ps = Decode (data);
530                                         ps.DeclarativeSecurity = true;
531                                         _declsecCache.Add (key, ps);
532                                 }
533                         }
534                         return ps;
535                 }
536
537                 internal static PermissionSet Decode (byte[] encodedPermissions)
538                 {
539                         if ((encodedPermissions == null) || (encodedPermissions.Length < 1))
540                                 throw new SecurityException ("Invalid metadata format.");
541
542                         switch (encodedPermissions [0]) {
543                         case 60:
544                                 // Fx 1.0/1.1 declarative security permissions metadata is in Unicode-encoded XML
545                                 string xml = Encoding.Unicode.GetString (encodedPermissions);
546                                 return new PermissionSet (xml);
547                         case 0x2E:
548                                 // Fx 2.0 are encoded "somewhat, but not enough, like" custom attributes
549                                 // note: we still support the older format!
550                                 return PermissionSet.CreateFromBinaryFormat (encodedPermissions);
551                         default:
552                                 throw new SecurityException (Locale.GetText ("Unknown metadata format."));
553                         }
554                 }
555
556                 private static IPermission UnmanagedCode {
557                         get {
558                                 lock (_lockObject) {
559                                         if (_unmanagedCode == null)
560                                                 _unmanagedCode = new SecurityPermission (SecurityPermissionFlag.UnmanagedCode);
561                                 }
562                                 return _unmanagedCode;
563                         }
564                 }
565
566                 //  security check when using reflection
567
568                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
569                 private static unsafe extern bool GetLinkDemandSecurity (MethodBase method, RuntimeDeclSecurityActions *cdecl, RuntimeDeclSecurityActions *mdecl);
570
571                 // When using reflection LinkDemand are promoted to full Demand (i.e. stack walk)
572                 internal unsafe static void ReflectedLinkDemandInvoke (MethodBase mb)
573                 {
574                         RuntimeDeclSecurityActions klass;
575                         RuntimeDeclSecurityActions method;
576
577                         if (!GetLinkDemandSecurity (mb, &klass, &method))
578                                 return;
579
580                         PermissionSet ps = null;
581
582                         if (klass.cas.size > 0) {
583                                 ps = Decode (klass.cas.blob, klass.cas.size);
584                         }
585                         if (klass.noncas.size > 0) {
586                                 PermissionSet p = Decode (klass.noncas.blob, klass.noncas.size);
587                                 ps = (ps == null) ? p : ps.Union (p);
588                         }
589
590                         if (method.cas.size > 0) {
591                                 PermissionSet p = Decode (method.cas.blob, method.cas.size);
592                                 ps = (ps == null) ? p : ps.Union (p);
593                         }
594                         if (method.noncas.size > 0) {
595                                 PermissionSet p = Decode (method.noncas.blob, method.noncas.size);
596                                 ps = (ps == null) ? p : ps.Union (p);
597                         }
598
599                         // in this case we union-ed the permission sets because we want to do 
600                         // a single stack walk (not up to 4).
601                         if (ps != null)
602                                 ps.Demand ();
603                 }
604
605                 internal unsafe static bool ReflectedLinkDemandQuery (MethodBase mb)
606                 {
607                         RuntimeDeclSecurityActions klass;
608                         RuntimeDeclSecurityActions method;
609
610                         if (!GetLinkDemandSecurity (mb, &klass, &method))
611                                 return true;
612
613                         return LinkDemand (mb.ReflectedType.Assembly, &klass, &method);
614                 }
615
616                 private unsafe static bool LinkDemand (Assembly a, RuntimeDeclSecurityActions *klass, RuntimeDeclSecurityActions *method)
617                 {
618                         try {
619                                 PermissionSet ps = null;
620                                 bool result = true;
621                                 if (klass->cas.size > 0) {
622                                         ps = Decode (klass->cas.blob, klass->cas.size);
623                                         result = (SecurityManager.CheckPermissionSet (a, ps, false) == null);
624                                 }
625                                 if (result && (klass->noncas.size > 0)) {
626                                         ps = Decode (klass->noncas.blob, klass->noncas.size);
627                                         result = (SecurityManager.CheckPermissionSet (a, ps, true) == null);
628                                 }
629
630                                 if (result && (method->cas.size > 0)) {
631                                         ps = Decode (method->cas.blob, method->cas.size);
632                                         result = (SecurityManager.CheckPermissionSet (a, ps, false) == null);
633                                 }
634                                 if (result && (method->noncas.size > 0)) {
635                                         ps = Decode (method->noncas.blob, method->noncas.size);
636                                         result = (SecurityManager.CheckPermissionSet (a, ps, true) == null);
637                                 }
638                                 return result;
639                         }
640                         catch (SecurityException) {
641                                 return false;
642                         }
643                 }
644
645 #pragma warning disable 169
646                 private static bool LinkDemandFullTrust (Assembly a)
647                 {
648                         // FullTrust is immutable (and means Unrestricted) 
649                         // so we can skip the subset operations and jump to IsUnrestricted.
650                         PermissionSet granted = a.GrantedPermissionSet;
651                         if ((granted != null) && !granted.IsUnrestricted ())
652                                 return false;
653
654                         PermissionSet denied = a.DeniedPermissionSet;
655                         if ((denied != null) && !denied.IsEmpty ())
656                                 return false;
657
658                         return true;
659                 }
660
661                 private static bool LinkDemandUnmanaged (Assembly a)
662                 {
663                         // note: we know that UnmanagedCode (SecurityPermission) implements IUnrestrictedPermission
664                         return IsGranted (a, UnmanagedCode);
665                 }
666
667                 // we try to provide as much details as possible to help debugging
668                 private static void LinkDemandSecurityException (int securityViolation, IntPtr methodHandle)
669                 {
670                         RuntimeMethodHandle runtimeHandle = new RuntimeMethodHandle (methodHandle);
671                         MethodInfo method = (MethodInfo)(MethodBase.GetMethodFromHandle (runtimeHandle));
672                         Assembly a = method.DeclaringType.Assembly;
673
674                         string message = null;
675                         AssemblyName an = null;
676                         PermissionSet granted = null;
677                         PermissionSet refused = null;
678                         object demanded = null;
679                         IPermission failed = null;
680
681                         if (a != null) {
682                                 an = a.UnprotectedGetName ();
683                                 granted = a.GrantedPermissionSet;
684                                 refused = a.DeniedPermissionSet;
685                         }
686
687                         switch (securityViolation) {
688                         case 1: // MONO_JIT_LINKDEMAND_PERMISSION
689                                 message = Locale.GetText ("Permissions refused to call this method.");
690                                 break;
691                         case 2: // MONO_JIT_LINKDEMAND_APTC
692                                 message = Locale.GetText ("Partially trusted callers aren't allowed to call into this assembly.");
693                                 demanded = (object) DefaultPolicies.FullTrust; // immutable
694                                 break;
695                         case 4: // MONO_JIT_LINKDEMAND_ECMA
696                                 message = Locale.GetText ("Calling internal calls is restricted to ECMA signed assemblies.");
697                                 break;
698                         case 8: // MONO_JIT_LINKDEMAND_PINVOKE
699                                 message = Locale.GetText ("Calling unmanaged code isn't allowed from this assembly.");
700                                 demanded = (object) _unmanagedCode;
701                                 failed = _unmanagedCode;
702                                 break;
703                         default:
704                                 message = Locale.GetText ("JIT time LinkDemand failed.");
705                                 break;
706                         }
707
708                         throw new SecurityException (message, an, granted, refused, method, SecurityAction.LinkDemand, demanded, failed, null);
709                 }
710
711                 private static void InheritanceDemandSecurityException (int securityViolation, Assembly a, Type t, MethodInfo method)
712                 {
713                         string message = null;
714                         AssemblyName an = null;
715                         PermissionSet granted = null;
716                         PermissionSet refused = null;
717
718                         if (a != null) {
719                                 an = a.UnprotectedGetName ();
720                                 granted = a.GrantedPermissionSet;
721                                 refused = a.DeniedPermissionSet;
722                         }
723
724                         switch (securityViolation) {
725                         case 1: // MONO_METADATA_INHERITANCEDEMAND_CLASS
726                                 message = String.Format (Locale.GetText ("Class inheritance refused for {0}."), t);
727                                 break;
728                         case 2: // MONO_METADATA_INHERITANCEDEMAND_CLASS
729                                 message = Locale.GetText ("Method override refused.");
730                                 break;
731                         default:
732                                 message = Locale.GetText ("Load time InheritDemand failed.");
733                                 break;
734                         }
735
736                         throw new SecurityException (message, an, granted, refused, method, SecurityAction.InheritanceDemand, null, null, null);
737                 }
738
739                 // called by the runtime when CoreCLR is enabled
740
741                 private static void ThrowException (Exception ex)
742                 {
743                         throw ex;
744                 }
745
746                 // internal - get called by the class loader
747
748                 // Called when
749                 // - class inheritance
750                 // - method overrides
751                 private unsafe static bool InheritanceDemand (AppDomain ad, Assembly a, RuntimeDeclSecurityActions *actions)
752                 {
753                         try {
754                                 PermissionSet ps = null;
755                                 bool result = true;
756                                 if (actions->cas.size > 0) {
757                                         ps = Decode (actions->cas.blob, actions->cas.size);
758                                         result = (SecurityManager.CheckPermissionSet (a, ps, false) == null);
759                                         if (result) {
760                                                 // also check appdomain
761                                                 result = (SecurityManager.CheckPermissionSet (ad, ps) == null);
762                                         }
763                                 }
764                                 if (actions->noncas.size > 0) {
765                                         ps = Decode (actions->noncas.blob, actions->noncas.size);
766                                         result = (SecurityManager.CheckPermissionSet (a, ps, true) == null);
767                                         if (result) {
768                                                 // also check appdomain
769                                                 result = (SecurityManager.CheckPermissionSet (ad, ps) == null);
770                                         }
771                                 }
772                                 return result;
773                         }
774                         catch (SecurityException) {
775                                 return false;
776                         }
777                 }
778
779                 // internal - get called at JIT time
780
781                 private static void DemandUnmanaged ()
782                 {
783                         UnmanagedCode.Demand ();
784                 }
785
786                 // internal - get called by JIT generated code
787
788                 private static void InternalDemand (IntPtr permissions, int length)
789                 {
790                         PermissionSet ps = Decode (permissions, length);
791                         ps.Demand ();
792                 }
793
794                 private static void InternalDemandChoice (IntPtr permissions, int length)
795                 {
796                         throw new SecurityException ("SecurityAction.DemandChoice was removed from 2.0");
797                 }
798 #pragma warning restore 169             
799         }
800 }
801
802 #endif
803