2 // System.Security.CodeAccessPermission.cs
5 // Miguel de Icaza (miguel@ximian.com)
6 // Nick Drochak, ndrochak@gol.com
7 // Sebastien Pouliot <sebastien@ximian.com>
9 // (C) Ximian, Inc. http://www.ximian.com
10 // Copyright (C) 2001 Nick Drochak, All Rights Reserved
11 // Portions (C) 2004 Motus Technologies Inc. (http://www.motus.com)
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System
.Diagnostics
;
35 using System
.Globalization
;
36 using System
.Reflection
;
37 using System
.Runtime
.CompilerServices
;
38 using System
.Security
.Permissions
;
40 namespace System
.Security
{
43 public abstract class CodeAccessPermission
: IPermission
, ISecurityEncodable
, IStackWalk
{
45 internal enum StackModifier
{
51 protected CodeAccessPermission ()
55 // LAMESPEC: Documented as virtual
56 [MonoTODO ("unmanaged side is incomplete")]
59 // Not everyone can assert freely so we must check for
60 // System.Security.Permissions.SecurityPermissionFlag.Assertion
61 new SecurityPermission (SecurityPermissionFlag
.Assertion
).Demand ();
63 // we must have the permission to assert it to others
64 if (SecurityManager
.IsGranted (this)) {
65 SetCurrentFrame (StackModifier
.Assert
, this.Copy ());
74 bool CheckAssert (CodeAccessPermission asserted
)
78 if (asserted
.GetType () != this.GetType ())
80 return IsSubsetOf (asserted
);
88 bool CheckDemand (CodeAccessPermission target
)
92 if (target
.GetType () != this.GetType ())
94 return IsSubsetOf (target
);
102 bool CheckDeny (CodeAccessPermission denied
)
106 if (denied
.GetType () != this.GetType ())
108 return (Intersect (denied
) == null);
116 virtual bool CheckPermitOnly (CodeAccessPermission target
)
120 if (target
.GetType () != this.GetType ())
122 return IsSubsetOf (target
);
125 public abstract IPermission
Copy ();
127 // LAMESPEC: Documented as virtual
128 [MonoTODO ("Assert, Deny and PermitOnly aren't yet supported")]
129 public void Demand ()
131 if (!SecurityManager
.SecurityEnabled
)
135 // 1. CheckDemand (current frame)
136 // note: for declarative attributes directly calls IsSubsetOf
139 StackTrace st
= new StackTrace (1); // skip ourself
140 StackFrame
[] frames
= st
.GetFrames ();
141 foreach (StackFrame sf
in frames
) {
142 MethodBase mb
= sf
.GetMethod ();
143 // however the "final" grant set is resolved by assembly, so
144 // there's no need to check it every time (just when we're
145 // changing assemblies between frames).
146 Assembly af
= mb
.ReflectedType
.Assembly
;
147 CodeAccessPermission cap
= null;
150 if (a
.GrantedPermissionSet
!= null)
151 cap
= (CodeAccessPermission
) a
.GrantedPermissionSet
.GetPermission (this.GetType ());
155 // CheckDemand will always return false in case cap is null
156 if ((cap
== null) || !CheckDemand (cap
)) {
157 if (a
.DeniedPermissionSet
!= null) {
158 cap
= (CodeAccessPermission
) a
.DeniedPermissionSet
.GetPermission (this.GetType ());
163 // IsSubsetOf "should" always return false if cap is null
164 if ((cap
!= null) && IsSubsetOf (cap
)) {
165 Type t
= this.GetType ();
166 // TODO add more details
167 throw new SecurityException ("ReqRefuse", t
);
171 throw new SecurityException ("Demand failed", a
.GetName (),
172 a
.GrantedPermissionSet
, a
.DeniedPermissionSet
, (MethodInfo
) mb
,
173 SecurityAction
.Demand
, this, cap
, a
.Evidence
);
176 object[] perms
= GetFramePermissions ();
180 // 2. CheckPermitOnly
181 object o
= perms
[(int)StackModifier
.PermitOnly
];
183 cap
= (o
as CodeAccessPermission
);
185 if (!CheckPermitOnly (cap
))
186 throw new SecurityException ("PermitOnly");
189 PermissionSet ps
= (o
as PermissionSet
);
190 foreach (IPermission p
in ps
) {
191 if (p
is CodeAccessPermission
) {
192 if (!CheckPermitOnly (p
as CodeAccessPermission
))
193 throw new SecurityException ("PermitOnly");
200 o
= perms
[(int)StackModifier
.Deny
];
202 cap
= (o
as CodeAccessPermission
) ;
204 if (!CheckDeny (cap
))
205 throw new SecurityException ("Deny");
208 PermissionSet ps
= (o
as PermissionSet
);
209 foreach (IPermission p
in ps
) {
210 if (p
is CodeAccessPermission
) {
211 if (!CheckPermitOnly (p
as CodeAccessPermission
))
212 throw new SecurityException ("Deny");
219 o
= perms
[(int)StackModifier
.Assert
];
221 cap
= (o
as CodeAccessPermission
);
223 if (CheckAssert (cap
)) {
224 return; // stop the stack walk
228 PermissionSet ps
= (o
as PermissionSet
);
229 foreach (IPermission p
in ps
) {
230 if (p
is CodeAccessPermission
) {
231 if (!CheckPermitOnly (p
as CodeAccessPermission
)) {
232 return; // stop the stack walk
241 // LAMESPEC: Documented as virtual
242 [MonoTODO ("unmanaged side is incomplete")]
245 SetCurrentFrame (StackModifier
.Deny
, this.Copy ());
250 public override bool Equals (object obj
)
254 if (obj
.GetType () != this.GetType ())
261 public abstract void FromXml (SecurityElement elem
);
265 public override int GetHashCode ()
267 return base.GetHashCode ();
271 public abstract IPermission
Intersect (IPermission target
);
273 public abstract bool IsSubsetOf (IPermission target
);
275 public override string ToString ()
277 SecurityElement elem
= ToXml ();
278 return elem
.ToString ();
281 public abstract SecurityElement
ToXml ();
283 public virtual IPermission
Union (IPermission other
)
286 throw new System
.NotSupportedException (); // other is not null.
290 // LAMESPEC: Documented as virtual
291 [MonoTODO ("unmanaged side is incomplete")]
292 public void PermitOnly ()
294 SetCurrentFrame (StackModifier
.PermitOnly
, this.Copy ());
297 [MonoTODO ("unmanaged side is incomplete")]
298 public static void RevertAll ()
300 if (!ClearFramePermissions ()) {
301 string msg
= Locale
.GetText ("No security frame present to be reverted.");
302 throw new ExecutionEngineException (msg
);
306 [MonoTODO ("unmanaged side is incomplete")]
307 public static void RevertAssert ()
309 RevertCurrentFrame (StackModifier
.Assert
);
312 [MonoTODO ("unmanaged side is incomplete")]
313 public static void RevertDeny ()
315 RevertCurrentFrame (StackModifier
.Deny
);
318 [MonoTODO ("unmanaged side is incomplete")]
319 public static void RevertPermitOnly ()
321 RevertCurrentFrame (StackModifier
.PermitOnly
);
326 // see mono/mono/metadata/cas.c for implementation
328 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
329 static extern bool ClearFramePermissions ();
331 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
332 static extern object[] GetFramePermissions ();
334 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
335 static extern bool SetFramePermissions (int index
, object permissions
);
337 // icalls are not yet commited so...
339 static bool ClearFramePermissions ()
344 static object[] GetFramePermissions ()
349 static bool SetFramePermissions (int index
, object permissions
)
355 // Internal helpers methods
357 // snippet moved from FileIOPermission (nickd) to be reused in all derived classes
358 internal SecurityElement
Element (int version
)
360 SecurityElement se
= new SecurityElement ("IPermission");
361 Type type
= this.GetType ();
362 se
.AddAttribute ("class", type
.FullName
+ ", " + type
.Assembly
.ToString ().Replace ('\"', '\''));
363 se
.AddAttribute ("version", version
.ToString ());
367 internal static PermissionState
CheckPermissionState (PermissionState state
, bool allowUnrestricted
)
371 case PermissionState
.None
:
373 case PermissionState
.Unrestricted
:
374 if (!allowUnrestricted
) {
375 msg
= Locale
.GetText ("Unrestricted isn't not allowed for identity permissions.");
376 throw new ArgumentException (msg
, "state");
380 msg
= String
.Format (Locale
.GetText ("Invalid enum {0}"), state
);
381 throw new ArgumentException (msg
, "state");
386 internal static int CheckSecurityElement (SecurityElement se
, string parameterName
, int minimumVersion
, int maximumVersion
)
389 throw new ArgumentNullException (parameterName
);
391 // Tag is case-sensitive
392 if (se
.Tag
!= "IPermission") {
393 string msg
= String
.Format (Locale
.GetText ("Invalid tag {0}"), se
.Tag
);
394 throw new ArgumentException (msg
, parameterName
);
397 // Note: we do not care about the class attribute at
398 // this stage (in fact we don't even if the class
399 // attribute is present or not). Anyway the object has
400 // already be created, with success, if we're loading it
402 // we assume minimum version if no version number is supplied
403 int version
= minimumVersion
;
404 string v
= se
.Attribute ("version");
407 version
= Int32
.Parse (v
);
409 catch (Exception e
) {
410 string msg
= Locale
.GetText ("Couldn't parse version from '{0}'.");
411 msg
= String
.Format (msg
, v
);
412 throw new ArgumentException (msg
, parameterName
, e
);
416 if ((version
< minimumVersion
) || (version
> maximumVersion
)) {
417 string msg
= Locale
.GetText ("Unknown version '{0}', expected versions between ['{1}','{2}'].");
418 msg
= String
.Format (msg
, version
, minimumVersion
, maximumVersion
);
419 throw new ArgumentException (msg
, parameterName
);
424 // must be called after CheckSecurityElement (i.e. se != null)
425 internal static bool IsUnrestricted (SecurityElement se
)
427 string value = se
.Attribute ("Unrestricted");
430 return (String
.Compare (value, Boolean
.TrueString
, true, CultureInfo
.InvariantCulture
) == 0);
433 internal static void ThrowInvalidPermission (IPermission target
, Type expected
)
435 string msg
= Locale
.GetText ("Invalid permission type '{0}', expected type '{1}'.");
436 msg
= String
.Format (msg
, target
.GetType (), expected
);
437 throw new ArgumentException (msg
, "target");
440 internal static void SetCurrentFrame (StackModifier stackmod
, object permissions
)
442 if (!SetFramePermissions ((int)stackmod
, permissions
)) {
443 string msg
= Locale
.GetText ("An {0} modifier is already present on the current stack frame.");
444 throw new SecurityException (String
.Format (msg
, stackmod
));
448 internal static void RevertCurrentFrame (StackModifier stackmod
)
450 if (!SetFramePermissions ((int)stackmod
, null)) {
451 string msg
= Locale
.GetText ("No {0} modifier is present on the current stack frame.");
452 throw new ExecutionEngineException (String
.Format (msg
, stackmod
));