* Evidence.cs:
[mono.git] / mcs / class / corlib / System.Security.Policy / PolicyLevel.cs
1 //
2 // System.Security.Policy.PolicyLevel.cs
3 //
4 // Authors:
5 //      Nick Drochak (ndrochak@gol.com)
6 //      Duncan Mak (duncan@ximian.com)
7 //      Sebastien Pouliot  <sebastien@ximian.com>
8 //
9 // (C) 2001 Nick Drochak
10 // (C) 2003 Duncan Mak, Ximian Inc.
11 // Portions (C) 2004 Motus Technologies Inc. (http://www.motus.com)
12 // Copyright (C) 2004 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; // for IList
35 using System.Globalization;
36 using System.IO;
37 using System.Reflection;
38 using System.Runtime.InteropServices;
39 using System.Security.Permissions;
40
41 using Mono.Xml;
42
43 namespace System.Security.Policy {
44
45         [Serializable]
46         public sealed class PolicyLevel {
47
48                 string label;
49                 CodeGroup root_code_group;
50                 private ArrayList full_trust_assemblies;
51                 private ArrayList named_permission_sets;
52                 private string _location;
53                 private PolicyLevelType _type;
54                 private Hashtable fullNames;
55
56                 internal PolicyLevel (string label, PolicyLevelType type)
57                 {
58                         this.label = label;
59                         _type = type;
60                         full_trust_assemblies = new ArrayList ();
61                         named_permission_sets = new ArrayList ();
62                 }
63
64                 internal PolicyLevel (string label, PolicyLevelType type, string filename)
65                         : this (label, type)
66                 {
67                         LoadFromFile (filename);
68                 }
69
70                 internal void LoadFromFile (string filename) 
71                 {
72                         bool loaded = false;
73                         try {
74                                 // check for policy file
75                                 if (!File.Exists (filename)) {
76                                         // if it doesn't exist use the default configuration (like Fx 2.0)
77                                         // ref: http://blogs.msdn.com/shawnfa/archive/2004/04/21/117833.aspx
78                                         string defcfg = filename + ".default";
79                                         if (File.Exists (defcfg)) {
80                                                 // create policy from default file
81                                                 File.Copy (defcfg, filename);
82                                         }
83                                 }
84                                 // load security policy configuration
85                                 if (File.Exists (filename)) {
86                                         using (StreamReader sr = File.OpenText (filename)) {
87                                                 LoadFromString (sr.ReadToEnd ());
88                                         }
89                                         loaded = true;
90                                 }
91                                 else {
92                                         CreateFromHardcodedDefault (_type);
93                                         loaded = true;
94                                         Save ();
95                                 }
96                         }
97                         catch {
98                                 // this can fail in many ways include
99                                 // * can't lookup policy (path discovery);
100                                 // * can't copy default file to policy
101                                 // * can't read policy file;
102                                 // * can't save hardcoded policy to filename
103                                 // * can't decode policy file
104                                 if (!loaded)
105                                         CreateFromHardcodedDefault (_type);
106                         }
107                         finally {
108                                 _location = filename;
109                         }
110                 }
111
112                 internal void LoadFromString (string xml) 
113                 {
114                         SecurityParser parser = new SecurityParser ();
115                         parser.LoadXml (xml);
116                         // configuration / mscorlib / security / policy / PolicyLevel
117                         SecurityElement configuration = parser.ToXml ();
118                         if (configuration.Tag != "configuration")
119                                 throw new ArgumentException (Locale.GetText ("missing <configuration> root element"));
120                         SecurityElement mscorlib = (SecurityElement) configuration.Children [0];
121                         if (mscorlib.Tag != "mscorlib")
122                                 throw new ArgumentException (Locale.GetText ("missing <mscorlib> tag"));
123                         SecurityElement security = (SecurityElement) mscorlib.Children [0];
124                         if (security.Tag != "security")
125                                 throw new ArgumentException (Locale.GetText ("missing <security> tag"));
126                         SecurityElement policy = (SecurityElement) security.Children [0];
127                         if (policy.Tag != "policy")
128                                 throw new ArgumentException (Locale.GetText ("missing <policy> tag"));
129                         SecurityElement policyLevel = (SecurityElement) policy.Children [0];
130                         FromXml (policyLevel);
131                 }
132
133                 // properties
134
135                 public IList FullTrustAssemblies
136                 {
137                         get { return full_trust_assemblies; }
138                 }
139
140                 public string Label {
141                         get { return label; }
142                 }
143
144                 public IList NamedPermissionSets {
145                         get { return named_permission_sets; }
146                 }
147
148                 public CodeGroup RootCodeGroup {
149                         get { return root_code_group; }
150                         set { 
151                                 if (value == null)
152                                         throw new ArgumentNullException ("value");
153                                 root_code_group = value; 
154                         }
155                 }
156
157                 public string StoreLocation {
158                         get { return _location; }
159                 }
160
161 #if NET_2_0
162                 [ComVisible (false)]
163                 public PolicyLevelType Type {
164                         get { return _type; }
165                 }
166 #endif
167
168                 // methods
169
170                 public void AddFullTrustAssembly (StrongName sn)
171                 {
172                         if (sn == null)
173                                 throw new ArgumentNullException ("sn");
174
175                         StrongNameMembershipCondition snMC = new StrongNameMembershipCondition(
176                                 sn.PublicKey, sn.Name, sn.Version);
177
178                         AddFullTrustAssembly (snMC);
179                 }
180
181                 public void AddFullTrustAssembly (StrongNameMembershipCondition snMC)
182                 {
183                         if (snMC == null)
184                                 throw new ArgumentNullException ("snMC");
185                         
186                         foreach (StrongNameMembershipCondition sn in full_trust_assemblies) {
187                                 if (sn.Equals (snMC)) {
188                                         throw new ArgumentException (Locale.GetText ("sn already has full trust."));
189                                 }
190                         }
191                         full_trust_assemblies.Add (snMC);
192                 }
193
194                 public void AddNamedPermissionSet (NamedPermissionSet permSet)
195                 {
196                         if (permSet == null)
197                                 throw new ArgumentNullException ("permSet");
198
199                         foreach (NamedPermissionSet n in named_permission_sets) {
200                                 if (permSet.Name == n.Name) {
201                                         throw new ArgumentException (
202                                                 Locale.GetText ("This NamedPermissionSet is the same an existing NamedPermissionSet."));
203                                 }
204                         }
205                         named_permission_sets.Add (permSet.Copy ());
206                 }
207
208                 public NamedPermissionSet ChangeNamedPermissionSet (string name, PermissionSet pSet)
209                 {
210                         if (name == null)
211                                 throw new ArgumentNullException ("name");
212                         if (pSet == null)
213                                 throw new ArgumentNullException ("pSet");
214                         if (IsReserved (name))
215                                 throw new ArgumentException (Locale.GetText ("Reserved name"));
216
217                         foreach (NamedPermissionSet n in named_permission_sets) {
218                                 if (name == n.Name) {
219                                         named_permission_sets.Remove (n);
220                                         AddNamedPermissionSet (new NamedPermissionSet (name, pSet));
221                                         return n;
222                                 }
223                         }
224                         throw new ArgumentException (Locale.GetText ("PermissionSet not found"));
225                 }
226
227                 public static PolicyLevel CreateAppDomainLevel ()
228                 {
229                         NamedPermissionSet fullTrust = new NamedPermissionSet ("FullTrust", PermissionState.Unrestricted);
230                         UnionCodeGroup cg = new UnionCodeGroup (new AllMembershipCondition (), new PolicyStatement (fullTrust));
231                         cg.Name = "All_Code";
232                         PolicyLevel pl = new PolicyLevel ("AppDomain", PolicyLevelType.AppDomain);
233                         pl.RootCodeGroup = cg;
234                         pl.Reset ();
235                         return pl;
236                 }
237
238                 public void FromXml (SecurityElement e)
239                 {
240                         if (e == null)
241                                 throw new ArgumentNullException ("e");
242 // MS doesn't throw an exception for this case
243 //                      if (e.Tag != "PolicyLevel")
244 //                              throw new ArgumentException (Locale.GetText ("Invalid XML"));
245
246                         SecurityElement sc = e.SearchForChildByTag ("SecurityClasses");
247                         if ((sc != null) && (sc.Children != null) && (sc.Children.Count > 0)) {
248                                 fullNames = new Hashtable (sc.Children.Count);
249                                 foreach (SecurityElement se in sc.Children) {
250                                         fullNames.Add (se.Attributes ["Name"], se.Attributes ["Description"]);
251                                 }
252                         }
253
254                         SecurityElement nps = e.SearchForChildByTag ("NamedPermissionSets");
255                         if ((nps != null) && (nps.Children != null) && (nps.Children.Count > 0)) {
256                                 named_permission_sets.Clear ();
257                                 foreach (SecurityElement se in nps.Children) {
258                                         NamedPermissionSet n = new NamedPermissionSet ();
259                                         n.Resolver = this;
260                                         n.FromXml (se);
261                                         named_permission_sets.Add (n);
262                                 }
263                         }
264
265                         SecurityElement cg = e.SearchForChildByTag ("CodeGroup");
266                         if ((cg != null) && (cg.Children != null) && (cg.Children.Count > 0)) {
267                                 root_code_group = CodeGroup.CreateFromXml (cg, this);
268                         }
269                         else
270                                 throw new ArgumentException (Locale.GetText ("Missing Root CodeGroup"));
271
272                         SecurityElement fta = e.SearchForChildByTag ("FullTrustAssemblies");
273                         if ((fta != null) && (fta.Children != null) && (fta.Children.Count > 0)) {
274                                 full_trust_assemblies.Clear ();
275                                 foreach (SecurityElement se in fta.Children) {
276                                         if (se.Tag != "IMembershipCondition")
277                                                 throw new ArgumentException (Locale.GetText ("Invalid XML"));
278                                         string className = se.Attribute ("class");
279                                         if (className.IndexOf ("StrongNameMembershipCondition") < 0)
280                                                 throw new ArgumentException (Locale.GetText ("Invalid XML - must be StrongNameMembershipCondition"));
281                                         // we directly use StrongNameMembershipCondition
282                                         full_trust_assemblies.Add (new StrongNameMembershipCondition (se));
283                                 }
284                         }
285                 }
286
287                 public NamedPermissionSet GetNamedPermissionSet (string name)
288                 {
289                         if (name == null)
290                                 throw new ArgumentNullException ("name");
291
292                         foreach (NamedPermissionSet n in named_permission_sets) {
293                                 if (n.Name == name)
294                                         return (NamedPermissionSet) n.Copy ();
295                         }
296                         return null;
297                 }
298
299                 [MonoTODO]
300                 public void Recover ()
301                 {
302                         throw new NotImplementedException ();
303                 }
304
305                 public void RemoveFullTrustAssembly (StrongName sn)
306                 {
307                         if (sn == null)
308                                 throw new ArgumentNullException ("sn");
309
310                         StrongNameMembershipCondition s = new StrongNameMembershipCondition (sn.PublicKey, sn.Name, sn.Version);
311                         RemoveFullTrustAssembly (s);
312                 }
313
314                 public void RemoveFullTrustAssembly (StrongNameMembershipCondition snMC)
315                 {
316                         if (snMC == null)
317                                 throw new ArgumentNullException ("snMC");
318
319                         if (((IList) full_trust_assemblies).Contains (snMC))
320                                 ((IList) full_trust_assemblies).Remove (snMC);
321
322                         else
323                                 throw new ArgumentException (
324                                         Locale.GetText ("sn does not have full trust."));
325                 }
326
327                 public NamedPermissionSet RemoveNamedPermissionSet (NamedPermissionSet permSet)
328                 {
329                         if (permSet == null)
330                                 throw new ArgumentNullException ("permSet");
331
332                         if (! ((IList )named_permission_sets).Contains (permSet))
333                                 throw new ArgumentException (
334                                         Locale.GetText ("permSet cannot be found."));
335
336                         ((IList) named_permission_sets).Remove (permSet);
337
338                         return permSet;
339                 }
340
341                 [MonoTODO ("Check for reserved names")]
342                 public NamedPermissionSet RemoveNamedPermissionSet (string name)
343                 {
344                         if (name == null)
345                                 throw new ArgumentNullException ("name");
346
347                         foreach (NamedPermissionSet nps in named_permission_sets) {
348                                 if (name == nps.Name) {
349                                         named_permission_sets.Remove (nps);
350                                         return nps;
351                                 }
352                         }
353                         string msg = String.Format (Locale.GetText ("Name '{0}' cannot be found."), name);
354                         throw new ArgumentException (msg, "name");
355                 }
356
357                 public void Reset ()
358                 {
359                         if (fullNames != null)
360                                 fullNames.Clear ();
361                         full_trust_assemblies.Clear ();
362                         named_permission_sets.Clear ();
363
364                         if (_type != PolicyLevelType.AppDomain) {
365                                 // because the policy doesn't exist LoadFromFile will try to
366                                 // 1. use the .default file if existing (like Fx 2.0 does); or
367                                 // 2. use the hard-coded default values
368                                 // and recreate a policy file
369                                 if ((_location != null) && (File.Exists (_location))) {
370                                         try {
371                                                 File.Delete (_location);
372                                         }
373                                         catch {}
374                                 }
375                                 LoadFromFile (_location);
376                         }
377                         else {
378                                 named_permission_sets.Add (new NamedPermissionSet ("LocalIntranet"));
379                                 named_permission_sets.Add (new NamedPermissionSet ("Internet"));
380                                 named_permission_sets.Add (new NamedPermissionSet ("SkipVerification"));
381                                 named_permission_sets.Add (new NamedPermissionSet ("Execution"));
382                                 named_permission_sets.Add (new NamedPermissionSet ("Nothing"));
383                                 named_permission_sets.Add (new NamedPermissionSet ("Everything"));
384                                 named_permission_sets.Add (new NamedPermissionSet ("FullTrust"));
385                         }
386                 }
387
388                 public PolicyStatement Resolve (Evidence evidence)
389                 {
390                         if (evidence == null)
391                                 throw new ArgumentNullException ("evidence");
392
393                         PolicyStatement ps = root_code_group.Resolve (evidence);
394                         return ((ps != null) ? ps : PolicyStatement.Empty ());
395                 }
396
397                 public CodeGroup ResolveMatchingCodeGroups (Evidence evidence)
398                 {
399                         if (evidence == null)
400                                 throw new ArgumentNullException ("evidence");
401
402                         CodeGroup cg = root_code_group.ResolveMatchingCodeGroups (evidence);
403                         // TODO
404                         return ((cg != null) ? cg : null);
405
406                 }
407
408                 public SecurityElement ToXml ()
409                 {
410                         Hashtable fullNames = new Hashtable ();
411                         // only StrongNameMembershipCondition so no need to loop
412                         if (full_trust_assemblies.Count > 0) {
413                                 if (!fullNames.Contains ("StrongNameMembershipCondition")) {
414                                         fullNames.Add ("StrongNameMembershipCondition", typeof (StrongNameMembershipCondition).FullName);
415                                 }
416                         }
417                         
418                         SecurityElement namedPSs = new SecurityElement ("NamedPermissionSets");
419                         foreach (NamedPermissionSet nps in named_permission_sets) {
420                                 SecurityElement se = nps.ToXml ();
421                                 object objectClass = se.Attributes ["class"];
422                                 if (!fullNames.Contains (objectClass)) {
423                                         fullNames.Add (objectClass, nps.GetType ().FullName);
424                                 }
425                                 namedPSs.AddChild (se);
426                         }
427
428                         SecurityElement fta = new SecurityElement ("FullTrustAssemblies");
429                         foreach (StrongNameMembershipCondition snmc in full_trust_assemblies) {
430                                 fta.AddChild (snmc.ToXml (this));
431                         }
432
433                         SecurityElement security_classes = new SecurityElement ("SecurityClasses");
434                         if (fullNames.Count > 0) {
435                                 foreach (DictionaryEntry de in fullNames) {
436                                         SecurityElement sc = new SecurityElement ("SecurityClass");
437                                         sc.AddAttribute ("Name", (string)de.Key);
438                                         sc.AddAttribute ("Description", (string)de.Value);
439                                         security_classes.AddChild (sc);
440                                 }
441                         }
442
443                         SecurityElement element = new SecurityElement (typeof (System.Security.Policy.PolicyLevel).Name);
444                         element.AddAttribute ("version", "1");
445                         element.AddChild (security_classes);
446                         element.AddChild (namedPSs);
447                         if (root_code_group != null) {
448                                 element.AddChild (root_code_group.ToXml (this));
449                         }
450                         element.AddChild (fta);
451
452                         return element;
453                 }
454
455                 // internal stuff
456
457                 internal bool IsReserved (string name) 
458                 {
459                         switch (name) {
460                                 case "FullTrust":
461                                 case "LocalIntranet":
462                                 case "Internet":
463                                 case "SkipVerification":
464                                 case "Execution":
465                                 case "Nothing":
466                                 case "Everything":
467                                         // FIXME: Are there others ?
468                                         return true;
469                                 default:
470                                         return false;
471                         }
472                 }
473
474                 // NOTE: Callers are expected to check for ControlPolicy
475                 internal void Save ()
476                 {
477                         if (_type == PolicyLevelType.AppDomain) {
478                                 throw new PolicyException (Locale.GetText (
479                                         "Can't save AppDomain PolicyLevel"));
480                         }
481
482                         if (_location != null) {
483                                 using (StreamWriter sw = new StreamWriter (_location)) {
484                                         sw.Write (ToXml ().ToString ());
485                                         sw.Close ();
486                                 }
487                         }
488                 }
489
490                 // TODO : hardcode defaults in case 
491                 // (a) the specified policy file doesn't exists; and
492                 // (b) no corresponding default policy file exists
493                 internal void CreateFromHardcodedDefault (PolicyLevelType type) 
494                 {
495                         PolicyStatement psu = new PolicyStatement (new PermissionSet (PermissionState.Unrestricted));
496
497                         switch (type) {
498                         case PolicyLevelType.Machine:
499                                 // by default all stuff is in the machine policy...
500                                 root_code_group = new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone.MyComputer), psu);
501                                 root_code_group.Name = "All_Code";
502                                 break;
503                         case PolicyLevelType.User:
504                         case PolicyLevelType.Enterprise:
505                         case PolicyLevelType.AppDomain:
506                                 // while the other policies don't restrict anything
507                                 root_code_group = new UnionCodeGroup (new AllMembershipCondition (), psu); 
508                                 root_code_group.Name = "All_Code";
509                                 break;
510                         }
511                 }
512
513                 internal string ResolveClassName (string className)
514                 {
515                         if (fullNames != null) {
516                                 object name = fullNames [className];
517                                 if (name != null)
518                                         return (string) name;
519                         }
520                         return className;
521                 }
522         }
523 }