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.Runtime.InteropServices;
39 using System.Security.Permissions;
41 namespace System.Security {
44 public abstract class CodeAccessPermission : IPermission, ISecurityEncodable, IStackWalk {
46 internal enum StackModifier {
52 protected CodeAccessPermission ()
56 // LAMESPEC: Documented as virtual
57 [MonoTODO ("unmanaged side is incomplete")]
60 // Not everyone can assert freely so we must check for
61 // System.Security.Permissions.SecurityPermissionFlag.Assertion
62 new SecurityPermission (SecurityPermissionFlag.Assertion).Demand ();
64 // we must have the permission to assert it to others
65 if (SecurityManager.IsGranted (this)) {
66 SetCurrentFrame (StackModifier.Assert, this.Copy ());
75 bool CheckAssert (CodeAccessPermission asserted)
79 if (asserted.GetType () != this.GetType ())
81 return IsSubsetOf (asserted);
89 bool CheckDemand (CodeAccessPermission target)
93 if (target.GetType () != this.GetType ())
95 return IsSubsetOf (target);
103 bool CheckDeny (CodeAccessPermission denied)
107 if (denied.GetType () != this.GetType ())
109 return (Intersect (denied) == null);
117 virtual bool CheckPermitOnly (CodeAccessPermission target)
121 if (target.GetType () != this.GetType ())
123 return IsSubsetOf (target);
126 public abstract IPermission Copy ();
128 // LAMESPEC: Documented as virtual
129 [MonoTODO ("Assert, Deny and PermitOnly aren't yet supported")]
130 public void Demand ()
132 if (!SecurityManager.SecurityEnabled)
136 // 1. CheckDemand (current frame)
137 // note: for declarative attributes directly calls IsSubsetOf
140 StackTrace st = new StackTrace (1); // skip ourself
141 StackFrame[] frames = st.GetFrames ();
142 foreach (StackFrame sf in frames) {
143 MethodBase mb = sf.GetMethod ();
144 // however the "final" grant set is resolved by assembly, so
145 // there's no need to check it every time (just when we're
146 // changing assemblies between frames).
147 Assembly af = mb.ReflectedType.Assembly;
148 CodeAccessPermission cap = null;
151 if (a.GrantedPermissionSet != null)
152 cap = (CodeAccessPermission) a.GrantedPermissionSet.GetPermission (this.GetType ());
156 // CheckDemand will always return false in case cap is null
157 if ((cap == null) || !CheckDemand (cap)) {
158 if (a.DeniedPermissionSet != null) {
159 cap = (CodeAccessPermission) a.DeniedPermissionSet.GetPermission (this.GetType ());
164 // IsSubsetOf "should" always return false if cap is null
165 if ((cap != null) && IsSubsetOf (cap)) {
166 Type t = this.GetType ();
167 // TODO add more details
168 throw new SecurityException ("ReqRefuse", t);
172 throw new SecurityException ("Demand failed", a.GetName (),
173 a.GrantedPermissionSet, a.DeniedPermissionSet, (MethodInfo) mb,
174 SecurityAction.Demand, this, cap, a.Evidence);
177 object[] perms = GetFramePermissions ();
181 // 2. CheckPermitOnly
182 object o = perms [(int)StackModifier.PermitOnly];
184 cap = (o as CodeAccessPermission);
186 if (!CheckPermitOnly (cap))
187 throw new SecurityException ("PermitOnly");
190 PermissionSet ps = (o as PermissionSet);
191 foreach (IPermission p in ps) {
192 if (p is CodeAccessPermission) {
193 if (!CheckPermitOnly (p as CodeAccessPermission))
194 throw new SecurityException ("PermitOnly");
201 o = perms [(int)StackModifier.Deny];
203 cap = (o as CodeAccessPermission) ;
205 if (!CheckDeny (cap))
206 throw new SecurityException ("Deny");
209 PermissionSet ps = (o as PermissionSet);
210 foreach (IPermission p in ps) {
211 if (p is CodeAccessPermission) {
212 if (!CheckPermitOnly (p as CodeAccessPermission))
213 throw new SecurityException ("Deny");
220 o = perms [(int)StackModifier.Assert];
222 cap = (o as CodeAccessPermission);
224 if (CheckAssert (cap)) {
225 return; // stop the stack walk
229 PermissionSet ps = (o as PermissionSet);
230 foreach (IPermission p in ps) {
231 if (p is CodeAccessPermission) {
232 if (!CheckPermitOnly (p as CodeAccessPermission)) {
233 return; // stop the stack walk
242 // LAMESPEC: Documented as virtual
243 [MonoTODO ("unmanaged side is incomplete")]
246 SetCurrentFrame (StackModifier.Deny, this.Copy ());
252 public override bool Equals (object obj)
256 if (obj.GetType () != this.GetType ())
263 public abstract void FromXml (SecurityElement elem);
268 public override int GetHashCode ()
270 return base.GetHashCode ();
274 public abstract IPermission Intersect (IPermission target);
276 public abstract bool IsSubsetOf (IPermission target);
278 public override string ToString ()
280 SecurityElement elem = ToXml ();
281 return elem.ToString ();
284 public abstract SecurityElement ToXml ();
286 public virtual IPermission Union (IPermission other)
289 throw new System.NotSupportedException (); // other is not null.
293 // LAMESPEC: Documented as virtual
294 [MonoTODO ("unmanaged side is incomplete")]
295 public void PermitOnly ()
297 SetCurrentFrame (StackModifier.PermitOnly, this.Copy ());
300 [MonoTODO ("unmanaged side is incomplete")]
301 public static void RevertAll ()
303 if (!ClearFramePermissions ()) {
304 string msg = Locale.GetText ("No security frame present to be reverted.");
305 throw new ExecutionEngineException (msg);
309 [MonoTODO ("unmanaged side is incomplete")]
310 public static void RevertAssert ()
312 RevertCurrentFrame (StackModifier.Assert);
315 [MonoTODO ("unmanaged side is incomplete")]
316 public static void RevertDeny ()
318 RevertCurrentFrame (StackModifier.Deny);
321 [MonoTODO ("unmanaged side is incomplete")]
322 public static void RevertPermitOnly ()
324 RevertCurrentFrame (StackModifier.PermitOnly);
329 // see mono/mono/metadata/cas.c for implementation
331 [MethodImplAttribute (MethodImplOptions.InternalCall)]
332 static extern bool ClearFramePermissions ();
334 [MethodImplAttribute (MethodImplOptions.InternalCall)]
335 static extern object[] GetFramePermissions ();
337 [MethodImplAttribute (MethodImplOptions.InternalCall)]
338 static extern bool SetFramePermissions (int index, object permissions);
340 // icalls are not yet commited so...
342 static bool ClearFramePermissions ()
347 static object[] GetFramePermissions ()
352 static bool SetFramePermissions (int index, object permissions)
358 // Internal helpers methods
360 // snippet moved from FileIOPermission (nickd) to be reused in all derived classes
361 internal SecurityElement Element (int version)
363 SecurityElement se = new SecurityElement ("IPermission");
364 Type type = this.GetType ();
365 se.AddAttribute ("class", type.FullName + ", " + type.Assembly.ToString ().Replace ('\"', '\''));
366 se.AddAttribute ("version", version.ToString ());
370 internal static PermissionState CheckPermissionState (PermissionState state, bool allowUnrestricted)
374 case PermissionState.None:
376 case PermissionState.Unrestricted:
377 if (!allowUnrestricted) {
378 msg = Locale.GetText ("Unrestricted isn't not allowed for identity permissions.");
379 throw new ArgumentException (msg, "state");
383 msg = String.Format (Locale.GetText ("Invalid enum {0}"), state);
384 throw new ArgumentException (msg, "state");
389 internal static int CheckSecurityElement (SecurityElement se, string parameterName, int minimumVersion, int maximumVersion)
392 throw new ArgumentNullException (parameterName);
394 // Tag is case-sensitive
395 if (se.Tag != "IPermission") {
396 string msg = String.Format (Locale.GetText ("Invalid tag {0}"), se.Tag);
397 throw new ArgumentException (msg, parameterName);
400 // Note: we do not care about the class attribute at
401 // this stage (in fact we don't even if the class
402 // attribute is present or not). Anyway the object has
403 // already be created, with success, if we're loading it
405 // we assume minimum version if no version number is supplied
406 int version = minimumVersion;
407 string v = se.Attribute ("version");
410 version = Int32.Parse (v);
412 catch (Exception e) {
413 string msg = Locale.GetText ("Couldn't parse version from '{0}'.");
414 msg = String.Format (msg, v);
415 throw new ArgumentException (msg, parameterName, e);
419 if ((version < minimumVersion) || (version > maximumVersion)) {
420 string msg = Locale.GetText ("Unknown version '{0}', expected versions between ['{1}','{2}'].");
421 msg = String.Format (msg, version, minimumVersion, maximumVersion);
422 throw new ArgumentException (msg, parameterName);
427 // must be called after CheckSecurityElement (i.e. se != null)
428 internal static bool IsUnrestricted (SecurityElement se)
430 string value = se.Attribute ("Unrestricted");
433 return (String.Compare (value, Boolean.TrueString, true, CultureInfo.InvariantCulture) == 0);
436 internal static void ThrowInvalidPermission (IPermission target, Type expected)
438 string msg = Locale.GetText ("Invalid permission type '{0}', expected type '{1}'.");
439 msg = String.Format (msg, target.GetType (), expected);
440 throw new ArgumentException (msg, "target");
443 internal static void SetCurrentFrame (StackModifier stackmod, object permissions)
445 if (!SetFramePermissions ((int)stackmod, permissions)) {
446 string msg = Locale.GetText ("An {0} modifier is already present on the current stack frame.");
447 throw new SecurityException (String.Format (msg, stackmod));
451 internal static void RevertCurrentFrame (StackModifier stackmod)
453 if (!SetFramePermissions ((int)stackmod, null)) {
454 string msg = Locale.GetText ("No {0} modifier is present on the current stack frame.");
455 throw new ExecutionEngineException (String.Format (msg, stackmod));