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