Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

592 lines
25 KiB

  1. /*=============================================================================
  2. **
  3. ** Class: AsmExecute
  4. **
  5. ** Purpose: Used to setup the correct hosting environment before executing an assembly
  6. **
  7. ** Date: 10/20/2000
  8. ** 5/10/2001 Rev for CLR Beta2
  9. **
  10. ** Copyright (c) Microsoft, 1999-2001
  11. **
  12. =============================================================================*/
  13. using System.Reflection;
  14. using System.Configuration.Assemblies;
  15. [assembly:AssemblyCultureAttribute("")]
  16. [assembly:AssemblyVersionAttribute("1.0.704.0")]
  17. [assembly:AssemblyKeyFileAttribute(/*"..\..\*/"asmexecKey.snk")]
  18. [assembly:AssemblyTitleAttribute("Microsoft Fusion .Net Assembly Execute Host")]
  19. [assembly:AssemblyDescriptionAttribute("Microsoft Fusion Network Services CLR Host for executing .Net assemblies")]
  20. [assembly:AssemblyProductAttribute("Microsoft Fusion Network Services")]
  21. [assembly:AssemblyInformationalVersionAttribute("1.0.0.0")]
  22. [assembly:AssemblyTrademarkAttribute("Microsoft� is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation")]
  23. [assembly:AssemblyCompanyAttribute("Microsoft Corporation")]
  24. [assembly:AssemblyCopyrightAttribute("Copyright � Microsoft Corp. 1999-2001. All rights reserved.")]
  25. //BUGBUG??
  26. [assembly:System.CLSCompliant(true)]
  27. //namespace Microsoft {
  28. namespace FusionCLRHost {
  29. using System;
  30. using System.Text;
  31. using System.Runtime.Remoting;
  32. using System.Globalization;
  33. using System.Security;
  34. using System.Security.Policy;
  35. using System.Security.Permissions;
  36. using System.Collections;
  37. using System.Runtime.InteropServices;
  38. using System.IO;
  39. using System.Net;
  40. // [GuidAttribute("E612D54D-B42A-32B5-B1D7-8490CE09705C")]
  41. public interface IAsmExecute
  42. {
  43. int Execute(string codebase, Int32 flags, Int32 evidenceZone, string evidenceSrcUrl, string stringArg);
  44. }
  45. [GuidAttribute("7EB9A84D-646E-3764-BBCA-3789CDB3447B")]
  46. public class AsmExecute : MarshalByRefObject, IAsmExecute
  47. {
  48. // this must be the same as defined in the caller...
  49. private static readonly int SECURITY_NONE = 0x00;
  50. private static readonly int SECURITY_ZONE = 0x01;
  51. private static readonly int SECURITY_SITE = 0x02;
  52. private static readonly int TYPE_AVALON = 0x1000;
  53. public AsmExecute()
  54. {
  55. appbasePath = null;
  56. appbaseURL = null;
  57. loadingAssembly = false;
  58. }
  59. // Arguments: Codebase, flags, zone, srcurl
  60. // If the flags indicate zone then a zone must be provided.
  61. // If the flags indicate a site then a srcurl must be provided, codebase must be a filepath
  62. public int Execute(string codebase, Int32 flags, Int32 evidenceZone, string evidenceSrcUrl, string stringArg)
  63. {
  64. string file = codebase;
  65. if((file.Length == 0) || (file[0] == '\0'))
  66. throw new ArgumentException("Invalid codebase");
  67. Console.WriteLine("Codebase- {0}", file);
  68. // Find the appbase of the executable. For now we assume the
  69. // form to be http://blah/... with forward slashes. This
  70. // need to be update.
  71. // Note: aso works with '\' as in file paths
  72. string appbase = null;
  73. string ConfigurationFile = null;
  74. int k = file.LastIndexOf('/');
  75. if(k <= 0)
  76. {
  77. k = file.LastIndexOf('\\');
  78. if(k == 0)
  79. {
  80. appbase = file;
  81. ConfigurationFile = file;
  82. }
  83. }
  84. if(k != 0)
  85. {
  86. // if k is still < 0 at this point, appbase should be an empty string
  87. appbase = file.Substring(0,k+1);
  88. if(k+1 < file.Length)
  89. ConfigurationFile = file.Substring(k+1);
  90. }
  91. // Check 1: disallow non-fully qualified path/codebase
  92. if ((appbase.Length == 0) || (appbase[0] == '.'))
  93. throw new ArgumentException("Codebase must be fully qualified");
  94. // BUGBUG: should appbase be the source of the code, not local?
  95. Console.WriteLine("AppBase- {0}", appbase);
  96. // Build up the configuration File name
  97. if(ConfigurationFile != null)
  98. {
  99. StringBuilder bld = new StringBuilder();
  100. bld.Append(ConfigurationFile);
  101. bld.Append(".config");
  102. ConfigurationFile = bld.ToString();
  103. }
  104. Console.WriteLine("Config- {0}", ConfigurationFile);
  105. // Get the flags
  106. // 0x1 we have Zone
  107. // 0x2 we have a unique id.
  108. int dwFlag = flags;
  109. Evidence securityEvidence = null;
  110. // Check 2: disallow called with no evidence
  111. if (dwFlag == SECURITY_NONE)
  112. {
  113. // BUGBUG?: disallow executing with no evidence
  114. throw new ArgumentException("Flag set at no evidence");
  115. }
  116. if((dwFlag & SECURITY_SITE) != 0 ||
  117. (dwFlag & SECURITY_ZONE) != 0)
  118. securityEvidence = new Evidence();
  119. // BUGBUG: check other invalid cases for dwFlag
  120. string appURLbase = null;
  121. if((dwFlag & SECURITY_ZONE) != 0)
  122. {
  123. int zone = evidenceZone;
  124. securityEvidence.AddHost( new Zone((System.Security.SecurityZone)zone) );
  125. Console.WriteLine("Evidence Zone- {0}", zone);
  126. }
  127. if((dwFlag & SECURITY_SITE) != 0)
  128. {
  129. if (file.Length<7||String.Compare(file.Substring(0,7),"file://",true)!=0)
  130. {
  131. securityEvidence.AddHost( System.Security.Policy.Site.CreateFromUrl(evidenceSrcUrl) );
  132. Console.WriteLine("Evidence SiteFromUrl- {0}", evidenceSrcUrl);
  133. // BUGBUG: possible security hole? - if this intersects with Url/Zone _may_ resolve to a less restrictive policy...
  134. // if srcUrl is given, assume file/appbase is a local file path
  135. StringBuilder bld = new StringBuilder();
  136. bld.Append("file://");
  137. bld.Append(appbase);
  138. securityEvidence.AddHost( new ApplicationDirectory(bld.ToString()) );
  139. Console.WriteLine("Evidence AppDir- {0}", bld);
  140. }
  141. // URLs may be matched exactly or by a wildcard in the final position,
  142. // for example: http://www.fourthcoffee.com/process/*
  143. StringBuilder bld2 = new StringBuilder();
  144. if (evidenceSrcUrl[evidenceSrcUrl.Length-1] == '/')
  145. bld2.Append(evidenceSrcUrl);
  146. else
  147. {
  148. int j = evidenceSrcUrl.LastIndexOf('/');
  149. if(j > 0)
  150. {
  151. if (j > 7) // evidenceSrcUrl == "http://a/file.exe"
  152. bld2.Append(evidenceSrcUrl.Substring(0,j+1));
  153. else
  154. {
  155. // evidenceSrcUrl == "http://foo.com" -> but why?
  156. bld2.Append(evidenceSrcUrl);
  157. bld2.Append('/');
  158. }
  159. }
  160. else
  161. throw new ArgumentException("Invalid Url format");
  162. }
  163. appURLbase = bld2.ToString();
  164. bld2.Append('*');
  165. securityEvidence.AddHost( new Url(bld2.ToString()) );
  166. Console.WriteLine("Evidence Url- {0}", bld2);
  167. }
  168. // other evidence: Hash, Publisher, StrongName
  169. // NOTENOTE: not effective if not both url and zone in evidence
  170. // Populate the PolicyLevel with code groups that will do the following:
  171. // 1) For all assemblies that come from this app's cache directory,
  172. // give permissions from retrieved permission set from SecurityManager.
  173. // 2) For all other assemblies, give FullTrust permission set. Remember,
  174. // since the permissions will be intersected with other policy levels,
  175. // just because we grant full trust to all other assemblies does not mean
  176. // those assemblies will end up with full trust.
  177. // Create a new System.Security.Policy.PolicyStatement that does not contain any permissions.
  178. PolicyStatement Nada = new PolicyStatement(new PermissionSet(PermissionState.None));//PermissionSet());
  179. // Create a System.Security.Policy.FirstMatchCodeGroup as the root that matches all
  180. // assemblies by supplying an AllMembershipCondition:
  181. FirstMatchCodeGroup RootCG = new FirstMatchCodeGroup(new AllMembershipCondition(), Nada);
  182. // ResolvePolicy will return a System.Security.PermissionSet
  183. PermissionSet AppPerms = SecurityManager.ResolvePolicy(securityEvidence);
  184. // Create another PolicyStatement for the permissions that we want to grant to code from the app directory:
  185. PolicyStatement AppStatement = new PolicyStatement(AppPerms);
  186. // Create a child UnionCodeGroup to handle the assemblies from the app cache. We do this
  187. // by using a UrlMembershipCondition set to the app cache directory:
  188. UnionCodeGroup AppCG = new UnionCodeGroup(new UrlMembershipCondition("file://"+appbase+"*"), AppStatement);
  189. // Add AppCG to RootCG as first child. This is important because we need it to be evaluated first
  190. // if ((dwFlag & TYPE_AVALON) == 0)
  191. RootCG.AddChild(AppCG);
  192. // Create another PolicyStatement so all other code gets full trust, by passing in an _unrestricted_ PermissionSet
  193. PolicyStatement FullTrustStatement = new PolicyStatement(new PermissionSet(PermissionState.Unrestricted));
  194. // Create a second child UnionCodeGroup to handle all other code, by using the AllMembershipCondition again
  195. UnionCodeGroup AllCG = new UnionCodeGroup(new AllMembershipCondition(), FullTrustStatement);
  196. // Add AllCG to RootCG after AppCG. If AppCG doesnt apply to the assembly, AllCG will.
  197. RootCG.AddChild(AllCG);
  198. // This will be the PolicyLevel that we will associate with the new AppDomain.
  199. PolicyLevel AppPolicy = PolicyLevel.CreateAppDomainLevel();
  200. // Set the RootCG as the root code group on the new policy level
  201. AppPolicy.RootCodeGroup = RootCG;
  202. // NOTENOTE
  203. // Code from the site that lives on the local machine will get the reduced permissions as expected.
  204. // Dependencies of this app (not under app dir or maybe dependencies that live in the GAC) would still get full trust.
  205. // If the full trust dependencies need to do something trusted, they carry the burden of asserting to overcome the stack walk.
  206. // Set domain name to site name if possible
  207. string friendlyName = null;
  208. if((dwFlag & SECURITY_SITE) != 0)
  209. friendlyName = GetSiteName(evidenceSrcUrl);
  210. else
  211. friendlyName = GetSiteName(file);
  212. Console.WriteLine("AppDomain friendlyName- {0}", friendlyName);
  213. // set up arguments
  214. // only allow 1 for now
  215. string[] args;
  216. if (stringArg != null)
  217. {
  218. args = new string[1];
  219. args[0] = stringArg;
  220. }
  221. else
  222. args = new string[0];
  223. AppDomainSetup properties = new AppDomainSetup();
  224. // properties.DisallowPublisherPolicy=true; // not allowed to set safe mode
  225. properties.ApplicationBase = appbase; // BUGBUG: security? see note on ApplicationDirectory above
  226. properties.PrivateBinPath = "bin";
  227. if(ConfigurationFile != null)
  228. properties.ConfigurationFile = ConfigurationFile; // should not set config file if it doesnot exist?
  229. AppDomain proxy = AppDomain.CreateDomain(friendlyName, null, properties);
  230. if(proxy != null)
  231. {
  232. // set the AppPolicy policy level as the policy level for the AppDomain
  233. proxy.SetAppDomainPolicy(AppPolicy);
  234. AssemblyName asmname = Assembly.GetExecutingAssembly().GetName();
  235. Console.WriteLine("AsmExecute name- {0}", asmname);
  236. try
  237. {
  238. // Use remoting. Otherwise asm will be loaded both in current and the new AppDomain
  239. // ... as explained by URT dev
  240. // asmexec.dll must be found on path (CorPath?) or in the GAC for this to work.
  241. ObjectHandle handle = proxy.CreateInstance(asmname.FullName, "FusionCLRHost.AsmExecute");
  242. if (handle != null)
  243. {
  244. AsmExecute execproxy = (AsmExecute)handle.Unwrap();
  245. int retVal = -1;
  246. if (execproxy != null)
  247. {
  248. // prepare for on-demand/asm resolution
  249. execproxy.InitOnDemand(appbase, appURLbase);
  250. }
  251. Console.WriteLine("\n========");
  252. if (execproxy != null)
  253. {
  254. if((dwFlag & TYPE_AVALON) != 0)
  255. retVal = execproxy.ExecuteAsAvalon(file, securityEvidence, args);
  256. else
  257. retVal = execproxy.ExecuteAsAssembly(file, securityEvidence, args);
  258. }
  259. Console.WriteLine("\n========");
  260. return retVal;
  261. }
  262. }
  263. catch(Exception e)
  264. {
  265. Console.WriteLine("AsmExecute CreateInstance(AsmExecute) / execute assembly failed:\n{0}: {1}", e.GetType(), e.Message);
  266. throw e;
  267. }
  268. }
  269. else
  270. Console.WriteLine("AsmExecute CreateDomain failed");
  271. // BUGBUG: throw Exception?
  272. return -1;
  273. }
  274. // This method must be internal, since it asserts the ControlEvidence permission.
  275. // private --> require ReflectionPermission not known how
  276. // solution: public but LinkDemand StrongNameIdentity of ours
  277. [ComVisible(false)]
  278. [StrongNameIdentityPermissionAttribute(SecurityAction.LinkDemand, PublicKey = "0x002400000480000094000000060200000024000052534131000400000100010013F3CD6C291DF1566D3C6E7269800C35D9212A622FA934492AD0833DAEA2574D12A9AA2A9392FF30A892ECD3F7F9B57211A541CC4712A184450992E143C1BDBC864E31826598B0D90BB2F04C5C50F004771370F9C76444696E8DC18999A3D8448D26EBF3A9E68796CA3A7D2ACC47B491455E462F4E6DDD9DF338171D911D88B2" )]
  279. public int ExecuteAsAssembly(string file, Evidence evidence, string[] args)
  280. {
  281. new PermissionSet(PermissionState.Unrestricted).Assert();
  282. return AppDomain.CurrentDomain.ExecuteAssembly(file, evidence, args);
  283. }
  284. // This method must be internal, since it asserts the ControlEvidence permission.
  285. [ComVisible(false)]
  286. [StrongNameIdentityPermissionAttribute(SecurityAction.LinkDemand, PublicKey = "0x002400000480000094000000060200000024000052534131000400000100010013F3CD6C291DF1566D3C6E7269800C35D9212A622FA934492AD0833DAEA2574D12A9AA2A9392FF30A892ECD3F7F9B57211A541CC4712A184450992E143C1BDBC864E31826598B0D90BB2F04C5C50F004771370F9C76444696E8DC18999A3D8448D26EBF3A9E68796CA3A7D2ACC47B491455E462F4E6DDD9DF338171D911D88B2" )]
  287. public int ExecuteAsAvalon(string file, Evidence evidence, string[] args)
  288. {
  289. new PermissionSet(PermissionState.Unrestricted).Assert();
  290. // evidence not used....??
  291. // do not catch exceptions
  292. Assembly assembly = Assembly.Load("Avalon.Application");
  293. Console.WriteLine("Avalon.Application name- {0}", assembly.GetName());
  294. Object obj = assembly.CreateInstance("Avalon.Application.AvalonContext", false);
  295. if (obj == null)
  296. throw new TypeLoadException("A failure has occurred while loading Avalon.Application.AvalonContext");
  297. Object [] argObjects = new Object [] {new String[] {file}};//args}; avalon arg hack
  298. // instance method, void ExecuteApp(string[] args)
  299. // BUGBUG: ensure matching sig/arg list?
  300. MethodInfo method = obj.GetType().GetMethod("ExecuteApp",
  301. BindingFlags.Instance|BindingFlags.Public|BindingFlags.DeclaredOnly);
  302. if (method == null)
  303. throw new MissingMethodException("Avalon.Application.AvalonContext", "ExecuteApp");
  304. try
  305. {
  306. // note: use BindingFlags.InvokeMethod|BindingFlags.ExactBinding|BindingFlags.SuppressChangeType?
  307. Object pRet=method.Invoke(obj, argObjects);
  308. Console.WriteLine("Avalon.Application.AvalonContext.ExecuteApp() method invoke succeeded");
  309. }
  310. catch (Exception e)
  311. {
  312. // unwrap the real exception, usually == e.InnerException
  313. throw e.GetBaseException();
  314. }
  315. return 0;
  316. }
  317. private static string GetSiteName(string pURL)
  318. {
  319. // BUGBUG: this does not work w/ UNC or file:// (?)
  320. string siteName = null;
  321. if(pURL != null) {
  322. int j = pURL.IndexOf(':');
  323. // If there is a protocal remove it. In a URL of the form
  324. // yyyy://xxxx/zzzz where yyyy is the protocal, xxxx is
  325. // the site and zzzz is extra we want to get xxxx.
  326. if(j != -1 &&
  327. j+3 < pURL.Length &&
  328. pURL[j+1] == '/' &&
  329. pURL[j+2] == '/')
  330. {
  331. j+=3;
  332. // Remove characters after the
  333. // next /.
  334. int i = pURL.IndexOf('/',j);
  335. if(i > -1)
  336. siteName = pURL.Substring(j,i-j);
  337. else
  338. siteName = pURL.Substring(j);
  339. }
  340. if(siteName == null)
  341. siteName = pURL;
  342. }
  343. return siteName;
  344. }
  345. //**************************************************************
  346. // InitOnDemand()
  347. //**************************************************************
  348. [ComVisible(false)]
  349. [StrongNameIdentityPermissionAttribute(SecurityAction.LinkDemand, PublicKey = "0x002400000480000094000000060200000024000052534131000400000100010013F3CD6C291DF1566D3C6E7269800C35D9212A622FA934492AD0833DAEA2574D12A9AA2A9392FF30A892ECD3F7F9B57211A541CC4712A184450992E143C1BDBC864E31826598B0D90BB2F04C5C50F004771370F9C76444696E8DC18999A3D8448D26EBF3A9E68796CA3A7D2ACC47B491455E462F4E6DDD9DF338171D911D88B2" )]
  350. public void InitOnDemand(string path, string url)
  351. {
  352. // initialize on-demand assmebly download and resolution
  353. // add assembly resolve event handler
  354. AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve);
  355. // set paths
  356. appbasePath = path;
  357. appbaseURL = url;
  358. }
  359. protected string appbasePath;
  360. protected string appbaseURL;
  361. protected bool loadingAssembly;
  362. //**************************************************************
  363. // OnAssemblyResolve()
  364. //**************************************************************
  365. private Assembly OnAssemblyResolve(Object sender, ResolveEventArgs args)
  366. {
  367. // Check to see if the AssemblyLoad in this event is what caused the
  368. // event to fire again. If so, the load failed.
  369. // If no URL is given, on-demand download cannot be done
  370. if (loadingAssembly==true || appbaseURL==null)
  371. return null;
  372. loadingAssembly=true;
  373. string[] AssemblyNameParts = args.Name.Split(new Char[] {','}, 2);
  374. string AssemblyName = AssemblyNameParts[0] + ".dll";
  375. // permission needed for file IO etc
  376. new PermissionSet(PermissionState.Unrestricted).Assert();
  377. try
  378. {
  379. GetFile(AssemblyName);
  380. }
  381. catch
  382. {
  383. // GetFile fails - next time may succeed
  384. // BUGBUG: offline or background download scenarios? set background download?
  385. loadingAssembly=false;
  386. return null;
  387. }
  388. Assembly assembly;
  389. try
  390. {
  391. assembly = Assembly.Load(args.Name);
  392. }
  393. catch
  394. {
  395. // should throw a custom exception or event here.
  396. assembly = null;
  397. // return null;
  398. }
  399. finally
  400. {
  401. loadingAssembly=false;
  402. }
  403. return assembly;
  404. }
  405. //**************************************************************
  406. // GetFile()
  407. //**************************************************************
  408. private void GetFile(string name)
  409. {
  410. HttpWebResponse Response;
  411. //Retrieve the File
  412. HttpWebRequest Request = (HttpWebRequest)HttpWebRequest.Create(appbaseURL + name);
  413. try
  414. {
  415. Response = (HttpWebResponse)Request.GetResponse();
  416. }
  417. catch(WebException e)
  418. {
  419. throw e;
  420. // BUGBUG: apply probing rules?
  421. }
  422. Stream responseStream = Response.GetResponseStream();
  423. // setup UI
  424. // BUGBUG: allow no UI case?
  425. // BUGBUG: test with file > 4GB
  426. Int64 totalLength = 0;
  427. int factor = (int) (Response.ContentLength / int.MaxValue);
  428. int max = int.MaxValue;
  429. if (factor <= 1)
  430. {
  431. factor = 1;
  432. max = (int) Response.ContentLength;
  433. }
  434. if (max <= -1)
  435. {
  436. // no content length returned from the server (-1),
  437. // or error (what does < -1 mean?)
  438. // no progress, set max to 0
  439. max = 0;
  440. }
  441. DownloadStatus statusForm = new DownloadStatus(0, max);
  442. statusForm.SetStatus(0);
  443. statusForm.Show();
  444. // write from stream to disk
  445. byte[] buffer = new byte[4096];
  446. int length;
  447. try{
  448. FileStream AFile = File.Open(appbasePath+name, FileMode.Create, FileAccess.ReadWrite);
  449. length = responseStream.Read(buffer, 0, 4096);
  450. while ( length != 0 )
  451. {
  452. AFile.Write(buffer, 0, length);
  453. if (max != 0)
  454. {
  455. totalLength += length;
  456. statusForm.SetStatus((int) (totalLength/factor));
  457. }
  458. length = responseStream.Read(buffer, 0, 4096);
  459. // dispatch messages
  460. System.Windows.Forms.Application.DoEvents();
  461. }
  462. AFile.Close();
  463. statusForm.SetMessage("Download complete");
  464. }
  465. catch(Exception e)
  466. {
  467. statusForm.SetMessage(e.Message);
  468. // BUGBUG: AFile may not be closed
  469. }
  470. responseStream.Close();
  471. //Pause for a moment to show the status dialog in
  472. //case the app downloaded extremely quickly (small file?).
  473. statusForm.Refresh();
  474. System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
  475. statusForm.Close();
  476. }
  477. }
  478. }