Merge pull request #3418 from BrzVlad/fix-arm64-finalizer-wait
[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-2005 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 #if !MOBILE
33
34 using System.Collections;
35 using System.Diagnostics;
36 using System.Globalization;
37 using System.IO;
38 using System.Reflection;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.InteropServices;
41 using System.Security.Permissions;
42 using System.Security.Policy;
43 using System.Text;
44
45 using Mono.Xml;
46
47 namespace System.Security {
48
49         // Must match MonoDeclSecurityActions in /mono/metadata/reflection.h
50         internal struct RuntimeDeclSecurityActions {
51                 public RuntimeDeclSecurityEntry cas;
52                 public RuntimeDeclSecurityEntry noncas;
53                 public RuntimeDeclSecurityEntry choice;
54         }
55
56         [ComVisible (true)]
57         public static class SecurityManager {
58                 private static object _lockObject;
59                 private static ArrayList _hierarchy;
60                 private static IPermission _unmanagedCode;
61                 private static Hashtable _declsecCache;
62                 private static PolicyLevel _level;
63
64                 static SecurityManager () 
65                 {
66                         // lock(this) is bad
67                         // http://msdn.microsoft.com/library/en-us/dnaskdr/html/askgui06032003.asp?frame=true
68                         _lockObject = new object ();
69                 }
70
71                 // properties
72
73                 [Obsolete]
74                 public static bool CheckExecutionRights {
75                         get {
76                                 return false;
77                         }
78                         set {
79                         }
80                 }
81
82                 [Obsolete ("The security manager cannot be turned off on MS runtime")]
83                 extern public static bool SecurityEnabled {
84                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
85                         get;
86
87                         [MethodImplAttribute (MethodImplOptions.InternalCall)]
88                         [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
89                         set;
90                 }
91
92                 internal static bool CheckElevatedPermissions ()
93                 {
94                         return true; // always true outside Moonlight
95                 }
96
97                 [Conditional ("ENABLE_SANDBOX")] //??
98                 internal static void EnsureElevatedPermissions ()
99                 {
100                         // do nothing outside of Moonlight
101                 }
102
103                 // methods
104
105                 // NOTE: This method doesn't show in the class library status page because
106                 // it cannot be "found" with the StrongNameIdentityPermission for ECMA key.
107                 // But it's there!
108                 // FIXME works for fulltrust (empty), documentation doesn't really make sense, type wise
109                 [MonoTODO ("CAS support is experimental (and unsupported). This method only works in FullTrust.")]
110                 [StrongNameIdentityPermission (SecurityAction.LinkDemand, PublicKey = "0x00000000000000000400000000000000")]
111                 public static void GetZoneAndOrigin (out ArrayList zone, out ArrayList origin) 
112                 {
113                         zone = new ArrayList ();
114                         origin = new ArrayList ();
115                 }
116
117                 [Obsolete]
118                 public static bool IsGranted (IPermission perm)
119                 {
120                         if (perm == null)
121                                 return true;
122                         if (!SecurityEnabled)
123                                 return true;
124
125                         // - Policy driven
126                         // - Only check the caller (no stack walk required)
127                         // - Not affected by overrides (like Assert, Deny and PermitOnly)
128                         // - calls IsSubsetOf even for non CAS permissions
129                         //   (i.e. it does call Demand so any code there won't be executed)
130                         // with 2.0 identity permission are unrestrictable
131                         return IsGranted (Assembly.GetCallingAssembly (), perm);
132                 }
133
134                 // note: in 2.0 *all* permissions (including identity permissions) support unrestricted
135                 internal static bool IsGranted (Assembly a, IPermission perm)
136                 {
137                         PermissionSet granted = a.GrantedPermissionSet;
138                         if ((granted != null) && !granted.IsUnrestricted ()) {
139                                 CodeAccessPermission grant = (CodeAccessPermission) granted.GetPermission (perm.GetType ());
140                                 if (!perm.IsSubsetOf (grant)) {
141                                         return false;
142                                 }
143                         }
144
145                         PermissionSet denied = a.DeniedPermissionSet;
146                         if ((denied != null) && !denied.IsEmpty ()) {
147                                 if (denied.IsUnrestricted ())
148                                         return false;
149                                 CodeAccessPermission refuse = (CodeAccessPermission) a.DeniedPermissionSet.GetPermission (perm.GetType ());
150                                 if ((refuse != null) && perm.IsSubsetOf (refuse))
151                                         return false;
152                         }
153                         return true;
154                 }
155
156                 [Obsolete]
157                 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
158                 public static PolicyLevel LoadPolicyLevelFromFile (string path, PolicyLevelType type)
159                 {
160                         if (path == null)
161                                 throw new ArgumentNullException ("path");
162
163                         PolicyLevel pl = null;
164                         try {
165                                 pl = new PolicyLevel (type.ToString (), type);
166                                 pl.LoadFromFile (path);
167                         }
168                         catch (Exception e) {
169                                 throw new ArgumentException (Locale.GetText ("Invalid policy XML"), e);
170                         }
171                         return pl;
172                 }
173
174                 [Obsolete]
175                 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
176                 public static PolicyLevel LoadPolicyLevelFromString (string str, PolicyLevelType type)
177                 {
178                         if (null == str)
179                                 throw new ArgumentNullException ("str");
180
181                         PolicyLevel pl = null;
182                         try {
183                                 pl = new PolicyLevel (type.ToString (), type);
184                                 pl.LoadFromString (str);
185                         }
186                         catch (Exception e) {
187                                 throw new ArgumentException (Locale.GetText ("Invalid policy XML"), e);
188                         }
189                         return pl;
190                 }
191
192                 [Obsolete]
193                 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
194                 public static IEnumerator PolicyHierarchy ()
195                 {
196                         return Hierarchy;
197                 }
198
199                 [Obsolete]
200                 public static PermissionSet ResolvePolicy (Evidence evidence)
201                 {
202                         // no evidence, no permission
203                         if (evidence == null)
204                                 return new PermissionSet (PermissionState.None);
205
206                         PermissionSet ps = null;
207                         // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
208                         IEnumerator ple = Hierarchy;
209                         while (ple.MoveNext ()) {
210                                 PolicyLevel pl = (PolicyLevel) ple.Current;
211                                 if (ResolvePolicyLevel (ref ps, pl, evidence)) {
212                                         break;  // i.e. PolicyStatementAttribute.LevelFinal
213                                 }
214                         }
215
216                         ResolveIdentityPermissions (ps, evidence);
217
218                         return ps;
219                 }
220
221                 [Obsolete]
222                 [MonoTODO ("(2.0) more tests are needed")]
223                 public static PermissionSet ResolvePolicy (Evidence[] evidences)
224                 {
225                         if ((evidences == null) || (evidences.Length == 0) ||
226                                 ((evidences.Length == 1) && (evidences [0].Count == 0))) {
227                                 return new PermissionSet (PermissionState.None);
228                         }
229
230                         // probably not optimal
231                         PermissionSet ps = ResolvePolicy (evidences [0]);
232                         for (int i=1; i < evidences.Length; i++) {
233                                 ps = ps.Intersect (ResolvePolicy (evidences [i]));
234                         }
235                         return ps;
236                 }
237
238                 [Obsolete]
239                 public static PermissionSet ResolveSystemPolicy (Evidence evidence)
240                 {
241                         // no evidence, no permission
242                         if (evidence == null)
243                                 return new PermissionSet (PermissionState.None);
244
245                         // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
246                         PermissionSet ps = null;
247                         IEnumerator ple = Hierarchy;
248                         while (ple.MoveNext ()) {
249                                 PolicyLevel pl = (PolicyLevel) ple.Current;
250                                 if (pl.Type == PolicyLevelType.AppDomain)
251                                         break;
252                                 if (ResolvePolicyLevel (ref ps, pl, evidence))
253                                         break;  // i.e. PolicyStatementAttribute.LevelFinal
254                         }
255
256                         ResolveIdentityPermissions (ps, evidence);
257                         return ps;
258                 }
259
260                 static private SecurityPermission _execution = new SecurityPermission (SecurityPermissionFlag.Execution);
261
262                 [Obsolete]
263                 public static PermissionSet ResolvePolicy (Evidence evidence, PermissionSet reqdPset, PermissionSet optPset, PermissionSet denyPset, out PermissionSet denied)
264                 {
265                         PermissionSet resolved = ResolvePolicy (evidence);
266                         // do we have the minimal permission requested by the assembly ?
267                         if ((reqdPset != null) && !reqdPset.IsSubsetOf (resolved)) {
268                                 throw new PolicyException (Locale.GetText (
269                                         "Policy doesn't grant the minimal permissions required to execute the assembly."));
270                         }
271
272                         // do we check for execution rights ?
273                         if (CheckExecutionRights) {
274                                 bool execute = false;
275                                 // an empty permissionset doesn't include Execution
276                                 if (resolved != null) {
277                                         // unless we have "Full Trust"...
278                                         if (resolved.IsUnrestricted ()) {
279                                                 execute = true;
280                                         } else {
281                                                 // ... we need to find a SecurityPermission
282                                                 IPermission security = resolved.GetPermission (typeof (SecurityPermission));
283                                                 execute = _execution.IsSubsetOf (security);
284                                         }
285                                 }
286
287                                 if (!execute) {
288                                         throw new PolicyException (Locale.GetText (
289                                                 "Policy doesn't grant the right to execute the assembly."));
290                                 }
291                         }
292
293                         denied = denyPset;
294                         return resolved;
295                 }
296
297                 [Obsolete]
298                 public static IEnumerator ResolvePolicyGroups (Evidence evidence)
299                 {
300                         if (evidence == null)
301                                 throw new ArgumentNullException ("evidence");
302
303                         ArrayList al = new ArrayList ();
304                         // Note: can't call PolicyHierarchy since ControlPolicy isn't required to resolve policies
305                         IEnumerator ple = Hierarchy;
306                         while (ple.MoveNext ()) {
307                                 PolicyLevel pl = (PolicyLevel) ple.Current;
308                                 CodeGroup cg = pl.ResolveMatchingCodeGroups (evidence);
309                                 al.Add (cg);
310                         }
311                         return al.GetEnumerator ();
312                 }
313
314                 [Obsolete]
315                 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
316                 public static void SavePolicy () 
317                 {
318                         IEnumerator e = Hierarchy;
319                         while (e.MoveNext ()) {
320                                 PolicyLevel level = (e.Current as PolicyLevel);
321                                 level.Save ();
322                         }
323                 }
324
325                 [Obsolete]
326                 [SecurityPermission (SecurityAction.Demand, ControlPolicy = true)]
327                 public static void SavePolicyLevel (PolicyLevel level) 
328                 {
329                         // Yes this will throw a NullReferenceException, just like MS (see FDBK13121)
330                         level.Save ();
331                 }
332
333                 // private/internal stuff
334
335                 private static IEnumerator Hierarchy {
336                         get {
337                                 lock (_lockObject) {
338                                         if (_hierarchy == null)
339                                                 InitializePolicyHierarchy ();
340                                 }
341                                 return _hierarchy.GetEnumerator ();
342                         }
343                 }
344
345                 private static void InitializePolicyHierarchy ()
346                 {
347                         string machinePolicyPath = Path.GetDirectoryName (Environment.GetMachineConfigPath ());
348                         // note: use InternalGetFolderPath to avoid recursive policy initialization
349                         string userPolicyPath = Path.Combine (Environment.UnixGetFolderPath (Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create), "mono");
350
351                         PolicyLevel enterprise = new PolicyLevel ("Enterprise", PolicyLevelType.Enterprise);
352                         _level = enterprise;
353                         enterprise.LoadFromFile (Path.Combine (machinePolicyPath, "enterprisesec.config"));
354
355                         PolicyLevel machine = new PolicyLevel ("Machine", PolicyLevelType.Machine);
356                         _level = machine;
357                         machine.LoadFromFile (Path.Combine (machinePolicyPath, "security.config"));
358
359                         PolicyLevel user = new PolicyLevel ("User", PolicyLevelType.User);
360                         _level = user;
361                         user.LoadFromFile (Path.Combine (userPolicyPath, "security.config"));
362
363                         ArrayList al = new ArrayList ();
364                         al.Add (enterprise);
365                         al.Add (machine);
366                         al.Add (user);
367
368                         _hierarchy = ArrayList.Synchronized (al);
369                         _level = null;
370                 }
371
372                 internal static bool ResolvePolicyLevel (ref PermissionSet ps, PolicyLevel pl, Evidence evidence)
373                 {
374                         PolicyStatement pst = pl.Resolve (evidence);
375                         if (pst != null) {
376                                 if (ps == null) {
377                                         // only for initial (first) policy level processed
378                                         ps = pst.PermissionSet;
379                                 } else {
380                                         ps = ps.Intersect (pst.PermissionSet);
381                                         if (ps == null) {
382                                                 // null is equals to None - exist that null can throw NullReferenceException ;-)
383                                                 ps = new PermissionSet (PermissionState.None);
384                                         }
385                                 }
386
387                                 if ((pst.Attributes & PolicyStatementAttribute.LevelFinal) == PolicyStatementAttribute.LevelFinal)
388                                         return true;
389                         }
390                         return false;
391                 }
392
393                 internal static void ResolveIdentityPermissions (PermissionSet ps, Evidence evidence)
394                 {
395                         // in 2.0 identity permissions can now be unrestricted
396                         if (ps.IsUnrestricted ())
397                                 return;
398
399                         // Only host evidence are used for policy resolution
400                         IEnumerator ee = evidence.GetHostEnumerator ();
401                         while (ee.MoveNext ()) {
402                                 IIdentityPermissionFactory ipf = (ee.Current as IIdentityPermissionFactory);
403                                 if (ipf != null) {
404                                         IPermission p = ipf.CreateIdentityPermission (evidence);
405                                         ps.AddPermission (p);
406                                 }
407                         }
408                 }
409
410                 internal static PolicyLevel ResolvingPolicyLevel {
411                         get { return _level; }
412                         set { _level = value; }
413                 }
414
415                 internal static PermissionSet Decode (IntPtr permissions, int length)
416                 {
417                         // Permission sets from the runtime (declarative security) can be cached
418                         // for performance as they can never change (i.e. they are read-only).
419                         PermissionSet ps = null;
420
421                         lock (_lockObject) {
422                                 if (_declsecCache == null) {
423                                         _declsecCache = new Hashtable ();
424                                 }
425
426                                 object key = (object) (int) permissions;
427                                 ps = (PermissionSet) _declsecCache [key];
428                                 if (ps == null) {
429                                         // create permissionset and add it to the cache
430                                         byte[] data = new byte [length];
431                                         Marshal.Copy (permissions, data, 0, length);
432                                         ps = Decode (data);
433                                         ps.DeclarativeSecurity = true;
434                                         _declsecCache.Add (key, ps);
435                                 }
436                         }
437                         return ps;
438                 }
439
440                 internal static PermissionSet Decode (byte[] encodedPermissions)
441                 {
442                         if ((encodedPermissions == null) || (encodedPermissions.Length < 1))
443                                 throw new SecurityException ("Invalid metadata format.");
444
445                         switch (encodedPermissions [0]) {
446                         case 60:
447                                 // Fx 1.0/1.1 declarative security permissions metadata is in Unicode-encoded XML
448                                 string xml = Encoding.Unicode.GetString (encodedPermissions);
449                                 return new PermissionSet (xml);
450                         case 0x2E:
451                                 // Fx 2.0 are encoded "somewhat, but not enough, like" custom attributes
452                                 // note: we still support the older format!
453                                 return PermissionSet.CreateFromBinaryFormat (encodedPermissions);
454                         default:
455                                 throw new SecurityException (Locale.GetText ("Unknown metadata format."));
456                         }
457                 }
458
459                 private static IPermission UnmanagedCode {
460                         get {
461                                 lock (_lockObject) {
462                                         if (_unmanagedCode == null)
463                                                 _unmanagedCode = new SecurityPermission (SecurityPermissionFlag.UnmanagedCode);
464                                 }
465                                 return _unmanagedCode;
466                         }
467                 }
468
469                 // called by the runtime when CoreCLR is enabled
470
471                 private static void ThrowException (Exception ex)
472                 {
473                         throw ex;
474                 }
475
476 #pragma warning restore 169
477
478                 public static PermissionSet GetStandardSandbox (Evidence evidence)
479                 {
480                         if (evidence == null)
481                                 throw new ArgumentNullException ("evidence");
482
483                         throw new NotImplementedException ();
484                 }
485
486                 public static bool CurrentThreadRequiresSecurityContextCapture ()
487                 {
488                         throw new NotImplementedException ();
489                 }
490         }
491 }
492
493 #endif
494