2 // System.Security.Policy.PolicyLevel.cs
5 // Nick Drochak (ndrochak@gol.com)
6 // Duncan Mak (duncan@ximian.com)
7 // Sebastien Pouliot <sebastien@ximian.com>
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)
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:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
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.
34 using System.Collections; // for IList
35 using System.Globalization;
37 using System.Reflection;
38 using System.Runtime.InteropServices;
39 using System.Security.Permissions;
43 namespace System.Security.Policy {
49 public sealed class PolicyLevel {
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;
59 internal PolicyLevel (string label, PolicyLevelType type)
63 full_trust_assemblies = new ArrayList ();
64 named_permission_sets = new ArrayList ();
67 internal PolicyLevel (string label, PolicyLevelType type, string filename)
70 LoadFromFile (filename);
73 internal void LoadFromFile (string filename)
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);
87 // load security policy configuration
88 if (File.Exists (filename)) {
89 using (StreamReader sr = File.OpenText (filename)) {
90 LoadFromString (sr.ReadToEnd ());
95 CreateFromHardcodedDefault (_type);
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
108 CreateFromHardcodedDefault (_type);
111 _location = filename;
115 internal void LoadFromString (string xml)
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);
138 public IList FullTrustAssemblies
140 get { return full_trust_assemblies; }
143 public string Label {
144 get { return label; }
147 public IList NamedPermissionSets {
148 get { return named_permission_sets; }
151 public CodeGroup RootCodeGroup {
152 get { return root_code_group; }
155 throw new ArgumentNullException ("value");
156 root_code_group = value;
160 public string StoreLocation {
161 get { return _location; }
166 public PolicyLevelType Type {
167 get { return _type; }
173 public void AddFullTrustAssembly (StrongName sn)
176 throw new ArgumentNullException ("sn");
178 StrongNameMembershipCondition snMC = new StrongNameMembershipCondition(
179 sn.PublicKey, sn.Name, sn.Version);
181 AddFullTrustAssembly (snMC);
184 public void AddFullTrustAssembly (StrongNameMembershipCondition snMC)
187 throw new ArgumentNullException ("snMC");
189 foreach (StrongNameMembershipCondition sn in full_trust_assemblies) {
190 if (sn.Equals (snMC)) {
191 throw new ArgumentException (Locale.GetText ("sn already has full trust."));
194 full_trust_assemblies.Add (snMC);
197 public void AddNamedPermissionSet (NamedPermissionSet permSet)
200 throw new ArgumentNullException ("permSet");
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."));
208 named_permission_sets.Add (permSet.Copy ());
211 public NamedPermissionSet ChangeNamedPermissionSet (string name, PermissionSet pSet)
214 throw new ArgumentNullException ("name");
216 throw new ArgumentNullException ("pSet");
217 if (DefaultPolicies.ReservedNames.IsReserved (name))
218 throw new ArgumentException (Locale.GetText ("Reserved name"));
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));
227 throw new ArgumentException (Locale.GetText ("PermissionSet not found"));
230 public static PolicyLevel CreateAppDomainLevel ()
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;
241 public void FromXml (SecurityElement e)
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"));
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"]);
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 ();
264 named_permission_sets.Add (n);
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);
273 throw new ArgumentException (Locale.GetText ("Missing Root CodeGroup"));
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));
290 public NamedPermissionSet GetNamedPermissionSet (string name)
293 throw new ArgumentNullException ("name");
295 foreach (NamedPermissionSet n in named_permission_sets) {
297 return (NamedPermissionSet) n.Copy ();
302 public void Recover ()
304 if (_location == null) {
305 string msg = Locale.GetText ("Only file based policies may be recovered.");
306 throw new PolicyException (msg);
309 string backup = _location + ".backup";
310 if (!File.Exists (backup)) {
311 string msg = Locale.GetText ("No policy backup exists.");
312 throw new PolicyException (msg);
316 File.Copy (backup, _location, true);
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);
324 public void RemoveFullTrustAssembly (StrongName sn)
327 throw new ArgumentNullException ("sn");
329 StrongNameMembershipCondition s = new StrongNameMembershipCondition (sn.PublicKey, sn.Name, sn.Version);
330 RemoveFullTrustAssembly (s);
333 public void RemoveFullTrustAssembly (StrongNameMembershipCondition snMC)
336 throw new ArgumentNullException ("snMC");
338 if (((IList) full_trust_assemblies).Contains (snMC))
339 ((IList) full_trust_assemblies).Remove (snMC);
342 throw new ArgumentException (
343 Locale.GetText ("sn does not have full trust."));
346 public NamedPermissionSet RemoveNamedPermissionSet (NamedPermissionSet permSet)
349 throw new ArgumentNullException ("permSet");
351 return RemoveNamedPermissionSet (permSet.Name);
354 public NamedPermissionSet RemoveNamedPermissionSet (string name)
357 throw new ArgumentNullException ("name");
358 if (DefaultPolicies.ReservedNames.IsReserved (name))
359 throw new ArgumentException (Locale.GetText ("Reserved name"));
361 foreach (NamedPermissionSet nps in named_permission_sets) {
362 if (name == nps.Name) {
363 named_permission_sets.Remove (nps);
367 string msg = String.Format (Locale.GetText ("Name '{0}' cannot be found."), name);
368 throw new ArgumentException (msg, "name");
373 if (fullNames != null)
375 full_trust_assemblies.Clear ();
376 named_permission_sets.Clear ();
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))) {
385 File.Delete (_location);
389 LoadFromFile (_location);
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);
402 public PolicyStatement Resolve (Evidence evidence)
404 if (evidence == null)
405 throw new ArgumentNullException ("evidence");
407 PolicyStatement ps = root_code_group.Resolve (evidence);
408 return ((ps != null) ? ps : PolicyStatement.Empty ());
411 public CodeGroup ResolveMatchingCodeGroups (Evidence evidence)
413 if (evidence == null)
414 throw new ArgumentNullException ("evidence");
416 CodeGroup cg = root_code_group.ResolveMatchingCodeGroups (evidence);
418 return ((cg != null) ? cg : null);
422 public SecurityElement ToXml ()
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);
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);
439 namedPSs.AddChild (se);
442 SecurityElement fta = new SecurityElement ("FullTrustAssemblies");
443 foreach (StrongNameMembershipCondition snmc in full_trust_assemblies) {
444 fta.AddChild (snmc.ToXml (this));
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);
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));
464 element.AddChild (fta);
471 // NOTE: Callers are expected to check for ControlPolicy
472 internal void Save ()
474 if (_type == PolicyLevelType.AppDomain) {
475 throw new PolicyException (Locale.GetText (
476 "Can't save AppDomain PolicyLevel"));
479 if (_location != null) {
481 if (File.Exists (_location)) {
482 File.Copy (_location, _location + ".backup", true);
488 using (StreamWriter sw = new StreamWriter (_location)) {
489 sw.Write (ToXml ().ToString ());
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)
501 PolicyStatement psu = new PolicyStatement (new PermissionSet (PermissionState.Unrestricted));
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";
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";
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);
528 internal string ResolveClassName (string className)
530 if (fullNames != null) {
531 object name = fullNames [className];
533 return (string) name;