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