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.
36 using System
.Collections
; // for IList
37 using System
.Globalization
;
39 using System
.Reflection
;
40 using System
.Runtime
.InteropServices
;
41 using System
.Security
.Permissions
;
45 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 ());
87 SecurityManager
.ResolvingPolicyLevel
= this;
91 SecurityManager
.ResolvingPolicyLevel
= this;
94 CreateDefaultFullTrustAssemblies ();
95 CreateDefaultNamedPermissionSets ();
96 CreateDefaultLevel (_type
);
101 // this can fail in many ways including...
102 // * can't lookup policy (path discovery);
103 // * can't copy default file to policy
104 // * can't read policy file;
105 // * can't decode policy file
106 // * can't save hardcoded policy to filename
109 _location
= filename
;
113 internal void LoadFromString (string xml
)
115 FromXml (FromString (xml
));
118 private SecurityElement
FromString (string xml
)
120 SecurityParser parser
= new SecurityParser ();
121 parser
.LoadXml (xml
);
122 // configuration / mscorlib / security / policy / PolicyLevel
123 SecurityElement configuration
= parser
.ToXml ();
124 if (configuration
.Tag
!= "configuration")
125 throw new ArgumentException (Locale
.GetText ("missing <configuration> root element"));
126 SecurityElement mscorlib
= (SecurityElement
) configuration
.Children
[0];
127 if (mscorlib
.Tag
!= "mscorlib")
128 throw new ArgumentException (Locale
.GetText ("missing <mscorlib> tag"));
129 SecurityElement security
= (SecurityElement
) mscorlib
.Children
[0];
130 if (security
.Tag
!= "security")
131 throw new ArgumentException (Locale
.GetText ("missing <security> tag"));
132 SecurityElement policy
= (SecurityElement
) security
.Children
[0];
133 if (policy
.Tag
!= "policy")
134 throw new ArgumentException (Locale
.GetText ("missing <policy> tag"));
135 SecurityElement policyLevel
= (SecurityElement
) policy
.Children
[0];
141 [Obsolete ("All GACed assemblies are now fully trusted and all permissions now succeed on fully trusted code.")]
142 public IList FullTrustAssemblies
{
143 get { return full_trust_assemblies; }
146 public string Label
{
147 get { return label; }
150 public IList NamedPermissionSets
{
151 get { return named_permission_sets; }
154 public CodeGroup RootCodeGroup
{
155 get { return root_code_group; }
158 throw new ArgumentNullException ("value");
159 root_code_group
= value;
163 public string StoreLocation
{
164 get { return _location; }
168 public PolicyLevelType Type
{
169 get { return _type; }
174 [Obsolete ("All GACed assemblies are now fully trusted and all permissions now succeed on fully trusted code.")]
175 public void AddFullTrustAssembly (StrongName sn
)
178 throw new ArgumentNullException ("sn");
180 StrongNameMembershipCondition snMC
= new StrongNameMembershipCondition(
181 sn
.PublicKey
, sn
.Name
, sn
.Version
);
183 AddFullTrustAssembly (snMC
);
186 [Obsolete ("All GACed assemblies are now fully trusted and all permissions now succeed on fully trusted code.")]
187 public void AddFullTrustAssembly (StrongNameMembershipCondition snMC
)
190 throw new ArgumentNullException ("snMC");
192 foreach (StrongNameMembershipCondition sn
in full_trust_assemblies
) {
193 if (sn
.Equals (snMC
)) {
194 throw new ArgumentException (Locale
.GetText ("sn already has full trust."));
197 full_trust_assemblies
.Add (snMC
);
200 public void AddNamedPermissionSet (NamedPermissionSet permSet
)
203 throw new ArgumentNullException ("permSet");
205 foreach (NamedPermissionSet n
in named_permission_sets
) {
206 if (permSet
.Name
== n
.Name
) {
207 throw new ArgumentException (
208 Locale
.GetText ("This NamedPermissionSet is the same an existing NamedPermissionSet."));
211 named_permission_sets
.Add (permSet
.Copy ());
214 public NamedPermissionSet
ChangeNamedPermissionSet (string name
, PermissionSet pSet
)
217 throw new ArgumentNullException ("name");
219 throw new ArgumentNullException ("pSet");
220 if (DefaultPolicies
.ReservedNames
.IsReserved (name
))
221 throw new ArgumentException (Locale
.GetText ("Reserved name"));
223 foreach (NamedPermissionSet n
in named_permission_sets
) {
224 if (name
== n
.Name
) {
225 named_permission_sets
.Remove (n
);
226 AddNamedPermissionSet (new NamedPermissionSet (name
, pSet
));
230 throw new ArgumentException (Locale
.GetText ("PermissionSet not found"));
233 public static PolicyLevel
CreateAppDomainLevel ()
235 UnionCodeGroup cg
= new UnionCodeGroup (new AllMembershipCondition (), new PolicyStatement (DefaultPolicies
.FullTrust
));
236 cg
.Name
= "All_Code";
237 PolicyLevel pl
= new PolicyLevel ("AppDomain", PolicyLevelType
.AppDomain
);
238 pl
.RootCodeGroup
= cg
;
244 public void FromXml (SecurityElement e
)
247 throw new ArgumentNullException ("e");
248 // MS doesn't throw an exception for this case
249 // if (e.Tag != "PolicyLevel")
250 // throw new ArgumentException (Locale.GetText ("Invalid XML"));
252 SecurityElement sc
= e
.SearchForChildByTag ("SecurityClasses");
253 if ((sc
!= null) && (sc
.Children
!= null) && (sc
.Children
.Count
> 0)) {
254 fullNames
= new Hashtable (sc
.Children
.Count
);
255 foreach (SecurityElement se
in sc
.Children
) {
256 fullNames
.Add (se
.Attributes
["Name"], se
.Attributes
["Description"]);
260 SecurityElement fta
= e
.SearchForChildByTag ("FullTrustAssemblies");
261 if ((fta
!= null) && (fta
.Children
!= null) && (fta
.Children
.Count
> 0)) {
262 full_trust_assemblies
.Clear ();
263 foreach (SecurityElement se
in fta
.Children
) {
264 if (se
.Tag
!= "IMembershipCondition")
265 throw new ArgumentException (Locale
.GetText ("Invalid XML"));
266 string className
= se
.Attribute ("class");
267 if (className
.IndexOf ("StrongNameMembershipCondition") < 0)
268 throw new ArgumentException (Locale
.GetText ("Invalid XML - must be StrongNameMembershipCondition"));
269 // we directly use StrongNameMembershipCondition
270 full_trust_assemblies
.Add (new StrongNameMembershipCondition (se
));
274 SecurityElement cg
= e
.SearchForChildByTag ("CodeGroup");
275 if ((cg
!= null) && (cg
.Children
!= null) && (cg
.Children
.Count
> 0)) {
276 root_code_group
= CodeGroup
.CreateFromXml (cg
, this);
278 throw new ArgumentException (Locale
.GetText ("Missing Root CodeGroup"));
281 SecurityElement nps
= e
.SearchForChildByTag ("NamedPermissionSets");
282 if ((nps
!= null) && (nps
.Children
!= null) && (nps
.Children
.Count
> 0)) {
283 named_permission_sets
.Clear ();
284 foreach (SecurityElement se
in nps
.Children
) {
285 NamedPermissionSet n
= new NamedPermissionSet ();
288 named_permission_sets
.Add (n
);
293 public NamedPermissionSet
GetNamedPermissionSet (string name
)
296 throw new ArgumentNullException ("name");
298 foreach (NamedPermissionSet n
in named_permission_sets
) {
300 return (NamedPermissionSet
) n
.Copy ();
305 public void Recover ()
307 if (_location
== null) {
308 string msg
= Locale
.GetText ("Only file based policies may be recovered.");
309 throw new PolicyException (msg
);
312 string backup
= _location
+ ".backup";
313 if (!File
.Exists (backup
)) {
314 string msg
= Locale
.GetText ("No policy backup exists.");
315 throw new PolicyException (msg
);
319 File
.Copy (backup
, _location
, true);
321 catch (Exception e
) {
322 string msg
= Locale
.GetText ("Couldn't replace the policy file with it's backup.");
323 throw new PolicyException (msg
, e
);
327 [Obsolete ("All GACed assemblies are now fully trusted and all permissions now succeed on fully trusted code.")]
328 public void RemoveFullTrustAssembly (StrongName sn
)
331 throw new ArgumentNullException ("sn");
333 StrongNameMembershipCondition s
= new StrongNameMembershipCondition (sn
.PublicKey
, sn
.Name
, sn
.Version
);
334 RemoveFullTrustAssembly (s
);
337 [Obsolete ("All GACed assemblies are now fully trusted and all permissions now succeed on fully trusted code.")]
338 public void RemoveFullTrustAssembly (StrongNameMembershipCondition snMC
)
341 throw new ArgumentNullException ("snMC");
343 if (((IList
) full_trust_assemblies
).Contains (snMC
))
344 ((IList
) full_trust_assemblies
).Remove (snMC
);
347 throw new ArgumentException (
348 Locale
.GetText ("sn does not have full trust."));
351 public NamedPermissionSet
RemoveNamedPermissionSet (NamedPermissionSet permSet
)
354 throw new ArgumentNullException ("permSet");
356 return RemoveNamedPermissionSet (permSet
.Name
);
359 public NamedPermissionSet
RemoveNamedPermissionSet (string name
)
362 throw new ArgumentNullException ("name");
363 if (DefaultPolicies
.ReservedNames
.IsReserved (name
))
364 throw new ArgumentException (Locale
.GetText ("Reserved name"));
366 foreach (NamedPermissionSet nps
in named_permission_sets
) {
367 if (name
== nps
.Name
) {
368 named_permission_sets
.Remove (nps
);
372 string msg
= String
.Format (Locale
.GetText ("Name '{0}' cannot be found."), name
);
373 throw new ArgumentException (msg
, "name");
378 if (fullNames
!= null)
381 if (_type
!= PolicyLevelType
.AppDomain
) {
382 full_trust_assemblies
.Clear ();
383 named_permission_sets
.Clear ();
385 // because the policy doesn't exist LoadFromFile will try to
386 // 1. use the .default file if existing (like Fx 2.0 does); or
387 // 2. use the hard-coded default values
388 // and recreate a policy file
389 if ((_location
!= null) && (File
.Exists (_location
))) {
391 File
.Delete (_location
);
395 LoadFromFile (_location
);
397 CreateDefaultFullTrustAssemblies ();
398 CreateDefaultNamedPermissionSets ();
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
);
417 return ((cg
!= null) ? cg
: null);
420 public SecurityElement
ToXml ()
422 Hashtable fullNames
= new Hashtable ();
423 // only StrongNameMembershipCondition so no need to loop
424 if (full_trust_assemblies
.Count
> 0) {
425 if (!fullNames
.Contains ("StrongNameMembershipCondition")) {
426 fullNames
.Add ("StrongNameMembershipCondition", typeof (StrongNameMembershipCondition
).FullName
);
430 SecurityElement namedPSs
= new SecurityElement ("NamedPermissionSets");
431 foreach (NamedPermissionSet nps
in named_permission_sets
) {
432 SecurityElement se
= nps
.ToXml ();
433 object objectClass
= se
.Attributes
["class"];
434 if (!fullNames
.Contains (objectClass
)) {
435 fullNames
.Add (objectClass
, nps
.GetType ().FullName
);
437 namedPSs
.AddChild (se
);
440 SecurityElement fta
= new SecurityElement ("FullTrustAssemblies");
441 foreach (StrongNameMembershipCondition snmc
in full_trust_assemblies
) {
442 fta
.AddChild (snmc
.ToXml (this));
445 SecurityElement security_classes
= new SecurityElement ("SecurityClasses");
446 if (fullNames
.Count
> 0) {
447 foreach (DictionaryEntry de
in fullNames
) {
448 SecurityElement sc
= new SecurityElement ("SecurityClass");
449 sc
.AddAttribute ("Name", (string)de
.Key
);
450 sc
.AddAttribute ("Description", (string)de
.Value
);
451 security_classes
.AddChild (sc
);
455 SecurityElement element
= new SecurityElement (typeof (System
.Security
.Policy
.PolicyLevel
).Name
);
456 element
.AddAttribute ("version", "1");
457 element
.AddChild (security_classes
);
458 element
.AddChild (namedPSs
);
459 if (root_code_group
!= null) {
460 element
.AddChild (root_code_group
.ToXml (this));
462 element
.AddChild (fta
);
469 // NOTE: Callers are expected to check for ControlPolicy
470 internal void Save ()
472 if (_type
== PolicyLevelType
.AppDomain
) {
473 throw new PolicyException (Locale
.GetText (
474 "Can't save AppDomain PolicyLevel"));
477 if (_location
!= null) {
479 if (File
.Exists (_location
)) {
480 File
.Copy (_location
, _location
+ ".backup", true);
486 using (StreamWriter sw
= new StreamWriter (_location
)) {
487 sw
.Write (ToXml ().ToString ());
494 // Hardcode defaults in case
495 // (a) the specified policy file doesn't exists; and
496 // (b) no corresponding default policy file exists
497 internal void CreateDefaultLevel (PolicyLevelType type
)
499 PolicyStatement psu
= new PolicyStatement (DefaultPolicies
.FullTrust
);
502 case PolicyLevelType
.Machine
:
503 // by default all stuff is in the machine policy...
504 PolicyStatement psn
= new PolicyStatement (DefaultPolicies
.Nothing
);
505 root_code_group
= new UnionCodeGroup (new AllMembershipCondition (), psn
);
506 root_code_group
.Name
= "All_Code";
508 UnionCodeGroup myComputerZone
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.MyComputer
), psu
);
509 myComputerZone
.Name
= "My_Computer_Zone";
510 // TODO: strongname code group for ECMA and MS keys
511 root_code_group
.AddChild (myComputerZone
);
513 UnionCodeGroup localIntranetZone
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.Intranet
),
514 new PolicyStatement (DefaultPolicies
.LocalIntranet
));
515 localIntranetZone
.Name
= "LocalIntranet_Zone";
516 // TODO: same site / same directory
517 root_code_group
.AddChild (localIntranetZone
);
519 PolicyStatement psi
= new PolicyStatement (DefaultPolicies
.Internet
);
520 UnionCodeGroup internetZone
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.Internet
), psi
);
521 internetZone
.Name
= "Internet_Zone";
523 root_code_group
.AddChild (internetZone
);
525 UnionCodeGroup restrictedZone
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.Untrusted
), psn
);
526 restrictedZone
.Name
= "Restricted_Zone";
527 root_code_group
.AddChild (restrictedZone
);
529 UnionCodeGroup trustedZone
= new UnionCodeGroup (new ZoneMembershipCondition (SecurityZone
.Trusted
), psi
);
530 trustedZone
.Name
= "Trusted_Zone";
532 root_code_group
.AddChild (trustedZone
);
534 case PolicyLevelType
.User
:
535 case PolicyLevelType
.Enterprise
:
536 case PolicyLevelType
.AppDomain
:
537 // while the other policies don't restrict anything
538 root_code_group
= new UnionCodeGroup (new AllMembershipCondition (), psu
);
539 root_code_group
.Name
= "All_Code";
544 internal void CreateDefaultFullTrustAssemblies ()
546 // (default) assemblies that are fully trusted during policy resolution
547 full_trust_assemblies
.Clear ();
548 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("mscorlib", DefaultPolicies
.Key
.Ecma
));
549 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System", DefaultPolicies
.Key
.Ecma
));
550 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System.Data", DefaultPolicies
.Key
.Ecma
));
551 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System.DirectoryServices", DefaultPolicies
.Key
.MsFinal
));
552 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System.Drawing", DefaultPolicies
.Key
.MsFinal
));
553 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System.Messaging", DefaultPolicies
.Key
.MsFinal
));
554 full_trust_assemblies
.Add (DefaultPolicies
.FullTrustMembership ("System.ServiceProcess", DefaultPolicies
.Key
.MsFinal
));
557 internal void CreateDefaultNamedPermissionSets ()
559 named_permission_sets
.Clear ();
561 SecurityManager
.ResolvingPolicyLevel
= this;
562 named_permission_sets
.Add (DefaultPolicies
.LocalIntranet
);
563 named_permission_sets
.Add (DefaultPolicies
.Internet
);
564 named_permission_sets
.Add (DefaultPolicies
.SkipVerification
);
565 named_permission_sets
.Add (DefaultPolicies
.Execution
);
566 named_permission_sets
.Add (DefaultPolicies
.Nothing
);
567 named_permission_sets
.Add (DefaultPolicies
.Everything
);
568 named_permission_sets
.Add (DefaultPolicies
.FullTrust
);
571 SecurityManager
.ResolvingPolicyLevel
= null;
575 internal string ResolveClassName (string className
)
577 if (fullNames
!= null) {
578 object name
= fullNames
[className
];
580 return (string) name
;
585 internal bool IsFullTrustAssembly (Assembly a
)
587 AssemblyName an
= a
.UnprotectedGetName ();
588 StrongNamePublicKeyBlob snpkb
= new StrongNamePublicKeyBlob (an
.GetPublicKey ());
589 StrongNameMembershipCondition snMC
= new StrongNameMembershipCondition (snpkb
, an
.Name
, an
.Version
);
590 foreach (StrongNameMembershipCondition sn
in full_trust_assemblies
) {
591 if (sn
.Equals (snMC
)) {