Merge pull request #839 from glinos/master
[mono.git] / mcs / class / corlib / System.Security.Permissions / SiteIdentityPermission.cs
1 //
2 // System.Security.Permissions.SiteIdentityPermission.cs
3 //
4 // Author
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // Copyright (C) 2003 Motus Technologies. 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.Globalization;
31 using System.Runtime.InteropServices;
32
33 namespace System.Security.Permissions {
34
35         [ComVisible (true)]
36         [Serializable]
37         public sealed class SiteIdentityPermission : CodeAccessPermission, IBuiltInPermission {
38
39                 private const int version = 1;
40
41                 private string _site;
42
43                 // Constructors
44
45                 public SiteIdentityPermission (PermissionState state) 
46                 {
47                         // false == do not allow Unrestricted for Identity Permissions
48                         CheckPermissionState (state, false);
49                 }
50
51                 public SiteIdentityPermission (string site) 
52                 {
53                         Site = site;
54                 }
55
56                 // Properties
57
58                 public string Site {
59                         get { 
60                                 if (IsEmpty ())
61                                         throw new NullReferenceException ("No site.");
62                                 return _site; 
63                         }
64                         set {
65                                 if (!IsValid (value))
66                                         throw new ArgumentException ("Invalid site.");
67                                 _site = value;
68                         }
69                 }
70
71                 // Methods
72
73                 public override IPermission Copy () 
74                 {
75                         if (IsEmpty ())
76                                 return new SiteIdentityPermission (PermissionState.None);
77                         else
78                                 return new SiteIdentityPermission (_site);
79                 }
80
81                 public override void FromXml (SecurityElement esd) 
82                 {
83                         // General validation in CodeAccessPermission
84                         CheckSecurityElement (esd, "esd", version, version);
85                         // Note: we do not (yet) care about the return value 
86                         // as we only accept version 1 (min/max values)
87
88                         string s = esd.Attribute ("Site");
89                         if (s != null)
90                                 Site = s;
91                 }
92
93                 public override IPermission Intersect (IPermission target)
94                 {
95                         SiteIdentityPermission sip = Cast (target);
96                         if ((sip == null) || (IsEmpty ()))
97                                 return null;
98
99                         if (Match (sip._site)) {
100                                 string s = ((_site.Length > sip._site.Length) ? _site : sip._site);
101                                 return new SiteIdentityPermission (s);
102                         }
103                         return null;
104                 }
105
106                 public override bool IsSubsetOf (IPermission target) 
107                 {
108                         SiteIdentityPermission sip = Cast (target);
109                         if (sip == null)
110                                 return IsEmpty ();
111                         if ((_site == null) && (sip._site == null))
112                                 return true;
113                         if ((_site == null) || (sip._site == null))
114                                 return false;
115
116                         int wildcard = sip._site.IndexOf ('*');
117                         if (wildcard == -1) {
118                                 // exact match
119                                 return (_site == sip._site);
120                         }
121                         return _site.EndsWith (sip._site.Substring (wildcard + 1));
122                 }
123
124                 public override SecurityElement ToXml ()
125                 {
126                         SecurityElement e = Element (version);
127                         if (_site != null)
128                                 e.AddAttribute ("Site", _site);
129                         return e;
130                 }
131
132                 public override IPermission Union (IPermission target) 
133                 {
134                         SiteIdentityPermission sip = Cast (target);
135                         if ((sip == null) || sip.IsEmpty ())
136                                 return Copy ();
137                         if (IsEmpty ())
138                                 return sip.Copy ();
139
140                         if (Match (sip._site)) {
141                                 string s = ((_site.Length < sip._site.Length) ? _site : sip._site);
142                                 return new SiteIdentityPermission (s);
143                         }
144                         throw new ArgumentException (Locale.GetText (
145                                 "Cannot union two different sites."), "target");
146                 }
147
148                 // IBuiltInPermission
149                 int IBuiltInPermission.GetTokenIndex ()
150                 {
151                         return (int) BuiltInToken.SiteIdentity;
152                 }
153
154                 // helpers
155
156                 private bool IsEmpty ()
157                 {
158                         return (_site == null);
159                 }
160
161                 private SiteIdentityPermission Cast (IPermission target)
162                 {
163                         if (target == null)
164                                 return null;
165
166                         SiteIdentityPermission sip = (target as SiteIdentityPermission);
167                         if (sip == null) {
168                                 ThrowInvalidPermission (target, typeof (SiteIdentityPermission));
169                         }
170
171                         return sip;
172                 }
173
174                 private static bool[] valid = new bool [94] {
175                         /*  33 */ true,  false, true,  true,  true,  true,  true,  true,  true,  true,
176                         /*  43 */ false, false, true,  true,  false, true,  true,  true,  true,  true,
177                         /*  53 */ true,  true,  true,  true,  false, false, false, false, false, false,
178                         /*  63 */ false, true,  true,  true,  true,  true,  true,  true,  true,  true,
179                         /*  73 */ true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
180                         /*  83 */ true,  true,  true,  true,  true,  true,  true,  true,  false, false,
181                         /*  93 */ false, true,  true,  false, true,  true,  true,  true,  true,  true,
182                         /* 103 */ true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
183                         /* 113 */ true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
184                         /* 123 */ true,  false, true,  true
185                 };
186
187                 private bool IsValid (string s)
188                 {
189                         if ((s == null) || (s.Length == 0))
190                                 return false;
191
192                         for (int i = 0; i < s.Length; i++) {
193                                 ushort x = (ushort) s [i];
194                                 if ((x < 33) || (x > 126)) {
195                                         return false;
196                                 }
197                                 if (x == 42) {
198                                         // special case for wildcards (*)
199                                         // must be alone or first and followed by a dot
200                                         if ((s.Length > 1) && ((s [i + 1] != '.') || (i > 0)))
201                                                 return false;
202                                 }
203                                 if (!valid [x - 33]) {
204                                         return false;
205                                 }
206                         }
207
208                         // a lone dot isn't valid
209                         if (s.Length == 1)
210                                 return (s [0] != '.');
211                         return true;
212                 }
213
214                 private bool Match (string target) 
215                 {
216                         if ((_site == null) || (target == null))
217                                 return false;
218
219                         int wcs = _site.IndexOf ('*');
220                         int wct = target.IndexOf ('*');
221
222                         if ((wcs == -1) && (wct == -1)) {
223                                 // no wildcard, this is an exact match
224                                 return (_site == target);
225                         }
226                         else if (wcs == -1) {
227                                 // only "target" has a wildcard, use it
228                                 return _site.EndsWith (target.Substring (wct + 1));
229                         }
230                         else if (wct == -1) {
231                                 // only "this" has a wildcard, use it
232                                 return target.EndsWith (_site.Substring (wcs + 1));
233                         }
234                         else {
235                                 // both have wildcards, partial match with the smallest
236                                 string s = _site.Substring (wcs + 1);
237                                 target = target.Substring (wct + 1);
238                                 if (s.Length > target.Length)
239                                         return s.EndsWith (target);
240                                 else
241                                         return target.EndsWith (s);
242                         }
243                 }
244         }
245 }