// Arguments: Codebase, flags, zone, srcurl // If the flags indicate zone then a zone must be provided. // If the flags indicate a site then a srcurl must be provided, codebase must be a filepath public int Execute(string codebase, Int32 flags, Int32 evidenceZone, string evidenceSrcUrl, string stringArg) { string file = codebase; if ((file.Length == 0) || (file[0] == '\0')) { throw new ArgumentException("Invalid codebase"); } Console.WriteLine("Codebase- {0}", file); // Find the appbase of the executable. For now we assume the // form to be http://blah/... with forward slashes. This // need to be update. // Note: aso works with '\' as in file paths string appbase = null; string ConfigurationFile = null; int k = file.LastIndexOf('/'); if (k <= 0) { k = file.LastIndexOf('\\'); if (k == 0) { appbase = file; ConfigurationFile = file; } } if (k != 0) { // if k is still < 0 at this point, appbase should be an empty string appbase = file.Substring(0, k + 1); if (k + 1 < file.Length) { ConfigurationFile = file.Substring(k + 1); } } // Check 1: disallow non-fully qualified path/codebase if ((appbase.Length == 0) || (appbase[0] == '.')) { throw new ArgumentException("Codebase must be fully qualified"); } // BUGBUG: should appbase be the source of the code, not local? Console.WriteLine("AppBase- {0}", appbase); // Build up the configuration File name if (ConfigurationFile != null) { StringBuilder bld = new StringBuilder(); bld.Append(ConfigurationFile); bld.Append(".config"); ConfigurationFile = bld.ToString(); } Console.WriteLine("Config- {0}", ConfigurationFile); // Get the flags // 0x1 we have Zone // 0x2 we have a unique id. int dwFlag = flags; Evidence documentSecurity = null; // Check 2: disallow called with no evidence if (dwFlag == SECURITY_NONE) { // BUGBUG?: disallow executing with no evidence throw new ArgumentException("Flag set at no evidence"); } if ((dwFlag & SECURITY_SITE) != 0 || (dwFlag & SECURITY_ZONE) != 0) { documentSecurity = new Evidence(); } // BUGBUG: check other invalid cases for dwFlag if ((dwFlag & SECURITY_ZONE) != 0) { int zone = evidenceZone; documentSecurity.AddHost(new Zone((System.Security.SecurityZone)zone)); Console.WriteLine("Evidence Zone- {0}", zone); } if ((dwFlag & SECURITY_SITE) != 0) { if (file.Length < 7 || String.Compare(file.Substring(0, 7), "file://", true) != 0) { documentSecurity.AddHost(System.Security.Policy.Site.CreateFromUrl(evidenceSrcUrl)); Console.WriteLine("Evidence SiteFromUrl- {0}", evidenceSrcUrl); // if srcUrl is given, assume file/appbase is a local file path StringBuilder bld = new StringBuilder(); bld.Append("file://"); bld.Append(appbase); documentSecurity.AddHost(new ApplicationDirectory(bld.ToString())); Console.WriteLine("Evidence AppDir- {0}", bld); } // URLs may be matched exactly or by a wildcard in the final position, // for example: http://www.fourthcoffee.com/process/* StringBuilder bld2 = new StringBuilder(); if (evidenceSrcUrl[evidenceSrcUrl.Length - 1] == '/') { bld2.Append(evidenceSrcUrl); } else { int j = evidenceSrcUrl.LastIndexOf('/'); if (j > 0) { if (j > 7) // evidenceSrcUrl == "http://a/file.exe" { bld2.Append(evidenceSrcUrl.Substring(0, j + 1)); } else { // evidenceSrcUrl == "http://foo.com" -> but why? bld2.Append(evidenceSrcUrl); bld2.Append('/'); } } else { throw new ArgumentException("Invalid Url format"); } } bld2.Append('*'); documentSecurity.AddHost(new Url(bld2.ToString())); Console.WriteLine("Evidence Url- {0}", bld2); } // other evidence: Hash, Publisher, StrongName // Set domain name to site name if possible string friendlyName = null; if ((dwFlag & SECURITY_SITE) != 0) { friendlyName = GetSiteName(evidenceSrcUrl); } else { friendlyName = GetSiteName(file); } Console.WriteLine("AppDomain friendlyName- {0}", friendlyName); // set up arguments // only allow 1 for now string[] args; if (stringArg != null) { args = new string[1]; args[0] = stringArg; } else { args = new string[0]; } AppDomainSetup properties = new AppDomainSetup(); properties.ApplicationBase = appbase; properties.PrivateBinPath = "bin"; if (ConfigurationFile != null) { properties.ConfigurationFile = ConfigurationFile; } AppDomain proxy = AppDomain.CreateDomain(friendlyName, documentSecurity, properties); if (proxy != null) { AssemblyName asmname = Assembly.GetExecutingAssembly().GetName(); Console.WriteLine("AsmExecute name- {0}", asmname); try { // Use remoting. Otherwise asm will be loaded both in current and the new AppDomain // ... as explained by URT dev // asmexec.dll must be found on path (CorPath?) or in the GAC for this to work. ObjectHandle handle = proxy.CreateInstance(asmname.FullName, "FusionCLRHost.AsmExecute"); if (handle != null) { AsmExecute execproxy = (AsmExecute)handle.Unwrap(); int retVal = -1; Console.WriteLine("\n========"); if (execproxy != null) { retVal = execproxy.ExecuteAsAssembly(file, documentSecurity, args); } Console.WriteLine("\n========"); return(retVal); } } catch (Exception e) { Console.WriteLine("AsmExecute CreateInstance(AsmExecute) failed: {0}", e.Message); throw e; } } else { Console.WriteLine("AsmExecute CreateDomain failed"); } // BUGBUG: throw Exception? return(-1); }
// Arguments: Codebase, flags, zone, srcurl // If the flags indicate zone then a zone must be provided. // If the flags indicate a site then a srcurl must be provided, codebase must be a filepath public int Execute(string codebase, Int32 flags, Int32 evidenceZone, string evidenceSrcUrl, string stringArg) { string file = codebase; if ((file.Length == 0) || (file[0] == '\0')) { throw new ArgumentException("Invalid codebase"); } Console.WriteLine("Codebase- {0}", file); // Find the appbase of the executable. For now we assume the // form to be http://blah/... with forward slashes. This // need to be update. // Note: aso works with '\' as in file paths string appbase = null; string ConfigurationFile = null; int k = file.LastIndexOf('/'); if (k <= 0) { k = file.LastIndexOf('\\'); if (k == 0) { appbase = file; ConfigurationFile = file; } } if (k != 0) { // if k is still < 0 at this point, appbase should be an empty string appbase = file.Substring(0, k + 1); if (k + 1 < file.Length) { ConfigurationFile = file.Substring(k + 1); } } // Check 1: disallow non-fully qualified path/codebase if ((appbase.Length == 0) || (appbase[0] == '.')) { throw new ArgumentException("Codebase must be fully qualified"); } // BUGBUG: should appbase be the source of the code, not local? Console.WriteLine("AppBase- {0}", appbase); // Build up the configuration File name if (ConfigurationFile != null) { StringBuilder bld = new StringBuilder(); bld.Append(ConfigurationFile); bld.Append(".config"); ConfigurationFile = bld.ToString(); } Console.WriteLine("Config- {0}", ConfigurationFile); // Get the flags // 0x1 we have Zone // 0x2 we have a unique id. int dwFlag = flags; Evidence securityEvidence = null; // Check 2: disallow called with no evidence if (dwFlag == SECURITY_NONE) { // BUGBUG?: disallow executing with no evidence throw new ArgumentException("Flag set at no evidence"); } if ((dwFlag & SECURITY_SITE) != 0 || (dwFlag & SECURITY_ZONE) != 0) { securityEvidence = new Evidence(); } // BUGBUG: check other invalid cases for dwFlag string appURLbase = null; if ((dwFlag & SECURITY_ZONE) != 0) { int zone = evidenceZone; securityEvidence.AddHost(new Zone((System.Security.SecurityZone)zone)); Console.WriteLine("Evidence Zone- {0}", zone); } if ((dwFlag & SECURITY_SITE) != 0) { if (file.Length < 7 || String.Compare(file.Substring(0, 7), "file://", true) != 0) { securityEvidence.AddHost(System.Security.Policy.Site.CreateFromUrl(evidenceSrcUrl)); Console.WriteLine("Evidence SiteFromUrl- {0}", evidenceSrcUrl); // BUGBUG: possible security hole? - if this intersects with Url/Zone _may_ resolve to a less restrictive policy... // if srcUrl is given, assume file/appbase is a local file path StringBuilder bld = new StringBuilder(); bld.Append("file://"); bld.Append(appbase); securityEvidence.AddHost(new ApplicationDirectory(bld.ToString())); Console.WriteLine("Evidence AppDir- {0}", bld); } // URLs may be matched exactly or by a wildcard in the final position, // for example: http://www.fourthcoffee.com/process/* StringBuilder bld2 = new StringBuilder(); if (evidenceSrcUrl[evidenceSrcUrl.Length - 1] == '/') { bld2.Append(evidenceSrcUrl); } else { int j = evidenceSrcUrl.LastIndexOf('/'); if (j > 0) { if (j > 7) // evidenceSrcUrl == "http://a/file.exe" { bld2.Append(evidenceSrcUrl.Substring(0, j + 1)); } else { // evidenceSrcUrl == "http://foo.com" -> but why? bld2.Append(evidenceSrcUrl); bld2.Append('/'); } } else { throw new ArgumentException("Invalid Url format"); } } appURLbase = bld2.ToString(); bld2.Append('*'); securityEvidence.AddHost(new Url(bld2.ToString())); Console.WriteLine("Evidence Url- {0}", bld2); } // other evidence: Hash, Publisher, StrongName // NOTENOTE: not effective if not both url and zone in evidence // Populate the PolicyLevel with code groups that will do the following: // 1) For all assemblies that come from this app's cache directory, // give permissions from retrieved permission set from SecurityManager. // 2) For all other assemblies, give FullTrust permission set. Remember, // since the permissions will be intersected with other policy levels, // just because we grant full trust to all other assemblies does not mean // those assemblies will end up with full trust. // Create a new System.Security.Policy.PolicyStatement that does not contain any permissions. PolicyStatement Nada = new PolicyStatement(new PermissionSet(PermissionState.None));//PermissionSet()); // Create a System.Security.Policy.FirstMatchCodeGroup as the root that matches all // assemblies by supplying an AllMembershipCondition: FirstMatchCodeGroup RootCG = new FirstMatchCodeGroup(new AllMembershipCondition(), Nada); // ResolvePolicy will return a System.Security.PermissionSet PermissionSet AppPerms = SecurityManager.ResolvePolicy(securityEvidence); // Create another PolicyStatement for the permissions that we want to grant to code from the app directory: PolicyStatement AppStatement = new PolicyStatement(AppPerms); // Create a child UnionCodeGroup to handle the assemblies from the app cache. We do this // by using a UrlMembershipCondition set to the app cache directory: UnionCodeGroup AppCG = new UnionCodeGroup(new UrlMembershipCondition("file://" + appbase + "*"), AppStatement); // Add AppCG to RootCG as first child. This is important because we need it to be evaluated first // if ((dwFlag & TYPE_AVALON) == 0) RootCG.AddChild(AppCG); // Create another PolicyStatement so all other code gets full trust, by passing in an _unrestricted_ PermissionSet PolicyStatement FullTrustStatement = new PolicyStatement(new PermissionSet(PermissionState.Unrestricted)); // Create a second child UnionCodeGroup to handle all other code, by using the AllMembershipCondition again UnionCodeGroup AllCG = new UnionCodeGroup(new AllMembershipCondition(), FullTrustStatement); // Add AllCG to RootCG after AppCG. If AppCG doesnt apply to the assembly, AllCG will. RootCG.AddChild(AllCG); // This will be the PolicyLevel that we will associate with the new AppDomain. PolicyLevel AppPolicy = PolicyLevel.CreateAppDomainLevel(); // Set the RootCG as the root code group on the new policy level AppPolicy.RootCodeGroup = RootCG; // NOTENOTE // Code from the site that lives on the local machine will get the reduced permissions as expected. // Dependencies of this app (not under app dir or maybe dependencies that live in the GAC) would still get full trust. // If the full trust dependencies need to do something trusted, they carry the burden of asserting to overcome the stack walk. // Set domain name to site name if possible string friendlyName = null; if ((dwFlag & SECURITY_SITE) != 0) { friendlyName = GetSiteName(evidenceSrcUrl); } else { friendlyName = GetSiteName(file); } Console.WriteLine("AppDomain friendlyName- {0}", friendlyName); // set up arguments // only allow 1 for now string[] args; if (stringArg != null) { args = new string[1]; args[0] = stringArg; } else { args = new string[0]; } AppDomainSetup properties = new AppDomainSetup(); // properties.DisallowPublisherPolicy=true; // not allowed to set safe mode properties.ApplicationBase = appbase; // BUGBUG: security? see note on ApplicationDirectory above properties.PrivateBinPath = "bin"; if (ConfigurationFile != null) { properties.ConfigurationFile = ConfigurationFile; // should not set config file if it doesnot exist? } AppDomain proxy = AppDomain.CreateDomain(friendlyName, null, properties); if (proxy != null) { // set the AppPolicy policy level as the policy level for the AppDomain proxy.SetAppDomainPolicy(AppPolicy); AssemblyName asmname = Assembly.GetExecutingAssembly().GetName(); Console.WriteLine("AsmExecute name- {0}", asmname); try { // Use remoting. Otherwise asm will be loaded both in current and the new AppDomain // ... as explained by URT dev // asmexec.dll must be found on path (CorPath?) or in the GAC for this to work. ObjectHandle handle = proxy.CreateInstance(asmname.FullName, "FusionCLRHost.AsmExecute"); if (handle != null) { AsmExecute execproxy = (AsmExecute)handle.Unwrap(); int retVal = -1; if (execproxy != null) { // prepare for on-demand/asm resolution execproxy.InitOnDemand(appbase, appURLbase); } Console.WriteLine("\n========"); if (execproxy != null) { if ((dwFlag & TYPE_AVALON) != 0) { retVal = execproxy.ExecuteAsAvalon(file, securityEvidence, args); } else { retVal = execproxy.ExecuteAsAssembly(file, securityEvidence, args); } } Console.WriteLine("\n========"); return(retVal); } } catch (Exception e) { Console.WriteLine("AsmExecute CreateInstance(AsmExecute) / execute assembly failed:\n{0}: {1}", e.GetType(), e.Message); throw e; } } else { Console.WriteLine("AsmExecute CreateDomain failed"); } // BUGBUG: throw Exception? return(-1); }