+
+ internal static bool ResolvePolicyLevel (ref PermissionSet ps, PolicyLevel pl, Evidence evidence)
+ {
+ PolicyStatement pst = pl.Resolve (evidence);
+ if (pst != null) {
+ if (ps == null) {
+ // only for initial (first) policy level processed
+ ps = pst.PermissionSet;
+ } else {
+ ps = ps.Intersect (pst.PermissionSet);
+ if (ps == null) {
+ // null is equals to None - exist that null can throw NullReferenceException ;-)
+ ps = new PermissionSet (PermissionState.None);
+ }
+ }
+
+ if ((pst.Attributes & PolicyStatementAttribute.LevelFinal) == PolicyStatementAttribute.LevelFinal)
+ return true;
+ }
+ return false;
+ }
+
+ // TODO: this changes in 2.0 as identity permissions can now be unrestricted
+ internal static void ResolveIdentityPermissions (PermissionSet ps, Evidence evidence)
+ {
+ // Only host evidence are used for policy resolution
+ IEnumerator ee = evidence.GetHostEnumerator ();
+ while (ee.MoveNext ()) {
+ IIdentityPermissionFactory ipf = (ee.Current as IIdentityPermissionFactory);
+ if (ipf != null) {
+ IPermission p = ipf.CreateIdentityPermission (evidence);
+ ps.AddPermission (p);
+ }
+ }
+ }
+
+ internal static PermissionSet Decode (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 ();
+ }
+ }
+ }
+
+ PermissionSet ps = null;
+ lock (_lockObject) {
+ object key = (object) (int) permissions;
+ ps = (PermissionSet) _declsecCache [key];
+ if (ps == null) {
+ // create permissionset and add it to the cache
+ byte[] data = new byte [length];
+ Marshal.Copy (permissions, data, 0, length);
+ ps = Decode (data);
+ ps.DeclarativeSecurity = true;
+ _declsecCache.Add (key, ps);
+ }
+ }
+ return ps;
+ }
+
+ internal static PermissionSet Decode (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
+ string xml = Encoding.Unicode.GetString (encodedPermissions);
+ return new PermissionSet (xml);
+ case 0x2E:
+ // Fx 2.0 are encoded "somewhat, but not enough, like" custom attributes
+ // note: we still support the older format!
+ return PermissionSet.CreateFromBinaryFormat (encodedPermissions);
+ default:
+ 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
+
+ // security check when using reflection
+
+ // When using reflection LinkDemand are promoted to full Demand (i.e. stack walk)
+ private unsafe static void ReflectedLinkDemand (RuntimeDeclSecurityActions *klass, RuntimeDeclSecurityActions *method)
+ {
+ PermissionSet ps = null;
+
+ if (klass->cas.size > 0) {
+ ps = Decode (klass->cas.blob, klass->cas.size);
+ }
+ if (klass->noncas.size > 0) {
+ PermissionSet p = Decode (klass->noncas.blob, klass->noncas.size);
+ ps = (ps == null) ? p : ps.Union (p);
+ }
+
+ if (method->cas.size > 0) {
+ PermissionSet p = Decode (method->cas.blob, method->cas.size);
+ ps = (ps == null) ? p : ps.Union (p);
+ }
+ if (method->noncas.size > 0) {
+ PermissionSet p = Decode (method->noncas.blob, method->noncas.size);
+ ps = (ps == null) ? p : ps.Union (p);
+ }
+
+ // in this case we union-ed the permission sets because we want to do
+ // 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 - get called at JIT time
+
+ private unsafe static bool LinkDemand (Assembly a, RuntimeDeclSecurityActions *klass, RuntimeDeclSecurityActions *method)
+ {
+ try {
+ PermissionSet ps = null;
+ bool result = true;
+ if (klass->cas.size > 0) {
+ ps = Decode (klass->cas.blob, klass->cas.size);
+ result = SecurityManager.IsGranted (a, ps, false);
+ }
+ if (result && (klass->noncas.size > 0)) {
+ ps = Decode (klass->noncas.blob, klass->noncas.size);
+ result = SecurityManager.IsGranted (a, ps, true);
+ }
+
+ if (result && (method->cas.size > 0)) {
+ ps = Decode (method->cas.blob, method->cas.size);
+ result = SecurityManager.IsGranted (a, ps, false);
+ }
+ if (result && (method->noncas.size > 0)) {
+ ps = Decode (method->noncas.blob, method->noncas.size);
+ result = SecurityManager.IsGranted (a, ps, true);
+ }
+#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.IsGranted (a, pset, false)) {
+ 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.IsGranted (a, pset, false)) {
+ result = true;
+ break;
+ }
+ }
+ }
+ }
+#endif
+ return result;
+ }
+ catch (SecurityException) {
+ return false;
+ }
+ }
+
+ private static bool LinkDemandFullTrust (Assembly a)
+ {
+ // double-lock pattern
+ if (_fullTrust == null) {
+ lock (_lockObject) {
+ if (_fullTrust == null)
+ _fullTrust = new NamedPermissionSet ("FullTrust");
+ }
+ }
+
+ try {
+ return SecurityManager.IsGranted (a, _fullTrust, false);
+ }
+ catch (SecurityException) {
+ return false;
+ }
+ }
+
+ private static bool LinkDemandUnmanaged (Assembly a)
+ {
+ // double-lock pattern
+ if (_unmanagedCode == null) {
+ lock (_lockObject) {
+ if (_unmanagedCode == null)
+ _unmanagedCode = new SecurityPermission (SecurityPermissionFlag.UnmanagedCode);
+ }
+ }
+
+ 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)
+ {
+ string message = null;
+ AssemblyName an = null;
+ PermissionSet granted = null;
+ PermissionSet refused = null;
+ object demanded = null;
+ IPermission failed = null;
+
+ if (a != null) {
+ an = a.GetName ();
+ granted = a.GrantedPermissionSet;
+ refused = a.DeniedPermissionSet;
+ }
+
+ switch (securityViolation) {
+ case 1: // MONO_JIT_LINKDEMAND_PERMISSION
+ message = Locale.GetText ("Permissions refused to call this method.");
+ break;
+ case 2: // MONO_JIT_LINKDEMAND_APTC
+ message = Locale.GetText ("Partially trusted callers aren't allowed to call into this assembly.");
+ demanded = (object) _fullTrust;
+ break;
+ case 4: // MONO_JIT_LINKDEMAND_ECMA
+ message = Locale.GetText ("Calling internal calls is restricted to ECMA signed assemblies.");
+ break;
+ case 8: // MONO_JIT_LINKDEMAND_PINVOKE
+ message = Locale.GetText ("Calling unmanaged code isn't allowed from this assembly.");
+ demanded = (object) _unmanagedCode;
+ failed = _unmanagedCode;
+ break;
+ default:
+ message = Locale.GetText ("JIT time LinkDemand failed.");
+ break;
+ }
+
+ throw new SecurityException (message, an, granted, refused, method, SecurityAction.LinkDemand, demanded, failed, null);
+ }
+
+ private static void InheritanceDemandSecurityException (int securityViolation, Assembly a, Type t, MethodInfo method)
+ {
+ string message = null;
+ AssemblyName an = null;
+ PermissionSet granted = null;
+ PermissionSet refused = null;
+
+ if (a != null) {
+ an = a.GetName ();
+ granted = a.GrantedPermissionSet;
+ refused = a.DeniedPermissionSet;
+ }
+
+ switch (securityViolation) {
+ case 1: // MONO_METADATA_INHERITANCEDEMAND_CLASS
+ message = String.Format (Locale.GetText ("Class inheritance refused for {0}."), t);
+ break;
+ case 2: // MONO_METADATA_INHERITANCEDEMAND_CLASS
+ message = Locale.GetText ("Method override refused.");
+ break;
+ default:
+ message = Locale.GetText ("Load time InheritDemand failed.");
+ break;
+ }
+
+ throw new SecurityException (message, an, granted, refused, method, SecurityAction.LinkDemand, null, null, null);
+ }
+
+ // internal - get called by the class loader
+
+ // Called when
+ // - class inheritance
+ // - method overrides
+ private unsafe static bool InheritanceDemand (Assembly a, RuntimeDeclSecurityActions *actions)
+ {
+ try {
+ PermissionSet ps = null;
+ bool result = true;
+ if (actions->cas.size > 0) {
+ ps = Decode (actions->cas.blob, actions->cas.size);
+ result = SecurityManager.IsGranted (a, ps, false);
+ }
+ if (actions->noncas.size > 0) {
+ ps = Decode (actions->noncas.blob, actions->noncas.size);
+ result = SecurityManager.IsGranted (a, ps, true);
+ }
+#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.IsGranted (a, pset, false)) {
+ result = true;
+ break;
+ }
+ }
+ }
+ }
+#endif
+ return result;
+ }
+ catch (SecurityException) {
+ return false;
+ }
+ }
+
+
+ // internal - get called by JIT generated code
+
+ private static void InternalDemand (IntPtr permissions, int length)
+ {
+ PermissionSet ps = Decode (permissions, length);
+ ps.Demand ();
+ }
+
+ 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
+ }