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;
58 private SecurityElement xml;
60 internal PolicyLevel (string label, PolicyLevelType type)
64 full_trust_assemblies = new ArrayList ();
65 named_permission_sets = new ArrayList ();
68 internal void LoadFromFile (string filename)
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);
81 // load security policy configuration
82 if (File.Exists (filename)) {
83 using (StreamReader sr = File.OpenText (filename)) {
84 xml = FromString (sr.ReadToEnd ());
88 CreateDefaultFullTrustAssemblies ();
89 CreateDefaultNamedPermissionSets ();
90 CreateDefaultLevel (_type);
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
103 _location = filename;
107 internal void LoadFromString (string xml)
109 FromXml (FromString (xml));
112 private SecurityElement FromString (string xml)
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];
135 public IList FullTrustAssemblies {
136 get { return full_trust_assemblies; }
139 public string Label {
140 get { return label; }
143 public IList NamedPermissionSets {
144 get { return named_permission_sets; }
147 public CodeGroup RootCodeGroup {
148 get { return root_code_group; }
151 throw new ArgumentNullException ("value");
152 root_code_group = value;
156 public string StoreLocation {
157 get { return _location; }
162 public PolicyLevelType Type {
163 get { return _type; }
169 public void AddFullTrustAssembly (StrongName sn)
172 throw new ArgumentNullException ("sn");
174 StrongNameMembershipCondition snMC = new StrongNameMembershipCondition(
175 sn.PublicKey, sn.Name, sn.Version);
177 AddFullTrustAssembly (snMC);
180 public void AddFullTrustAssembly (StrongNameMembershipCondition snMC)
183 throw new ArgumentNullException ("snMC");
185 foreach (StrongNameMembershipCondition sn in full_trust_assemblies) {
186 if (sn.Equals (snMC)) {
187 throw new ArgumentException (Locale.GetText ("sn already has full trust."));
190 full_trust_assemblies.Add (snMC);
193 public void AddNamedPermissionSet (NamedPermissionSet permSet)
196 throw new ArgumentNullException ("permSet");
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."));
204 named_permission_sets.Add (permSet.Copy ());
207 public NamedPermissionSet ChangeNamedPermissionSet (string name, PermissionSet pSet)
210 throw new ArgumentNullException ("name");
212 throw new ArgumentNullException ("pSet");
213 if (DefaultPolicies.ReservedNames.IsReserved (name))
214 throw new ArgumentException (Locale.GetText ("Reserved name"));
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));
223 throw new ArgumentException (Locale.GetText ("PermissionSet not found"));
226 public static PolicyLevel CreateAppDomainLevel ()
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;
237 public void FromXml (SecurityElement e)
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"));
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"]);
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));
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);
271 throw new ArgumentException (Locale.GetText ("Missing Root CodeGroup"));
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 ();
281 named_permission_sets.Add (n);
286 public NamedPermissionSet GetNamedPermissionSet (string name)
289 throw new ArgumentNullException ("name");
291 foreach (NamedPermissionSet n in named_permission_sets) {
293 return (NamedPermissionSet) n.Copy ();
298 public void Recover ()
300 if (_location == null) {
301 string msg = Locale.GetText ("Only file based policies may be recovered.");
302 throw new PolicyException (msg);
305 string backup = _location + ".backup";
306 if (!File.Exists (backup)) {
307 string msg = Locale.GetText ("No policy backup exists.");
308 throw new PolicyException (msg);
312 File.Copy (backup, _location, true);
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);
320 public void RemoveFullTrustAssembly (StrongName sn)
323 throw new ArgumentNullException ("sn");
325 StrongNameMembershipCondition s = new StrongNameMembershipCondition (sn.PublicKey, sn.Name, sn.Version);
326 RemoveFullTrustAssembly (s);
329 public void RemoveFullTrustAssembly (StrongNameMembershipCondition snMC)
332 throw new ArgumentNullException ("snMC");
334 if (((IList) full_trust_assemblies).Contains (snMC))
335 ((IList) full_trust_assemblies).Remove (snMC);
338 throw new ArgumentException (
339 Locale.GetText ("sn does not have full trust."));
342 public NamedPermissionSet RemoveNamedPermissionSet (NamedPermissionSet permSet)
345 throw new ArgumentNullException ("permSet");
347 return RemoveNamedPermissionSet (permSet.Name);
350 public NamedPermissionSet RemoveNamedPermissionSet (string name)
353 throw new ArgumentNullException ("name");
354 if (DefaultPolicies.ReservedNames.IsReserved (name))
355 throw new ArgumentException (Locale.GetText ("Reserved name"));
357 foreach (NamedPermissionSet nps in named_permission_sets) {
358 if (name == nps.Name) {
359 named_permission_sets.Remove (nps);
363 string msg = String.Format (Locale.GetText ("Name '{0}' cannot be found."), name);
364 throw new ArgumentException (msg, "name");
369 if (fullNames != null)
372 if (_type != PolicyLevelType.AppDomain) {
373 full_trust_assemblies.Clear ();
374 named_permission_sets.Clear ();
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))) {
382 File.Delete (_location);
386 LoadFromFile (_location);
388 CreateDefaultFullTrustAssemblies ();
389 CreateDefaultNamedPermissionSets ();
393 public PolicyStatement Resolve (Evidence evidence)
395 if (evidence == null)
396 throw new ArgumentNullException ("evidence");
398 PolicyStatement ps = root_code_group.Resolve (evidence);
399 return ((ps != null) ? ps : PolicyStatement.Empty ());
402 public CodeGroup ResolveMatchingCodeGroups (Evidence evidence)
404 if (evidence == null)
405 throw new ArgumentNullException ("evidence");
407 CodeGroup cg = root_code_group.ResolveMatchingCodeGroups (evidence);
408 return ((cg != null) ? cg : null);
411 public SecurityElement ToXml ()
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);
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);
428 namedPSs.AddChild (se);
431 SecurityElement fta = new SecurityElement ("FullTrustAssemblies");
432 foreach (StrongNameMembershipCondition snmc in full_trust_assemblies) {
433 fta.AddChild (snmc.ToXml (this));
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);
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));
453 element.AddChild (fta);
460 // NOTE: Callers are expected to check for ControlPolicy
461 internal void Save ()
463 if (_type == PolicyLevelType.AppDomain) {
464 throw new PolicyException (Locale.GetText (
465 "Can't save AppDomain PolicyLevel"));
468 if (_location != null) {
470 if (File.Exists (_location)) {
471 File.Copy (_location, _location + ".backup", true);
477 using (StreamWriter sw = new StreamWriter (_location)) {
478 sw.Write (ToXml ().ToString ());
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)
490 PolicyStatement psu = new PolicyStatement (DefaultPolicies.FullTrust);
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";
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);
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);
510 PolicyStatement psi = new PolicyStatement (DefaultPolicies.Internet);
511 UnionCodeGroup internetZone = new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone.Internet), psi);
512 internetZone.Name = "Internet_Zone";
514 root_code_group.AddChild (internetZone);
516 UnionCodeGroup restrictedZone = new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone.Untrusted), psn);
517 restrictedZone.Name = "Restricted_Zone";
518 root_code_group.AddChild (restrictedZone);
520 UnionCodeGroup trustedZone = new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone.Trusted), psi);
521 trustedZone.Name = "Trusted_Zone";
523 root_code_group.AddChild (trustedZone);
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";
535 internal void CreateDefaultFullTrustAssemblies ()
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));
548 internal void CreateDefaultNamedPermissionSets ()
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);
560 internal string ResolveClassName (string className)
562 if (fullNames != null) {
563 object name = fullNames [className];
565 return (string) name;
570 internal bool IsFullTrustAssembly (Assembly a)
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)) {