2 // System.Security.PermissionSet.cs
5 // Nick Drochak(ndrochak@gol.com)
6 // Sebastien Pouliot <sebastien@ximian.com>
9 // Portions (C) 2003, 2004 Motus Technologies Inc. (http://www.motus.com)
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System
.Collections
;
33 using System
.Diagnostics
;
35 using System
.Reflection
;
36 using System
.Runtime
.Serialization
;
37 using System
.Runtime
.Serialization
.Formatters
.Binary
;
38 using System
.Security
.Permissions
;
39 using System
.Security
.Policy
;
42 namespace System
.Security
{
45 public class PermissionSet
: ISecurityEncodable
, ICollection
, IEnumerable
, IStackWalk
, IDeserializationCallback
{
47 private static string tagName
= "PermissionSet";
48 private const int version
= 1;
49 private static object[] psNone
= new object [1] { PermissionState.None }
;
51 private PermissionState state
;
52 private ArrayList list
;
53 private int _hashcode
;
54 private PolicyLevel _policyLevel
;
58 // for PolicyLevel (to avoid validation duplication)
59 internal PermissionSet ()
61 list
= new ArrayList ();
64 public PermissionSet (PermissionState state
) : this ()
66 if (!Enum
.IsDefined (typeof (PermissionState
), state
))
67 throw new System
.ArgumentException ("state");
71 public PermissionSet (PermissionSet permSet
) : this ()
73 // LAMESPEC: This would be handled by the compiler. No way permSet is not a PermissionSet.
74 //if (!(permSet is PermissionSet))
75 // throw new System.ArgumentException(); // permSet is not an instance of System.Security.PermissionSet.
77 state
= PermissionState
.Unrestricted
;
79 state
= permSet
.state
;
80 foreach (IPermission p
in permSet
.list
)
85 internal PermissionSet (string xml
)
88 state
= PermissionState
.None
;
90 SecurityElement se
= SecurityElement
.FromString (xml
);
97 public virtual IPermission
AddPermission (IPermission perm
)
102 // we don't add to an unrestricted permission set unless...
103 if (state
== PermissionState
.Unrestricted
) {
104 // we're adding identity permission as they don't support unrestricted
105 if (perm
is IUnrestrictedPermission
) {
106 // we return the union of the permission with unrestricted
107 // which results in a permission of the same type initialized
108 // with PermissionState.Unrestricted
109 object[] args
= new object [1] { PermissionState.Unrestricted }
;
110 return (IPermission
) Activator
.CreateInstance (perm
.GetType (), args
);
114 // we can't add two permissions of the same type in a set
115 // so we remove an existing one, union with it and add it back
116 IPermission existing
= RemovePermission (perm
.GetType ());
117 if (existing
!= null) {
118 perm
= perm
.Union (existing
);
125 [MonoTODO ("unmanaged side is incomplete")]
126 public virtual void Assert ()
128 new SecurityPermission (SecurityPermissionFlag
.Assertion
).Demand ();
130 // we (current frame) must have the permission to assert it to others
131 // otherwise we don't assert (but we don't throw an exception)
132 foreach (IPermission p
in list
) {
133 // note: we ignore non-CAS permissions
134 if (p
is IStackWalk
) {
135 if (!SecurityManager
.IsGranted (p
)) {
141 CodeAccessPermission
.SetCurrentFrame (CodeAccessPermission
.StackModifier
.Assert
, this.Copy ());
144 internal void Clear ()
149 public virtual PermissionSet
Copy ()
151 return new PermissionSet (this);
154 public virtual void CopyTo (Array array
, int index
)
157 throw new ArgumentNullException ("array");
159 if (list
.Count
> 0) {
160 if (array
.Rank
> 1) {
161 throw new ArgumentException (Locale
.GetText (
162 "Array has more than one dimension"));
164 if (index
< 0 || index
>= array
.Length
) {
165 throw new IndexOutOfRangeException ("index");
168 list
.CopyTo (array
, index
);
172 [MonoTODO ("Assert, Deny and PermitOnly aren't yet supported")]
173 public virtual void Demand ()
178 PermissionSet cas
= this;
179 // avoid copy (if possible)
180 if (ContainsNonCodeAccessPermissions ()) {
181 // non CAS permissions (e.g. PrincipalPermission) do not requires a stack walk
183 foreach (IPermission p
in list
) {
184 Type t
= p
.GetType ();
185 if (!t
.IsSubclassOf (typeof (CodeAccessPermission
))) {
187 // we wont have to process this one in the stack walk
188 cas
.RemovePermission (t
);
192 // don't start the walk if the permission set only contains non CAS permissions
197 // Note: SecurityEnabled only applies to CAS permissions
198 if (!SecurityManager
.SecurityEnabled
)
202 foreach (IPermission p
in cas
.list
) {
207 [MonoTODO ("unmanaged side is incomplete")]
208 public virtual void Deny ()
210 CodeAccessPermission
.SetCurrentFrame (CodeAccessPermission
.StackModifier
.Deny
, this.Copy ());
213 [MonoTODO ("adjust class version with current runtime - unification")]
214 public virtual void FromXml (SecurityElement et
)
217 throw new ArgumentNullException ("et");
218 if (et
.Tag
!= tagName
) {
219 string msg
= String
.Format ("Invalid tag {0} expected {1}", et
.Tag
, tagName
);
220 throw new ArgumentException (msg
, "et");
223 if (CodeAccessPermission
.IsUnrestricted (et
))
224 state
= PermissionState
.Unrestricted
;
226 state
= PermissionState
.None
;
229 if (et
.Children
!= null) {
230 foreach (SecurityElement se
in et
.Children
) {
231 string className
= se
.Attribute ("class");
232 if (className
== null) {
233 throw new ArgumentException (Locale
.GetText (
234 "No permission class is specified."));
236 if (Resolver
!= null) {
237 // policy class names do not have to be fully qualified
238 className
= Resolver
.ResolveClassName (className
);
240 // TODO: adjust class version with current runtime (unification)
241 // http://blogs.msdn.com/shawnfa/archive/2004/08/05/209320.aspx
242 Type classType
= Type
.GetType (className
);
243 if (classType
!= null) {
244 IPermission p
= (IPermission
) Activator
.CreateInstance (classType
, psNone
);
250 string msg
= Locale
.GetText ("Can't create an instance of permission class {0}.");
251 throw new ArgumentException (String
.Format (msg
, se
.Attribute ("class")));
258 public virtual IEnumerator
GetEnumerator ()
260 return list
.GetEnumerator ();
263 public virtual bool IsSubsetOf (PermissionSet target
)
265 // if target is empty we must be empty too
266 if ((target
== null) || (target
.IsEmpty ()))
267 return this.IsEmpty ();
269 // TODO - non CAS permissions must be evaluated for unrestricted
271 // if target is unrestricted then we are a subset
272 if (!this.IsUnrestricted () && target
.IsUnrestricted ())
274 // else target isn't unrestricted.
275 // so if we are unrestricted, the we can't be a subset
276 if (this.IsUnrestricted () && !target
.IsUnrestricted ())
279 // if each of our permission is (a) present and (b) a subset of target
280 foreach (IPermission p
in list
) {
281 // for every type in both list
282 IPermission i
= target
.GetPermission (p
.GetType ());
284 return false; // not present (condition a)
285 if (!p
.IsSubsetOf (i
))
286 return false; // not a subset (condition b)
291 [MonoTODO ("unmanaged side is incomplete")]
292 public virtual void PermitOnly ()
294 CodeAccessPermission
.SetCurrentFrame (CodeAccessPermission
.StackModifier
.PermitOnly
, this.Copy ());
297 public bool ContainsNonCodeAccessPermissions ()
299 foreach (IPermission p
in list
) {
300 if (! p
.GetType ().IsSubclassOf (typeof (CodeAccessPermission
)))
306 [MonoTODO ("little documentation in Fx 2.0 beta 1")]
307 public static byte[] ConvertPermissionSet (string inFormat
, byte[] inData
, string outFormat
)
309 if (inFormat
== null)
310 throw new ArgumentNullException ("inFormat");
311 if (outFormat
== null)
312 throw new ArgumentNullException ("outFormat");
316 if (inFormat
== outFormat
)
319 PermissionSet ps
= null;
321 if (inFormat
== "BINARY") {
322 if (outFormat
.StartsWith ("XML")) {
323 using (MemoryStream ms
= new MemoryStream (inData
)) {
324 BinaryFormatter formatter
= new BinaryFormatter ();
325 ps
= (PermissionSet
) formatter
.Deserialize (ms
);
328 string xml
= ps
.ToString ();
332 return Encoding
.ASCII
.GetBytes (xml
);
334 return Encoding
.Unicode
.GetBytes (xml
);
338 else if (inFormat
.StartsWith ("XML")) {
339 if (outFormat
== "BINARY") {
344 xml
= Encoding
.ASCII
.GetString (inData
);
347 xml
= Encoding
.Unicode
.GetString (inData
);
351 ps
= new PermissionSet (PermissionState
.None
);
352 ps
.FromXml (SecurityElement
.FromString (xml
));
354 MemoryStream ms
= new MemoryStream ();
355 BinaryFormatter formatter
= new BinaryFormatter ();
356 formatter
.Serialize (ms
, ps
);
358 return ms
.ToArray ();
361 else if (outFormat
.StartsWith ("XML")) {
362 string msg
= String
.Format (Locale
.GetText ("Can't convert from {0} to {1}"), inFormat
, outFormat
);
364 throw new XmlSyntaxException (msg
);
366 throw new ArgumentException (msg
);
371 // unknown inFormat, returns null
374 // unknown outFormat, throw
375 throw new SerializationException (String
.Format (Locale
.GetText ("Unknown output format {0}."), outFormat
));
378 public virtual IPermission
GetPermission (Type permClass
)
380 foreach (object o
in list
) {
381 if (o
.GetType ().Equals (permClass
))
382 return (IPermission
) o
;
384 // it's normal to return null for unrestricted sets
388 public virtual PermissionSet
Intersect (PermissionSet other
)
390 // no intersection possible
391 if ((other
== null) || (other
.IsEmpty ()) || (this.IsEmpty ()))
394 PermissionState state
= PermissionState
.None
;
395 if (this.IsUnrestricted () && other
.IsUnrestricted ())
396 state
= PermissionState
.Unrestricted
;
398 PermissionSet interSet
= new PermissionSet (state
);
399 if (state
== PermissionState
.Unrestricted
) {
400 InternalIntersect (interSet
, this, other
, true);
401 InternalIntersect (interSet
, other
, this, true);
403 else if (this.IsUnrestricted ()) {
404 InternalIntersect (interSet
, this, other
, true);
406 else if (other
.IsUnrestricted ()) {
407 InternalIntersect (interSet
, other
, this, true);
410 InternalIntersect (interSet
, this, other
, false);
415 internal void InternalIntersect (PermissionSet intersect
, PermissionSet a
, PermissionSet b
, bool unrestricted
)
417 foreach (IPermission p
in b
.list
) {
418 // for every type in both list
419 IPermission i
= a
.GetPermission (p
.GetType ());
421 // add intersection for this type
422 intersect
.AddPermission (p
.Intersect (i
));
424 else if (unrestricted
&& (p
is IUnrestrictedPermission
)) {
425 intersect
.AddPermission (p
);
431 public virtual bool IsEmpty ()
433 // note: Unrestricted isn't empty
434 if (state
== PermissionState
.Unrestricted
)
436 if ((list
== null) || (list
.Count
== 0))
438 // the set may include some empty permissions
439 foreach (IPermission p
in list
) {
440 // empty == fully restricted == IsSubsetOg(null) == true
441 if (!p
.IsSubsetOf (null))
447 public virtual bool IsUnrestricted ()
449 return (state
== PermissionState
.Unrestricted
);
452 public virtual IPermission
RemovePermission (Type permClass
)
454 if (permClass
== null)
457 foreach (object o
in list
) {
458 if (o
.GetType ().Equals (permClass
)) {
460 return (IPermission
) o
;
466 public virtual IPermission
SetPermission (IPermission perm
)
470 if (perm
is IUnrestrictedPermission
)
471 state
= PermissionState
.None
;
472 RemovePermission (perm
.GetType ());
477 public override string ToString ()
479 return ToXml ().ToString ();
482 public virtual SecurityElement
ToXml ()
484 SecurityElement se
= new SecurityElement (tagName
);
485 se
.AddAttribute ("class", GetType ().FullName
);
486 se
.AddAttribute ("version", version
.ToString ());
487 if (state
== PermissionState
.Unrestricted
)
488 se
.AddAttribute ("Unrestricted", "true");
490 // required for permissions that do not implement IUnrestrictedPermission
491 foreach (IPermission p
in list
) {
492 se
.AddChild (p
.ToXml ());
497 public virtual PermissionSet
Union (PermissionSet other
)
502 PermissionSet copy
= this.Copy ();
503 if (this.IsUnrestricted () || other
.IsUnrestricted ()) {
504 // so we keep the "right" type
506 copy
.state
= PermissionState
.Unrestricted
;
507 // copy all permissions that do not implement IUnrestrictedPermission
508 foreach (IPermission p
in this.list
) {
509 if (!(p
is IUnrestrictedPermission
))
510 copy
.AddPermission (p
);
512 foreach (IPermission p
in other
.list
) {
513 if (!(p
is IUnrestrictedPermission
))
514 copy
.AddPermission (p
);
518 // PermissionState.None -> copy all permissions
519 foreach (IPermission p
in other
.list
) {
520 copy
.AddPermission (p
);
526 public virtual int Count
{
527 get { return list.Count; }
530 public virtual bool IsSynchronized
{
531 get { return list.IsSynchronized; }
534 public virtual bool IsReadOnly
{
535 get { return false; }
// always false
538 public virtual object SyncRoot
{
543 void IDeserializationCallback
.OnDeserialization (object sender
)
548 public override bool Equals (object obj
)
552 PermissionSet ps
= (obj
as PermissionSet
);
555 if (list
.Count
!= ps
.Count
)
558 for (int i
=0; i
< list
.Count
; i
++) {
560 for (int j
=0; i
< ps
.list
.Count
; j
++) {
561 if (list
[i
].Equals (ps
.list
[j
])) {
572 public override int GetHashCode ()
577 if (_hashcode
== 0) {
578 _hashcode
= state
.GetHashCode ();
579 foreach (IPermission p
in list
) {
580 _hashcode ^
= p
.GetHashCode ();
586 [MonoTODO ("what's it doing here?")]
587 static public void RevertAssert ()
594 internal PolicyLevel Resolver
{
595 get { return _policyLevel; }
596 set { _policyLevel = value; }
600 internal void ImmediateCallerDemand ()
602 if (!SecurityManager
.SecurityEnabled
)
607 StackTrace st
= new StackTrace (1); // skip ourself
608 StackFrame sf
= st
.GetFrame (0);
609 MethodBase mb
= sf
.GetMethod ();
610 Assembly af
= mb
.ReflectedType
.Assembly
;
611 if (!af
.Demand (this)) {
612 Type t
= this.GetType ();
613 // TODO add more details
614 throw new SecurityException ("LinkDemand failed", t
);
618 // Note: Non-CAS demands aren't affected by SecurityManager.SecurityEnabled
619 internal void ImmediateCallerNonCasDemand ()
624 // non CAS permissions (e.g. PrincipalPermission) requires direct call to Demand
625 foreach (IPermission p
in list
) {