2 // System.Security.Permissions.ResourcePermissionBase.cs
5 // Jonathan Pryor (jonpryor@vt.edu)
6 // Sebastien Pouliot <sebastien@ximian.com>
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System
.Collections
;
32 using System
.Globalization
;
34 namespace System
.Security
.Permissions
{
37 public abstract class ResourcePermissionBase
: CodeAccessPermission
, IUnrestrictedPermission
{
39 private const int version
= 1;
41 private ArrayList _list
;
42 private bool _unrestricted
;
44 private string[] _tags
;
46 protected ResourcePermissionBase ()
48 _list
= new ArrayList ();
51 protected ResourcePermissionBase (PermissionState state
) : this ()
53 // there are no validation of the permission state
54 _unrestricted
= (state
== PermissionState
.Unrestricted
);
55 // but any invalid value results in a restricted set
58 public const string Any
= "*";
59 public const string Local
= ".";
61 protected Type PermissionAccessType
{
65 throw new ArgumentNullException ("PermissionAccessType");
67 throw new ArgumentException ("!Enum", "PermissionAccessType");
72 protected string[] TagNames
{
76 throw new ArgumentNullException ("TagNames");
77 if (value.Length
== 0)
78 throw new ArgumentException ("Length==0", "TagNames");
83 protected void AddPermissionAccess (ResourcePermissionBaseEntry entry
)
87 string msg
= Locale
.GetText ("Entry already exists.");
88 throw new InvalidOperationException (msg
);
94 protected void Clear ()
99 public override IPermission
Copy ()
101 ResourcePermissionBase copy
= CreateFromType (this.GetType (), _unrestricted
);
103 copy
._tags
= (string[]) _tags
.Clone ();
105 // FIXME: shallow or deep copy ?
106 copy
._list
.AddRange (_list
);
110 [MonoTODO ("incomplete - need more test")]
111 public override void FromXml (SecurityElement securityElement
)
113 // duplicate MS behaviour - reported as FDBK15052
114 if (securityElement
== null)
115 throw new NullReferenceException ("securityElement");
116 CheckSecurityElement (securityElement
, "securityElement", version
, version
);
117 // Note: we do not (yet) care about the return value
118 // as we only accept version 1 (min/max values)
120 _unrestricted
= PermissionHelper
.IsUnrestricted (securityElement
);
124 protected ResourcePermissionBaseEntry
[] GetPermissionEntries ()
126 ResourcePermissionBaseEntry
[] entries
= new ResourcePermissionBaseEntry
[_list
.Count
];
127 _list
.CopyTo (entries
, 0);
131 public override IPermission
Intersect (IPermission target
)
133 ResourcePermissionBase rpb
= Cast (target
);
137 bool su
= this.IsUnrestricted ();
138 bool tu
= rpb
.IsUnrestricted ();
140 // if one is empty we return null (unless the other one is unrestricted)
141 if (IsEmpty () && !tu
)
143 if (rpb
.IsEmpty () && !su
)
146 ResourcePermissionBase result
= CreateFromType (this.GetType (), (su
&& tu
));
147 foreach (ResourcePermissionBaseEntry entry
in _list
) {
148 if (tu
|| rpb
.Exists (entry
))
149 result
.AddPermissionAccess (entry
);
151 foreach (ResourcePermissionBaseEntry entry
in rpb
._list
) {
153 if ((su
|| this.Exists (entry
)) && !result
.Exists (entry
))
154 result
.AddPermissionAccess (entry
);
159 public override bool IsSubsetOf (IPermission target
)
161 // do not use Cast - different permissions return false :-/
164 ResourcePermissionBase rpb
= (target
as ResourcePermissionBase
);
167 if (rpb
.IsUnrestricted ())
169 if (IsUnrestricted ())
170 return rpb
.IsUnrestricted ();
171 foreach (ResourcePermissionBaseEntry entry
in _list
) {
172 if (!rpb
.Exists (entry
))
178 public bool IsUnrestricted ()
180 return _unrestricted
;
183 protected void RemovePermissionAccess (ResourcePermissionBaseEntry entry
)
186 for (int i
= 0; i
< _list
.Count
; i
++) {
187 ResourcePermissionBaseEntry rpbe
= (ResourcePermissionBaseEntry
) _list
[i
];
188 if (Equals (entry
, rpbe
)) {
193 string msg
= Locale
.GetText ("Entry doesn't exists.");
194 throw new InvalidOperationException (msg
);
197 public override SecurityElement
ToXml ()
199 SecurityElement se
= PermissionHelper
.Element (this.GetType (), version
);
200 if (IsUnrestricted ()) {
201 se
.AddAttribute ("Unrestricted", "true");
204 foreach (ResourcePermissionBaseEntry entry
in _list
) {
205 SecurityElement container
= se
;
206 for (int i
=0; i
< _tags
.Length
; i
++) {
207 SecurityElement child
= new SecurityElement (_tags
[i
]);
208 child
.AddAttribute ("name", entry
.PermissionAccessPath
[i
]);
209 container
.AddChild (child
);
217 public override IPermission
Union (IPermission target
)
219 ResourcePermissionBase rpb
= Cast (target
);
222 if (IsEmpty () && rpb
.IsEmpty ())
229 bool unrestricted
= (IsUnrestricted () || rpb
.IsUnrestricted ());
230 ResourcePermissionBase result
= CreateFromType (this.GetType (), unrestricted
);
231 // strangely unrestricted union doesn't process the elements (while intersect does)
233 foreach (ResourcePermissionBaseEntry entry
in _list
) {
234 result
.AddPermissionAccess (entry
);
236 foreach (ResourcePermissionBaseEntry entry
in rpb
._list
) {
238 if (!result
.Exists (entry
))
239 result
.AddPermissionAccess (entry
);
247 private bool IsEmpty ()
249 return (!_unrestricted
&& (_list
.Count
== 0));
252 private ResourcePermissionBase
Cast (IPermission target
)
257 ResourcePermissionBase rp
= (target
as ResourcePermissionBase
);
259 PermissionHelper
.ThrowInvalidPermission (target
, typeof (ResourcePermissionBase
));
265 internal void CheckEntry (ResourcePermissionBaseEntry entry
)
268 throw new ArgumentNullException ("entry");
269 if ((entry
.PermissionAccessPath
== null) || (entry
.PermissionAccessPath
.Length
!= _tags
.Length
)) {
270 string msg
= Locale
.GetText ("Entry doesn't match TagNames");
271 throw new InvalidOperationException (msg
);
275 internal bool Equals (ResourcePermissionBaseEntry entry1
, ResourcePermissionBaseEntry entry2
)
277 if (entry1
.PermissionAccess
!= entry2
.PermissionAccess
)
279 if (entry1
.PermissionAccessPath
.Length
!= entry2
.PermissionAccessPath
.Length
)
281 for (int i
=0; i
< entry1
.PermissionAccessPath
.Length
; i
++) {
282 if (entry1
.PermissionAccessPath
[i
] != entry2
.PermissionAccessPath
[i
])
288 internal bool Exists (ResourcePermissionBaseEntry entry
)
290 if (_list
.Count
== 0)
292 foreach (ResourcePermissionBaseEntry rpbe
in _list
) {
293 if (Equals (rpbe
, entry
))
299 // logic isn't identical to PermissionHelper.CheckSecurityElement
300 // - no throw on version mismatch
301 internal int CheckSecurityElement (SecurityElement se
, string parameterName
, int minimumVersion
, int maximumVersion
)
304 throw new ArgumentNullException (parameterName
);
306 // Note: we do not care about the class attribute at
307 // this stage (in fact we don't even if the class
308 // attribute is present or not). Anyway the object has
309 // already be created, with success, if we're loading it
311 // we assume minimum version if no version number is supplied
312 int version
= minimumVersion
;
313 string v
= se
.Attribute ("version");
316 version
= Int32
.Parse (v
);
318 catch (Exception e
) {
319 string msg
= Locale
.GetText ("Couldn't parse version from '{0}'.");
320 msg
= String
.Format (msg
, v
);
321 throw new ArgumentException (msg
, parameterName
, e
);
330 private static char[] invalidChars
= new char[] { '\t', '\n', '\v', '\f', '\r', ' ', '\\', '\x160' }
;
332 internal static void ValidateMachineName (string name
)
334 // FIXME: maybe other checks are required (but not documented)
335 if ((name
== null) || (name
.Length
== 0) || (name
.IndexOfAny (invalidChars
) != -1)) {
336 string msg
= Locale
.GetText ("Invalid machine name '{0}'.");
339 msg
= String
.Format (msg
, name
);
340 throw new ArgumentException (msg
, "MachineName");
344 internal static ResourcePermissionBase
CreateFromType (Type type
, bool unrestricted
)
346 object[] parameters
= new object [1];
347 parameters
[0] = (object) ((unrestricted
) ? PermissionState
.Unrestricted
: PermissionState
.None
);
348 // we must return the derived type - this is why an empty constructor is required ;-)
349 return (ResourcePermissionBase
) Activator
.CreateInstance (type
, parameters
);