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