Copied remotely
[mono.git] / mcs / class / corlib / System.Security / CodeAccessPermission.cs
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)
13 //
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.
32 //
33
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;
40
41 namespace System.Security {
42
43         [Serializable]
44         public abstract class CodeAccessPermission : IPermission, ISecurityEncodable, IStackWalk {
45
46                 internal enum StackModifier {
47                         Assert = 1,
48                         Deny = 2,
49                         PermitOnly = 3
50                 }
51
52                 protected CodeAccessPermission ()
53                 {
54                 }
55
56                 // LAMESPEC: Documented as virtual
57                 [MonoTODO ("unmanaged side is incomplete")]
58                 public void Assert ()
59                 {
60                         // Not everyone can assert freely so we must check for
61                         // System.Security.Permissions.SecurityPermissionFlag.Assertion
62                         new SecurityPermission (SecurityPermissionFlag.Assertion).Demand ();
63
64                         // we must have the permission to assert it to others
65                         if (SecurityManager.IsGranted (this)) {
66                                 SetCurrentFrame (StackModifier.Assert, this.Copy ());
67                         }
68                 }
69
70 #if NET_2_0
71                 public virtual
72 #else
73                 internal
74 #endif
75                 bool CheckAssert (CodeAccessPermission asserted)
76                 {
77                         if (asserted == null)
78                                 return false;
79                         if (asserted.GetType () != this.GetType ())
80                                 return false;
81                         return IsSubsetOf (asserted);
82                 }
83
84 #if NET_2_0
85                 public virtual
86 #else
87                 internal
88 #endif
89                 bool CheckDemand (CodeAccessPermission target)
90                 {
91                         if (target == null)
92                                 return false;
93                         if (target.GetType () != this.GetType ())
94                                 return false;
95                         return IsSubsetOf (target);
96                 }
97
98 #if NET_2_0
99                 public virtual
100 #else
101                 internal
102 #endif
103                 bool CheckDeny (CodeAccessPermission denied)
104                 {
105                         if (denied == null)
106                                 return true;
107                         if (denied.GetType () != this.GetType ())
108                                 return true;
109                         return (Intersect (denied) == null);
110                 }
111
112 #if NET_2_0
113                 public 
114 #else
115                 internal
116 #endif
117                 virtual bool CheckPermitOnly (CodeAccessPermission target)
118                 {
119                         if (target == null)
120                                 return false;
121                         if (target.GetType () != this.GetType ())
122                                 return false;
123                         return IsSubsetOf (target);
124                 }
125
126                 public abstract IPermission Copy ();
127
128                 // LAMESPEC: Documented as virtual
129                 [MonoTODO ("Assert, Deny and PermitOnly aren't yet supported")]
130                 public void Demand ()
131                 {
132                         if (!SecurityManager.SecurityEnabled)
133                                 return;
134
135                         // Order is:
136                         // 1. CheckDemand (current frame)
137                         //      note: for declarative attributes directly calls IsSubsetOf
138
139                         Assembly a = null;
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;
149                                 if (a != af) {
150                                         a = af;
151                                         if (a.GrantedPermissionSet != null)
152                                                 cap = (CodeAccessPermission) a.GrantedPermissionSet.GetPermission (this.GetType ());
153                                         else
154                                                 cap = null;
155
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 ());
160                                                 }
161                                                 else
162                                                         cap = null;
163
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);
169                                                 }
170                                         }
171                                         else {
172                                                 throw new SecurityException ("Demand failed", a.GetName (),
173                                                         a.GrantedPermissionSet, a.DeniedPermissionSet, (MethodInfo) mb, 
174                                                         SecurityAction.Demand, this, cap, a.Evidence);
175                                         }
176                                 }
177                                 object[] perms = GetFramePermissions ();
178                                 if (perms == null)
179                                         continue;
180
181                                 // 2. CheckPermitOnly
182                                 object o = perms [(int)StackModifier.PermitOnly];
183                                 if (o != null) {
184                                         cap = (o as CodeAccessPermission);
185                                         if (cap != null) {
186                                                 if (!CheckPermitOnly (cap))
187                                                         throw new SecurityException ("PermitOnly");
188                                         }
189                                         else {
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");
195                                                         }
196                                                 }
197                                         }
198                                 }
199
200                                 // 3. CheckDeny
201                                 o = perms [(int)StackModifier.Deny];
202                                 if (o != null) {
203                                         cap = (o as CodeAccessPermission) ;
204                                         if (cap != null) {
205                                                 if (!CheckDeny (cap))
206                                                         throw new SecurityException ("Deny");
207                                         }
208                                         else {
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");
214                                                         }
215                                                 }
216                                         }
217                                 }
218
219                                 // 4. CheckAssert
220                                 o = perms [(int)StackModifier.Assert];
221                                 if (o != null) {
222                                         cap = (o as CodeAccessPermission);
223                                         if (cap != null) {
224                                                 if (CheckAssert (cap)) {
225                                                         return; // stop the stack walk
226                                                 }
227                                         }
228                                         else {
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
234                                                                 }
235                                                         }
236                                                 }
237                                         }
238                                 }
239                         }
240                 }
241
242                 // LAMESPEC: Documented as virtual
243                 [MonoTODO ("unmanaged side is incomplete")]
244                 public void Deny ()
245                 {
246                         SetCurrentFrame (StackModifier.Deny, this.Copy ());
247                 }
248
249 #if NET_2_0
250                 [MonoTODO]
251                 [ComVisible (false)]
252                 public override bool Equals (object obj)
253                 {
254                         if (obj == null)
255                                 return false;
256                         if (obj.GetType () != this.GetType ())
257                                 return false;
258                         // TODO: compare
259                         return true;
260                 }
261 #endif
262
263                 public abstract void FromXml (SecurityElement elem);
264
265 #if NET_2_0
266                 [MonoTODO]
267                 [ComVisible (false)]
268                 public override int GetHashCode ()
269                 {
270                         return base.GetHashCode ();
271                 }
272 #endif
273
274                 public abstract IPermission Intersect (IPermission target);
275
276                 public abstract bool IsSubsetOf (IPermission target);
277
278                 public override string ToString ()
279                 {
280                         SecurityElement elem = ToXml ();
281                         return elem.ToString ();
282                 }
283
284                 public abstract SecurityElement ToXml ();
285
286                 public virtual IPermission Union (IPermission other)
287                 {
288                         if (null != other)
289                                 throw new System.NotSupportedException (); // other is not null.
290                         return null;
291                 }
292
293                 // LAMESPEC: Documented as virtual
294                 [MonoTODO ("unmanaged side is incomplete")]
295                 public void PermitOnly ()
296                 {
297                         SetCurrentFrame (StackModifier.PermitOnly, this.Copy ());
298                 }
299
300                 [MonoTODO ("unmanaged side is incomplete")]
301                 public static void RevertAll ()
302                 {
303                         if (!ClearFramePermissions ()) {
304                                 string msg = Locale.GetText ("No security frame present to be reverted.");
305                                 throw new ExecutionEngineException (msg);
306                         }
307                 }
308
309                 [MonoTODO ("unmanaged side is incomplete")]
310                 public static void RevertAssert ()
311                 {
312                         RevertCurrentFrame (StackModifier.Assert);
313                 }
314
315                 [MonoTODO ("unmanaged side is incomplete")]
316                 public static void RevertDeny ()
317                 {
318                         RevertCurrentFrame (StackModifier.Deny);
319                 }
320
321                 [MonoTODO ("unmanaged side is incomplete")]
322                 public static void RevertPermitOnly ()
323                 {
324                         RevertCurrentFrame (StackModifier.PermitOnly);
325                 }
326
327                 // Internal calls
328 #if false
329                 // see mono/mono/metadata/cas.c for implementation
330
331                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
332                 static extern bool ClearFramePermissions ();
333
334                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
335                 static extern object[] GetFramePermissions ();
336
337                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
338                 static extern bool SetFramePermissions (int index, object permissions);
339 #else
340                 // icalls are not yet commited so...
341
342                 static bool ClearFramePermissions () 
343                 {
344                         return true;
345                 }
346
347                 static object[] GetFramePermissions () 
348                 {
349                         return null;
350                 }
351
352                 static bool SetFramePermissions (int index, object permissions)
353                 {
354                         return true;
355                 }
356 #endif
357
358                 // Internal helpers methods
359
360                 // snippet moved from FileIOPermission (nickd) to be reused in all derived classes
361                 internal SecurityElement Element (int version) 
362                 {
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 ());
367                         return se;
368                 }
369
370                 internal static PermissionState CheckPermissionState (PermissionState state, bool allowUnrestricted)
371                 {
372                         string msg;
373                         switch (state) {
374                         case PermissionState.None:
375                                 break;
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");
380                                 }
381                                 break;
382                         default:
383                                 msg = String.Format (Locale.GetText ("Invalid enum {0}"), state);
384                                 throw new ArgumentException (msg, "state");
385                         }
386                         return state;
387                 }
388
389                 internal static int CheckSecurityElement (SecurityElement se, string parameterName, int minimumVersion, int maximumVersion) 
390                 {
391                         if (se == null)
392                                 throw new ArgumentNullException (parameterName);
393
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);
398                         }
399
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
404
405                         // we assume minimum version if no version number is supplied
406                         int version = minimumVersion;
407                         string v = se.Attribute ("version");
408                         if (v != null) {
409                                 try {
410                                         version = Int32.Parse (v);
411                                 }
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);
416                                 }
417                         }
418
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);
423                         }
424                         return version;
425                 }
426
427                 // must be called after CheckSecurityElement (i.e. se != null)
428                 internal static bool IsUnrestricted (SecurityElement se) 
429                 {
430                         string value = se.Attribute ("Unrestricted");
431                         if (value == null)
432                                 return false;
433                         return (String.Compare (value, Boolean.TrueString, true, CultureInfo.InvariantCulture) == 0);
434                 }
435
436                 internal static void ThrowInvalidPermission (IPermission target, Type expected) 
437                 {
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");
441                 }
442
443                 internal static void SetCurrentFrame (StackModifier stackmod, object permissions)
444                 {
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));
448                         }
449                 }
450
451                 internal static void RevertCurrentFrame (StackModifier stackmod)
452                 {
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));
456                         }
457                 }
458         }
459 }