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 SecurityManager()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 CheckElevatedPermissions()92 internal static bool CheckElevatedPermissions () 93 { 94 return true; // always true outside Moonlight 95 } 96 97 [Conditional ("ENABLE_SANDBOX")] //?? EnsureElevatedPermissions()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")] GetZoneAndOrigin(out ArrayList zone, out ArrayList origin)111 public static void GetZoneAndOrigin (out ArrayList zone, out ArrayList origin) 112 { 113 zone = new ArrayList (); 114 origin = new ArrayList (); 115 } 116 117 [Obsolete] IsGranted(IPermission perm)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 IsGranted(Assembly a, IPermission perm)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)] LoadPolicyLevelFromFile(string path, PolicyLevelType type)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)] LoadPolicyLevelFromString(string str, PolicyLevelType type)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)] PolicyHierarchy()194 public static IEnumerator PolicyHierarchy () 195 { 196 return Hierarchy; 197 } 198 199 [Obsolete] ResolvePolicy(Evidence evidence)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")] ResolvePolicy(Evidence[] evidences)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] ResolveSystemPolicy(Evidence evidence)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] ResolvePolicy(Evidence evidence, PermissionSet reqdPset, PermissionSet optPset, PermissionSet denyPset, out PermissionSet denied)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] ResolvePolicyGroups(Evidence evidence)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)] SavePolicy()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)] SavePolicyLevel(PolicyLevel level)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 InitializePolicyHierarchy()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 ResolvePolicyLevel(ref PermissionSet ps, PolicyLevel pl, Evidence evidence)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 ResolveIdentityPermissions(PermissionSet ps, Evidence evidence)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 Decode(IntPtr permissions, int length)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 Decode(byte[] encodedPermissions)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 ThrowException(Exception ex)471 private static void ThrowException (Exception ex) 472 { 473 throw ex; 474 } 475 476 #pragma warning restore 169 477 GetStandardSandbox(Evidence evidence)478 public static PermissionSet GetStandardSandbox (Evidence evidence) 479 { 480 if (evidence == null) 481 throw new ArgumentNullException ("evidence"); 482 483 throw new NotImplementedException (); 484 } 485 CurrentThreadRequiresSecurityContextCapture()486 public static bool CurrentThreadRequiresSecurityContextCapture () 487 { 488 throw new NotImplementedException (); 489 } 490 } 491 } 492 493 #endif 494 495