2 // System.Security.SecurityManager.cs
5 // Nick Drochak(ndrochak@gol.com)
6 // Sebastien Pouliot <sebastien@ximian.com>
9 // Portions (C) 2004 Motus Technologies Inc. (http://www.motus.com)
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
32 using System.Collections;
33 using System.Globalization;
35 using System.Reflection;
36 using System.Runtime.CompilerServices;
37 using System.Runtime.InteropServices;
38 using System.Security.Permissions;
39 using System.Security.Policy;
44 namespace System.Security {
46 public sealed class SecurityManager {
48 private static bool checkExecutionRights;
49 private static bool securityEnabled;
50 private static object _lockObject;
51 private static ArrayList _hierarchy;
52 private static PermissionSet _fullTrust; // for [AllowPartiallyTrustedCallers]
53 private static Hashtable _declsecCache;
55 static SecurityManager ()
58 // http://msdn.microsoft.com/library/en-us/dnaskdr/html/askgui06032003.asp?frame=true
59 _lockObject = new object ();
60 securityEnabled = true;
61 // checkExecutionRights = true;
64 private SecurityManager ()
70 public static bool CheckExecutionRights {
71 get { return checkExecutionRights; }
73 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
75 // throw a SecurityException if we don't have ControlPolicy permission
76 checkExecutionRights = value;
80 public static bool SecurityEnabled {
81 get { return securityEnabled; }
83 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
85 // throw a SecurityException if we don't have ControlPolicy permission
86 securityEnabled = value;
94 [StrongNameIdentityPermission (SecurityAction.LinkDemand, PublicKey = "0x00000000000000000400000000000000")]
95 public static void GetZoneAndOrigin (out ArrayList zone, out ArrayList origin)
102 public static bool IsGranted (IPermission perm)
106 if (!securityEnabled)
110 // - Only check the caller (no stack walk required)
111 // - Not affected by overrides (like Assert, Deny and PermitOnly)
112 // - calls IsSubsetOf even for non CAS permissions
113 // (i.e. it does call Demand so any code there won't be executed)
114 return IsGranted (Assembly.GetCallingAssembly (), perm);
117 internal static bool IsGranted (Assembly a, IPermission perm)
119 CodeAccessPermission grant = null;
121 if (a.GrantedPermissionSet != null)
122 grant = (CodeAccessPermission) a.GrantedPermissionSet.GetPermission (perm.GetType ());
124 if ((grant == null) || !perm.IsSubsetOf (grant)) {
125 if (a.DeniedPermissionSet != null) {
126 CodeAccessPermission refuse = (CodeAccessPermission) a.DeniedPermissionSet.GetPermission (perm.GetType ());
127 if ((refuse != null) && perm.IsSubsetOf (refuse))
135 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
136 public static PolicyLevel LoadPolicyLevelFromFile (string path, PolicyLevelType type)
138 // throw a SecurityException if we don't have ControlPolicy permission
140 throw new ArgumentNullException ("path");
142 PolicyLevel pl = null;
144 pl = new PolicyLevel (type.ToString (), PolicyLevelType.AppDomain);
145 pl.LoadFromFile (path);
147 catch (Exception e) {
148 throw new ArgumentException (Locale.GetText ("Invalid policy XML"), e);
153 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
154 public static PolicyLevel LoadPolicyLevelFromString (string str, PolicyLevelType type)
156 // throw a SecurityException if we don't have ControlPolicy permission
158 throw new ArgumentNullException ("str");
160 PolicyLevel pl = null;
162 pl = new PolicyLevel (type.ToString (), PolicyLevelType.AppDomain);
163 pl.LoadFromString (str);
165 catch (Exception e) {
166 throw new ArgumentException (Locale.GetText ("Invalid policy XML"), e);
171 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
172 public static IEnumerator PolicyHierarchy ()
174 // throw a SecurityException if we don't have ControlPolicy permission
178 public static PermissionSet ResolvePolicy (Evidence evidence)
180 // no evidence, no permission
181 if (evidence == null)
182 return new PermissionSet (PermissionState.None);
184 PermissionSet ps = null;
185 // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
186 IEnumerator ple = Hierarchy;
187 while (ple.MoveNext ()) {
188 PolicyLevel pl = (PolicyLevel) ple.Current;
189 PolicyStatement pst = pl.Resolve (evidence);
192 ps = pst.PermissionSet; // for first time only
194 ps = ps.Intersect (pst.PermissionSet);
196 // some permissions returns null, other returns an empty set
197 // sadly we must adjust for every variations :(
199 ps = new PermissionSet (PermissionState.None);
201 if ((pst.Attributes & PolicyStatementAttribute.LevelFinal) == PolicyStatementAttribute.LevelFinal)
206 // Only host evidence are used for policy resolution
207 IEnumerator ee = evidence.GetHostEnumerator ();
208 while (ee.MoveNext ()) {
209 IIdentityPermissionFactory ipf = (ee.Current as IIdentityPermissionFactory);
211 IPermission p = ipf.CreateIdentityPermission (evidence);
212 ps.AddPermission (p);
220 public static PermissionSet ResolvePolicy (Evidence[] evidences)
222 if (evidences == null)
223 return new PermissionSet (PermissionState.None);
225 // probably not optimal
226 PermissionSet ps = null;
227 foreach (Evidence evidence in evidences) {
229 ps = ResolvePolicy (evidence);
231 ps = ps.Intersect (ResolvePolicy (evidence));
237 static private SecurityPermission _execution = new SecurityPermission (SecurityPermissionFlag.Execution);
240 public static PermissionSet ResolvePolicy (Evidence evidence, PermissionSet reqdPset, PermissionSet optPset, PermissionSet denyPset, out PermissionSet denied)
242 PermissionSet resolved = ResolvePolicy (evidence);
243 // do we have the minimal permission requested by the assembly ?
244 if ((reqdPset != null) && !reqdPset.IsSubsetOf (resolved)) {
245 throw new PolicyException (Locale.GetText (
246 "Policy doesn't grant the minimal permissions required to execute the assembly."));
248 // do we have the right to execute ?
249 if (checkExecutionRights) {
250 // unless we have "Full Trust"...
251 if (!resolved.IsUnrestricted ()) {
252 // ... we need to find a SecurityPermission
253 IPermission security = resolved.GetPermission (typeof (SecurityPermission));
254 if (!_execution.IsSubsetOf (security)) {
255 throw new PolicyException (Locale.GetText (
256 "Policy doesn't grant the right to execute to the assembly."));
265 public static IEnumerator ResolvePolicyGroups (Evidence evidence)
267 if (evidence == null)
268 throw new ArgumentNullException ("evidence");
270 ArrayList al = new ArrayList ();
271 // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
272 IEnumerator ple = Hierarchy;
273 while (ple.MoveNext ()) {
274 PolicyLevel pl = (PolicyLevel) ple.Current;
275 CodeGroup cg = pl.ResolveMatchingCodeGroups (evidence);
278 return al.GetEnumerator ();
281 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
282 public static void SavePolicy ()
284 // throw a SecurityException if we don't have ControlPolicy permission
285 IEnumerator e = Hierarchy;
286 while (e.MoveNext ()) {
287 PolicyLevel level = (e.Current as PolicyLevel);
292 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
293 public static void SavePolicyLevel (PolicyLevel level)
295 // Yes this will throw a NullReferenceException, just like MS (see FDBK13121)
299 // private/internal stuff
301 private static IEnumerator Hierarchy {
303 // double-lock pattern
304 if (_hierarchy == null) {
306 if (_hierarchy == null)
307 InitializePolicyHierarchy ();
310 return _hierarchy.GetEnumerator ();
314 private static void InitializePolicyHierarchy ()
316 string machinePolicyPath = Path.GetDirectoryName (Environment.GetMachineConfigPath ());
317 string userPolicyPath = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "mono");
319 ArrayList al = new ArrayList ();
320 al.Add (new PolicyLevel ("Enterprise", PolicyLevelType.Enterprise,
321 Path.Combine (machinePolicyPath, "enterprisesec.config")));
323 al.Add (new PolicyLevel ("Machine", PolicyLevelType.Machine,
324 Path.Combine (machinePolicyPath, "security.config")));
326 al.Add (new PolicyLevel ("User", PolicyLevelType.User,
327 Path.Combine (userPolicyPath, "security.config")));
329 _hierarchy = ArrayList.Synchronized (al);
332 internal static PermissionSet Decode (IntPtr permissions, int length)
334 // Permission sets from the runtime (declarative security) can be cached
335 // for performance as they can never change (i.e. they are read-only).
337 if (_declsecCache == null) {
339 if (_declsecCache == null) {
340 _declsecCache = new Hashtable ();
345 PermissionSet ps = null;
347 object key = (object) (int) permissions;
348 ps = (PermissionSet) _declsecCache [key];
350 // create permissionset and add it to the cache
351 byte[] data = new byte [length];
352 Marshal.Copy (permissions, data, 0, length);
354 ps.DeclarativeSecurity = true;
355 _declsecCache.Add (key, ps);
361 internal static PermissionSet Decode (byte[] encodedPermissions)
363 switch (encodedPermissions [0]) {
365 // Fx 1.0/1.1 declarative security permissions metadata is in Unicode-encoded XML
366 string xml = Encoding.Unicode.GetString (encodedPermissions);
367 return new PermissionSet (xml);
370 throw new SecurityException ("Unsupported 2.0 metadata format.");
372 throw new SecurityException ("Unknown metadata format.");
376 private static PermissionSet Union (byte[] classPermissions, byte[] methodPermissions)
378 if (classPermissions != null) {
379 PermissionSet ps = Decode (classPermissions);
380 if (methodPermissions != null) {
381 ps = ps.Union (Decode (methodPermissions));
386 return Decode (methodPermissions);
389 // internal - get called at JIT time
391 unsafe private static void LinkDemand (
392 IntPtr casClassPermission, int casClassLength,
393 IntPtr nonCasClassPermission, int nonCasClassLength,
394 IntPtr casMethodPermission, int casMethodLength,
395 IntPtr nonCasMethodPermission, int nonCasMethodLength,
396 bool requiresFullTrust)
398 PermissionSet ps = null;
400 if (casClassLength > 0) {
401 ps = Decode (casClassPermission, casClassLength);
402 ps.ImmediateCallerDemand ();
404 if (nonCasClassLength > 0) {
405 ps = Decode (nonCasClassPermission, nonCasClassLength);
406 ps.ImmediateCallerNonCasDemand ();
409 if (casMethodLength > 0) {
410 ps = Decode (casMethodPermission, casMethodLength);
411 ps.ImmediateCallerDemand ();
413 if (nonCasMethodLength > 0) {
414 ps = Decode (nonCasMethodPermission, nonCasMethodLength);
415 ps.ImmediateCallerNonCasDemand ();
418 if (requiresFullTrust) {
419 // double-lock pattern
420 if (_fullTrust == null) {
422 if (_fullTrust == null)
423 _fullTrust = new NamedPermissionSet ("FullTrust");
426 // FIXME: to be optimized with a flag
427 _fullTrust.ImmediateCallerDemand ();
431 // internal - get called by the class loader
434 // - class inheritance
435 // - method overrides
436 private static void InheritanceDemand (byte[] permissions, byte[] nonCasPermissions)
438 if (permissions != null) {
439 PermissionSet ps = Decode (permissions);
441 ps.ImmediateCallerDemand ();
443 if (nonCasPermissions != null) {
444 PermissionSet ps = Decode (nonCasPermissions);
446 ps.ImmediateCallerNonCasDemand ();
450 // internal - get called by JIT generated code
452 unsafe private static void InternalDemand (IntPtr permissions, int length)
454 PermissionSet ps = Decode (permissions, length);
458 unsafe private static void InternalDemandChoice (IntPtr permissions, int length)
461 PermissionSet ps = Decode (permissions, length);
464 throw new SecurityException ("SecurityAction.DemandChoice is only possible in 2.0");