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