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
{
47 public sealed class PolicyLevel
{
50 CodeGroup root_code_group
;
51 private ArrayList full_trust_assemblies
;
52 private ArrayList named_permission_sets
;
53 private string _location
;
54 private PolicyLevelType _type
;
55 private Hashtable fullNames
;
56 private SecurityElement xml
;
58 internal PolicyLevel (string label
, PolicyLevelType type
)
62 full_trust_assemblies
= new ArrayList ();
63 named_permission_sets
= new ArrayList ();
66 internal void LoadFromFile (string filename
)
69 // check for policy file
70 if (!File
.Exists (filename
)) {
71 // if it doesn't exist use the default configuration (like Fx 2.0)
72 // ref: http://blogs.msdn.com/shawnfa/archive/2004/04/21/117833.aspx
73 string defcfg
= filename
+ ".default";
74 if (File
.Exists (defcfg
)) {
75 // create policy from default file
76 File
.Copy (defcfg
, filename
);
79 // load security policy configuration
80 if (File
.Exists (filename
)) {
81 using (StreamReader sr
= File
.OpenText (filename
)) {
82 xml
= FromString (sr
.ReadToEnd ());
85 SecurityManager
.ResolvingPolicyLevel
= this;
89 SecurityManager
.ResolvingPolicyLevel
= this;
92 CreateDefaultFullTrustAssemblies ();
93 CreateDefaultNamedPermissionSets ();
94 CreateDefaultLevel (_type
);
99 // this can fail in many ways including...
100 // * can't lookup policy (path discovery);
101 // * can't copy default file to policy
102 // * can't read policy file;
103 // * can't decode policy file
104 // * can't save hardcoded policy to filename
107 _location
= filename
;
111 internal void LoadFromString (string xml
)
113 FromXml (FromString (xml
));
116 private SecurityElement
FromString (string xml
)
118 SecurityParser parser
= new SecurityParser ();
119 parser
.LoadXml (xml
);
120 // configuration / mscorlib / security / policy / PolicyLevel
121 SecurityElement configuration
= parser
.ToXml ();
122 if (configuration
.Tag
!= "configuration")
123 throw new ArgumentException (Locale
.GetText ("missing <configuration> root element"));
124 SecurityElement mscorlib
= (SecurityElement
) configuration
.Children
[0];
125 if (mscorlib
.Tag
!= "mscorlib")
126 throw new ArgumentException (Locale
.GetText ("missing <mscorlib> tag"));
127 SecurityElement security
= (SecurityElement
) mscorlib
.Children
[0];
128 if (security
.Tag
!= "security")
129 throw new ArgumentException (Locale
.GetText ("missing <security> tag"));
130 SecurityElement policy
= (SecurityElement
) security
.Children
[0];
131 if (policy
.Tag
!= "policy")
132 throw new ArgumentException (Locale
.GetText ("missing <policy> tag"));
133 SecurityElement policyLevel
= (SecurityElement
) policy
.Children
[0];
139 [Obsolete ("All GACed assemblies are now fully trusted and all permissions now succeed on fully trusted code.")]
140 public IList FullTrustAssemblies
{
141 get { return full_trust_assemblies; }
144 public string Label
{
145 get { return label; }
148 public IList NamedPermissionSets
{
149 get { return named_permission_sets; }
152 public CodeGroup RootCodeGroup
{
153 get { return root_code_group; }
156 throw new ArgumentNullException ("value");
157 root_code_group
= value;
161 public string StoreLocation
{
162 get { return _location; }
166 public PolicyLevelType Type
{
167 get { return _type; }
172 [Obsolete ("All GACed assemblies are now fully trusted and all permissions now succeed on fully trusted code.")]
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 [Obsolete ("All GACed assemblies are now fully trusted and all permissions now succeed on fully trusted code.")]
185 public void AddFullTrustAssembly (StrongNameMembershipCondition snMC
)
188 throw new ArgumentNullException ("snMC");
190 foreach (StrongNameMembershipCondition sn
in full_trust_assemblies
) {
191 if (sn
.Equals (snMC
)) {
192 throw new ArgumentException (Locale
.GetText ("sn already has full trust."));
195 full_trust_assemblies
.Add (snMC
);
198 public void AddNamedPermissionSet (NamedPermissionSet permSet
)
201 throw new ArgumentNullException ("permSet");
203 foreach (NamedPermissionSet n
in named_permission_sets
) {
204 if (permSet
.Name
== n
.Name
) {
205 throw new ArgumentException (
206 Locale
.GetText ("This NamedPermissionSet is the same an existing NamedPermissionSet."));
209 named_permission_sets
.Add (permSet
.Copy ());
212 public NamedPermissionSet
ChangeNamedPermissionSet (string name
, PermissionSet pSet
)
215 throw new ArgumentNullException ("name");
217 throw new ArgumentNullException ("pSet");
218 if (DefaultPolicies
.ReservedNames
.IsReserved (name
))
219 throw new ArgumentException (Locale
.GetText ("Reserved name"));
221 foreach (NamedPermissionSet n
in named_permission_sets
) {
222 if (name
== n
.Name
) {
223 named_permission_sets
.Remove (n
);
224 AddNamedPermissionSet (new NamedPermissionSet (name
, pSet
));
228 throw new ArgumentException (Locale
.GetText ("PermissionSet not found"));
231 public static PolicyLevel
CreateAppDomainLevel ()
233 UnionCodeGroup cg
= new UnionCodeGroup (new AllMembershipCondition (), new PolicyStatement (DefaultPolicies
.FullTrust
));
234 cg
.Name
= "All_Code";
235 PolicyLevel pl
= new PolicyLevel ("AppDomain", PolicyLevelType
.AppDomain
);
236 pl
.RootCodeGroup
= cg
;
242 public void FromXml (SecurityElement e
)
245 throw new ArgumentNullException ("e");
246 // MS doesn't throw an exception for this case
247 // if (e.Tag != "PolicyLevel")
248 // throw new ArgumentException (Locale.GetText ("Invalid XML"));
250 SecurityElement sc
= e
.SearchForChildByTag ("SecurityClasses");
251 if ((sc
!= null) && (sc
.Children
!= null) && (sc
.Children
.Count
> 0)) {
252 fullNames
= new Hashtable (sc
.Children
.Count
);
253 foreach (SecurityElement se
in sc
.Children
) {
254 fullNames
.Add (se
.Attributes
["Name"], se
.Attributes
["Description"]);
258 SecurityElement fta
= e
.SearchForChildByTag ("FullTrustAssemblies");
259 if ((fta
!= null) && (fta
.Children
!= null) && (fta
.Children
.Count
> 0)) {
260 full_trust_assemblies
.Clear ();
261 foreach (SecurityElement se
in fta
.Children
) {
262 if (se
.Tag
!= "IMembershipCondition")
263 throw new ArgumentException (Locale
.GetText ("Invalid XML"));
264 string className
= se
.Attribute ("class");
265 if (className
.IndexOf ("StrongNameMembershipCondition") < 0)
266 throw new ArgumentException (Locale
.GetText ("Invalid XML - must be StrongNameMembershipCondition"));
267 // we directly use StrongNameMembershipCondition
268 full_trust_assemblies
.Add (new StrongNameMembershipCondition (se
));
272 SecurityElement cg
= e
.SearchForChildByTag ("CodeGroup");
273 if ((cg
!= null) && (cg
.Children
!= null) && (cg
.Children
.Count
> 0)) {
274 root_code_group
= CodeGroup
.CreateFromXml (cg
, this);
276 throw new ArgumentException (Locale
.GetText ("Missing Root CodeGroup"));
279 SecurityElement nps
= e
.SearchForChildByTag ("NamedPermissionSets");
280 if ((nps
!= null) && (nps
.Children
!= null) && (nps
.Children
.Count
> 0)) {
281 named_permission_sets
.Clear ();
282 foreach (SecurityElement se
in nps
.Children
) {
283 NamedPermissionSet n
= new NamedPermissionSet ();
286 named_permission_sets
.Add (n
);
291 public NamedPermissionSet
GetNamedPermissionSet (string name
)
294 throw new ArgumentNullException ("name");
296 foreach (NamedPermissionSet n
in named_permission_sets
) {
298 return (NamedPermissionSet
) n
.Copy ();
303 public void Recover ()
305 if (_location
== null) {
306 string msg
= Locale
.GetText ("Only file based policies may be recovered.");
307 throw new PolicyException (msg
);
310 string backup
= _location
+ ".backup";
311 if (!File
.Exists (backup
)) {
312 string msg
= Locale
.GetText ("No policy backup exists.");
313 throw new PolicyException (msg
);
317 File
.Copy (backup
, _location
, true);
319 catch (Exception e
) {
320 string msg
= Locale
.GetText ("Couldn't replace the policy file with it's backup.");
321 throw new PolicyException (msg
, e
);
325 [Obsolete ("All GACed assemblies are now fully trusted and all permissions now succeed on fully trusted code.")]
326 public void RemoveFullTrustAssembly (StrongName sn
)
329 throw new ArgumentNullException ("sn");
331 StrongNameMembershipCondition s
= new StrongNameMembershipCondition (sn
.PublicKey
, sn
.Name
, sn
.Version
);
332 RemoveFullTrustAssembly (s
);
335 [Obsolete ("All GACed assemblies are now fully trusted and all permissions now succeed on fully trusted code.")]
336 public void RemoveFullTrustAssembly (StrongNameMembershipCondition snMC
)
339 throw new ArgumentNullException ("snMC");
341 if (((IList
) full_trust_assemblies
).Contains (snMC
))
342 ((IList
) full_trust_assemblies
).Remove (snMC
);
345 throw new ArgumentException (
346 Locale
.GetText ("sn does not have full trust."));
349 public NamedPermissionSet
RemoveNamedPermissionSet (NamedPermissionSet permSet
)
352 throw new ArgumentNullException ("permSet");
354 return RemoveNamedPermissionSet (permSet
.Name
);
357 public NamedPermissionSet
RemoveNamedPermissionSet (string name
)
360 throw new ArgumentNullException ("name");
361 if (DefaultPolicies
.ReservedNames
.IsReserved (name
))
362 throw new ArgumentException (Locale
.GetText ("Reserved name"));
364 foreach (NamedPermissionSet nps
in named_permission_sets
) {
365 if (name
== nps
.Name
) {
366 named_permission_sets
.Remove (nps
);
370 string msg
= String
.Format (Locale
.GetText ("Name '{0}' cannot be found."), name
);
371 throw new ArgumentException (msg
, "name");
376 if (fullNames
!= null)
379 if (_type
!= PolicyLevelType
.AppDomain
) {
380 full_trust_assemblies
.Clear ();
381 named_permission_sets
.Clear ();
383 // because the policy doesn't exist LoadFromFile will try to
384 // 1. use the .default file if existing (like Fx 2.0 does); or
385 // 2. use the hard-coded default values
386 // and recreate a policy file
387 if ((_location
!= null) && (File
.Exists (_location
))) {
389 File
.Delete (_location
);
393 LoadFromFile (_location
);
395 CreateDefaultFullTrustAssemblies ();
396 CreateDefaultNamedPermissionSets ();
400 public PolicyStatement
Resolve (Evidence evidence
)
402 if (evidence
== null)
403 throw new ArgumentNullException ("evidence");
405 PolicyStatement ps
= root_code_group
.Resolve (evidence
);
406 return ((ps
!= null) ? ps
: PolicyStatement
.Empty ());
409 public CodeGroup
ResolveMatchingCodeGroups (Evidence evidence
)
411 if (evidence
== null)
412 throw new ArgumentNullException ("evidence");
414 CodeGroup cg
= root_code_group
.ResolveMatchingCodeGroups (evidence
);
415 return ((cg
!= null) ? cg
: null);
418 public SecurityElement
ToXml ()
420 Hashtable fullNames
= new Hashtable ();
421 // only StrongNameMembershipCondition so no need to loop
422 if (full_trust_assemblies
.Count
> 0) {
423 if (!fullNames
.Contains ("StrongNameMembershipCondition")) {
424 fullNames
.Add ("StrongNameMembershipCondition", typeof (StrongNameMembershipCondition
).FullName
);
428 SecurityElement namedPSs
= new SecurityElement ("NamedPermissionSets");
429 foreach (NamedPermissionSet nps
in named_permission_sets
) {
430 SecurityElement se
= nps
.ToXml ();
431 object objectClass
= se
.Attributes
["class"];
432 if (!fullNames
.Contains (objectClass
)) {
433 fullNames
.Add (objectClass
, nps
.GetType ().FullName
);
435 namedPSs
.AddChild (se
);
438 SecurityElement fta
= new SecurityElement ("FullTrustAssemblies");
439 foreach (StrongNameMembershipCondition snmc
in full_trust_assemblies
) {
440 fta
.AddChild (snmc
.ToXml (this));
443 SecurityElement security_classes
= new SecurityElement ("SecurityClasses");
444 if (fullNames
.Count
> 0) {
445 foreach (DictionaryEntry de
in fullNames
) {
446 SecurityElement sc
= new SecurityElement ("SecurityClass");
447 sc
.AddAttribute ("Name", (string)de
.Key
);
448 sc
.AddAttribute ("Description", (string)de
.Value
);
449 security_classes
.AddChild (sc
);
453 SecurityElement element
= new SecurityElement (typeof (System
.Security
.Policy
.PolicyLevel
).Name
);
454 element
.AddAttribute ("version", "1");
455 element
.AddChild (security_classes
);
456 element
.AddChild (namedPSs
);
457 if (root_code_group
!= null) {
458 element
.AddChild (root_code_group
.ToXml (this));
460 element
.AddChild (fta
);
467 // NOTE: Callers are expected to check for ControlPolicy
468 internal void Save ()
470 if (_type
== PolicyLevelType
.AppDomain
) {
471 throw new PolicyException (Locale
.GetText (
472 "Can't save AppDomain PolicyLevel"));
475 if (_location
!= null) {
477 if (File
.Exists (_location
)) {
478 File
.Copy (_location
, _location
+ ".backup", true);
484 using (StreamWriter sw
= new StreamWriter (_location
)) {
485 sw
.Write (ToXml ().ToString ());
492 // Hardcode defaults in case
493 // (a) the specified policy file doesn't exists; and
494 // (b) no corresponding default policy file exists
495 internal void CreateDefaultLevel (PolicyLevelType type
)
497 PolicyStatement psu
= new PolicyStatement (DefaultPolicies
.FullTrust
);
500 case PolicyLevelType
.Machine
:
501 // by default all stuff is in the machine policy...
502 PolicyStatement psn
= new PolicyStatement (DefaultPolicies
.Nothing
);
503 root_code_group
= new UnionCodeGroup (new AllMembershipCondition (), psn
);
504 root_code_group
.Name
= "All_Code";
506 UnionCodeGroup myComputerZone
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.MyComputer
), psu
);
507 myComputerZone
.Name
= "My_Computer_Zone";
508 // TODO: strongname code group for ECMA and MS keys
509 root_code_group
.AddChild (myComputerZone
);
511 UnionCodeGroup localIntranetZone
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.Intranet
),
512 new PolicyStatement (DefaultPolicies
.LocalIntranet
));
513 localIntranetZone
.Name
= "LocalIntranet_Zone";
514 // TODO: same site / same directory
515 root_code_group
.AddChild (localIntranetZone
);
517 PolicyStatement psi
= new PolicyStatement (DefaultPolicies
.Internet
);
518 UnionCodeGroup internetZone
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.Internet
), psi
);
519 internetZone
.Name
= "Internet_Zone";
521 root_code_group
.AddChild (internetZone
);
523 UnionCodeGroup restrictedZone
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.Untrusted
), psn
);
524 restrictedZone
.Name
= "Restricted_Zone";
525 root_code_group
.AddChild (restrictedZone
);
527 UnionCodeGroup trustedZone
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.Trusted
), psi
);
528 trustedZone
.Name
= "Trusted_Zone";
530 root_code_group
.AddChild (trustedZone
);
532 case PolicyLevelType
.User
:
533 case PolicyLevelType
.Enterprise
:
534 case PolicyLevelType
.AppDomain
:
535 // while the other policies don't restrict anything
536 root_code_group
= new UnionCodeGroup (new AllMembershipCondition (), psu
);
537 root_code_group
.Name
= "All_Code";
542 internal void CreateDefaultFullTrustAssemblies ()
544 // (default) assemblies that are fully trusted during policy resolution
545 full_trust_assemblies
.Clear ();
546 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("mscorlib", DefaultPolicies
.Key
.Ecma
));
547 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System", DefaultPolicies
.Key
.Ecma
));
548 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System.Data", DefaultPolicies
.Key
.Ecma
));
549 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System.DirectoryServices", DefaultPolicies
.Key
.MsFinal
));
550 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System.Drawing", DefaultPolicies
.Key
.MsFinal
));
551 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System.Messaging", DefaultPolicies
.Key
.MsFinal
));
552 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System.ServiceProcess", DefaultPolicies
.Key
.MsFinal
));
555 internal void CreateDefaultNamedPermissionSets ()
557 named_permission_sets
.Clear ();
559 SecurityManager
.ResolvingPolicyLevel
= this;
560 named_permission_sets
.Add (DefaultPolicies
.LocalIntranet
);
561 named_permission_sets
.Add (DefaultPolicies
.Internet
);
562 named_permission_sets
.Add (DefaultPolicies
.SkipVerification
);
563 named_permission_sets
.Add (DefaultPolicies
.Execution
);
564 named_permission_sets
.Add (DefaultPolicies
.Nothing
);
565 named_permission_sets
.Add (DefaultPolicies
.Everything
);
566 named_permission_sets
.Add (DefaultPolicies
.FullTrust
);
569 SecurityManager
.ResolvingPolicyLevel
= null;
573 internal string ResolveClassName (string className
)
575 if (fullNames
!= null) {
576 object name
= fullNames
[className
];
578 return (string) name
;
583 internal bool IsFullTrustAssembly (Assembly a
)
585 AssemblyName an
= a
.GetName ();
586 StrongNamePublicKeyBlob snpkb
= new StrongNamePublicKeyBlob (an
.GetPublicKey ());
587 StrongNameMembershipCondition snMC
= new StrongNameMembershipCondition (snpkb
, an
.Name
, an
.Version
);
588 foreach (StrongNameMembershipCondition sn
in full_trust_assemblies
) {
589 if (sn
.Equals (snMC
)) {