**** Merged from MCS ****
[mono-project.git] / mcs / class / corlib / System.Security / CodeAccessPermission.cs
blob447191f52159060b4e2e749799ac38c07f6bb724
1 //
2 // System.Security.CodeAccessPermission.cs
3 //
4 // Authors:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Nick Drochak, ndrochak@gol.com
7 // Sebastien Pouliot <sebastien@ximian.com>
8 //
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:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
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 {
42 [Serializable]
43 public abstract class CodeAccessPermission : IPermission, ISecurityEncodable, IStackWalk {
45 internal enum StackModifier {
46 Assert = 1,
47 Deny = 2,
48 PermitOnly = 3
51 protected CodeAccessPermission ()
55 // LAMESPEC: Documented as virtual
56 [MonoTODO ("unmanaged side is incomplete")]
57 public void Assert ()
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 ());
69 #if NET_2_0
70 public virtual
71 #else
72 internal
73 #endif
74 bool CheckAssert (CodeAccessPermission asserted)
76 if (asserted == null)
77 return false;
78 if (asserted.GetType () != this.GetType ())
79 return false;
80 return IsSubsetOf (asserted);
83 #if NET_2_0
84 public virtual
85 #else
86 internal
87 #endif
88 bool CheckDemand (CodeAccessPermission target)
90 if (target == null)
91 return false;
92 if (target.GetType () != this.GetType ())
93 return false;
94 return IsSubsetOf (target);
97 #if NET_2_0
98 public virtual
99 #else
100 internal
101 #endif
102 bool CheckDeny (CodeAccessPermission denied)
104 if (denied == null)
105 return true;
106 if (denied.GetType () != this.GetType ())
107 return true;
108 return (Intersect (denied) == null);
111 #if NET_2_0
112 public
113 #else
114 internal
115 #endif
116 virtual bool CheckPermitOnly (CodeAccessPermission target)
118 if (target == null)
119 return false;
120 if (target.GetType () != this.GetType ())
121 return false;
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)
132 return;
134 // Order is:
135 // 1. CheckDemand (current frame)
136 // note: for declarative attributes directly calls IsSubsetOf
138 Assembly a = null;
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;
148 if (a != af) {
149 a = af;
150 if (a.GrantedPermissionSet != null)
151 cap = (CodeAccessPermission) a.GrantedPermissionSet.GetPermission (this.GetType ());
152 else
153 cap = null;
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 ());
160 else
161 cap = null;
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);
170 else {
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 ();
177 if (perms == null)
178 continue;
180 // 2. CheckPermitOnly
181 object o = perms [(int)StackModifier.PermitOnly];
182 if (o != null) {
183 cap = (o as CodeAccessPermission);
184 if (cap != null) {
185 if (!CheckPermitOnly (cap))
186 throw new SecurityException ("PermitOnly");
188 else {
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");
199 // 3. CheckDeny
200 o = perms [(int)StackModifier.Deny];
201 if (o != null) {
202 cap = (o as CodeAccessPermission) ;
203 if (cap != null) {
204 if (!CheckDeny (cap))
205 throw new SecurityException ("Deny");
207 else {
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");
218 // 4. CheckAssert
219 o = perms [(int)StackModifier.Assert];
220 if (o != null) {
221 cap = (o as CodeAccessPermission);
222 if (cap != null) {
223 if (CheckAssert (cap)) {
224 return; // stop the stack walk
227 else {
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")]
243 public void Deny ()
245 SetCurrentFrame (StackModifier.Deny, this.Copy ());
248 #if NET_2_0
249 [MonoTODO]
250 public override bool Equals (object obj)
252 if (obj == null)
253 return false;
254 if (obj.GetType () != this.GetType ())
255 return false;
256 // TODO: compare
257 return true;
259 #endif
261 public abstract void FromXml (SecurityElement elem);
263 #if NET_2_0
264 [MonoTODO]
265 public override int GetHashCode ()
267 return base.GetHashCode ();
269 #endif
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)
285 if (null != other)
286 throw new System.NotSupportedException (); // other is not null.
287 return 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);
324 // Internal calls
325 #if false
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);
336 #else
337 // icalls are not yet commited so...
339 static bool ClearFramePermissions ()
341 return true;
344 static object[] GetFramePermissions ()
346 return null;
349 static bool SetFramePermissions (int index, object permissions)
351 return true;
353 #endif
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 ());
364 return se;
367 internal static PermissionState CheckPermissionState (PermissionState state, bool allowUnrestricted)
369 string msg;
370 switch (state) {
371 case PermissionState.None:
372 break;
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");
378 break;
379 default:
380 msg = String.Format (Locale.GetText ("Invalid enum {0}"), state);
381 throw new ArgumentException (msg, "state");
383 return state;
386 internal static int CheckSecurityElement (SecurityElement se, string parameterName, int minimumVersion, int maximumVersion)
388 if (se == null)
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");
405 if (v != null) {
406 try {
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);
421 return version;
424 // must be called after CheckSecurityElement (i.e. se != null)
425 internal static bool IsUnrestricted (SecurityElement se)
427 string value = se.Attribute ("Unrestricted");
428 if (value == null)
429 return false;
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));