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