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-2005 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.
34 using System.Collections;
35 using System.Diagnostics;
36 using System.Globalization;
38 using System.Reflection;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Security.Permissions;
42 using System.Security.Policy;
47 namespace System.Security {
49 // Must match MonoDeclSecurityActions in /mono/metadata/reflection.h
50 internal struct RuntimeDeclSecurityActions {
51 public RuntimeDeclSecurityEntry cas;
52 public RuntimeDeclSecurityEntry noncas;
53 public RuntimeDeclSecurityEntry choice;
57 public static class SecurityManager {
58 private static object _lockObject;
59 private static ArrayList _hierarchy;
60 private static IPermission _unmanagedCode;
61 private static Hashtable _declsecCache;
62 private static PolicyLevel _level;
64 static SecurityManager ()
67 // http://msdn.microsoft.com/library/en-us/dnaskdr/html/askgui06032003.asp?frame=true
68 _lockObject = new object ();
74 public static bool CheckExecutionRights {
82 [Obsolete ("The security manager cannot be turned off on MS runtime")]
83 extern public static bool SecurityEnabled {
84 [MethodImplAttribute (MethodImplOptions.InternalCall)]
87 [MethodImplAttribute (MethodImplOptions.InternalCall)]
88 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
92 internal static bool CheckElevatedPermissions ()
94 return true; // always true outside Moonlight
97 [Conditional ("ENABLE_SANDBOX")] //??
98 internal static void EnsureElevatedPermissions ()
100 // do nothing outside of Moonlight
105 // NOTE: This method doesn't show in the class library status page because
106 // it cannot be "found" with the StrongNameIdentityPermission for ECMA key.
108 // FIXME works for fulltrust (empty), documentation doesn't really make sense, type wise
109 [MonoTODO ("CAS support is experimental (and unsupported). This method only works in FullTrust.")]
110 [StrongNameIdentityPermission (SecurityAction.LinkDemand, PublicKey = "0x00000000000000000400000000000000")]
111 public static void GetZoneAndOrigin (out ArrayList zone, out ArrayList origin)
113 zone = new ArrayList ();
114 origin = new ArrayList ();
118 public static bool IsGranted (IPermission perm)
122 if (!SecurityEnabled)
126 // - Only check the caller (no stack walk required)
127 // - Not affected by overrides (like Assert, Deny and PermitOnly)
128 // - calls IsSubsetOf even for non CAS permissions
129 // (i.e. it does call Demand so any code there won't be executed)
130 // with 2.0 identity permission are unrestrictable
131 return IsGranted (Assembly.GetCallingAssembly (), perm);
134 // note: in 2.0 *all* permissions (including identity permissions) support unrestricted
135 internal static bool IsGranted (Assembly a, IPermission perm)
137 PermissionSet granted = a.GrantedPermissionSet;
138 if ((granted != null) && !granted.IsUnrestricted ()) {
139 CodeAccessPermission grant = (CodeAccessPermission) granted.GetPermission (perm.GetType ());
140 if (!perm.IsSubsetOf (grant)) {
145 PermissionSet denied = a.DeniedPermissionSet;
146 if ((denied != null) && !denied.IsEmpty ()) {
147 if (denied.IsUnrestricted ())
149 CodeAccessPermission refuse = (CodeAccessPermission) a.DeniedPermissionSet.GetPermission (perm.GetType ());
150 if ((refuse != null) && perm.IsSubsetOf (refuse))
157 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
158 public static PolicyLevel LoadPolicyLevelFromFile (string path, PolicyLevelType type)
161 throw new ArgumentNullException ("path");
163 PolicyLevel pl = null;
165 pl = new PolicyLevel (type.ToString (), type);
166 pl.LoadFromFile (path);
168 catch (Exception e) {
169 throw new ArgumentException (Locale.GetText ("Invalid policy XML"), e);
175 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
176 public static PolicyLevel LoadPolicyLevelFromString (string str, PolicyLevelType type)
179 throw new ArgumentNullException ("str");
181 PolicyLevel pl = null;
183 pl = new PolicyLevel (type.ToString (), type);
184 pl.LoadFromString (str);
186 catch (Exception e) {
187 throw new ArgumentException (Locale.GetText ("Invalid policy XML"), e);
193 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
194 public static IEnumerator PolicyHierarchy ()
200 public static PermissionSet ResolvePolicy (Evidence evidence)
202 // no evidence, no permission
203 if (evidence == null)
204 return new PermissionSet (PermissionState.None);
206 PermissionSet ps = null;
207 // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
208 IEnumerator ple = Hierarchy;
209 while (ple.MoveNext ()) {
210 PolicyLevel pl = (PolicyLevel) ple.Current;
211 if (ResolvePolicyLevel (ref ps, pl, evidence)) {
212 break; // i.e. PolicyStatementAttribute.LevelFinal
216 ResolveIdentityPermissions (ps, evidence);
222 [MonoTODO ("(2.0) more tests are needed")]
223 public static PermissionSet ResolvePolicy (Evidence[] evidences)
225 if ((evidences == null) || (evidences.Length == 0) ||
226 ((evidences.Length == 1) && (evidences [0].Count == 0))) {
227 return new PermissionSet (PermissionState.None);
230 // probably not optimal
231 PermissionSet ps = ResolvePolicy (evidences [0]);
232 for (int i=1; i < evidences.Length; i++) {
233 ps = ps.Intersect (ResolvePolicy (evidences [i]));
239 public static PermissionSet ResolveSystemPolicy (Evidence evidence)
241 // no evidence, no permission
242 if (evidence == null)
243 return new PermissionSet (PermissionState.None);
245 // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
246 PermissionSet ps = null;
247 IEnumerator ple = Hierarchy;
248 while (ple.MoveNext ()) {
249 PolicyLevel pl = (PolicyLevel) ple.Current;
250 if (pl.Type == PolicyLevelType.AppDomain)
252 if (ResolvePolicyLevel (ref ps, pl, evidence))
253 break; // i.e. PolicyStatementAttribute.LevelFinal
256 ResolveIdentityPermissions (ps, evidence);
260 static private SecurityPermission _execution = new SecurityPermission (SecurityPermissionFlag.Execution);
263 public static PermissionSet ResolvePolicy (Evidence evidence, PermissionSet reqdPset, PermissionSet optPset, PermissionSet denyPset, out PermissionSet denied)
265 PermissionSet resolved = ResolvePolicy (evidence);
266 // do we have the minimal permission requested by the assembly ?
267 if ((reqdPset != null) && !reqdPset.IsSubsetOf (resolved)) {
268 throw new PolicyException (Locale.GetText (
269 "Policy doesn't grant the minimal permissions required to execute the assembly."));
272 // do we check for execution rights ?
273 if (CheckExecutionRights) {
274 bool execute = false;
275 // an empty permissionset doesn't include Execution
276 if (resolved != null) {
277 // unless we have "Full Trust"...
278 if (resolved.IsUnrestricted ()) {
281 // ... we need to find a SecurityPermission
282 IPermission security = resolved.GetPermission (typeof (SecurityPermission));
283 execute = _execution.IsSubsetOf (security);
288 throw new PolicyException (Locale.GetText (
289 "Policy doesn't grant the right to execute the assembly."));
298 public static IEnumerator ResolvePolicyGroups (Evidence evidence)
300 if (evidence == null)
301 throw new ArgumentNullException ("evidence");
303 ArrayList al = new ArrayList ();
304 // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
305 IEnumerator ple = Hierarchy;
306 while (ple.MoveNext ()) {
307 PolicyLevel pl = (PolicyLevel) ple.Current;
308 CodeGroup cg = pl.ResolveMatchingCodeGroups (evidence);
311 return al.GetEnumerator ();
315 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
316 public static void SavePolicy ()
318 IEnumerator e = Hierarchy;
319 while (e.MoveNext ()) {
320 PolicyLevel level = (e.Current as PolicyLevel);
326 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
327 public static void SavePolicyLevel (PolicyLevel level)
329 // Yes this will throw a NullReferenceException, just like MS (see FDBK13121)
333 // private/internal stuff
335 private static IEnumerator Hierarchy {
338 if (_hierarchy == null)
339 InitializePolicyHierarchy ();
341 return _hierarchy.GetEnumerator ();
345 private static void InitializePolicyHierarchy ()
347 string machinePolicyPath = Path.GetDirectoryName (Environment.GetMachineConfigPath ());
348 // note: use InternalGetFolderPath to avoid recursive policy initialization
349 string userPolicyPath = Path.Combine (Environment.UnixGetFolderPath (Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create), "mono");
351 PolicyLevel enterprise = new PolicyLevel ("Enterprise", PolicyLevelType.Enterprise);
353 enterprise.LoadFromFile (Path.Combine (machinePolicyPath, "enterprisesec.config"));
355 PolicyLevel machine = new PolicyLevel ("Machine", PolicyLevelType.Machine);
357 machine.LoadFromFile (Path.Combine (machinePolicyPath, "security.config"));
359 PolicyLevel user = new PolicyLevel ("User", PolicyLevelType.User);
361 user.LoadFromFile (Path.Combine (userPolicyPath, "security.config"));
363 ArrayList al = new ArrayList ();
368 _hierarchy = ArrayList.Synchronized (al);
372 internal static bool ResolvePolicyLevel (ref PermissionSet ps, PolicyLevel pl, Evidence evidence)
374 PolicyStatement pst = pl.Resolve (evidence);
377 // only for initial (first) policy level processed
378 ps = pst.PermissionSet;
380 ps = ps.Intersect (pst.PermissionSet);
382 // null is equals to None - exist that null can throw NullReferenceException ;-)
383 ps = new PermissionSet (PermissionState.None);
387 if ((pst.Attributes & PolicyStatementAttribute.LevelFinal) == PolicyStatementAttribute.LevelFinal)
393 internal static void ResolveIdentityPermissions (PermissionSet ps, Evidence evidence)
395 // in 2.0 identity permissions can now be unrestricted
396 if (ps.IsUnrestricted ())
399 // Only host evidence are used for policy resolution
400 IEnumerator ee = evidence.GetHostEnumerator ();
401 while (ee.MoveNext ()) {
402 IIdentityPermissionFactory ipf = (ee.Current as IIdentityPermissionFactory);
404 IPermission p = ipf.CreateIdentityPermission (evidence);
405 ps.AddPermission (p);
410 internal static PolicyLevel ResolvingPolicyLevel {
411 get { return _level; }
412 set { _level = value; }
415 internal static PermissionSet Decode (IntPtr permissions, int length)
417 // Permission sets from the runtime (declarative security) can be cached
418 // for performance as they can never change (i.e. they are read-only).
419 PermissionSet ps = null;
422 if (_declsecCache == null) {
423 _declsecCache = new Hashtable ();
426 object key = (object) (int) permissions;
427 ps = (PermissionSet) _declsecCache [key];
429 // create permissionset and add it to the cache
430 byte[] data = new byte [length];
431 Marshal.Copy (permissions, data, 0, length);
433 ps.DeclarativeSecurity = true;
434 _declsecCache.Add (key, ps);
440 internal static PermissionSet Decode (byte[] encodedPermissions)
442 if ((encodedPermissions == null) || (encodedPermissions.Length < 1))
443 throw new SecurityException ("Invalid metadata format.");
445 switch (encodedPermissions [0]) {
447 // Fx 1.0/1.1 declarative security permissions metadata is in Unicode-encoded XML
448 string xml = Encoding.Unicode.GetString (encodedPermissions);
449 return new PermissionSet (xml);
451 // Fx 2.0 are encoded "somewhat, but not enough, like" custom attributes
452 // note: we still support the older format!
453 return PermissionSet.CreateFromBinaryFormat (encodedPermissions);
455 throw new SecurityException (Locale.GetText ("Unknown metadata format."));
459 private static IPermission UnmanagedCode {
462 if (_unmanagedCode == null)
463 _unmanagedCode = new SecurityPermission (SecurityPermissionFlag.UnmanagedCode);
465 return _unmanagedCode;
469 // called by the runtime when CoreCLR is enabled
471 private static void ThrowException (Exception ex)
476 #pragma warning restore 169
478 public static PermissionSet GetStandardSandbox (Evidence evidence)
480 if (evidence == null)
481 throw new ArgumentNullException ("evidence");
483 throw new NotImplementedException ();
486 public static bool CurrentThreadRequiresSecurityContextCapture ()
488 throw new NotImplementedException ();