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