using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Xml; using AppHostAdminLibrary; using System.Runtime.InteropServices; namespace configure { public class ModSecurityConfigurator { public void Install(string installDir) { if (installDir.EndsWith("\"")) { installDir = installDir.Substring(0, installDir.Length - 1); } if (installDir.StartsWith("\"")) { installDir = installDir.Substring(1); } Console.WriteLine("Copying 32-bit binaries..."); string dstpath = Environment.ExpandEnvironmentVariables("%windir%\\SysWow64"); if (!Directory.Exists(dstpath)) dstpath = Environment.ExpandEnvironmentVariables("%windir%\\system32"); CopyBinaries(Path.Combine(installDir, "x86"), Path.Combine(dstpath, "inetsrv")); dstpath = Environment.ExpandEnvironmentVariables("%windir%\\SysNative"); if (Directory.Exists(dstpath)) { Console.WriteLine("Copying 64-bit binaries..."); CopyBinaries(Path.Combine(installDir, "amd64"), Path.Combine(dstpath, "inetsrv")); } string text = Path.Combine(installDir, "ModSecurity.xml"); string text2 = null; IntPtr zero = IntPtr.Zero; try { bool flag = false; if (Wow64Redirection.IsWow64Process(new IntPtr(-1), out flag) && flag) { Wow64Redirection.Wow64DisableWow64FsRedirection(out zero); } if (!File.Exists(text)) { throw new FileNotFoundException("The specified schema file does not exist", text); } Console.WriteLine("Installing schema file: " + text); text2 = Path.Combine(Environment.ExpandEnvironmentVariables("%windir%\\system32\\inetsrv\\config\\schema\\"), Path.GetFileName(text)); if (!text2.Equals(text, StringComparison.InvariantCultureIgnoreCase)) { File.Copy(text, text2, true); Console.WriteLine("Installed schema file: " + text2); } else { Console.WriteLine("Schema file is already in the destination location."); } } finally { if (IntPtr.Zero != zero) { Wow64Redirection.Wow64RevertWow64FsRedirection(zero); } } SectionList configurationSections = GetConfigurationSections(text2); RegisterConfigurationSections(configurationSections, false); Console.WriteLine("Finished"); } /* add specific cleanup logic here (basically mirror install) * No need to clean Program Files or other aspects of install, just revert the things you manually modified in Install() */ public void Uninstall() { } private SectionList GetConfigurationSections(string schemaPath) { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(schemaPath); SectionList sectionList = new SectionList(); XmlElement documentElement = xmlDocument.DocumentElement; foreach (XmlNode xmlNode in documentElement.ChildNodes) { if (xmlNode.LocalName.Equals("sectionSchema", StringComparison.InvariantCultureIgnoreCase)) { sectionList.Add(new SectionDefinition(xmlNode.Attributes["name"].Value)); } } return sectionList; } private static SectionList GetConfigurationSections(string sectionGroupName, IAppHostSectionGroup sectionGroup) { SectionList sectionList = new SectionList(); string text = string.IsNullOrEmpty(sectionGroupName) ? sectionGroup.Name : (sectionGroupName + "/" + sectionGroup.Name); for (uint num = 0u; num < sectionGroup.Count; num += 1u) { IAppHostSectionGroup sectionGroup2 = sectionGroup[num]; SectionList configurationSections = GetConfigurationSections(text, sectionGroup2); sectionList.AddRange(configurationSections); } IAppHostSectionDefinitionCollection sections = sectionGroup.Sections; for (uint num2 = 0u; num2 < sections.Count; num2 += 1u) { IAppHostSectionDefinition appHostSectionDefinition = sections[num2]; sectionList.Add(new SectionDefinition(string.IsNullOrEmpty(text) ? appHostSectionDefinition.Name : (text + "/" + appHostSectionDefinition.Name), (AllowDefinition)Enum.Parse(typeof(AllowDefinition), appHostSectionDefinition.AllowDefinition, true), (OverrideModeDefault)Enum.Parse(typeof(OverrideModeDefault), appHostSectionDefinition.OverrideModeDefault, true), appHostSectionDefinition.Type)); } return sectionList; } private static bool RegisterConfigSection(IAppHostWritableAdminManager adminManager, SectionDefinition sectionDefinition, string sectionName, IAppHostSectionGroup sectionGroup, bool remove) { string text = null; string sectionName2 = sectionName; int num = sectionName.IndexOf('/'); if (num >= 0) { text = sectionName.Substring(0, num); sectionName2 = sectionName.Substring(num + 1, sectionName.Length - num - 1); } if (text != null) { uint count = sectionGroup.Count; for (uint num2 = 0u; num2 < count; num2 += 1u) { IAppHostSectionGroup appHostSectionGroup = sectionGroup[num2]; if (appHostSectionGroup.Name.Equals(text, StringComparison.InvariantCultureIgnoreCase)) { return RegisterConfigSection(adminManager, sectionDefinition, sectionName2, appHostSectionGroup, remove); } } if (remove) { return false; } IAppHostSectionGroup sectionGroup2 = sectionGroup.AddSectionGroup(text); return RegisterConfigSection(adminManager, sectionDefinition, sectionName2, sectionGroup2, remove); } else { IAppHostSectionDefinitionCollection sections = sectionGroup.Sections; bool flag = false; uint count2 = sections.Count; for (uint num3 = 0u; num3 < count2; num3 += 1u) { IAppHostSectionDefinition appHostSectionDefinition = sections[num3]; if (appHostSectionDefinition.Name.Equals(sectionName, StringComparison.InvariantCultureIgnoreCase)) { flag = true; break; } } if (!flag) { if (remove) { return false; } IAppHostSectionDefinition appHostSectionDefinition2 = sections.AddSection(sectionName); appHostSectionDefinition2.OverrideModeDefault = sectionDefinition.OverrideModeDefault.ToString(); appHostSectionDefinition2.AllowDefinition = sectionDefinition.AllowDefinition.ToString(); appHostSectionDefinition2.Type = sectionDefinition.Type; return true; } else { if (remove) { try { IAppHostElement adminSection = adminManager.GetAdminSection(sectionName, "MACHINE/WEBROOT/APPHOST"); adminSection.Clear(); } catch (Exception) { } sections.DeleteSection(sectionName); return true; } return false; } } } private void RegisterConfigurationSections(SectionList sectionList, bool remove) { IAppHostWritableAdminManager appHostWritableAdminManager = new AppHostWritableAdminManagerClass(); appHostWritableAdminManager.CommitPath = "MACHINE/WEBROOT/APPHOST"; IAppHostConfigManager configManager = appHostWritableAdminManager.ConfigManager; IAppHostConfigFile configFile = configManager.GetConfigFile("MACHINE/WEBROOT/APPHOST"); IAppHostSectionGroup rootSectionGroup = configFile.RootSectionGroup; foreach (SectionDefinition current in sectionList) { if (RegisterConfigSection(appHostWritableAdminManager, current, current.Name, rootSectionGroup, remove)) { if (remove) { Console.WriteLine("Unregistered section: " + current.Name); } else { Console.WriteLine("Registered section: " + current.Name); } } else { if (remove) { Console.WriteLine("Section not currently registered, ignoring: " + current.Name); } else { Console.WriteLine("Section already registered, ignoring: " + current.Name); } } } appHostWritableAdminManager.CommitChanges(); } internal class Wow64Redirection { [DllImport("Kernel32.dll", CharSet = CharSet.Auto)] public static extern bool IsWow64Process(IntPtr hProcess, out bool isWow64); [DllImport("Kernel32.dll", CharSet = CharSet.Auto)] public static extern bool Wow64DisableWow64FsRedirection(out IntPtr oldValue); [DllImport("Kernel32.dll", CharSet = CharSet.Auto)] public static extern bool Wow64RevertWow64FsRedirection(IntPtr oldValue); } private void CopyBinaries(string srcpath, string dstpath) { string[] files = { "libapr-1.dll", "libapriconv-1.dll", "libaprutil-1.dll", "libxml2.dll", "lua5.1.dll", "pcre.dll", "zlib1.dll", "ModSecurityIIS.dll" }; foreach (string s in files) File.Copy(Path.Combine(srcpath, s), Path.Combine(dstpath, s), true); } public enum AllowDefinition { MachineOnly, MachineToWebRoot, MachineToApplication, AppHostOnly, Everywhere } public enum OverrideModeDefault { Allow, Deny } public class SectionDefinition { public const AllowDefinition DefaultAllowDefinition = AllowDefinition.Everywhere; public const OverrideModeDefault DefaultOverrideModeDefault = OverrideModeDefault.Allow; private string name; private AllowDefinition allowDefinition; private OverrideModeDefault overrideModeDefault; private string type; public string Name { get { return this.name; } } public AllowDefinition AllowDefinition { get { return this.allowDefinition; } } public OverrideModeDefault OverrideModeDefault { get { return this.overrideModeDefault; } } public string Type { get { return this.type; } set { this.type = value; } } public SectionDefinition(string sectionName) : this(sectionName, AllowDefinition.Everywhere, OverrideModeDefault.Allow, null) { } public SectionDefinition(string sectionName, AllowDefinition allowDefinition, OverrideModeDefault overrideModeDefault, string type) { this.name = sectionName; this.allowDefinition = allowDefinition; this.overrideModeDefault = overrideModeDefault; this.type = type; } } internal class SectionList : List {} } }