//
// (C) Nick Drochak
// Portions (C) 2003, 2004 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
using System.Security.Permissions;
using System.Security.Policy;
using System.Text;
+using System.Threading;
namespace System.Security {
private ArrayList list;
private int _hashcode;
private PolicyLevel _policyLevel;
+ private bool _declsec;
// constructors
}
}
+ // Light version for creating a (non unrestricted) PermissionSet with
+ // a single permission. This allows to relax most validations.
+ internal PermissionSet (IPermission perm)
+ : this ()
+ {
+ if (perm != null) {
+ // note: we do not copy IPermission like AddPermission
+ list.Add (perm);
+ }
+ }
+
// methods
public virtual IPermission AddPermission (IPermission perm)
perm = perm.Union (existing);
}
+ // note: Add doesn't copy
list.Add (perm);
return perm;
}
- [MonoTODO ("unmanaged side is incomplete")]
+ [MonoTODO ("Imperative mode isn't supported")]
public virtual void Assert ()
{
new SecurityPermission (SecurityPermissionFlag.Assertion).Demand ();
+ int count = this.Count;
+
// we (current frame) must have the permission to assert it to others
// otherwise we don't assert (but we don't throw an exception)
foreach (IPermission p in list) {
if (!SecurityManager.IsGranted (p)) {
return;
}
- }
+ } else
+ count--;
}
- CodeAccessPermission.SetCurrentFrame (CodeAccessPermission.StackModifier.Assert, this.Copy ());
+ // note: we must ignore the stack modifiers for the non-CAS permissions
+ if (count > 0)
+ throw new NotSupportedException ("Currently only declarative Assert are supported.");
}
internal void Clear ()
}
}
- [MonoTODO ("Assert, Deny and PermitOnly aren't yet supported")]
+ [MonoTODO ("Imperative Assert, Deny and PermitOnly aren't yet supported")]
public virtual void Demand ()
{
+ // Note: SecurityEnabled only applies to CAS permissions
+ // so we're not checking for it (yet)
if (IsEmpty ())
return;
cas.RemovePermission (t);
}
}
-
- // don't start the walk if the permission set only contains non CAS permissions
- if (cas.Count == 0)
- return;
}
- // Note: SecurityEnabled only applies to CAS permissions
- if (!SecurityManager.SecurityEnabled)
- return;
+ // don't start the stack walk if
+ // - the permission set only contains non CAS permissions; or
+ // - security isn't enabled (applis only to CAS!)
+ if (!cas.IsEmpty () && SecurityManager.SecurityEnabled)
+ CasOnlyDemand (_declsec ? 4 : 2);
+ }
- // FIXME: optimize
- foreach (IPermission p in cas.list) {
- p.Demand ();
+ // The number of frames to skip depends on who's calling
+ // - CodeAccessPermission.Demand (imperative)
+ // - PermissionSet.Demand (imperative)
+ // - SecurityManager.InternalDemand (declarative)
+ internal void CasOnlyDemand (int skip)
+ {
+ Assembly current = null;
+
+ // skip ourself, Demand and other security runtime methods
+ foreach (SecurityFrame sf in SecurityFrame.GetStack (skip)) {
+ if (ProcessFrame (sf, ref current))
+ return; // reached Assert
+ }
+
+ // Is there a CompressedStack to handle ?
+ CompressedStack stack = Thread.CurrentThread.GetCompressedStack ();
+ if ((stack != null) && !stack.IsEmpty ()) {
+ foreach (SecurityFrame frame in stack.List) {
+ if (ProcessFrame (frame, ref current))
+ return; // reached Assert
+ }
}
}
- [MonoTODO ("unmanaged side is incomplete")]
+ [MonoTODO ("Imperative mode isn't supported")]
public virtual void Deny ()
{
- CodeAccessPermission.SetCurrentFrame (CodeAccessPermission.StackModifier.Deny, this.Copy ());
+ foreach (IPermission p in list) {
+ // note: we ignore non-CAS permissions
+ if (p is IStackWalk) {
+ throw new NotSupportedException ("Currently only declarative Deny are supported.");
+ }
+ }
}
[MonoTODO ("adjust class version with current runtime - unification")]
return true;
}
- [MonoTODO ("unmanaged side is incomplete")]
+ [MonoTODO ("Imperative mode isn't supported")]
public virtual void PermitOnly ()
{
- CodeAccessPermission.SetCurrentFrame (CodeAccessPermission.StackModifier.PermitOnly, this.Copy ());
+ foreach (IPermission p in list) {
+ // note: we ignore non-CAS permissions
+ if (p is IStackWalk) {
+ throw new NotSupportedException ("Currently only declarative Deny are supported.");
+ }
+ }
}
public bool ContainsNonCodeAccessPermissions ()
get { return this; }
}
+ internal bool DeclarativeSecurity {
+ get { return _declsec; }
+ set { _declsec = value; }
+ }
+
[MonoTODO()]
void IDeserializationCallback.OnDeserialization (object sender)
{
[ComVisible (false)]
public override int GetHashCode ()
{
- if (list.Count == 0)
- return (int) state;
-
- if (_hashcode == 0) {
- _hashcode = state.GetHashCode ();
- foreach (IPermission p in list) {
- _hashcode ^= p.GetHashCode ();
- }
- }
- return _hashcode;
+ return (list.Count == 0) ? (int) state : base.GetHashCode ();
}
[MonoTODO ("what's it doing here?")]
static public void RevertAssert ()
{
+ // FIXME: There's probably a reason this was added here ?
+ CodeAccessPermission.RevertAssert ();
}
#endif
internal void ImmediateCallerDemand ()
{
- if (!SecurityManager.SecurityEnabled)
- return;
if (IsEmpty ())
return;
- StackTrace st = new StackTrace (1); // skip ourself
- StackFrame sf = st.GetFrame (0);
- MethodBase mb = sf.GetMethod ();
- Assembly af = mb.ReflectedType.Assembly;
- if (!af.Demand (this)) {
- Type t = this.GetType ();
- // TODO add more details
- throw new SecurityException ("LinkDemand failed", t);
+ // skip ourself
+ SecurityFrame sf = new SecurityFrame (1); // FIXME skip
+ foreach (IPermission p in list) {
+ // note: this may contains non CAS permissions
+ if (p is CodeAccessPermission) {
+ if (SecurityManager.SecurityEnabled)
+ SecurityManager.IsGranted (sf.Assembly, p);
+ } else {
+ p.Demand ();
+ }
}
}
p.Demand ();
}
}
+
+ internal bool ProcessFrame (SecurityFrame frame, ref Assembly current)
+ {
+ if (IsUnrestricted ()) {
+ // we request unrestricted
+ if (frame.Deny != null) {
+ // but have restrictions (some denied permissions)
+ CodeAccessPermission.ThrowSecurityException (this, "Deny", frame.Assembly,
+ frame.Method, SecurityAction.Demand, null);
+ } else if (frame.PermitOnly != null) {
+ // but have restrictions (onyl some permitted permissions)
+ CodeAccessPermission.ThrowSecurityException (this, "PermitOnly", frame.Assembly,
+ frame.Method, SecurityAction.Demand, null);
+ }
+ }
+
+ foreach (CodeAccessPermission cap in list) {
+ if (cap.ProcessFrame (frame, ref current))
+ return true; // Assert reached - abort stack walk!
+ }
+ return false;
+ }
}
}