2007-11-30 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / corlib / System.Security.Permissions / StrongNameIdentityPermission.cs
1 //
2 // StrongNameIdentityPermission.cs: Strong Name Identity Permission
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System.Collections;
31 using System.Globalization;
32 using System.Runtime.InteropServices;
33
34 namespace System.Security.Permissions {
35
36 #if NET_2_0
37         [ComVisible (true)]
38 #endif
39         [Serializable]
40         public sealed class StrongNameIdentityPermission : CodeAccessPermission, IBuiltInPermission {
41         
42                 private const int version = 1;
43                 static private Version defaultVersion = new Version (0, 0);
44
45                 private struct SNIP {
46                         public StrongNamePublicKeyBlob PublicKey;
47                         public string Name;
48                         public Version AssemblyVersion;
49
50                         internal SNIP (StrongNamePublicKeyBlob pk, string name, Version version)
51                         {
52                                 PublicKey = pk;
53                                 Name = name;
54                                 AssemblyVersion = version;
55                         }
56
57                         internal static SNIP CreateDefault ()
58                         {
59                                 return new SNIP (null, String.Empty, (Version) defaultVersion.Clone ());
60                         }
61
62                         internal bool IsNameSubsetOf (string target) 
63                         {
64                                 if (Name == null)
65                                         return (target == null);
66                                 if (target == null)
67                                         return true;
68
69                                 int wildcard = Name.LastIndexOf ('*');
70                                 if (wildcard == 0)
71                                         return true;            // *
72                                 if (wildcard == -1)
73                                         wildcard = Name.Length; // exact match
74
75                                 return (String.Compare (Name, 0, target, 0, wildcard, true, CultureInfo.InvariantCulture) == 0);
76                         }
77
78                         internal bool IsSubsetOf (SNIP target)
79                         {
80                                 if ((PublicKey != null) && PublicKey.Equals (target.PublicKey))
81                                         return true;
82
83                                 if (!IsNameSubsetOf (target.Name))
84                                         return false;
85                                 if ((AssemblyVersion != null) && !AssemblyVersion.Equals (target.AssemblyVersion))
86                                         return false;
87                                 // in case PermissionState.None was used in the constructor
88                                 if (PublicKey == null)
89                                         return (target.PublicKey == null);
90                                 return false;
91                         }
92                 }
93
94 #if NET_2_0
95                 private PermissionState _state;
96                 private ArrayList _list;
97
98                 public StrongNameIdentityPermission (PermissionState state) 
99                 {
100                         // Identity Permissions can be unrestricted in Fx 2.0
101                         _state = CheckPermissionState (state, true);
102                         // default values
103                         _list = new ArrayList ();
104                         _list.Add (SNIP.CreateDefault ());
105                 }
106
107                 public StrongNameIdentityPermission (StrongNamePublicKeyBlob blob, string name, Version version) 
108                 {
109                         if (blob == null)
110                                 throw new ArgumentNullException ("blob");
111                         if ((name != null) && (name.Length == 0))
112                                 throw new ArgumentException ("name");
113
114                         _state = PermissionState.None;
115                         _list = new ArrayList ();
116                         _list.Add (new SNIP (blob, name, version));
117                 }
118
119                 internal StrongNameIdentityPermission (StrongNameIdentityPermission snip) 
120                 {
121                         _state = snip._state;
122                         _list = new ArrayList (snip._list.Count);
123                         foreach (SNIP e in snip._list) {
124                                 _list.Add (new SNIP (e.PublicKey, e.Name, e.AssemblyVersion));
125                         }
126                 }
127 #else
128                 private SNIP _single;
129
130                 public StrongNameIdentityPermission (PermissionState state) 
131                 {
132                         // false == do not allow Unrestricted for Identity Permissions
133                         CheckPermissionState (state, false);
134                         // default values
135                         _single = SNIP.CreateDefault ();
136                 }
137
138                 public StrongNameIdentityPermission (StrongNamePublicKeyBlob blob, string name, Version version) 
139                 {
140                         if (blob == null)
141                                 throw new ArgumentNullException ("blob");
142
143                         _single = new SNIP (blob, name, version);
144                 }
145
146                 internal StrongNameIdentityPermission (StrongNameIdentityPermission snip) 
147                         : this (snip.PublicKey, snip.Name, snip.Version)
148                 {
149                 }
150 #endif
151
152                 // Properties
153
154 #if NET_2_0
155                 public string Name { 
156                         get {
157                                 if (_list.Count > 1)
158                                         throw new NotSupportedException ();
159                                 return ((SNIP)_list [0]).Name;
160                         }
161                         set { 
162                                 if ((value != null) && (value.Length == 0))
163                                         throw new ArgumentException ("name");
164                                 if (_list.Count > 1)
165                                         ResetToDefault ();
166                                 SNIP snip = (SNIP) _list [0];
167                                 snip.Name = value;
168                                 _list [0] = snip;
169                         }
170                 }
171
172                 public StrongNamePublicKeyBlob PublicKey { 
173                         get {
174                                 if (_list.Count > 1)
175                                         throw new NotSupportedException ();
176                                 return ((SNIP)_list [0]).PublicKey;
177                         }
178                         set {
179                                 if (value == null)
180                                         throw new ArgumentNullException ("value");
181                                 if (_list.Count > 1)
182                                         ResetToDefault ();
183                                 SNIP snip = (SNIP) _list [0];
184                                 snip.PublicKey = value;
185                                 _list [0] = snip;
186                         }
187                 }
188         
189                 public Version Version { 
190                         get {
191                                 if (_list.Count > 1)
192                                         throw new NotSupportedException ();
193                                 return ((SNIP)_list [0]).AssemblyVersion;
194                         }
195                         set {
196                                 if (_list.Count > 1)
197                                         ResetToDefault ();
198                                 SNIP snip = (SNIP) _list [0];
199                                 snip.AssemblyVersion = value;
200                                 _list [0] = snip;
201                         }
202                 }
203
204                 internal void ResetToDefault ()
205                 {
206                         _list.Clear ();
207                         _list.Add (SNIP.CreateDefault ());
208                 }
209 #else
210                 public string Name { 
211                         get { return _single.Name; }
212                         set { _single.Name = value; }
213                 }
214
215                 public StrongNamePublicKeyBlob PublicKey { 
216                         get { return _single.PublicKey; }
217                         set {
218                                 if (value == null)
219                                         throw new ArgumentNullException ("value");
220                                 _single.PublicKey = value;
221                         }
222                 }
223         
224                 public Version Version { 
225                         get { return _single.AssemblyVersion; }
226                         set { _single.AssemblyVersion = value; }
227                 }
228 #endif
229
230                 // Methods
231         
232                 public override IPermission Copy () 
233                 {
234                         if (IsEmpty ())
235                                 return new StrongNameIdentityPermission (PermissionState.None);
236                         else
237                                 return new StrongNameIdentityPermission (this);
238                 }
239         
240                 public override void FromXml (SecurityElement e) 
241                 {
242                         // General validation in CodeAccessPermission
243                         CheckSecurityElement (e, "e", version, version);
244                         // Note: we do not (yet) care about the return value 
245                         // as we only accept version 1 (min/max values)
246 #if NET_2_0
247                         _list.Clear ();
248                         if ((e.Children != null) && (e.Children.Count > 0)) {
249                                 foreach (SecurityElement se in e.Children) {
250                                         _list.Add (FromSecurityElement (se));
251                                 }
252                         } else {
253                                 _list.Add (FromSecurityElement (e));
254                         }
255 #else
256                         _single = FromSecurityElement (e);
257 #endif
258                 }
259
260                 private SNIP FromSecurityElement (SecurityElement se)
261                 {
262                         string name = se.Attribute ("Name");
263                         StrongNamePublicKeyBlob publickey = StrongNamePublicKeyBlob.FromString (se.Attribute ("PublicKeyBlob"));
264                         string v = se.Attribute ("AssemblyVersion");
265                         Version assemblyVersion = (v == null) ? null : new Version (v);
266
267                         return new SNIP (publickey, name, assemblyVersion);
268                 }
269 #if NET_2_0
270                 public override IPermission Intersect (IPermission target) 
271                 {
272                         if (target == null)
273                                 return null;
274                         StrongNameIdentityPermission snip = (target as StrongNameIdentityPermission);
275                         if (snip == null) 
276                                 throw new ArgumentException (Locale.GetText ("Wrong permission type."));
277                         if (IsEmpty () || snip.IsEmpty ())
278                                 return null;
279                         if (!Match (snip.Name))
280                                 return null;
281
282                         string n = ((Name.Length < snip.Name.Length) ? Name : snip.Name);
283                         if (!Version.Equals (snip.Version))
284                                 return null;
285                         if (!PublicKey.Equals (snip.PublicKey))
286                                 return null;
287
288                         return new StrongNameIdentityPermission (this.PublicKey, n, this.Version);
289                 }
290
291                 public override bool IsSubsetOf (IPermission target) 
292                 {
293                         StrongNameIdentityPermission snip = Cast (target);
294                         if (snip == null)
295                                 return IsEmpty ();
296
297                         if (IsEmpty ())
298                                 return true;
299                         if (IsUnrestricted ())
300                                 return snip.IsUnrestricted ();
301                         else if (snip.IsUnrestricted ())
302                                 return true;
303
304                         foreach (SNIP e in _list) {
305                                 foreach (SNIP t in snip._list) {
306                                         if (!e.IsSubsetOf (t))
307                                                 return false;
308                                 }
309                         }
310                         return true;
311                 }
312 #else
313                 public override IPermission Intersect (IPermission target) 
314                 {
315                         StrongNameIdentityPermission snip = (target as StrongNameIdentityPermission);
316                         if ((snip == null) || IsEmpty ())
317                                 return null;
318                         if (snip.IsEmpty ())
319                                 return new StrongNameIdentityPermission (PermissionState.None);
320                         if (!Match (snip.Name))
321                                 return null;
322
323                         string n = ((Name.Length < snip.Name.Length) ? Name : snip.Name);
324                         if (!Version.Equals (snip.Version))
325                                 return null;
326                         if (!PublicKey.Equals (snip.PublicKey))
327                                 return null;
328
329                         return new StrongNameIdentityPermission (this.PublicKey, n, this.Version);
330                 }
331
332                 public override bool IsSubsetOf (IPermission target) 
333                 {
334                         StrongNameIdentityPermission snip = Cast (target);
335                         if (snip == null)
336                                 return IsEmpty ();
337                         if (IsEmpty ())
338                                 return true;
339
340                         return _single.IsSubsetOf (snip._single);
341                 }
342 #endif
343         
344                 public override SecurityElement ToXml () 
345                 {
346                         SecurityElement se = Element (version);
347 #if NET_2_0
348                         if (_list.Count > 1) {
349                                 foreach (SNIP snip in _list) {
350                                         SecurityElement child = new SecurityElement ("StrongName");
351                                         ToSecurityElement (child, snip);
352                                         se.AddChild (child);
353                                 }
354                         } else if (_list.Count == 1) {
355                                 SNIP snip = (SNIP)_list [0];
356                                 if (!IsEmpty (snip))
357                                         ToSecurityElement (se, snip);
358                         }
359 #else
360                         ToSecurityElement (se, _single);
361 #endif
362                         return se;
363                 }
364
365                 private void ToSecurityElement (SecurityElement se, SNIP snip)
366                 {
367                         if (snip.PublicKey != null)
368                                 se.AddAttribute ("PublicKeyBlob", snip.PublicKey.ToString ());
369                         if (snip.Name != null)
370                                 se.AddAttribute ("Name", snip.Name);
371                         if (snip.AssemblyVersion != null)
372                                 se.AddAttribute ("AssemblyVersion", snip.AssemblyVersion.ToString ());
373                 }
374
375 #if NET_2_0
376                 public override IPermission Union (IPermission target) 
377                 {
378                         StrongNameIdentityPermission snip = Cast (target);
379                         if ((snip == null) || snip.IsEmpty ())
380                                 return Copy ();
381
382                         if (IsEmpty ())
383                                 return snip.Copy ();
384
385                         StrongNameIdentityPermission union = (StrongNameIdentityPermission) Copy ();
386                         foreach (SNIP e in snip._list) {
387                                 if (!IsEmpty (e) && !Contains (e)) {
388                                         union._list.Add (e);
389                                 }
390                         }
391                         return union;
392                 }
393 #else
394                 public override IPermission Union (IPermission target) 
395                 {
396                         StrongNameIdentityPermission snip = Cast (target);
397                         if ((snip == null) || snip.IsEmpty ())
398                                 return Copy ();
399
400                         if (IsEmpty ())
401                                 return snip.Copy ();
402
403                         if (!PublicKey.Equals (snip.PublicKey)) {
404                                 return null;
405                         }
406
407                         string n = Name;
408                         if ((n == null) || (n.Length == 0)) {
409                                 n = snip.Name;
410                         }
411                         else if (Match (snip.Name)) {
412                                 n = ((Name.Length > snip.Name.Length) ? Name : snip.Name);
413                         }
414                         else if ((snip.Name != null) && (snip.Name.Length > 0) && (n != snip.Name)) {
415                                 return null;
416                         }
417
418                         Version v = Version;
419                         if (v == null) {
420                                 v = snip.Version;
421                         }
422                         else if ((snip.Version != null) && (v != snip.Version)) {
423                                 return null;
424                         }
425
426                         return new StrongNameIdentityPermission (PublicKey, n, v);
427                 }
428 #endif
429         
430                 // IBuiltInPermission
431                 int IBuiltInPermission.GetTokenIndex ()
432                 {
433                         return (int) BuiltInToken.StrongNameIdentity;
434                 }
435
436                 // helpers
437
438 #if NET_2_0
439                 private bool IsUnrestricted ()
440                 {
441                         return (_state == PermissionState.Unrestricted);
442                 }
443
444                 private bool Contains (SNIP snip)
445                 {
446                         foreach (SNIP e in _list) {
447                                 bool pk = (((e.PublicKey == null) && (snip.PublicKey == null)) ||
448                                         ((e.PublicKey != null) && e.PublicKey.Equals (snip.PublicKey)));
449                                 bool name = e.IsNameSubsetOf (snip.Name);
450                                 bool version = (((e.AssemblyVersion == null) && (snip.AssemblyVersion == null)) ||
451                                         ((e.AssemblyVersion != null) && e.AssemblyVersion.Equals (snip.AssemblyVersion)));
452
453                                 if (pk && name && version)
454                                         return true;
455                         }
456                         return false;
457                 }
458
459                 private bool IsEmpty (SNIP snip)
460                 {
461                         if (PublicKey != null)
462                                 return false;
463                         if ((Name != null) && (Name.Length > 0))
464                                 return false;
465                         return ((Version == null) || defaultVersion.Equals (Version));
466                 }
467
468 #endif
469                 private bool IsEmpty ()
470                 {
471 #if NET_2_0
472                         if (IsUnrestricted () || (_list.Count > 1))
473                                 return false;
474 #endif
475                         if (PublicKey != null)
476                                 return false;
477                         if ((Name != null) && (Name.Length > 0))
478                                 return false;
479                         return ((Version == null) || defaultVersion.Equals (Version));
480                 }
481
482                 private StrongNameIdentityPermission Cast (IPermission target)
483                 {
484                         if (target == null)
485                                 return null;
486
487                         StrongNameIdentityPermission snip = (target as StrongNameIdentityPermission);
488                         if (snip == null) {
489                                 ThrowInvalidPermission (target, typeof (StrongNameIdentityPermission));
490                         }
491
492                         return snip;
493                 }
494
495                 private bool Match (string target) 
496                 {
497                         if ((Name == null) || (target == null))
498                                 return false;
499
500                         int wcu = Name.LastIndexOf ('*');
501                         int wct = target.LastIndexOf ('*');
502                         int length = Int32.MaxValue;
503
504                         if ((wcu == -1) && (wct == -1)) {
505                                 // no wildcard, this is an exact match
506                                 length = Math.Max (Name.Length, target.Length);
507                         }
508                         else if (wcu == -1) {
509                                 // only "target" has a wildcard, use it
510                                 length = wct;
511                         }
512                         else if (wct == -1) {
513                                 // only "this" has a wildcard, use it
514                                 length = wcu;
515                         }
516                         else {
517                                 // both have wildcards, partial match with the smallest
518                                 length = Math.Min (wcu, wct);
519                         }
520
521                         return (String.Compare (Name, 0, target, 0, length, true, CultureInfo.InvariantCulture) == 0);
522                 }
523         } 
524 }