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 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 {
46 public sealed class PolicyLevel {
49 CodeGroup root_code_group;
50 private ArrayList full_trust_assemblies;
51 private ArrayList named_permission_sets;
52 private string _location;
53 private PolicyLevelType _type;
54 private Hashtable fullNames;
56 internal PolicyLevel (string label, PolicyLevelType type)
60 full_trust_assemblies = new ArrayList ();
61 named_permission_sets = new ArrayList ();
64 internal PolicyLevel (string label, PolicyLevelType type, string filename)
67 LoadFromFile (filename);
70 internal void LoadFromFile (string filename)
74 // check for policy file
75 if (!File.Exists (filename)) {
76 // if it doesn't exist use the default configuration (like Fx 2.0)
77 // ref: http://blogs.msdn.com/shawnfa/archive/2004/04/21/117833.aspx
78 string defcfg = filename + ".default";
79 if (File.Exists (defcfg)) {
80 // create policy from default file
81 File.Copy (defcfg, filename);
84 // load security policy configuration
85 if (File.Exists (filename)) {
86 using (StreamReader sr = File.OpenText (filename)) {
87 LoadFromString (sr.ReadToEnd ());
92 CreateFromHardcodedDefault (_type);
98 // this can fail in many ways include
99 // * can't lookup policy (path discovery);
100 // * can't copy default file to policy
101 // * can't read policy file;
102 // * can't save hardcoded policy to filename
103 // * can't decode policy file
105 CreateFromHardcodedDefault (_type);
108 _location = filename;
112 internal void LoadFromString (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];
130 FromXml (policyLevel);
135 public IList FullTrustAssemblies
137 get { return full_trust_assemblies; }
140 public string Label {
141 get { return label; }
144 public IList NamedPermissionSets {
145 get { return named_permission_sets; }
148 public CodeGroup RootCodeGroup {
149 get { return root_code_group; }
152 throw new ArgumentNullException ("value");
153 root_code_group = value;
157 public string StoreLocation {
158 get { return _location; }
163 public PolicyLevelType Type {
164 get { return _type; }
170 public void AddFullTrustAssembly (StrongName sn)
173 throw new ArgumentNullException ("sn");
175 StrongNameMembershipCondition snMC = new StrongNameMembershipCondition(
176 sn.PublicKey, sn.Name, sn.Version);
178 AddFullTrustAssembly (snMC);
181 public void AddFullTrustAssembly (StrongNameMembershipCondition snMC)
184 throw new ArgumentNullException ("snMC");
186 foreach (StrongNameMembershipCondition sn in full_trust_assemblies) {
187 if (sn.Equals (snMC)) {
188 throw new ArgumentException (Locale.GetText ("sn already has full trust."));
191 full_trust_assemblies.Add (snMC);
194 public void AddNamedPermissionSet (NamedPermissionSet permSet)
197 throw new ArgumentNullException ("permSet");
199 foreach (NamedPermissionSet n in named_permission_sets) {
200 if (permSet.Name == n.Name) {
201 throw new ArgumentException (
202 Locale.GetText ("This NamedPermissionSet is the same an existing NamedPermissionSet."));
205 named_permission_sets.Add (permSet.Copy ());
208 public NamedPermissionSet ChangeNamedPermissionSet (string name, PermissionSet pSet)
211 throw new ArgumentNullException ("name");
213 throw new ArgumentNullException ("pSet");
214 if (IsReserved (name))
215 throw new ArgumentException (Locale.GetText ("Reserved name"));
217 foreach (NamedPermissionSet n in named_permission_sets) {
218 if (name == n.Name) {
219 named_permission_sets.Remove (n);
220 AddNamedPermissionSet (new NamedPermissionSet (name, pSet));
224 throw new ArgumentException (Locale.GetText ("PermissionSet not found"));
227 public static PolicyLevel CreateAppDomainLevel ()
229 NamedPermissionSet fullTrust = new NamedPermissionSet ("FullTrust", PermissionState.Unrestricted);
230 UnionCodeGroup cg = new UnionCodeGroup (new AllMembershipCondition (), new PolicyStatement (fullTrust));
231 cg.Name = "All_Code";
232 PolicyLevel pl = new PolicyLevel ("AppDomain", PolicyLevelType.AppDomain);
233 pl.RootCodeGroup = cg;
238 public void FromXml (SecurityElement e)
241 throw new ArgumentNullException ("e");
242 // MS doesn't throw an exception for this case
243 // if (e.Tag != "PolicyLevel")
244 // throw new ArgumentException (Locale.GetText ("Invalid XML"));
246 SecurityElement sc = e.SearchForChildByTag ("SecurityClasses");
247 if ((sc != null) && (sc.Children != null) && (sc.Children.Count > 0)) {
248 fullNames = new Hashtable (sc.Children.Count);
249 foreach (SecurityElement se in sc.Children) {
250 fullNames.Add (se.Attributes ["Name"], se.Attributes ["Description"]);
254 SecurityElement nps = e.SearchForChildByTag ("NamedPermissionSets");
255 if ((nps != null) && (nps.Children != null) && (nps.Children.Count > 0)) {
256 named_permission_sets.Clear ();
257 foreach (SecurityElement se in nps.Children) {
258 NamedPermissionSet n = new NamedPermissionSet ();
261 named_permission_sets.Add (n);
265 SecurityElement cg = e.SearchForChildByTag ("CodeGroup");
266 if ((cg != null) && (cg.Children != null) && (cg.Children.Count > 0)) {
267 root_code_group = CodeGroup.CreateFromXml (cg, this);
270 throw new ArgumentException (Locale.GetText ("Missing Root CodeGroup"));
272 SecurityElement fta = e.SearchForChildByTag ("FullTrustAssemblies");
273 if ((fta != null) && (fta.Children != null) && (fta.Children.Count > 0)) {
274 full_trust_assemblies.Clear ();
275 foreach (SecurityElement se in fta.Children) {
276 if (se.Tag != "IMembershipCondition")
277 throw new ArgumentException (Locale.GetText ("Invalid XML"));
278 string className = se.Attribute ("class");
279 if (className.IndexOf ("StrongNameMembershipCondition") < 0)
280 throw new ArgumentException (Locale.GetText ("Invalid XML - must be StrongNameMembershipCondition"));
281 // we directly use StrongNameMembershipCondition
282 full_trust_assemblies.Add (new StrongNameMembershipCondition (se));
287 public NamedPermissionSet GetNamedPermissionSet (string name)
290 throw new ArgumentNullException ("name");
292 foreach (NamedPermissionSet n in named_permission_sets) {
294 return (NamedPermissionSet) n.Copy ();
300 public void Recover ()
302 throw new NotImplementedException ();
305 public void RemoveFullTrustAssembly (StrongName sn)
308 throw new ArgumentNullException ("sn");
310 StrongNameMembershipCondition s = new StrongNameMembershipCondition (sn.PublicKey, sn.Name, sn.Version);
311 RemoveFullTrustAssembly (s);
314 public void RemoveFullTrustAssembly (StrongNameMembershipCondition snMC)
317 throw new ArgumentNullException ("snMC");
319 if (((IList) full_trust_assemblies).Contains (snMC))
320 ((IList) full_trust_assemblies).Remove (snMC);
323 throw new ArgumentException (
324 Locale.GetText ("sn does not have full trust."));
327 public NamedPermissionSet RemoveNamedPermissionSet (NamedPermissionSet permSet)
330 throw new ArgumentNullException ("permSet");
332 if (! ((IList )named_permission_sets).Contains (permSet))
333 throw new ArgumentException (
334 Locale.GetText ("permSet cannot be found."));
336 ((IList) named_permission_sets).Remove (permSet);
341 [MonoTODO ("Check for reserved names")]
342 public NamedPermissionSet RemoveNamedPermissionSet (string name)
345 throw new ArgumentNullException ("name");
347 foreach (NamedPermissionSet nps in named_permission_sets) {
348 if (name == nps.Name) {
349 named_permission_sets.Remove (nps);
353 string msg = String.Format (Locale.GetText ("Name '{0}' cannot be found."), name);
354 throw new ArgumentException (msg, "name");
359 if (fullNames != null)
361 full_trust_assemblies.Clear ();
362 named_permission_sets.Clear ();
364 if (_type != PolicyLevelType.AppDomain) {
365 // because the policy doesn't exist LoadFromFile will try to
366 // 1. use the .default file if existing (like Fx 2.0 does); or
367 // 2. use the hard-coded default values
368 // and recreate a policy file
369 if ((_location != null) && (File.Exists (_location))) {
371 File.Delete (_location);
375 LoadFromFile (_location);
378 named_permission_sets.Add (new NamedPermissionSet ("LocalIntranet"));
379 named_permission_sets.Add (new NamedPermissionSet ("Internet"));
380 named_permission_sets.Add (new NamedPermissionSet ("SkipVerification"));
381 named_permission_sets.Add (new NamedPermissionSet ("Execution"));
382 named_permission_sets.Add (new NamedPermissionSet ("Nothing"));
383 named_permission_sets.Add (new NamedPermissionSet ("Everything"));
384 named_permission_sets.Add (new NamedPermissionSet ("FullTrust"));
388 public PolicyStatement Resolve (Evidence evidence)
390 if (evidence == null)
391 throw new ArgumentNullException ("evidence");
393 PolicyStatement ps = root_code_group.Resolve (evidence);
394 return ((ps != null) ? ps : PolicyStatement.Empty ());
397 public CodeGroup ResolveMatchingCodeGroups (Evidence evidence)
399 if (evidence == null)
400 throw new ArgumentNullException ("evidence");
402 CodeGroup cg = root_code_group.ResolveMatchingCodeGroups (evidence);
404 return ((cg != null) ? cg : null);
408 public SecurityElement ToXml ()
410 Hashtable fullNames = new Hashtable ();
411 // only StrongNameMembershipCondition so no need to loop
412 if (full_trust_assemblies.Count > 0) {
413 if (!fullNames.Contains ("StrongNameMembershipCondition")) {
414 fullNames.Add ("StrongNameMembershipCondition", typeof (StrongNameMembershipCondition).FullName);
418 SecurityElement namedPSs = new SecurityElement ("NamedPermissionSets");
419 foreach (NamedPermissionSet nps in named_permission_sets) {
420 SecurityElement se = nps.ToXml ();
421 object objectClass = se.Attributes ["class"];
422 if (!fullNames.Contains (objectClass)) {
423 fullNames.Add (objectClass, nps.GetType ().FullName);
425 namedPSs.AddChild (se);
428 SecurityElement fta = new SecurityElement ("FullTrustAssemblies");
429 foreach (StrongNameMembershipCondition snmc in full_trust_assemblies) {
430 fta.AddChild (snmc.ToXml (this));
433 SecurityElement security_classes = new SecurityElement ("SecurityClasses");
434 if (fullNames.Count > 0) {
435 foreach (DictionaryEntry de in fullNames) {
436 SecurityElement sc = new SecurityElement ("SecurityClass");
437 sc.AddAttribute ("Name", (string)de.Key);
438 sc.AddAttribute ("Description", (string)de.Value);
439 security_classes.AddChild (sc);
443 SecurityElement element = new SecurityElement (typeof (System.Security.Policy.PolicyLevel).Name);
444 element.AddAttribute ("version", "1");
445 element.AddChild (security_classes);
446 element.AddChild (namedPSs);
447 if (root_code_group != null) {
448 element.AddChild (root_code_group.ToXml (this));
450 element.AddChild (fta);
457 internal bool IsReserved (string name)
461 case "LocalIntranet":
463 case "SkipVerification":
467 // FIXME: Are there others ?
474 // NOTE: Callers are expected to check for ControlPolicy
475 internal void Save ()
477 if (_type == PolicyLevelType.AppDomain) {
478 throw new PolicyException (Locale.GetText (
479 "Can't save AppDomain PolicyLevel"));
482 if (_location != null) {
483 using (StreamWriter sw = new StreamWriter (_location)) {
484 sw.Write (ToXml ().ToString ());
490 // TODO : hardcode defaults in case
491 // (a) the specified policy file doesn't exists; and
492 // (b) no corresponding default policy file exists
493 internal void CreateFromHardcodedDefault (PolicyLevelType type)
495 PolicyStatement psu = new PolicyStatement (new PermissionSet (PermissionState.Unrestricted));
498 case PolicyLevelType.Machine:
499 // by default all stuff is in the machine policy...
500 root_code_group = new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone.MyComputer), psu);
501 root_code_group.Name = "All_Code";
503 case PolicyLevelType.User:
504 case PolicyLevelType.Enterprise:
505 case PolicyLevelType.AppDomain:
506 // while the other policies don't restrict anything
507 root_code_group = new UnionCodeGroup (new AllMembershipCondition (), psu);
508 root_code_group.Name = "All_Code";
513 internal string ResolveClassName (string className)
515 if (fullNames != null) {
516 object name = fullNames [className];
518 return (string) name;