using System; using System.Linq; using System.Windows.Forms; using System.Collections.Generic; using Microsoft.Web.Administration; namespace PdMagic.Windows { public class VirtualFolder { public VirtualFolder(string aAlias, string aPhysicalFolder) { Alias = aAlias; PhysicalFolder = aPhysicalFolder; } public string Alias { get; set; } public string PhysicalFolder { get; set; } } public class MimeEntry { public MimeEntry(string aExtension, string aMIMEType) { Extension = aExtension; MimeType = aMIMEType; } public string Extension { get; set; } public string MimeType { get; set; } } public class PdIISManager { private ServerManager mServerManager; public PdIISManager( ) { mServerManager = new ServerManager(); } public void ReLoad() { mServerManager = new ServerManager(); } public SiteCollection Sites { get { return mServerManager.Sites; } } public ApplicationPoolCollection ApplicationPools { get { return mServerManager.ApplicationPools; } } public void AddNewSite(string aName, string aFolder, List<string> aStatus) { aStatus.Add("NEW SITE"); try { // Create and add site const string lProtocol = "http"; const string lBinding = "*:80:"; mServerManager.Sites.Add(aName, lProtocol, lBinding, aFolder); mServerManager.CommitChanges(); aStatus.Add($"+ Name: ({aName})"); aStatus.Add($"+ Protocol: ({lProtocol}), binding: ({lBinding})"); } catch (Exception lAddNewSite) { throw new Exception("AddNewSite", lAddNewSite); } } public void DeleteSite(string aName, List<string> aStatus) { aStatus.Add("DELETE SITE"); try { var lSite = mServerManager.Sites[aName]; mServerManager.Sites.Remove(lSite); mServerManager.CommitChanges(); aStatus.Add($"+ Name: ({aName})"); } catch (Exception lDeleteSite) { throw new Exception( "DeleteSite", lDeleteSite); } } public void VerifyDLLAllowed(string aName, string aDLLPath, string aDescription, List<string> aStatus) { aStatus.Add("NEW ISAPI CGI RESTRICTION"); const string lSection = "system.webServer/security/isapiCgiRestriction"; var lConfig = mServerManager.GetApplicationHostConfiguration(); var lIsapiCgiRestrictionSection = lConfig.GetSection(lSection); ConfigurationElementCollection lIsapiCgiRestrictionCollection = lIsapiCgiRestrictionSection.GetCollection(); aStatus.Add( $"* Section: ({lSection})"); var lExists = lIsapiCgiRestrictionCollection.Any( aConfigurationElement => aConfigurationElement.Attributes["path"].Value.Equals(aDLLPath)); if (lExists) { aStatus.Add($"= An element already exists that points to ({aDLLPath})"); } else { ConfigurationElement lAddElement = lIsapiCgiRestrictionCollection.CreateElement("add"); lAddElement["groupId"] = aName; lAddElement["path"] = aDLLPath; lAddElement["allowed"] = true; lAddElement["description"] = aDescription; lIsapiCgiRestrictionCollection.Add(lAddElement); mServerManager.CommitChanges(); aStatus.Add($"+ GroupId: ({lAddElement["groupId"]})"); aStatus.Add($"+ Path=({lAddElement["path"]})"); aStatus.Add($"+ Allowed=({lAddElement["allowed"]})"); aStatus.Add($"+ Description=({lAddElement["description"]})"); } } public void CreateISAPIHandler(string aSiteName, string aVirtualPath,string aHandlerName, string aDLLPath, List<string> aStatus) { aStatus.Add("ADD ISAPI HANDLER"); var lParams = $"(SiteName={aSiteName}, VirtualPath={aVirtualPath}, Handler={aHandlerName}, DllPath={aDLLPath})"; try { Configuration lSiteConfig; ConfigurationSection lHandlersSection; ConfigurationElementCollection lHandlersCollection; bool lExists; //var lSiteConfig = mServerManager.GetApplicationHostConfiguration(); try { lSiteConfig = mServerManager.GetWebConfiguration(aSiteName, aVirtualPath); aStatus.Add($"* Site / Path: ({aSiteName}{aVirtualPath})"); } catch (Exception lGetWebConfiguration) { throw new Exception("GetWebConfiguration()", lGetWebConfiguration); } try { const string lSection = "system.webServer/handlers"; const string lPolicy = "Read, Script, Execute"; lHandlersSection = lSiteConfig.GetSection(lSection); lHandlersSection["accessPolicy"] = lPolicy; aStatus.Add($"* Set {lSection}/accessPolicy to ({lPolicy})"); } catch (Exception lGetSection) { throw new Exception("GetSection() and set accessPolicy", lGetSection); } try { lHandlersCollection = lHandlersSection.GetCollection(); } catch (Exception lGetCollection) { throw new Exception("GetCollection()", lGetCollection); } try { lExists = lHandlersCollection.Any( aConfigurationElement => aConfigurationElement.Attributes["name"].Value.Equals(aHandlerName)); } catch (Exception lCheckExists) { throw new Exception("Check Handler Exists", lCheckExists); } if (lExists) { aStatus.Add($"= Handler: ({aHandlerName}) already exists"); } else { try { ConfigurationElement lAddElement = lHandlersCollection.CreateElement("add"); lAddElement["name"] = aHandlerName; lAddElement["path"] = "CrashMagicOnline_ISAPI.dll"; lAddElement["allowPathInfo"] = "true"; lAddElement["verb"] = "*"; lAddElement["modules"] = "IsapiModule"; lAddElement["scriptProcessor"] = aDLLPath; lAddElement["resourceType"] = "File"; lAddElement["requireAccess"] = "Execute"; lAddElement["preCondition"] = "bitness32"; lHandlersCollection.Add(lAddElement); mServerManager.CommitChanges(); aStatus.Add($"+ name: ({lAddElement["name"]})"); aStatus.Add($"+ path: ({ lAddElement["path"]})"); aStatus.Add($"+ allowPathInfo: ({ lAddElement["allowPathInfo"]})"); aStatus.Add($"+ verb: ({ lAddElement["verb"]})"); aStatus.Add($"+ modules: ({ lAddElement["modules"]})"); aStatus.Add($"+ scriptProcessor: ({ lAddElement["scriptProcessor"]})"); aStatus.Add($"+ resourceType: ({ lAddElement["resourceType"]})"); aStatus.Add($"+ requireAccess: ({ lAddElement["requireAccess"]})"); aStatus.Add($"+ preCondition: ({ lAddElement["preCondition"]})"); } catch (Exception lAddHandler) { throw new Exception("Add Handler", lAddHandler); } } } catch (Exception lException) { throw new Exception($"CreateISAPIHandler{lParams}", lException); } } public void SetMaxAllowedContentLength(string aSiteName, int aLength, List<string> aStatus) { aStatus.Add("SET MAX ALLOWED CONTENT LENGTH"); const string lSectionPath = "system.webServer/security/requestFiltering"; var lStatus = new List<string>(); // Unlock section: var lConf = mServerManager.GetApplicationHostConfiguration(); var lSection = lConf.RootSectionGroup.SectionGroups["system.webServer"].SectionGroups["security"].Sections["requestFiltering"]; lSection.OverrideModeDefault = "Allow"; mServerManager.CommitChanges(); aStatus.Add($"* Section: ({lSectionPath}) Set OverrideModeDefault to (Allow)."); // Set value: var lConfig = mServerManager.GetWebConfiguration(aSiteName); var lRequestFilteringSection = lConfig.GetSection(lSectionPath); var lRequestLimitsElement = lRequestFilteringSection.GetChildElement("requestLimits"); var lOldLength = Convert.ToInt64(lRequestLimitsElement.GetAttributeValue("maxAllowedContentLength")); if (lOldLength == aLength) { aStatus.Add($"= requestLimits/maxAllowedContentLength already set to ({lOldLength})"); } else { lRequestLimitsElement.SetAttributeValue("maxAllowedContentLength", aLength); mServerManager.CommitChanges(); aStatus.Add($"+ Set requestLimits/maxAllowedContentLength to ({lRequestLimitsElement.GetAttributeValue("maxAllowedContentLength")})"); } } public void SetServerRuntimeValues(string aSiteName, uint aUploadReadAheadSize, uint aMaxRequestEntityAllowed, List<string> aStatus) { aStatus.Add("SET SERVER RUNTIME PARAMETERS"); const string lSectionPath = "system.webServer/serverRuntime"; // Unlock section: var lConf = mServerManager.GetApplicationHostConfiguration(); var lSection = lConf.RootSectionGroup.SectionGroups["system.webServer"].Sections["serverRuntime"]; lSection.OverrideModeDefault = "Allow"; mServerManager.CommitChanges(); aStatus.Add($"* Section ({lSectionPath}) Set OverrideModeDefault to (Allow)."); // Set value: var lConfig = mServerManager.GetWebConfiguration(aSiteName); var lServerRuntimeSection = lConfig.GetSection(lSectionPath); var lOldReadAheadSize = Convert.ToInt64(lServerRuntimeSection.GetAttributeValue("uploadReadAheadSize")); if (lOldReadAheadSize == aUploadReadAheadSize) { aStatus.Add($"= uploadReadAheadSize already set to ({lOldReadAheadSize})"); } else { lServerRuntimeSection.SetAttributeValue("uploadReadAheadSize", aUploadReadAheadSize); aStatus.Add($"+ Set uploadReadAheadSize: ({lServerRuntimeSection.GetAttributeValue("uploadReadAheadSize")})"); } var lOldMaxRequestEntity = Convert.ToInt64(lServerRuntimeSection.GetAttributeValue("maxRequestEntityAllowed")); if (lOldMaxRequestEntity == aMaxRequestEntityAllowed) { aStatus.Add($"= uploadReadAheadSize already set to ({lOldMaxRequestEntity})"); } else { lServerRuntimeSection.SetAttributeValue("maxRequestEntityAllowed", aMaxRequestEntityAllowed); mServerManager.CommitChanges(); aStatus.Add($"+ Set maxRequestEntityAllowed: ({lServerRuntimeSection.GetAttributeValue("maxRequestEntityAllowed")})"); } } public void VerifyDefaultDocument(string aSiteName, string aVirtualPath, string aFileName, List<string> aStatus) { aStatus.Add("SET DEFAULT DOCUMENT"); const string lSectionPath = "system.webServer/defaultDocument"; var lConfig = mServerManager.GetWebConfiguration(aSiteName, aVirtualPath); var lDefaultDocumentSection = lConfig.GetSection(lSectionPath); lDefaultDocumentSection["enabled"] = true; aStatus.Add($"* Section: ({lSectionPath}) Set enabled = true"); aStatus.Add($"* Site / Path: ({aSiteName}{aVirtualPath})"); var lExists = false; var lFilesCollection = lDefaultDocumentSection.GetCollection("files"); foreach (var lDefaultPage in lFilesCollection) { if (aFileName.ToLower() == ((string)lDefaultPage["value"]).ToLower()) lExists = true; } if (lExists) { aStatus.Add($"= ({aFileName}) already exists as default"); } else { ConfigurationElement lAddElement = lFilesCollection.CreateElement("add"); lAddElement["value"] = aFileName; lFilesCollection.AddAt(0, lAddElement); mServerManager.CommitChanges(); aStatus.Add($"+ Inserted ({aFileName}) as the first default document"); } } public bool MimeTypeRegistered(string aSiteName, string aVirtualPath, string aExtension, string aMimeType) { bool lExists = false; if (aVirtualPath != "/") lExists = MimeTypeRegistered(aSiteName, "/", aExtension, aMimeType); if (!lExists) { var lVDirConfig = mServerManager.GetWebConfiguration(aSiteName, aVirtualPath); var lStaticContentSection = lVDirConfig.GetSection("system.webServer/staticContent"); var lMimeMap = lStaticContentSection.GetCollection(); var lMt = lMimeMap.FirstOrDefault( aMapEntry => (string) aMapEntry.Attributes["fileExtension"].Value == aExtension); lExists = lMt != null; } return lExists; } public void VerifyMimeType(string aSiteName, string aVirtualPath, string aExtension, string aMimeType, List<string> aStatus) { const string lSectionPath = "system.webServer/staticContent"; if (MimeTypeRegistered(aSiteName, aVirtualPath, aExtension, aMimeType)) { aStatus.Add($"= Mime entry already exists for ({aExtension})"); } else { var lVDirConfig = mServerManager.GetWebConfiguration(aSiteName, aVirtualPath); var lStaticContentSection = lVDirConfig.GetSection(lSectionPath); var lMimeMap = lStaticContentSection.GetCollection(); var lMimeMapElement = lMimeMap.CreateElement("mimeMap"); lMimeMapElement["fileExtension"] = aExtension; lMimeMapElement["mimeType"] = aMimeType; lMimeMap.Add(lMimeMapElement); mServerManager.CommitChanges(); aStatus.Add($"+ Added mime type: ({aMimeType}) for ({aExtension})"); } } public void VerifyMimeTypes(string aSiteName, string aApplicationPath, List<MimeEntry> aMimeEntries, List<string> aStatus) { const string lSectionPath = "system.webServer/staticContent"; aStatus.Add("SET MIME TYPES"); aStatus.Add($"* Section: ({lSectionPath})"); aStatus.Add($"* Site / Path: ({aSiteName}{aApplicationPath})"); foreach (MimeEntry lEntry in aMimeEntries) { VerifyMimeType(aSiteName, aApplicationPath, lEntry.Extension, lEntry.MimeType, aStatus); } } private static ConfigurationElement FindElement(ConfigurationElementCollection aCollection, string aElementTagName, params string[] aKeyValues) { foreach (ConfigurationElement lElement in aCollection) { if (String.Equals(lElement.ElementTagName, aElementTagName, StringComparison.OrdinalIgnoreCase)) { bool lMatches = true; for (int i = 0; i < aKeyValues.Length; i += 2) { object o = lElement.GetAttributeValue(aKeyValues[i]); string lValue = null; if (o != null) { lValue = o.ToString(); } if (!String.Equals(lValue, aKeyValues[i + 1], StringComparison.OrdinalIgnoreCase)) { lMatches = false; break; } } if (lMatches) { return lElement; } } } return null; } public void SetApplicationUser(string aSite, string aApplication, string aUserName, string aPassword, List<string> aStatus) { aStatus.Add("SET APPLICATION USER"); try { const string lSectionPath = "system.applicationHost/sites"; var lConfig = mServerManager.GetApplicationHostConfiguration(); var lSitesSection = lConfig.GetSection(lSectionPath); var lSitesCollection = lSitesSection.GetCollection(); var lSiteElement = FindElement(lSitesCollection, "site", "name", aSite); var lApplicationCollection = lSiteElement.GetCollection(); ConfigurationElement lApplicationElement = FindElement(lApplicationCollection, "application", "path", aApplication); ConfigurationElementCollection lVirtualDirCollection = lApplicationElement.GetCollection(); ConfigurationElement lVirtualDirElement = FindElement(lVirtualDirCollection, "virtualDirectory", "path", @"/"); aStatus.Add($"* Application: ({aApplication})"); aStatus.Add($"* Site: ({aSite})"); if (lVirtualDirElement.Attributes["userName"].Value.Equals(aUserName)) { aStatus.Add($"= UserName: ({lVirtualDirElement.Attributes["userName"].Value}) already set"); } else { lVirtualDirElement.Attributes["userName"].Value = aUserName; lVirtualDirElement.Attributes["password"].Value = aPassword; aStatus.Add($"+ Set userName: ({lVirtualDirElement.Attributes["userName"].Value})"); aStatus.Add($"+ Set password: (***)"); } } catch (Exception lSetApplicationUser) { throw new Exception("SetApplicationUser", lSetApplicationUser); } } public void AddNewApplication(string aSite, string aApplication, string aPath, List<string> aStatus) { aStatus.Add("ADD APPLICATION"); try { mServerManager.Sites[aSite].Applications.Add(aApplication, aPath); mServerManager.CommitChanges(); aStatus.Add($"+ Site / Path: ({ aSite}{aPath})"); aStatus.Add($"+ Application: ({aApplication})"); } catch (Exception lAddNewApplication) { throw new Exception("Add New Application", lAddNewApplication); } } private void VerifyVirtualDirectory(string aSite, string aApplication, string aVirtualName, string aPhysicalDir, List<string> aStatus ) { try { var lExists = false; var lApplication = mServerManager.Sites[aSite].Applications[aApplication]; foreach (var lDirectory in lApplication.VirtualDirectories) { if (lDirectory.PhysicalPath.ToLower() == aPhysicalDir.ToLower()) lExists = true; } if (lExists) { aStatus.Add($"= Virtual directory ({aVirtualName}) already exists"); } else { lApplication.VirtualDirectories.Add(aVirtualName, aPhysicalDir); mServerManager.CommitChanges(); aStatus.Add($"+ Added virtual directory ({aVirtualName}={aPhysicalDir})"); } } catch (Exception lAddNewVirtualDirectory) { throw new Exception("Add New Virtual Directory ", lAddNewVirtualDirectory); } } public void VerifyVirtualFolders( string aSiteName, string aApplicationPath, List<VirtualFolder> aFolders, List<string> aStatus) { aStatus.Add($"ADD VIRTUAL FOLDERS"); aStatus.Add($"* Site / Path: ({aSiteName}{aApplicationPath})"); foreach (VirtualFolder lVirtualFolder in aFolders) { VerifyVirtualDirectory( aSiteName, aApplicationPath, $"/{lVirtualFolder.Alias}", lVirtualFolder.PhysicalFolder, aStatus); } } public void SetUpApplicationPool(string aApplicationPoolName, string aUserName, string aPassword, List<string> aStatus) { aStatus.Add("PREPARE APPLICATION POOL"); try { aStatus.Add($"* Pool name: ({aApplicationPoolName})"); var lAppPool = mServerManager.ApplicationPools[aApplicationPoolName]; lAppPool.ManagedRuntimeVersion = "v4.0"; aStatus.Add($"+ Set ManagedRuntimeVersion: ({lAppPool.ManagedRuntimeVersion})"); lAppPool.ManagedPipelineMode = ManagedPipelineMode.Integrated; aStatus.Add($"+ Set ManagedPipelineMode: ({lAppPool.ManagedPipelineMode})"); lAppPool.Enable32BitAppOnWin64 = true; aStatus.Add($"+ Set Enable32BitAppOnWin64: ({lAppPool.Enable32BitAppOnWin64})"); lAppPool.AutoStart = true; aStatus.Add($"+ Set AutoStart: ({lAppPool.AutoStart})"); lAppPool.ProcessModel.IdleTimeout = new TimeSpan(0, 360, 0); aStatus.Add($"+ Set ProcessModel.IdleTimeout: ({lAppPool.ProcessModel.IdleTimeout})"); lAppPool.Recycling.DisallowOverlappingRotation = true; aStatus.Add($"+ Set Recycling.DisallowoverlappingRotation: ({lAppPool.Recycling.DisallowOverlappingRotation})"); lAppPool.Recycling.PeriodicRestart.Time = new TimeSpan(0, 0, 0); aStatus.Add($"+ Set Recycling.PeriodicRestart.Time: ({new TimeSpan(0, 0, 0)})"); lAppPool.Recycling.PeriodicRestart.Schedule.Clear(); lAppPool.Recycling.PeriodicRestart.Schedule.Add(new TimeSpan(3,0,0)); aStatus.Add($"+ Set Recycling.PeriodicRestart.Schedule: ({new TimeSpan(3,0,0)})"); if (aUserName != string.Empty) { lAppPool.ProcessModel.UserName = Environment.MachineName + "\\" + aUserName; lAppPool.ProcessModel.IdentityType = ProcessModelIdentityType.SpecificUser; lAppPool.ProcessModel.Password = aPassword; aStatus.Add($"+ Set ProcessModelUserName: ({lAppPool.ProcessModel.UserName}) Password: (***)"); aStatus.Add($"+ Set IdentityType: (SpecificUser)"); } else { aStatus.Add("* No User Name sent"); } mServerManager.CommitChanges(); } catch (Exception lSetUpApplicationPool) { throw new Exception("Set Up ApplicationPool", lSetUpApplicationPool); } } public void AddNewApplicationPool(string aApplicationPoolName, List<string> aStatus) { aStatus.Add("ADD APPLICATION POOL"); try { mServerManager.ApplicationPools.Add(aApplicationPoolName); mServerManager.CommitChanges(); aStatus.Add($"+ Pool name: ({aApplicationPoolName})"); } catch (Exception lAddNewApplicationPool) { throw new Exception("Add New ApplicationPool", lAddNewApplicationPool); } } public void DeleteApplicationPool(string aApplicationPoolName, List<string> aStatus) { aStatus.Add("DELETE APPLICATION POOL"); try { ApplicationPool lAppPool = mServerManager.ApplicationPools[aApplicationPoolName]; if (lAppPool == null) { throw new Exception("DeleteApplicationPool - Application pool not found"); } ApplicationPoolCollection lAppColl = mServerManager.ApplicationPools; lAppColl.Remove(lAppPool); mServerManager.CommitChanges(); aStatus.Add($"+ Pool name: ({aApplicationPoolName})"); } catch (Exception lDeleteApplication) { throw new Exception("Delete Application", lDeleteApplication); } } public void AttachSiteToApplicationPool(string aSite, string aApplicationPath, string aApplicationPool, List<string> aStatus) { aStatus.Add("ADD SITE TO APPLICATION POOL"); try { mServerManager.Sites[aSite].Applications[aApplicationPath].ApplicationPoolName = aApplicationPool; ApplicationPool lAppPool = mServerManager.ApplicationPools[aApplicationPool]; aStatus.Add($"+ Site: ({mServerManager.Sites[aSite].Name}) added to pool: ({lAppPool.Name})"); mServerManager.CommitChanges(); } catch (Exception lAttachSiteToAppPool) { throw new Exception("Attach Site To Application Pool", lAttachSiteToAppPool); } } } }