New test.
[mono.git] / mcs / class / corlib / System.Security / SecurityManager.cs
index 3ca8d108bd41ec7fb151d8100fd1dc12f3a848a8..531b5439a410f1a87bf772c47752c13c442eb1e6 100644 (file)
@@ -29,6 +29,8 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+#if !MOONLIGHT
+
 using System.Collections;
 using System.Globalization;
 using System.IO;
@@ -50,19 +52,10 @@ namespace System.Security {
                public RuntimeDeclSecurityEntry choice;
        }
 
-#if NET_2_0
        [ComVisible (true)]
        public static class SecurityManager {
-#else
-       public sealed class SecurityManager {
-
-               private SecurityManager ()
-               {
-               }
-#endif
                private static object _lockObject;
                private static ArrayList _hierarchy;
-               private static PermissionSet _fullTrust; // for [AllowPartiallyTrustedCallers]
                private static IPermission _unmanagedCode;
                private static Hashtable _declsecCache;
                private static PolicyLevel _level;
@@ -81,33 +74,33 @@ namespace System.Security {
                        get;
 
                        [MethodImplAttribute (MethodImplOptions.InternalCall)]
-                       [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
+                       [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
                        set;
                }
 
+               [Obsolete ("The security manager cannot be turned off on MS runtime")]
                extern public static bool SecurityEnabled {
                        [MethodImplAttribute (MethodImplOptions.InternalCall)]
                        get;
 
                        [MethodImplAttribute (MethodImplOptions.InternalCall)]
-                       [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
+                       [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
                        set;
                }
 
                // methods
 
-#if NET_1_1
                // NOTE: This method doesn't show in the class library status page because
                // it cannot be "found" with the StrongNameIdentityPermission for ECMA key.
                // But it's there!
-               [MonoTODO]
+               // FIXME works for fulltrust (empty), documentation doesn't really make sense, type wise
+               [MonoTODO ("CAS support is experimental (and unsupported). This method only works in FullTrust.")]
                [StrongNameIdentityPermission (SecurityAction.LinkDemand, PublicKey = "0x00000000000000000400000000000000")]
                public static void GetZoneAndOrigin (out ArrayList zone, out ArrayList origin) 
                {
                        zone = new ArrayList ();
                        origin = new ArrayList ();
                }
-#endif
 
                public static bool IsGranted (IPermission perm)
                {
@@ -121,25 +114,25 @@ namespace System.Security {
                        // - Not affected by overrides (like Assert, Deny and PermitOnly)
                        // - calls IsSubsetOf even for non CAS permissions
                        //   (i.e. it does call Demand so any code there won't be executed)
+                       // with 2.0 identity permission are unrestrictable
                        return IsGranted (Assembly.GetCallingAssembly (), perm);
                }
 
+               // note: in 2.0 *all* permissions (including identity permissions) support unrestricted
                internal static bool IsGranted (Assembly a, IPermission perm)
                {
-                       CodeAccessPermission grant = null;
-
-                       if (a.GrantedPermissionSet != null) {
-                               grant = (CodeAccessPermission) a.GrantedPermissionSet.GetPermission (perm.GetType ());
-                               if (grant == null) {
-                                       if (!a.GrantedPermissionSet.IsUnrestricted () || !(perm is IUnrestrictedPermission)) {
-                                               return perm.IsSubsetOf (null);
-                                       }
-                               } else if (!perm.IsSubsetOf (grant)) {
+                       PermissionSet granted = a.GrantedPermissionSet;
+                       if ((granted != null) && !granted.IsUnrestricted ()) {
+                               CodeAccessPermission grant = (CodeAccessPermission) granted.GetPermission (perm.GetType ());
+                               if (!perm.IsSubsetOf (grant)) {
                                        return false;
                                }
                        }
 
-                       if (a.DeniedPermissionSet != null) {
+                       PermissionSet denied = a.DeniedPermissionSet;
+                       if ((denied != null) && !denied.IsEmpty ()) {
+                               if (denied.IsUnrestricted ())
+                                       return false;
                                CodeAccessPermission refuse = (CodeAccessPermission) a.DeniedPermissionSet.GetPermission (perm.GetType ());
                                if ((refuse != null) && perm.IsSubsetOf (refuse))
                                        return false;
@@ -155,7 +148,7 @@ namespace System.Security {
                        foreach (IPermission p in ps) {
                                // note: this may contains non CAS permissions
                                if ((!noncas) && (p is CodeAccessPermission)) {
-                                       if (!SecurityManager.IsGranted (a, p))
+                                       if (!IsGranted (a, p))
                                                return p;
                                } else {
                                        // but non-CAS will throw on failure...
@@ -179,8 +172,10 @@ namespace System.Security {
                        PermissionSet granted = ad.GrantedPermissionSet;
                        if (granted == null)
                                return null;
-                       if ((ad.GrantedPermissionSet.Count == 0) && ad.GrantedPermissionSet.IsUnrestricted ())
+                       if (granted.IsUnrestricted ())
                                return null;
+                       if (ps.IsUnrestricted ())
+                               return new SecurityPermission (SecurityPermissionFlag.NoFlags);
 
                        foreach (IPermission p in ps) {
                                if (p is CodeAccessPermission) {
@@ -207,7 +202,7 @@ namespace System.Security {
                        return null;
                }
 
-               [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
+               [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
                public static PolicyLevel LoadPolicyLevelFromFile (string path, PolicyLevelType type)
                {
                        if (path == null)
@@ -224,7 +219,7 @@ namespace System.Security {
                        return pl;
                }
 
-               [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
+               [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
                public static PolicyLevel LoadPolicyLevelFromString (string str, PolicyLevelType type)
                {
                        if (null == str)
@@ -241,7 +236,7 @@ namespace System.Security {
                        return pl;
                }
 
-               [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
+               [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
                public static IEnumerator PolicyHierarchy ()
                {
                        return Hierarchy;
@@ -265,24 +260,10 @@ namespace System.Security {
 
                        ResolveIdentityPermissions (ps, evidence);
 
-                       // do we have the right to execute ?
-                       if (CheckExecutionRights) {
-                               // unless we have "Full Trust"...
-                               if (!ps.IsUnrestricted ()) {
-                                       // ... we need to find a SecurityPermission
-                                       IPermission security = ps.GetPermission (typeof (SecurityPermission));
-                                       if (!_execution.IsSubsetOf (security)) {
-                                               throw new PolicyException (Locale.GetText (
-                                                       "Policy doesn't grant the right to execute to the assembly."));
-                                       }
-                               }
-                       }
-
                        return ps;
                }
 
-#if NET_2_0
-               [MonoTODO ("more tests are needed")]
+               [MonoTODO ("(2.0) more tests are needed")]
                public static PermissionSet ResolvePolicy (Evidence[] evidences)
                {
                        if ((evidences == null) || (evidences.Length == 0) ||
@@ -318,11 +299,9 @@ namespace System.Security {
                        ResolveIdentityPermissions (ps, evidence);
                        return ps;
                }
-#endif
 
                static private SecurityPermission _execution = new SecurityPermission (SecurityPermissionFlag.Execution);
 
-               [MonoTODO()]
                public static PermissionSet ResolvePolicy (Evidence evidence, PermissionSet reqdPset, PermissionSet optPset, PermissionSet denyPset, out PermissionSet denied)
                {
                        PermissionSet resolved = ResolvePolicy (evidence);
@@ -332,6 +311,27 @@ namespace System.Security {
                                        "Policy doesn't grant the minimal permissions required to execute the assembly."));
                        }
 
+                       // do we check for execution rights ?
+                       if (CheckExecutionRights) {
+                               bool execute = false;
+                               // an empty permissionset doesn't include Execution
+                               if (resolved != null) {
+                                       // unless we have "Full Trust"...
+                                       if (resolved.IsUnrestricted ()) {
+                                               execute = true;
+                                       } else {
+                                               // ... we need to find a SecurityPermission
+                                               IPermission security = resolved.GetPermission (typeof (SecurityPermission));
+                                               execute = _execution.IsSubsetOf (security);
+                                       }
+                               }
+
+                               if (!execute) {
+                                       throw new PolicyException (Locale.GetText (
+                                               "Policy doesn't grant the right to execute the assembly."));
+                               }
+                       }
+
                        denied = denyPset;
                        return resolved;
                }
@@ -352,7 +352,7 @@ namespace System.Security {
                        return al.GetEnumerator ();
                }
 
-               [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
+               [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
                public static void SavePolicy () 
                {
                        IEnumerator e = Hierarchy;
@@ -362,7 +362,7 @@ namespace System.Security {
                        }
                }
 
-               [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
+               [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
                public static void SavePolicyLevel (PolicyLevel level) 
                {
                        // Yes this will throw a NullReferenceException, just like MS (see FDBK13121)
@@ -429,9 +429,12 @@ namespace System.Security {
                        return false;
                }
 
-               // TODO: this changes in 2.0 as identity permissions can now be unrestricted
                internal static void ResolveIdentityPermissions (PermissionSet ps, Evidence evidence)
                {
+                       // in 2.0 identity permissions can now be unrestricted
+                       if (ps.IsUnrestricted ())
+                               return;
+
                        // Only host evidence are used for policy resolution
                        IEnumerator ee = evidence.GetHostEnumerator ();
                        while (ee.MoveNext ()) {
@@ -452,17 +455,13 @@ namespace System.Security {
                {
                        // Permission sets from the runtime (declarative security) can be cached
                        // for performance as they can never change (i.e. they are read-only).
+                       PermissionSet ps = null;
 
-                       if (_declsecCache == null) {
-                               lock (_lockObject) {
-                                       if (_declsecCache == null) {
-                                               _declsecCache = new Hashtable ();
-                                       }
+                       lock (_lockObject) {
+                               if (_declsecCache == null) {
+                                       _declsecCache = new Hashtable ();
                                }
-                       }
 
-                       PermissionSet ps = null;
-                       lock (_lockObject) {
                                object key = (object) (int) permissions;
                                ps = (PermissionSet) _declsecCache [key];
                                if (ps == null) {
@@ -495,53 +494,6 @@ namespace System.Security {
                                throw new SecurityException (Locale.GetText ("Unknown metadata format."));
                        }
                }
-#if NET_2_0
-               internal static PermissionSetCollection DecodeCollection (IntPtr permissions, int length)
-               {
-                       // Permission sets from the runtime (declarative security) can be cached
-                       // for performance as they can never change (i.e. they are read-only).
-
-                       if (_declsecCache == null) {
-                               lock (_lockObject) {
-                                       if (_declsecCache == null) {
-                                               _declsecCache = new Hashtable ();
-                                       }
-                               }
-                       }
-
-                       PermissionSetCollection psc = null;
-                       lock (_lockObject) {
-                               object key = (object) (int) permissions;
-                               psc = (PermissionSetCollection) _declsecCache [key];
-                               if (psc == null) {
-                                       // create permissionset and add it to the cache
-                                       byte[] data = new byte [length];
-                                       Marshal.Copy (permissions, data, 0, length);
-                                       psc = DecodeCollection (data);
-                                       _declsecCache.Add (key, psc);
-                               }
-                       }
-                       return psc;
-               }
-
-               internal static PermissionSetCollection DecodeCollection (byte[] encodedPermissions)
-               {
-                       if ((encodedPermissions == null) || (encodedPermissions.Length < 1))
-                               throw new SecurityException ("Invalid metadata format.");
-
-                       switch (encodedPermissions [0]) {
-                       case 60:
-                               // Fx 1.0/1.1 declarative security permissions metadata is in Unicode-encoded XML
-                               throw new SecurityException (Locale.GetText ("1.0 metadata format doesn't support collections."));
-                       case 0x2E:
-                               // Fx 2.0 are encoded "somewhat, but not enough, like" custom attributes
-                               // note: we still support the older format!
-                               return PermissionSetCollection.CreateFromBinaryFormat (encodedPermissions);
-                       default:
-                               throw new SecurityException (Locale.GetText ("Unknown metadata format."));
-                       }
-               }
-#endif
 
                private static IPermission UnmanagedCode {
                        get {
@@ -590,17 +542,6 @@ namespace System.Security {
                        // a single stack walk (not up to 4).
                        if (ps != null)
                                ps.Demand ();
-#if NET_2_0
-                       // Process LinkDemandChoice (2.0)
-                       if (klass.choice.size > 0) {
-                               PermissionSetCollection psc = DecodeCollection (klass.choice.blob, klass.choice.size);
-                               psc.DemandChoice ();
-                       }
-                       if (method.choice.size > 0) {
-                               PermissionSetCollection psc = DecodeCollection (method.choice.blob, method.choice.size);
-                               psc.DemandChoice ();
-                       }
-#endif
                }
 
                internal unsafe static bool ReflectedLinkDemandQuery (MethodBase mb)
@@ -614,13 +555,6 @@ namespace System.Security {
                        return LinkDemand (mb.ReflectedType.Assembly, &klass, &method);
                }
 
-               // internal - get called at JIT time
-
-               private static void DemandUnmanaged ()
-               {
-                       UnmanagedCode.Demand ();
-               }
-
                private unsafe static bool LinkDemand (Assembly a, RuntimeDeclSecurityActions *klass, RuntimeDeclSecurityActions *method)
                {
                        try {
@@ -643,33 +577,6 @@ namespace System.Security {
                                        ps = Decode (method->noncas.blob, method->noncas.size);
                                        result = (SecurityManager.CheckPermissionSet (a, ps, true) == null);
                                }
-#if NET_2_0
-                               // success if one of the permission is granted
-                               if (result && (klass->choice.size > 0)) {
-                                       PermissionSetCollection psc = DecodeCollection (klass->choice.blob, klass->choice.size);
-                                       if (psc.Count > 0) {
-                                               result = false;
-                                               foreach (PermissionSet pset in psc) {
-                                                       if (SecurityManager.CheckPermissionSet (a, pset, false) == null) {
-                                                               result = true;
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                               }
-                               if (result && (method->choice.size > 0)) {
-                                       PermissionSetCollection psc = DecodeCollection (method->choice.blob, method->choice.size);
-                                       if (psc.Count > 0) {
-                                               result = false;
-                                               foreach (PermissionSet pset in psc) {
-                                                       if (SecurityManager.CheckPermissionSet (a, pset, false) == null) {
-                                                               result = true;
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                               }
-#endif
                                return result;
                        }
                        catch (SecurityException) {
@@ -677,32 +584,35 @@ namespace System.Security {
                        }
                }
 
+#pragma warning disable 169
                private static bool LinkDemandFullTrust (Assembly a)
                {
-                       // double-lock pattern
-                       if (_fullTrust == null) {
-                               lock (_lockObject) {
-                                       if (_fullTrust == null)
-                                               _fullTrust = new NamedPermissionSet ("FullTrust");
-                               }
-                       }
+                       // FullTrust is immutable (and means Unrestricted) 
+                       // so we can skip the subset operations and jump to IsUnrestricted.
+                       PermissionSet granted = a.GrantedPermissionSet;
+                       if ((granted != null) && !granted.IsUnrestricted ())
+                               return false;
 
-                       try {
-                               return (SecurityManager.CheckPermissionSet (a, _fullTrust, false) == null);
-                       }
-                       catch (SecurityException) {
+                       PermissionSet denied = a.DeniedPermissionSet;
+                       if ((denied != null) && !denied.IsEmpty ())
                                return false;
-                       }
+
+                       return true;
                }
 
                private static bool LinkDemandUnmanaged (Assembly a)
                {
+                       // note: we know that UnmanagedCode (SecurityPermission) implements IUnrestrictedPermission
                        return IsGranted (a, UnmanagedCode);
                }
 
                // we try to provide as much details as possible to help debugging
-               private static void LinkDemandSecurityException (int securityViolation, Assembly a, MethodInfo method)
+               private static void LinkDemandSecurityException (int securityViolation, IntPtr methodHandle)
                {
+                       RuntimeMethodHandle runtimeHandle = new RuntimeMethodHandle (methodHandle);
+                       MethodInfo method = (MethodInfo)(MethodBase.GetMethodFromHandle (runtimeHandle));
+                       Assembly a = method.DeclaringType.Assembly;
+
                        string message = null;
                        AssemblyName an = null;
                        PermissionSet granted = null;
@@ -722,7 +632,7 @@ namespace System.Security {
                                break;
                        case 2: // MONO_JIT_LINKDEMAND_APTC
                                message = Locale.GetText ("Partially trusted callers aren't allowed to call into this assembly.");
-                               demanded = (object) _fullTrust;
+                               demanded = (object) DefaultPolicies.FullTrust; // immutable
                                break;
                        case 4: // MONO_JIT_LINKDEMAND_ECMA
                                message = Locale.GetText ("Calling internal calls is restricted to ECMA signed assemblies.");
@@ -765,7 +675,14 @@ namespace System.Security {
                                break;
                        }
 
-                       throw new SecurityException (message, an, granted, refused, method, SecurityAction.LinkDemand, null, null, null);
+                       throw new SecurityException (message, an, granted, refused, method, SecurityAction.InheritanceDemand, null, null, null);
+               }
+
+               // called by the runtime when CoreCLR is enabled
+
+               private static void ThrowException (Exception ex)
+               {
+                       throw ex;
                }
 
                // internal - get called by the class loader
@@ -773,7 +690,7 @@ namespace System.Security {
                // Called when
                // - class inheritance
                // - method overrides
-               private unsafe static bool InheritanceDemand (Assembly a, RuntimeDeclSecurityActions *actions)
+               private unsafe static bool InheritanceDemand (AppDomain ad, Assembly a, RuntimeDeclSecurityActions *actions)
                {
                        try {
                                PermissionSet ps = null;
@@ -781,26 +698,19 @@ namespace System.Security {
                                if (actions->cas.size > 0) {
                                        ps = Decode (actions->cas.blob, actions->cas.size);
                                        result = (SecurityManager.CheckPermissionSet (a, ps, false) == null);
+                                       if (result) {
+                                               // also check appdomain
+                                               result = (SecurityManager.CheckPermissionSet (ad, ps) == null);
+                                       }
                                }
                                if (actions->noncas.size > 0) {
                                        ps = Decode (actions->noncas.blob, actions->noncas.size);
                                        result = (SecurityManager.CheckPermissionSet (a, ps, true) == null);
-                               }
-#if NET_2_0
-                               // success if one of the permission is granted
-                               if (result && (actions->choice.size > 0)) {
-                                       PermissionSetCollection psc = DecodeCollection (actions->choice.blob, actions->choice.size);
-                                       if (psc.Count > 0) {
-                                               result = false;
-                                               foreach (PermissionSet pset in psc) {
-                                                       if (SecurityManager.CheckPermissionSet (a, pset, false) == null) {
-                                                               result = true;
-                                                               break;
-                                                       }
-                                               }
+                                       if (result) {
+                                               // also check appdomain
+                                               result = (SecurityManager.CheckPermissionSet (ad, ps) == null);
                                        }
                                }
-#endif
                                return result;
                        }
                        catch (SecurityException) {
@@ -808,6 +718,12 @@ namespace System.Security {
                        }
                }
 
+               // internal - get called at JIT time
+
+               private static void DemandUnmanaged ()
+               {
+                       UnmanagedCode.Demand ();
+               }
 
                // internal - get called by JIT generated code
 
@@ -819,12 +735,11 @@ namespace System.Security {
 
                private static void InternalDemandChoice (IntPtr permissions, int length)
                {
-#if NET_2_0
-                       PermissionSetCollection psc = DecodeCollection (permissions, length);
-                       psc.DemandChoice ();
-#else
-                       throw new SecurityException ("SecurityAction.DemandChoice is only possible in 2.0");
-#endif
+                       throw new SecurityException ("SecurityAction.DemandChoice was removed from 2.0");
                }
+#pragma warning restore 169            
        }
 }
+
+#endif
+