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