1 //
2 // System.AppDomainSetup.cs
3 //
4 // Authors:
5 //	Dietmar Maurer (dietmar@ximian.com)
6 //	Sebastien Pouliot  <sebastien@ximian.com>
7 //
8 // (C) 2001 Ximian, Inc.  http://www.ximian.com
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
10 //
11 // Known Problems:
12 //    	Fix serialization compatibility with MS.NET.
13 //
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:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
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.
32 //
33 
34 using System.Collections.Generic;
35 using System.IO;
36 using System.Runtime.CompilerServices;
37 using System.Runtime.InteropServices;
38 using System.Security;
39 using System.Security.Permissions;
40 using System.Runtime.Serialization.Formatters.Binary;
41 
42 using System.Runtime.Hosting;
43 using System.Security.Policy;
44 
45 namespace System
46 {
47 	[Serializable]
48 	[ClassInterface (ClassInterfaceType.None)]
49 	[ComVisible (true)]
50 	[StructLayout (LayoutKind.Sequential)]
51 #if MOBILE
52 	public sealed class AppDomainSetup
53 #else
54 	public sealed class AppDomainSetup : IAppDomainSetup
55 #endif
56 	{
57 		string application_base;
58 		string application_name;
59 		string cache_path;
60 		string configuration_file;
61 		string dynamic_base;
62 		string license_file;
63 		string private_bin_path;
64 		string private_bin_path_probe;
65 		string shadow_copy_directories;
66 		string shadow_copy_files;
67 		bool publisher_policy;
68 		private bool path_changed;
69 #if MOBILE
70 		private int loader_optimization;
71 #else
72 		private LoaderOptimization loader_optimization;
73 #endif
74 		bool disallow_binding_redirects;
75 		bool disallow_code_downloads;
76 
77 #if MOBILE
78 		object _activationArguments;
79 		object domain_initializer;
80 		object application_trust;
81 #else
82 		private ActivationArguments _activationArguments;
83 		AppDomainInitializer domain_initializer;
84 		[NonSerialized]
85 		ApplicationTrust application_trust;
86 #endif
87 		string [] domain_initializer_args;
88 
89 		bool disallow_appbase_probe;
90 		byte [] configuration_bytes;
91 
92 		byte [] serialized_non_primitives;
93 
AppDomainSetup()94 		public AppDomainSetup ()
95 		{
96 		}
97 
AppDomainSetup(AppDomainSetup setup)98 		internal AppDomainSetup (AppDomainSetup setup)
99 		{
100 			application_base = setup.application_base;
101 			application_name = setup.application_name;
102 			cache_path = setup.cache_path;
103 			configuration_file = setup.configuration_file;
104 			dynamic_base = setup.dynamic_base;
105 			license_file = setup.license_file;
106 			private_bin_path = setup.private_bin_path;
107 			private_bin_path_probe = setup.private_bin_path_probe;
108 			shadow_copy_directories = setup.shadow_copy_directories;
109 			shadow_copy_files = setup.shadow_copy_files;
110 			publisher_policy = setup.publisher_policy;
111 			path_changed = setup.path_changed;
112 			loader_optimization = setup.loader_optimization;
113 			disallow_binding_redirects = setup.disallow_binding_redirects;
114 			disallow_code_downloads = setup.disallow_code_downloads;
115 			_activationArguments = setup._activationArguments;
116 			domain_initializer = setup.domain_initializer;
117 			application_trust = setup.application_trust;
118 			domain_initializer_args = setup.domain_initializer_args;
119 			disallow_appbase_probe = setup.disallow_appbase_probe;
120 			configuration_bytes = setup.configuration_bytes;
121 		}
122 
AppDomainSetup(ActivationArguments activationArguments)123 		public AppDomainSetup (ActivationArguments activationArguments)
124 		{
125 			_activationArguments = activationArguments;
126 		}
127 
AppDomainSetup(ActivationContext activationContext)128 		public AppDomainSetup (ActivationContext activationContext)
129 		{
130 			_activationArguments = new ActivationArguments (activationContext);
131 		}
132 
GetAppBase(string appBase)133 		static string GetAppBase (string appBase)
134 		{
135 			if (appBase == null)
136 				return null;
137 
138 			int len = appBase.Length;
139 			if (len >= 8 && appBase.ToLower ().StartsWith ("file://")) {
140 				appBase = appBase.Substring (7);
141 				if (Path.DirectorySeparatorChar != '/')
142 					appBase = appBase.Replace ('/', Path.DirectorySeparatorChar);
143 			}
144 			appBase = Path.GetFullPath (appBase);
145 
146 			if (Path.DirectorySeparatorChar != '/') {
147 				bool isExtendedPath = appBase.StartsWith (@"\\?\", StringComparison.Ordinal);
148 				if (appBase.IndexOf (':', isExtendedPath ? 6 : 2) != -1) {
149 					throw new NotSupportedException ("The given path's format is not supported.");
150 				}
151 			}
152 
153 			// validate the path
154 			string dir = Path.GetDirectoryName (appBase);
155 			if ((dir != null) && (dir.LastIndexOfAny (Path.GetInvalidPathChars ()) >= 0)) {
156 				string msg = String.Format (Locale.GetText ("Invalid path characters in path: '{0}'"), appBase);
157 				throw new ArgumentException (msg, "appBase");
158 			}
159 
160 			string fname = Path.GetFileName (appBase);
161 			if ((fname != null) && (fname.LastIndexOfAny (Path.GetInvalidFileNameChars ()) >= 0)) {
162 				string msg = String.Format (Locale.GetText ("Invalid filename characters in path: '{0}'"), appBase);
163 				throw new ArgumentException (msg, "appBase");
164 			}
165 
166 			return appBase;
167 		}
168 
169 		public string ApplicationBase {
170 			get { return GetAppBase (application_base); }
171 			set { application_base = value; }
172 		}
173 
174 		public string ApplicationName {
175 			get {
176 				return application_name;
177 			}
178 			set {
179 				application_name = value;
180 			}
181 		}
182 
183 		public string CachePath {
184 			get {
185 				return cache_path;
186 			}
187 			set {
188 				cache_path = value;
189 			}
190 		}
191 
192 		public string ConfigurationFile {
193 			get {
194 				if (configuration_file == null)
195 					return null;
196 				if (Path.IsPathRooted(configuration_file))
197 					return configuration_file;
198 				if (ApplicationBase == null)
199 					throw new MemberAccessException("The ApplicationBase must be set before retrieving this property.");
200 				return Path.Combine(ApplicationBase, configuration_file);
201 			}
202 			set {
203 				configuration_file = value;
204 			}
205 		}
206 
207 		public bool DisallowPublisherPolicy {
208 			get {
209 				return publisher_policy;
210 			}
211 			set {
212 				publisher_policy = value;
213 			}
214 		}
215 
216 		public string DynamicBase {
217 			get {
218 				if (dynamic_base == null)
219 					return null;
220 
221 				if (Path.IsPathRooted (dynamic_base))
222 					return dynamic_base;
223 
224 				if (ApplicationBase == null)
225 					throw new MemberAccessException ("The ApplicationBase must be set before retrieving this property.");
226 
227 				return Path.Combine (ApplicationBase, dynamic_base);
228 			}
229 			set {
230 				if (application_name == null)
231 					throw new MemberAccessException ("ApplicationName must be set before the DynamicBase can be set.");
232 				uint id = (uint) application_name.GetHashCode ();
233 				dynamic_base = Path.Combine (value, id.ToString("x"));
234 			}
235 		}
236 
237 		public string LicenseFile {
238 			get {
239 				return license_file;
240 			}
241 			set {
242 				license_file = value;
243 			}
244 		}
245 
246 		[MonoLimitation ("In Mono this is controlled by the --share-code flag")]
247 		public LoaderOptimization LoaderOptimization {
248 			get {
249 				return (LoaderOptimization)loader_optimization;
250 			}
251 			set {
252 #if MOBILE
253 				loader_optimization = (int)value;
254 #else
255 				loader_optimization = value;
256 #endif
257 			}
258 		}
259 
260 		public string PrivateBinPath {
261 			get {
262 				return private_bin_path;
263 			}
264 			set {
265 				private_bin_path = value;
266 				path_changed = true;
267 			}
268 		}
269 
270 		public string PrivateBinPathProbe {
271 			get {
272 				return private_bin_path_probe;
273 			}
274 			set {
275 				private_bin_path_probe = value;
276 				path_changed = true;
277 			}
278 		}
279 
280 		public string ShadowCopyDirectories {
281 			get {
282 				return shadow_copy_directories;
283 			}
284 			set {
285 				shadow_copy_directories = value;
286 			}
287 		}
288 
289 		public string ShadowCopyFiles {
290 			get {
291 				return shadow_copy_files;
292 			}
293 			set {
294 				shadow_copy_files = value;
295 			}
296 		}
297 
298 		public bool DisallowBindingRedirects {
299 			get {
300 				return disallow_binding_redirects;
301 			}
302 			set {
303 				disallow_binding_redirects = value;
304 			}
305 		}
306 
307 		public bool DisallowCodeDownload {
308 			get {
309 				return disallow_code_downloads;
310 			}
311 			set {
312 				disallow_code_downloads = value;
313 			}
314 		}
315 
316 		public string TargetFrameworkName { get; set; }
317 
318 		public ActivationArguments ActivationArguments {
319 			get {
320 				if (_activationArguments != null)
321 					return (ActivationArguments)_activationArguments;
322 				DeserializeNonPrimitives ();
323 				return (ActivationArguments)_activationArguments;
324 			}
325 			set { _activationArguments = value; }
326 		}
327 
328 #if MONO_FEATURE_MULTIPLE_APPDOMAINS
329 		[MonoLimitation ("it needs to be invoked within the created domain")]
330 		public AppDomainInitializer AppDomainInitializer {
331 			get {
332 				if (domain_initializer != null)
333 					return (AppDomainInitializer)domain_initializer;
334 				DeserializeNonPrimitives ();
335 				return (AppDomainInitializer)domain_initializer;
336 			}
337 			set { domain_initializer = value; }
338 		}
339 #else
340 		[Obsolete ("AppDomainSetup.AppDomainInitializer is not supported on this platform.", true)]
341 		public AppDomainInitializer AppDomainInitializer {
342 			get { throw new PlatformNotSupportedException ("AppDomainSetup.AppDomainInitializer is not supported on this platform."); }
343 			set { throw new PlatformNotSupportedException ("AppDomainSetup.AppDomainInitializer is not supported on this platform."); }
344 		}
345 #endif // MONO_FEATURE_MULTIPLE_APPDOMAINS
346 
347 
348 		[MonoLimitation ("it needs to be used to invoke the initializer within the created domain")]
349 		public string [] AppDomainInitializerArguments {
350 			get { return domain_initializer_args; }
351 			set { domain_initializer_args = value; }
352 		}
353 
354 		[MonoNotSupported ("This property exists but not considered.")]
355 		public ApplicationTrust ApplicationTrust {
356 			get {
357 				if (application_trust != null)
358 					return (ApplicationTrust)application_trust;
359 				DeserializeNonPrimitives ();
360 				if (application_trust == null)
361 					application_trust = new ApplicationTrust ();
362 				return (ApplicationTrust)application_trust;
363 			}
364 			set { application_trust = value; }
365 		}
366 
367 		[MonoNotSupported ("This property exists but not considered.")]
368 		public bool DisallowApplicationBaseProbing {
369 			get { return disallow_appbase_probe; }
370 			set { disallow_appbase_probe = value; }
371 		}
372 
373 		[MonoNotSupported ("This method exists but not considered.")]
GetConfigurationBytes()374 		public byte [] GetConfigurationBytes ()
375 		{
376 			return configuration_bytes != null ? configuration_bytes.Clone () as byte [] : null;
377 		}
378 
379 		[MonoNotSupported ("This method exists but not considered.")]
SetConfigurationBytes(byte [] value)380 		public void SetConfigurationBytes (byte [] value)
381 		{
382 			configuration_bytes = value;
383 		}
384 
DeserializeNonPrimitives()385 		private void DeserializeNonPrimitives ()
386 		{
387 			lock (this) {
388 				if (serialized_non_primitives == null)
389 					return;
390 
391 				BinaryFormatter bf = new BinaryFormatter ();
392 				MemoryStream ms = new MemoryStream (serialized_non_primitives);
393 
394 				object [] arr = (object []) bf.Deserialize (ms);
395 
396 				_activationArguments = (ActivationArguments) arr [0];
397 #if MONO_FEATURE_MULTIPLE_APPDOMAINS
398 				domain_initializer = (AppDomainInitializer) arr [1];
399 #endif
400 				application_trust = (ApplicationTrust) arr [2];
401 
402 				serialized_non_primitives = null;
403 			}
404 		}
405 
SerializeNonPrimitives()406 		internal void SerializeNonPrimitives ()
407 		{
408 			object [] arr = new object [3];
409 
410 			arr [0] = _activationArguments;
411 			arr [1] = domain_initializer;
412 			arr [2] = application_trust;
413 
414 			BinaryFormatter bf = new BinaryFormatter ();
415 			MemoryStream ms = new MemoryStream ();
416 
417 			bf.Serialize (ms, arr);
418 
419 			serialized_non_primitives = ms.ToArray ();
420 		}
421 
422 		[MonoTODO ("not implemented, does not throw because it's used in testing moonlight")]
SetCompatibilitySwitches(IEnumerable<string> switches)423 		public void SetCompatibilitySwitches (IEnumerable<string> switches)
424 		{
425 		}
426 	}
427 }
428