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
.Security
.Permissions
;
42 namespace System
.Security
.Policy
{
45 public sealed class PolicyLevel
{
48 CodeGroup root_code_group
;
49 private ArrayList full_trust_assemblies
;
50 private ArrayList named_permission_sets
;
51 private string _location
;
52 private PolicyLevelType _type
;
53 private Hashtable fullNames
;
55 internal PolicyLevel (string label
, PolicyLevelType type
)
59 full_trust_assemblies
= new ArrayList ();
60 named_permission_sets
= new ArrayList ();
63 internal PolicyLevel (string label
, PolicyLevelType type
, string filename
)
66 LoadFromFile (filename
);
69 internal void LoadFromFile (string filename
)
73 // check for policy file
74 if (!File
.Exists (filename
)) {
75 // if it doesn't exist use the default configuration (like Fx 2.0)
76 // ref: http://blogs.msdn.com/shawnfa/archive/2004/04/21/117833.aspx
77 string defcfg
= filename
+ ".default";
78 if (File
.Exists (defcfg
)) {
79 // create policy from default file
80 File
.Copy (defcfg
, filename
);
83 // load security policy configuration
84 if (File
.Exists (filename
)) {
85 using (StreamReader sr
= File
.OpenText (filename
)) {
86 LoadFromString (sr
.ReadToEnd ());
91 CreateFromHardcodedDefault (_type
);
97 // this can fail in many ways include
98 // * can't lookup policy (path discovery);
99 // * can't copy default file to policy
100 // * can't read policy file;
101 // * can't save hardcoded policy to filename
102 // * can't decode policy file
104 CreateFromHardcodedDefault (_type
);
107 _location
= filename
;
111 internal void LoadFromString (string xml
)
113 SecurityParser parser
= new SecurityParser ();
114 parser
.LoadXml (xml
);
115 // configuration / mscorlib / security / policy / PolicyLevel
116 SecurityElement configuration
= parser
.ToXml ();
117 if (configuration
.Tag
!= "configuration")
118 throw new ArgumentException (Locale
.GetText ("missing <configuration> root element"));
119 SecurityElement mscorlib
= (SecurityElement
) configuration
.Children
[0];
120 if (mscorlib
.Tag
!= "mscorlib")
121 throw new ArgumentException (Locale
.GetText ("missing <mscorlib> tag"));
122 SecurityElement security
= (SecurityElement
) mscorlib
.Children
[0];
123 if (security
.Tag
!= "security")
124 throw new ArgumentException (Locale
.GetText ("missing <security> tag"));
125 SecurityElement policy
= (SecurityElement
) security
.Children
[0];
126 if (policy
.Tag
!= "policy")
127 throw new ArgumentException (Locale
.GetText ("missing <policy> tag"));
128 SecurityElement policyLevel
= (SecurityElement
) policy
.Children
[0];
129 FromXml (policyLevel
);
134 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; }
161 public PolicyLevelType Type
{
162 get { return _type; }
168 public void AddFullTrustAssembly (StrongName sn
)
171 throw new ArgumentNullException ("sn");
173 StrongNameMembershipCondition snMC
= new StrongNameMembershipCondition(
174 sn
.PublicKey
, sn
.Name
, sn
.Version
);
176 AddFullTrustAssembly (snMC
);
179 public void AddFullTrustAssembly (StrongNameMembershipCondition snMC
)
182 throw new ArgumentNullException ("snMC");
184 foreach (StrongNameMembershipCondition sn
in full_trust_assemblies
) {
185 if (sn
.Equals (snMC
)) {
186 throw new ArgumentException (Locale
.GetText ("sn already has full trust."));
189 full_trust_assemblies
.Add (snMC
);
192 public void AddNamedPermissionSet (NamedPermissionSet permSet
)
195 throw new ArgumentNullException ("permSet");
197 foreach (NamedPermissionSet n
in named_permission_sets
) {
198 if (permSet
.Name
== n
.Name
) {
199 throw new ArgumentException (
200 Locale
.GetText ("This NamedPermissionSet is the same an existing NamedPermissionSet."));
203 named_permission_sets
.Add (permSet
.Copy ());
206 public NamedPermissionSet
ChangeNamedPermissionSet (string name
, PermissionSet pSet
)
209 throw new ArgumentNullException ("name");
211 throw new ArgumentNullException ("pSet");
212 if (IsReserved (name
))
213 throw new ArgumentException (Locale
.GetText ("Reserved name"));
215 foreach (NamedPermissionSet n
in named_permission_sets
) {
216 if (name
== n
.Name
) {
217 named_permission_sets
.Remove (n
);
218 AddNamedPermissionSet (new NamedPermissionSet (name
, pSet
));
222 throw new ArgumentException (Locale
.GetText ("PermissionSet not found"));
225 public static PolicyLevel
CreateAppDomainLevel ()
227 NamedPermissionSet fullTrust
= new NamedPermissionSet ("FullTrust", PermissionState
.Unrestricted
);
228 UnionCodeGroup cg
= new UnionCodeGroup (new AllMembershipCondition (), new PolicyStatement (fullTrust
));
229 cg
.Name
= "All_Code";
230 PolicyLevel pl
= new PolicyLevel ("AppDomain", PolicyLevelType
.AppDomain
);
231 pl
.RootCodeGroup
= cg
;
236 public void FromXml (SecurityElement e
)
239 throw new ArgumentNullException ("e");
240 // MS doesn't throw an exception for this case
241 // if (e.Tag != "PolicyLevel")
242 // throw new ArgumentException (Locale.GetText ("Invalid XML"));
244 SecurityElement sc
= e
.SearchForChildByTag ("SecurityClasses");
245 if ((sc
!= null) && (sc
.Children
!= null) && (sc
.Children
.Count
> 0)) {
246 fullNames
= new Hashtable (sc
.Children
.Count
);
247 foreach (SecurityElement se
in sc
.Children
) {
248 fullNames
.Add (se
.Attributes
["Name"], se
.Attributes
["Description"]);
252 SecurityElement nps
= e
.SearchForChildByTag ("NamedPermissionSets");
253 if ((nps
!= null) && (nps
.Children
!= null) && (nps
.Children
.Count
> 0)) {
254 named_permission_sets
.Clear ();
255 foreach (SecurityElement se
in nps
.Children
) {
256 NamedPermissionSet n
= new NamedPermissionSet ();
259 named_permission_sets
.Add (n
);
263 SecurityElement cg
= e
.SearchForChildByTag ("CodeGroup");
264 if ((cg
!= null) && (cg
.Children
!= null) && (cg
.Children
.Count
> 0)) {
265 root_code_group
= CodeGroup
.CreateFromXml (cg
, this);
268 throw new ArgumentException (Locale
.GetText ("Missing Root CodeGroup"));
270 SecurityElement fta
= e
.SearchForChildByTag ("FullTrustAssemblies");
271 if ((fta
!= null) && (fta
.Children
!= null) && (fta
.Children
.Count
> 0)) {
272 full_trust_assemblies
.Clear ();
273 foreach (SecurityElement se
in fta
.Children
) {
274 if (se
.Tag
!= "IMembershipCondition")
275 throw new ArgumentException (Locale
.GetText ("Invalid XML"));
276 string className
= se
.Attribute ("class");
277 if (className
.IndexOf ("StrongNameMembershipCondition") < 0)
278 throw new ArgumentException (Locale
.GetText ("Invalid XML - must be StrongNameMembershipCondition"));
279 // we directly use StrongNameMembershipCondition
280 full_trust_assemblies
.Add (new StrongNameMembershipCondition (se
));
285 public NamedPermissionSet
GetNamedPermissionSet (string name
)
288 throw new ArgumentNullException ("name");
290 foreach (NamedPermissionSet n
in named_permission_sets
) {
292 return (NamedPermissionSet
) n
.Copy ();
298 public void Recover ()
300 throw new NotImplementedException ();
303 public void RemoveFullTrustAssembly (StrongName sn
)
306 throw new ArgumentNullException ("sn");
308 StrongNameMembershipCondition s
= new StrongNameMembershipCondition (sn
.PublicKey
, sn
.Name
, sn
.Version
);
309 RemoveFullTrustAssembly (s
);
312 public void RemoveFullTrustAssembly (StrongNameMembershipCondition snMC
)
315 throw new ArgumentNullException ("snMC");
317 if (((IList
) full_trust_assemblies
).Contains (snMC
))
318 ((IList
) full_trust_assemblies
).Remove (snMC
);
321 throw new ArgumentException (
322 Locale
.GetText ("sn does not have full trust."));
325 public NamedPermissionSet
RemoveNamedPermissionSet (NamedPermissionSet permSet
)
328 throw new ArgumentNullException ("permSet");
330 if (! ((IList
)named_permission_sets
).Contains (permSet
))
331 throw new ArgumentException (
332 Locale
.GetText ("permSet cannot be found."));
334 ((IList
) named_permission_sets
).Remove (permSet
);
339 [MonoTODO ("Check for reserved names")]
340 public NamedPermissionSet
RemoveNamedPermissionSet (string name
)
343 throw new ArgumentNullException ("name");
345 foreach (NamedPermissionSet nps
in named_permission_sets
) {
346 if (name
== nps
.Name
) {
347 named_permission_sets
.Remove (nps
);
351 string msg
= String
.Format (Locale
.GetText ("Name '{0}' cannot be found."), name
);
352 throw new ArgumentException (msg
, "name");
357 if (fullNames
!= null)
359 full_trust_assemblies
.Clear ();
360 named_permission_sets
.Clear ();
362 if (_type
!= PolicyLevelType
.AppDomain
) {
363 // because the policy doesn't exist LoadFromFile will try to
364 // 1. use the .default file if existing (like Fx 2.0 does); or
365 // 2. use the hard-coded default values
366 // and recreate a policy file
367 if ((_location
!= null) && (File
.Exists (_location
))) {
369 File
.Delete (_location
);
373 LoadFromFile (_location
);
376 named_permission_sets
.Add (new NamedPermissionSet ("LocalIntranet"));
377 named_permission_sets
.Add (new NamedPermissionSet ("Internet"));
378 named_permission_sets
.Add (new NamedPermissionSet ("SkipVerification"));
379 named_permission_sets
.Add (new NamedPermissionSet ("Execution"));
380 named_permission_sets
.Add (new NamedPermissionSet ("Nothing"));
381 named_permission_sets
.Add (new NamedPermissionSet ("Everything"));
382 named_permission_sets
.Add (new NamedPermissionSet ("FullTrust"));
386 public PolicyStatement
Resolve (Evidence evidence
)
388 if (evidence
== null)
389 throw new ArgumentNullException ("evidence");
391 PolicyStatement ps
= root_code_group
.Resolve (evidence
);
392 return ((ps
!= null) ? ps
: PolicyStatement
.Empty ());
395 public CodeGroup
ResolveMatchingCodeGroups (Evidence evidence
)
397 if (evidence
== null)
398 throw new ArgumentNullException ("evidence");
400 CodeGroup cg
= root_code_group
.ResolveMatchingCodeGroups (evidence
);
402 return ((cg
!= null) ? cg
: null);
406 public SecurityElement
ToXml ()
408 Hashtable fullNames
= new Hashtable ();
409 // only StrongNameMembershipCondition so no need to loop
410 if (full_trust_assemblies
.Count
> 0) {
411 if (!fullNames
.Contains ("StrongNameMembershipCondition")) {
412 fullNames
.Add ("StrongNameMembershipCondition", typeof (StrongNameMembershipCondition
).FullName
);
416 SecurityElement namedPSs
= new SecurityElement ("NamedPermissionSets");
417 foreach (NamedPermissionSet nps
in named_permission_sets
) {
418 SecurityElement se
= nps
.ToXml ();
419 object objectClass
= se
.Attributes
["class"];
420 if (!fullNames
.Contains (objectClass
)) {
421 fullNames
.Add (objectClass
, nps
.GetType ().FullName
);
423 namedPSs
.AddChild (se
);
426 SecurityElement fta
= new SecurityElement ("FullTrustAssemblies");
427 foreach (StrongNameMembershipCondition snmc
in full_trust_assemblies
) {
428 fta
.AddChild (snmc
.ToXml (this));
431 SecurityElement security_classes
= new SecurityElement ("SecurityClasses");
432 if (fullNames
.Count
> 0) {
433 foreach (DictionaryEntry de
in fullNames
) {
434 SecurityElement sc
= new SecurityElement ("SecurityClass");
435 sc
.AddAttribute ("Name", (string)de
.Key
);
436 sc
.AddAttribute ("Description", (string)de
.Value
);
437 security_classes
.AddChild (sc
);
441 SecurityElement element
= new SecurityElement (typeof (System
.Security
.Policy
.PolicyLevel
).Name
);
442 element
.AddAttribute ("version", "1");
443 element
.AddChild (security_classes
);
444 element
.AddChild (namedPSs
);
445 if (root_code_group
!= null) {
446 element
.AddChild (root_code_group
.ToXml (this));
448 element
.AddChild (fta
);
455 internal bool IsReserved (string name
)
459 case "LocalIntranet":
461 case "SkipVerification":
465 // FIXME: Are there others ?
472 // NOTE: Callers are expected to check for ControlPolicy
473 internal void Save ()
475 if (_type
== PolicyLevelType
.AppDomain
) {
476 throw new PolicyException (Locale
.GetText (
477 "Can't save AppDomain PolicyLevel"));
480 if (_location
!= null) {
481 using (StreamWriter sw
= new StreamWriter (_location
)) {
482 sw
.Write (ToXml ().ToString ());
488 // TODO : hardcode defaults in case
489 // (a) the specified policy file doesn't exists; and
490 // (b) no corresponding default policy file exists
491 internal void CreateFromHardcodedDefault (PolicyLevelType type
)
493 PolicyStatement psu
= new PolicyStatement (new PermissionSet (PermissionState
.Unrestricted
));
496 case PolicyLevelType
.Machine
:
497 // by default all stuff is in the machine policy...
498 root_code_group
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.MyComputer
), psu
);
499 root_code_group
.Name
= "All_Code";
501 case PolicyLevelType
.User
:
502 case PolicyLevelType
.Enterprise
:
503 case PolicyLevelType
.AppDomain
:
504 // while the other policies don't restrict anything
505 root_code_group
= new UnionCodeGroup (new AllMembershipCondition (), psu
);
506 root_code_group
.Name
= "All_Code";
511 internal string ResolveClassName (string className
)
513 if (fullNames
!= null) {
514 object name
= fullNames
[className
];
516 return (string) name
;