Fix problems with overlong directory names: phase #1
[mono.git] / mcs / class / corlib / System.Security.Policy / Evidence.cs
1 //
2 // System.Security.Policy.Evidence
3 //
4 // Authors:
5 //      Sean MacIsaac (macisaac@ximian.com)
6 //      Nick Drochak (ndrochak@gol.com)
7 //      Jackson Harper (Jackson@LatitudeGeo.com)
8 //      Sebastien Pouliot  <sebastien@ximian.com>
9 //
10 // (C) 2001 Ximian, Inc.
11 // Portions (C) 2003, 2004 Motus Technologies Inc. (http://www.motus.com)
12 // Copyright (C) 2004-2005 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.Collections;
35 using System.Globalization;
36 using System.Reflection;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
39 using System.Security.Permissions;
40 using System.Security.Cryptography.X509Certificates;
41
42 using Mono.Security.Authenticode;
43
44 namespace System.Security.Policy {
45
46         [Serializable]
47         [MonoTODO ("Fix serialization compatibility with MS.NET")]
48 #if NET_2_0
49         [ComVisible (true)]
50 #endif
51         public sealed class Evidence : ICollection, IEnumerable {
52         
53                 private bool _locked;
54                 private ArrayList hostEvidenceList;     
55                 private ArrayList assemblyEvidenceList;
56                 private int _hashCode;
57
58                 public Evidence () 
59                 {
60                 }
61
62                 public Evidence (Evidence evidence)
63                 {
64                         if (evidence != null)
65                                 Merge (evidence);       
66                 }
67
68                 public Evidence (object[] hostEvidence, object[] assemblyEvidence)
69                 {
70                         if (null != hostEvidence)
71                                 HostEvidenceList.AddRange (hostEvidence);
72                         if (null != assemblyEvidence)
73                                 AssemblyEvidenceList.AddRange (assemblyEvidence);
74                 }
75                 
76                 //
77                 // Public Properties
78                 //
79         
80                 public int Count {
81                         get {
82                                 int count = 0;
83                                 if (hostEvidenceList != null)
84                                         count += hostEvidenceList.Count;
85                                 if (assemblyEvidenceList!= null)
86                                         count += assemblyEvidenceList.Count;
87                                 return count;
88                         }
89                 }
90
91                 public bool IsReadOnly {
92                         get{ return false; }
93                 }
94                 
95                 public bool IsSynchronized {
96 #if NET_2_0
97                         get { return false; }
98 #else
99                         // LAMESPEC: Always TRUE (not FALSE)
100                         get { return true; }
101 #endif
102                 }
103
104                 public bool Locked {
105                         get { return _locked; }
106                         [SecurityPermission (SecurityAction.Demand, ControlEvidence = true)]
107                         set { 
108                                 _locked = value; 
109                         }
110                 }       
111
112                 public object SyncRoot {
113                         get { return this; }
114                 }
115
116                 internal ArrayList HostEvidenceList {
117                         get {
118                                 if (hostEvidenceList == null)
119                                         hostEvidenceList = ArrayList.Synchronized (new ArrayList ());
120                                 return hostEvidenceList;
121                         }
122                 }
123
124                 internal ArrayList AssemblyEvidenceList {
125                         get {
126                                 if (assemblyEvidenceList == null)
127                                         assemblyEvidenceList = ArrayList.Synchronized (new ArrayList ());
128                                 return assemblyEvidenceList;
129                         }
130                 }
131
132                 //
133                 // Public Methods
134                 //
135
136                 public void AddAssembly (object id) 
137                 {
138                         AssemblyEvidenceList.Add (id);
139                         _hashCode = 0;
140                 }
141
142                 public void AddHost (object id) 
143                 {
144                         if (_locked && SecurityManager.SecurityEnabled) {
145                                 new SecurityPermission (SecurityPermissionFlag.ControlEvidence).Demand ();
146                         }
147                         HostEvidenceList.Add (id);
148                         _hashCode = 0;
149                 }
150
151 #if NET_2_0
152                 [ComVisible (false)]
153                 public void Clear ()
154                 {
155                         if (hostEvidenceList != null)
156                                 hostEvidenceList.Clear ();
157                         if (assemblyEvidenceList != null)
158                                 assemblyEvidenceList.Clear ();
159                         _hashCode = 0;
160                 }
161 #endif
162
163                 public void CopyTo (Array array, int index) 
164                 {
165                         int hc = 0;
166                         if (hostEvidenceList != null) {
167                                 hc = hostEvidenceList.Count;
168                                 if (hc > 0)
169                                         hostEvidenceList.CopyTo (array, index);
170                         }
171                         if ((assemblyEvidenceList != null) && (assemblyEvidenceList.Count > 0))
172                                 assemblyEvidenceList.CopyTo (array, index + hc);
173                 }
174
175 #if NET_2_0
176                 [ComVisible (false)]
177                 public override bool Equals (object obj)
178                 {
179                         if (obj == null)
180                                 return false;
181                         Evidence e = (obj as Evidence);
182                         if (e == null)
183                                 return false;
184
185                         if (HostEvidenceList.Count != e.HostEvidenceList.Count)
186                                 return false;
187                         if (AssemblyEvidenceList.Count != e.AssemblyEvidenceList.Count)
188                                 return false;
189
190                         for (int i = 0; i < hostEvidenceList.Count; i++) {
191                                 bool found = false;
192                                 for (int j = 0; j < e.hostEvidenceList.Count; i++) {
193                                         if (hostEvidenceList [i].Equals (e.hostEvidenceList [j])) {
194                                                 found = true;
195                                                 break;
196                                         }
197                                 }
198                                 if (!found)
199                                         return false;
200                         }
201                         for (int i = 0; i < assemblyEvidenceList.Count; i++) {
202                                 bool found = false;
203                                 for (int j = 0; j < e.assemblyEvidenceList.Count; i++) {
204                                         if (assemblyEvidenceList [i].Equals (e.assemblyEvidenceList [j])) {
205                                                 found = true;
206                                                 break;
207                                         }
208                                 }
209                                 if (!found)
210                                         return false;
211                         }
212                         
213                         return true;
214                 }
215 #endif
216
217                 public IEnumerator GetEnumerator () 
218                 {
219                         IEnumerator he = null;
220                         if (hostEvidenceList != null)
221                                 he = hostEvidenceList.GetEnumerator ();
222                         IEnumerator ae = null;
223                         if (assemblyEvidenceList != null)
224                                 assemblyEvidenceList.GetEnumerator ();
225                         return new EvidenceEnumerator (he, ae);
226                 }
227
228                 public IEnumerator GetAssemblyEnumerator () 
229                 {
230                         return AssemblyEvidenceList.GetEnumerator ();
231                 }
232
233 #if NET_2_0
234                 [ComVisible (false)]
235                 public override int GetHashCode ()
236                 {
237                         // kind of long so we cache it
238                         if (_hashCode == 0) {
239                                 if (hostEvidenceList != null) {
240                                         for (int i = 0; i < hostEvidenceList.Count; i++)
241                                                 _hashCode ^= hostEvidenceList [i].GetHashCode ();
242                                 }
243                                 if (assemblyEvidenceList != null) {
244                                         for (int i = 0; i < assemblyEvidenceList.Count; i++)
245                                                 _hashCode ^= assemblyEvidenceList [i].GetHashCode ();
246                                 }
247                         }
248                         return _hashCode;
249                 }
250 #endif
251
252                 public IEnumerator GetHostEnumerator () 
253                 {
254                         return HostEvidenceList.GetEnumerator ();
255                 }
256
257                 public void Merge (Evidence evidence) 
258                 {
259                         if ((evidence != null) && (evidence.Count > 0)) {
260                                 if (evidence.hostEvidenceList != null) {
261                                         foreach (object o in evidence.hostEvidenceList)
262                                                 AddHost (o);
263                                 }
264                                 if (evidence.assemblyEvidenceList != null) {
265                                         foreach (object o in evidence.assemblyEvidenceList)
266                                                 AddAssembly (o);
267                                 }
268                                 _hashCode = 0;
269                         }
270                 }
271
272 #if NET_2_0
273                 [ComVisible (false)]
274                 public void RemoveType (Type t)
275                 {
276                         for (int i = hostEvidenceList.Count; i >= 0; i--) {
277                                 if (hostEvidenceList.GetType () == t) {
278                                         hostEvidenceList.RemoveAt (i);
279                                         _hashCode = 0;
280                                 }
281                         }
282                         for (int i = assemblyEvidenceList.Count; i >= 0; i--) {
283                                 if (assemblyEvidenceList.GetType () == t) {
284                                         assemblyEvidenceList.RemoveAt (i);
285                                         _hashCode = 0;
286                                 }
287                         }
288                 }
289 #endif
290
291                 // Use an icall to avoid multiple file i/o to detect the 
292                 // "possible" presence of an Authenticode signature
293                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
294                 static extern bool IsAuthenticodePresent (Assembly a);
295
296                 // this avoid us to build all evidences from the runtime
297                 // (i.e. multiple unmanaged->managed calls) and also allows
298                 // to delay their creation until (if) needed
299                 [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
300                 static internal Evidence GetDefaultHostEvidence (Assembly a) 
301                 {
302                         Evidence e = new Evidence ();
303                         string aname = a.EscapedCodeBase;
304
305                         // by default all assembly have the Zone, Url and Hash evidences
306                         e.AddHost (Zone.CreateFromUrl (aname));
307                         e.AddHost (new Url (aname));
308                         e.AddHost (new Hash (a));
309
310                         // non local files (e.g. http://) also get a Site evidence
311                         if (String.Compare ("FILE://", 0, aname, 0, 7, true, CultureInfo.InvariantCulture) != 0) {
312                                 e.AddHost (Site.CreateFromUrl (aname));
313                         }
314
315                         // strongnamed assemblies gets a StrongName evidence
316                         AssemblyName an = a.UnprotectedGetName ();
317                         byte[] pk = an.GetPublicKey ();
318                         if ((pk != null) && (pk.Length > 0)) {
319                                 StrongNamePublicKeyBlob blob = new StrongNamePublicKeyBlob (pk);
320                                 e.AddHost (new StrongName (blob, an.Name, an.Version));
321                         }
322
323                         // Authenticode(r) signed assemblies get a Publisher evidence
324                         if (IsAuthenticodePresent (a)) {
325                                 // Note: The certificate is part of the evidences even if it is not trusted!
326                                 // so we can't call X509Certificate.CreateFromSignedFile
327                                 AuthenticodeDeformatter ad = new AuthenticodeDeformatter (a.Location);
328                                 if (ad.SigningCertificate != null) {
329                                         X509Certificate x509 = new X509Certificate (ad.SigningCertificate.RawData);
330                                         if (x509.GetHashCode () != 0) {
331                                                 e.AddHost (new Publisher (x509));
332                                         }
333                                 }
334                         }
335 #if NET_2_0
336                         // assemblies loaded from the GAC also get a Gac evidence (new in Fx 2.0)
337                         if (a.GlobalAssemblyCache) {
338                                 e.AddHost (new GacInstalled ());
339                         }
340
341                         // the current HostSecurityManager may add/remove some evidence
342                         AppDomainManager dommgr = AppDomain.CurrentDomain.DomainManager;
343                         if (dommgr != null) {
344                                 if ((dommgr.HostSecurityManager.Flags & HostSecurityManagerOptions.HostAssemblyEvidence) ==
345                                         HostSecurityManagerOptions.HostAssemblyEvidence) {
346                                         e = dommgr.HostSecurityManager.ProvideAssemblyEvidence (a, e);
347                                 }
348                         }
349 #endif
350                         return e;
351                 }
352         
353                 private class EvidenceEnumerator : IEnumerator {
354                         
355                         private IEnumerator currentEnum, hostEnum, assemblyEnum;                
356         
357                         public EvidenceEnumerator (IEnumerator hostenum, IEnumerator assemblyenum) 
358                         {
359                                 this.hostEnum = hostenum;
360                                 this.assemblyEnum = assemblyenum;
361                                 currentEnum = hostEnum;         
362                         }
363
364                         public bool MoveNext () 
365                         {
366                                 if (currentEnum == null)
367                                         return false;
368
369                                 bool ret = currentEnum.MoveNext ();
370                                 
371                                 if (!ret && (hostEnum == currentEnum) && (assemblyEnum != null)) {
372                                         currentEnum = assemblyEnum;
373                                         ret = assemblyEnum.MoveNext ();
374                                 }
375
376                                 return ret;
377                         }
378
379                         public void Reset () 
380                         {
381                                 if (hostEnum != null) {
382                                         hostEnum.Reset ();
383                                         currentEnum = hostEnum;
384                                 } else {
385                                         currentEnum = assemblyEnum;
386                                 }
387                                 if (assemblyEnum != null)
388                                         assemblyEnum.Reset ();
389                         }
390
391                         public object Current {
392                                 get {
393                                         return currentEnum.Current;
394                                 }
395                         }
396                 }
397         }
398 }
399