2004-08-26 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / corlib / System.Security / SecurityManager.cs
1 //
2 // System.Security.SecurityManager.cs
3 //
4 // Authors:
5 //      Nick Drochak(ndrochak@gol.com)
6 //      Sebastien Pouliot  <sebastien@ximian.com>
7 //
8 // (C) Nick Drochak
9 // Portions (C) 2004 Motus Technologies Inc. (http://www.motus.com)
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Collections;
33 using System.Globalization;
34 using System.IO;
35 using System.Reflection;
36 using System.Security.Permissions;
37 using System.Security.Policy;
38
39 using Mono.Xml;
40
41 namespace System.Security {
42
43         // Note: Using [SecurityPermissionAttribute] would be cool but triggers an error
44         // as you can't reference a custom security attribute from it's own assembly (CS0647)
45
46         public sealed class SecurityManager {
47
48                 private static bool checkExecutionRights;
49                 private static bool securityEnabled;
50                 private static object _lockObject;
51                 private static ArrayList _hierarchy;
52
53                 static SecurityManager () 
54                 {
55                         // lock(this) is bad
56                         // http://msdn.microsoft.com/library/en-us/dnaskdr/html/askgui06032003.asp?frame=true
57                         _lockObject = new object ();
58                         securityEnabled = true;
59 //                      checkExecutionRights = true;
60                 }
61
62                 private SecurityManager ()
63                 {
64                 }
65
66                 // properties
67
68                 public static bool CheckExecutionRights {
69                         get { return checkExecutionRights; }
70
71                         [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
72                         set {
73                                 // throw a SecurityException if we don't have ControlPolicy permission
74                                 checkExecutionRights = value; 
75                         }
76                 }
77
78                 public static bool SecurityEnabled {
79                         get { return securityEnabled; }
80
81                         [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
82                         set {
83                                 // throw a SecurityException if we don't have ControlPolicy permission
84                                 securityEnabled = value; 
85                         }
86                 }
87
88                 // methods
89
90 #if NET_2_0
91                 [MonoTODO]
92                 [StrongNameIdentityPermission (SecurityAction.LinkDemand, PublicKey = "0x00000000000000000400000000000000")]
93                 public static void GetZoneAndOrigin (out ArrayList zone, out ArrayList origin) 
94                 {
95                         zone = null;
96                         origin = null;
97                 }
98 #endif
99
100                 public static bool IsGranted (IPermission perm)
101                 {
102                         if (perm == null)
103                                 return true;
104                         if (!securityEnabled)
105                                 return true;
106
107                         // - Policy driven
108                         // - Only check the caller (no stack walk required)
109                         // - Not affected by overrides (like Assert, Deny and PermitOnly)
110                         return Assembly.GetCallingAssembly ().Demand (perm);
111                 }
112
113                 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
114                 public static PolicyLevel LoadPolicyLevelFromFile (string path, PolicyLevelType type)
115                 {
116                         // throw a SecurityException if we don't have ControlPolicy permission
117                         if (path == null)
118                                 throw new ArgumentNullException ("path");
119
120                         PolicyLevel pl = null;
121                         try {
122                                 pl = new PolicyLevel (type.ToString (), PolicyLevelType.AppDomain);
123                                 pl.LoadFromFile (path);
124                         }
125                         catch (Exception e) {
126                                 throw new ArgumentException (Locale.GetText ("Invalid policy XML"), e);
127                         }
128                         return pl;
129                 }
130
131                 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
132                 public static PolicyLevel LoadPolicyLevelFromString (string str, PolicyLevelType type)
133                 {
134                         // throw a SecurityException if we don't have ControlPolicy permission
135                         if (null == str)
136                                 throw new ArgumentNullException ("str");
137
138                         PolicyLevel pl = null;
139                         try {
140                                 pl = new PolicyLevel (type.ToString (), PolicyLevelType.AppDomain);
141                                 pl.LoadFromString (str);
142                         }
143                         catch (Exception e) {
144                                 throw new ArgumentException (Locale.GetText ("Invalid policy XML"), e);
145                         }
146                         return pl;
147                 }
148
149                 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
150                 public static IEnumerator PolicyHierarchy ()
151                 {
152                         // throw a SecurityException if we don't have ControlPolicy permission
153                         return Hierarchy;
154                 }
155
156                 public static PermissionSet ResolvePolicy (Evidence evidence)
157                 {
158                         // no evidence, no permission
159                         if (evidence == null)
160                                 return new PermissionSet (PermissionState.None);
161
162                         PermissionSet ps = null;
163                         // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
164                         IEnumerator ple = Hierarchy;
165                         while (ple.MoveNext ()) {
166                                 PolicyLevel pl = (PolicyLevel) ple.Current;
167                                 PolicyStatement pst = pl.Resolve (evidence);
168                                 if (pst != null) {
169                                         if (ps == null)
170                                                 ps = pst.PermissionSet;
171                                         else
172                                                 ps = ps.Intersect (pst.PermissionSet);
173         
174                                         if ((pst.Attributes & PolicyStatementAttribute.LevelFinal) == PolicyStatementAttribute.LevelFinal)
175                                                 break;
176                                 }
177                         }
178
179                         // Only host evidence are used for policy resolution
180                         IEnumerator ee = evidence.GetHostEnumerator ();
181                         while (ee.MoveNext ()) {
182                                 IIdentityPermissionFactory ipf = (ee.Current as IIdentityPermissionFactory);
183                                 if (ipf != null) {
184                                         IPermission p = ipf.CreateIdentityPermission (evidence);
185                                         ps.AddPermission (p);
186                                 }
187                         }
188
189                         return ps;
190                 }
191
192 #if NET_2_0
193                 public static PermissionSet ResolvePolicy (Evidence[] evidences)
194                 {
195                         // probably not optimal
196                         PermissionSet ps = null;
197                         foreach (Evidence evidence in evidences) {
198                                 if (ps == null)
199                                         ps = ResolvePolicy (evidence);
200                                 else
201                                         ps = ps.Intersect (ResolvePolicy (evidence));
202                         }
203                         return ps;
204                 }
205 #endif
206
207                 static private SecurityPermission _execution = new SecurityPermission (SecurityPermissionFlag.Execution);
208
209                 [MonoTODO()]
210                 public static PermissionSet ResolvePolicy (Evidence evidence, PermissionSet reqdPset, PermissionSet optPset, PermissionSet denyPset, out PermissionSet denied)
211                 {
212                         PermissionSet resolved = ResolvePolicy (evidence);
213                         // do we have the minimal permission requested by the assembly ?
214                         if ((reqdPset != null) && !reqdPset.IsSubsetOf (resolved)) {
215                                 throw new PolicyException (Locale.GetText (
216                                         "Policy doesn't grant the minimal permissions required to execute the assembly."));
217                         }
218                         // do we have the right to execute ?
219                         if (checkExecutionRights) {
220                                 // unless we have "Full Trust"...
221                                 if (!resolved.IsUnrestricted ()) {
222                                         // ... we need to find a SecurityPermission
223                                         IPermission security = resolved.GetPermission (typeof (SecurityPermission));
224                                         if (!_execution.IsSubsetOf (security)) {
225                                                 throw new PolicyException (Locale.GetText (
226                                                         "Policy doesn't grant the right to execute to the assembly."));
227                                         }
228                                 }
229                         }
230
231                         denied = denyPset;
232                         return resolved;
233                 }
234
235                 public static IEnumerator ResolvePolicyGroups (Evidence evidence)
236                 {
237                         if (evidence == null)
238                                 throw new ArgumentNullException ("evidence");
239
240                         ArrayList al = new ArrayList ();
241                         // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
242                         IEnumerator ple = Hierarchy;
243                         while (ple.MoveNext ()) {
244                                 PolicyLevel pl = (PolicyLevel) ple.Current;
245                                 CodeGroup cg = pl.ResolveMatchingCodeGroups (evidence);
246                                 al.Add (cg);
247                         }
248                         return al.GetEnumerator ();
249                 }
250
251                 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
252                 public static void SavePolicy () 
253                 {
254                         // throw a SecurityException if we don't have ControlPolicy permission
255                         IEnumerator e = Hierarchy;
256                         while (e.MoveNext ()) {
257                                 PolicyLevel level = (e.Current as PolicyLevel);
258                                 level.Save ();
259                         }
260                 }
261
262                 [SecurityPermission (SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPolicy)]
263                 public static void SavePolicyLevel (PolicyLevel level) 
264                 {
265                         // Yes this will throw a NullReferenceException, just like MS (see FDBK13121)
266                         level.Save ();
267                 }
268
269                 // private/internal stuff
270
271                 private static IEnumerator Hierarchy {
272                         get {
273                                 if (_hierarchy == null) {
274                                         lock (_lockObject) {
275                                                 InitializePolicyHierarchy ();
276                                         }
277                                 }
278                                 return _hierarchy.GetEnumerator ();
279                         }
280                 }
281
282                 private static void InitializePolicyHierarchy ()
283                 {
284                         string machinePolicyPath = Path.GetDirectoryName (Environment.GetMachineConfigPath ());
285                         string userPolicyPath = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "mono");
286
287                         ArrayList al = new ArrayList ();
288                         al.Add (new PolicyLevel ("Enterprise", PolicyLevelType.Enterprise,
289                                 Path.Combine (machinePolicyPath, "enterprisesec.config")));
290
291                         al.Add (new PolicyLevel ("Machine", PolicyLevelType.Machine,
292                                 Path.Combine (machinePolicyPath, "security.config")));
293
294                         al.Add (new PolicyLevel ("User", PolicyLevelType.User,
295                                 Path.Combine (userPolicyPath, "security.config")));
296
297                         _hierarchy = ArrayList.Synchronized (al);
298                 }
299         }
300 }