From 53cab92f5556b29870407e12c61ba30ccdd67032 Mon Sep 17 00:00:00 2001 From: Olov Karlsson Date: Mon, 15 Sep 2014 11:31:43 +0200 Subject: [PATCH 1/6] Support for ActiveDirectory User Isolation Mode in IIS FTP Provider --- .../WebsitePanel.Providers.FTP.IIs70/MsFTP.cs | 327 +++++++++++++----- .../SecurityUtils.cs | 8 + .../MSFTP70_Settings.ascx.resx | 7 +- .../ProviderControls/MSFTP70_Settings.ascx | 92 +++-- .../ProviderControls/MSFTP70_Settings.ascx.cs | 37 +- .../MSFTP70_Settings.ascx.designer.cs | 49 ++- 6 files changed, 383 insertions(+), 137 deletions(-) diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.FTP.IIs70/MsFTP.cs b/WebsitePanel/Sources/WebsitePanel.Providers.FTP.IIs70/MsFTP.cs index 69413bc7..418d8c22 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.FTP.IIs70/MsFTP.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.FTP.IIs70/MsFTP.cs @@ -30,6 +30,7 @@ using System; using System.Collections.Generic; using System.DirectoryServices.ActiveDirectory; using System.IO; +using System.Linq; using System.Net; using System.Net.Sockets; using WebsitePanel.Providers.FTP.IIs70; @@ -99,6 +100,20 @@ namespace WebsitePanel.Providers.FTP { get { return ProviderSettings["ADGroupsOU"]; } } + + protected string AdFtpRoot + { + get { return ProviderSettings["AdFtpRoot"]; } + } + + protected Mode UserIsolationMode + { + get + { + var site = GetSite(ProviderSettings["SiteId"]); + return (Mode)Enum.Parse(typeof(Mode), site["UserIsolationMode"]); + } + } #endregion #region IFtpServer Members @@ -291,134 +306,275 @@ namespace WebsitePanel.Providers.FTP this.ftpSitesService.DeleteSite(siteId); } - /// - /// Checks whether account with given name exists. - /// - /// Account name to check. - /// true - if it exists; false - otherwise. + /// + /// Checks whether account with given name exists. + /// + /// Account name to check. + /// true - if it exists; false - otherwise. public bool AccountExists(string accountName) { if (String.IsNullOrEmpty(accountName)) { - return false; + return false; } - // check acocunt on FTP server - bool ftpExists = this.ftpSitesService.VirtualDirectoryExists(this.SiteId, accountName); + switch (UserIsolationMode) + { + case Mode.ActiveDirectory: + return SecurityUtils.UserExists(accountName, ServerSettings, UsersOU); - // check account in the system - bool systemExists = SecurityUtils.UserExists(accountName, ServerSettings, UsersOU); - return (ftpExists || systemExists); + default: + // check acocunt on FTP server + bool ftpExists = this.ftpSitesService.VirtualDirectoryExists(this.SiteId, accountName); + + // check account in the system + bool systemExists = SecurityUtils.UserExists(accountName, ServerSettings, UsersOU); + return (ftpExists || systemExists); + } } - /// + /// /// Gets available ftp accounts. /// /// List of avaialble accounts. public FtpAccount[] GetAccounts() { - List accounts = new List(); + switch (UserIsolationMode) + { + case Mode.ActiveDirectory: + return SecurityUtils.GetUsers(ServerSettings, UsersOU).Select(GetAccount).ToArray(); + default: + List accounts = new List(); - foreach (string directory in this.ftpSitesService.GetVirtualDirectoriesNames(this.SiteId)) - { - // Skip root virtual directory - if (String.Equals(directory, "/")) - continue; - // - accounts.Add(this.GetAccount(directory.Substring(1))); - } + foreach (string directory in this.ftpSitesService.GetVirtualDirectoriesNames(this.SiteId)) + { + // Skip root virtual directory + if (String.Equals(directory, "/")) + continue; + // + accounts.Add(this.GetAccount(directory.Substring(1))); + } - return accounts.ToArray(); + return accounts.ToArray(); + } } - /// - /// Gets account with given name. - /// - /// Account's name to get. - /// Ftp account. + /// + /// Gets account with given name. + /// + /// Account's name to get. + /// Ftp account. public FtpAccount GetAccount(string accountName) { - FtpAccount acc = new FtpAccount(); - acc.Name = accountName; - this.FillFtpAccountFromIis(acc); - return acc; + switch (UserIsolationMode) + { + case Mode.ActiveDirectory: + var user = SecurityUtils.GetUser(accountName, ServerSettings, UsersOU); + + var path = Path.Combine(user.MsIIS_FTPRoot, user.MsIIS_FTPDir); + var permission = GetUserPermission(accountName, path); + var account = new FtpAccount() + { + CanRead = permission.Read, + CanWrite = permission.Write, + CreatedDate = user.CreatedDate, + Enabled = !user.AccountDisabled, + Folder = path, + GroupName = user.GroupName, + Name = user.Name + }; + + return account; + default: + FtpAccount acc = new FtpAccount(); + acc.Name = accountName; + this.FillFtpAccountFromIis(acc); + return acc; + } } - /// + protected UserPermission GetUserPermission(string accountName, string folder) + { + var userPermission = new UserPermission {AccountName = accountName}; + return SecurityUtils.GetGroupNtfsPermissions(folder, new[] {userPermission}, ServerSettings, UsersOU, GroupsOU)[0]; + } + + + /// /// Creates ftp account under root ftp site. /// /// Ftp account to create. public void CreateAccount(FtpAccount account) { - // Create user account. - SystemUser user = new SystemUser(); - user.Name = account.Name; - user.FullName = account.Name; - user.Description = "WebsitePanel System Account"; - user.MemberOf = new string[] { FtpGroupName }; - user.Password = account.Password; - user.PasswordCantChange = true; - user.PasswordNeverExpires = true; - user.AccountDisabled = !account.Enabled; - user.System = true; + switch (UserIsolationMode) + { + case Mode.ActiveDirectory: + SecurityUtils.EnsureOrganizationalUnitsExist(ServerSettings, UsersOU, GroupsOU); - // Create in the operating system. - if (SecurityUtils.UserExists(user.Name, ServerSettings, UsersOU)) - { - SecurityUtils.DeleteUser(user.Name, ServerSettings, UsersOU); - } - SecurityUtils.CreateUser(user, ServerSettings, UsersOU, GroupsOU); + var systemUser = SecurityUtils.GetUser(account.Name, ServerSettings, UsersOU); - // Prepare account's home folder. - this.EnsureUserHomeFolderExists(account.Folder, account.Name, account.CanRead, account.CanWrite); + if (systemUser == null) + { + systemUser = new SystemUser + { + Name = account.Name, + FullName = account.Name, + Password = account.Password, + PasswordCantChange = true, + PasswordNeverExpires = true, + System = true + }; - // Future account will be given virtual directory under default ftp web site. - this.ftpSitesService.CreateFtpAccount(this.SiteId, account); - // - this.ftpSitesService.ConfigureConnectAs(account.Folder, this.SiteId, account.VirtualPath, - this.GetQualifiedAccountName(account.Name), account.Password, true); - } + SecurityUtils.CreateUser(systemUser, ServerSettings, UsersOU, GroupsOU); + } - /// - /// Updates ftp account. - /// - /// Accoun to update. + UpdateAccount(account); + + break; + + default: + // Create user account. + SystemUser user = new SystemUser(); + user.Name = account.Name; + user.FullName = account.Name; + user.Description = "WebsitePanel System Account"; + user.MemberOf = new string[] {FtpGroupName}; + user.Password = account.Password; + user.PasswordCantChange = true; + user.PasswordNeverExpires = true; + user.AccountDisabled = !account.Enabled; + user.System = true; + + // Create in the operating system. + if (SecurityUtils.UserExists(user.Name, ServerSettings, UsersOU)) + { + SecurityUtils.DeleteUser(user.Name, ServerSettings, UsersOU); + } + SecurityUtils.CreateUser(user, ServerSettings, UsersOU, GroupsOU); + + // Prepare account's home folder. + this.EnsureUserHomeFolderExists(account.Folder, account.Name, account.CanRead, account.CanWrite); + + // Future account will be given virtual directory under default ftp web site. + this.ftpSitesService.CreateFtpAccount(this.SiteId, account); + // + this.ftpSitesService.ConfigureConnectAs(account.Folder, this.SiteId, account.VirtualPath, + this.GetQualifiedAccountName(account.Name), account.Password, true); + break; + } + } + + /// + /// Updates ftp account. + /// + /// Accoun to update. public void UpdateAccount(FtpAccount account) { - // Change user account state and password (if required). - SystemUser user = SecurityUtils.GetUser(account.Name, ServerSettings, UsersOU); - user.Password = account.Password; - user.AccountDisabled = !account.Enabled; - SecurityUtils.UpdateUser(user, ServerSettings, UsersOU, GroupsOU); - // Update iis configuration. - this.FillIisFromFtpAccount(account); + var user = SecurityUtils.GetUser(account.Name, ServerSettings, UsersOU); + + switch (UserIsolationMode) + { + case Mode.ActiveDirectory: + var ftpRoot = AdFtpRoot.ToLower(); + var ftpDir = account.Folder.ToLower().Replace(ftpRoot, ""); + + var oldDir = user.MsIIS_FTPDir; + + user.Password = account.Password; + user.PasswordCantChange = true; + user.PasswordNeverExpires = true; + user.Description = "WebsitePanel FTP Account with AD User Isolation"; + user.MemberOf = new[] {FtpGroupName}; + user.AccountDisabled = !account.Enabled; + user.MsIIS_FTPRoot = ftpRoot; + user.MsIIS_FTPDir = ftpDir; + user.System = true; + + SecurityUtils.UpdateUser(user, ServerSettings, UsersOU, GroupsOU); + + // Set NTFS permissions + var userPermission = GetUserPermission(account.Name, account.Folder); + + // Do we need to change the NTFS permissions? i.e. is users home dir changed or are permissions changed? + if (oldDir != ftpDir || account.CanRead != userPermission.Read || account.CanWrite != userPermission.Write) + { + // First get sid of user account + var sid = SecurityUtils.GetAccountSid(account.Name, ServerSettings, UsersOU, GroupsOU); + + // Remove the permissions set for this account on previous folder + SecurityUtils.RemoveNtfsPermissionsBySid(Path.Combine(ftpRoot, oldDir), sid); + + // If no permissions is to be set, exit + if (!account.CanRead && !account.CanWrite) + { + return; + } + + // Add the new permissions + var ntfsPermissions = account.CanRead ? NTFSPermission.Read : NTFSPermission.Write; + if (account.CanRead && account.CanWrite) + { + ntfsPermissions = NTFSPermission.Modify; + } + + SecurityUtils.GrantNtfsPermissionsBySid(account.Folder, sid, ntfsPermissions, true, true); + } + break; + + default: + + // Change user account state and password (if required). + user.Password = account.Password; + user.AccountDisabled = !account.Enabled; + SecurityUtils.UpdateUser(user, ServerSettings, UsersOU, GroupsOU); + // Update iis configuration. + this.FillIisFromFtpAccount(account); + break; + } } - /// - /// Deletes account with given name. - /// - /// Account's name to be deleted. + /// + /// Deletes account with given name. + /// + /// Account's name to be deleted. public void DeleteAccount(string accountName) { - string virtualDirectory = String.Format("/{0}", accountName); - string currentPhysicalPath = this.ftpSitesService.GetSitePhysicalPath(this.SiteId, virtualDirectory); + switch (UserIsolationMode) + { + case Mode.ActiveDirectory: + var account = GetAccount(accountName); - // Delete virtual directory - this.ftpSitesService.DeleteFtpAccount(this.SiteId, virtualDirectory); + // Remove the NTFS permissions first + SecurityUtils.RemoveNtfsPermissions(account.Folder, account.Name, ServerSettings, UsersOU, GroupsOU); - this.ftpSitesService.CommitChanges(); + if (SecurityUtils.UserExists(accountName, ServerSettings, UsersOU)) + { + SecurityUtils.DeleteUser(accountName, ServerSettings, UsersOU); + } + break; - // Remove permissions - RemoveFtpFolderPermissions(currentPhysicalPath, accountName); + default: + string virtualDirectory = String.Format("/{0}", accountName); + string currentPhysicalPath = this.ftpSitesService.GetSitePhysicalPath(this.SiteId, virtualDirectory); - // Delete system user account - if (SecurityUtils.UserExists(accountName, ServerSettings, UsersOU)) - { - SecurityUtils.DeleteUser(accountName, ServerSettings, UsersOU); - } + // Delete virtual directory + this.ftpSitesService.DeleteFtpAccount(this.SiteId, virtualDirectory); + + this.ftpSitesService.CommitChanges(); + + // Remove permissions + RemoveFtpFolderPermissions(currentPhysicalPath, accountName); + + // Delete system user account + if (SecurityUtils.UserExists(accountName, ServerSettings, UsersOU)) + { + SecurityUtils.DeleteUser(accountName, ServerSettings, UsersOU); + } + break; + } } - /// + /// /// Fills iis configuration from ftp account. /// /// Ftp account to fill from. @@ -519,6 +675,7 @@ namespace WebsitePanel.Providers.FTP ftpSite.AllowAnonymous = iisFtpSite.Security.Authentication.AnonymousAuthentication.Enabled; ftpSite.AnonymousUsername = iisFtpSite.Security.Authentication.AnonymousAuthentication.UserName; ftpSite.AnonymousUserPassword = iisFtpSite.Security.Authentication.AnonymousAuthentication.Password; + ftpSite["UserIsolationMode"] = iisFtpSite.UserIsolation.Mode.ToString(); // Logging settings. ftpSite[FtpSite.MSFTP7_SITE_ID] = iisFtpSite.SiteServiceId; if (iisFtpSite.LogFile.Enabled) diff --git a/WebsitePanel/Sources/WebsitePanel.Server.Utils/SecurityUtils.cs b/WebsitePanel/Sources/WebsitePanel.Server.Utils/SecurityUtils.cs index a2fcd1a9..27ddaa75 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server.Utils/SecurityUtils.cs +++ b/WebsitePanel/Sources/WebsitePanel.Server.Utils/SecurityUtils.cs @@ -511,6 +511,8 @@ namespace WebsitePanel.Providers.Utils user.PasswordCantChange = ((userFlags & ADAccountOptions.UF_PASSWD_CANT_CHANGE) != 0); user.PasswordNeverExpires = ((userFlags & ADAccountOptions.UF_DONT_EXPIRE_PASSWD) != 0); user.AccountDisabled = ((userFlags & ADAccountOptions.UF_ACCOUNTDISABLE) != 0); + user.MsIIS_FTPDir = GetObjectProperty(objUser, "msIIS-FTPDir").ToString(); + user.MsIIS_FTPRoot = GetObjectProperty(objUser, "msIIS-FTPRoot").ToString(); // get user groups user.MemberOf = GetUserGroups(objUser); @@ -727,6 +729,12 @@ namespace WebsitePanel.Providers.Utils objUser.Properties["description"].Value = String.IsNullOrEmpty(user.Description) ? "WebsitePanel System Account" : user.Description; + if (user.MsIIS_FTPDir != string.Empty) + { + SetObjectProperty(objUser, "msIIS-FTPDir", user.MsIIS_FTPDir); + SetObjectProperty(objUser, "msIIS-FTPRoot", user.MsIIS_FTPRoot); + } + ADAccountOptions userFlags = ADAccountOptions.UF_NORMAL_ACCOUNT; if (user.PasswordCantChange) diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/App_LocalResources/MSFTP70_Settings.ascx.resx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/App_LocalResources/MSFTP70_Settings.ascx.resx index d6149f97..4021bbe7 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/App_LocalResources/MSFTP70_Settings.ascx.resx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/App_LocalResources/MSFTP70_Settings.ascx.resx @@ -112,10 +112,10 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Yes @@ -138,4 +138,7 @@ <Select FTP Site> + + FTP RootDir: + \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx index 831772d8..bb35b384 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx @@ -1,45 +1,61 @@ <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MSFTP70_Settings.ascx.cs" Inherits="WebsitePanel.Portal.ProviderControls.MSFTP70_Settings" %> <%@ Register Src="Common_ActiveDirectoryIntegration.ascx" TagName="ActiveDirectoryIntegration" TagPrefix="uc1" %> <%@ Register Src="../UserControls/SelectIPAddress.ascx" TagName="SelectIPAddress" TagPrefix="uc1" %> - - - - + + + + + +
- - + + + + - - - - - - - - +
+ + -
- - -
- - +
+ + + + + + + + + + + +
+ + + +
+ + + + +
+
+
+ + + + - - - - - - - - + + - -
+ +
- - - -
- - - - +
+
\ No newline at end of file +
+ +
+ + + +
diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx.cs index 9caf61df..71c18d09 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx.cs @@ -27,10 +27,12 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using System; +using System.Collections.Generic; using System.Data; using System.Configuration; using System.Collections; using System.Collections.Specialized; +using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; @@ -51,7 +53,8 @@ namespace WebsitePanel.Portal.ProviderControls { int selectedAddressid = this.FindAddressByText(settings["SharedIP"]); ipAddress.AddressId = (selectedAddressid > 0) ? selectedAddressid : 0; - txtSiteId.Text = settings["SiteId"]; + BindSiteId(settings); + txtAdFtpRoot.Text = settings["AdFtpRoot"]; txtFtpGroupName.Text = settings["FtpGroupName"]; chkBuildUncFilesPath.Checked = Utils.ParseBool(settings["BuildUncFilesPath"], false); ActiveDirectoryIntegration.BindSettings(settings); @@ -75,7 +78,11 @@ namespace WebsitePanel.Portal.ProviderControls { settings["SharedIP"] = String.Empty; } - settings["SiteId"] = txtSiteId.Text.Trim(); + settings["SiteId"] = ddlSite.SelectedValue; + if (!string.IsNullOrWhiteSpace(txtAdFtpRoot.Text)) + { + settings["AdFtpRoot"] = txtAdFtpRoot.Text.Trim(); + } settings["FtpGroupName"] = txtFtpGroupName.Text.Trim(); settings["BuildUncFilesPath"] = chkBuildUncFilesPath.Checked.ToString(); ActiveDirectoryIntegration.SaveSettings(settings); @@ -92,5 +99,31 @@ namespace WebsitePanel.Portal.ProviderControls } return 0; } + + private void BindSiteId(StringDictionary settings) + { + var sites = ES.Services.FtpServers.GetFtpSites(PanelRequest.ServiceId); + + foreach (var site in sites) + { + var item = new ListItem(site.Name + " (User Isolation Mode: " + site["UserIsolationMode"] + ")", site.Name); + + if (item.Value == settings["SiteId"]) + { + item.Selected = true; + } + + ddlSite.Items.Add(item); + } + + ddlSite_SelectedIndexChanged(this, null); + } + + protected void ddlSite_SelectedIndexChanged(object sender, EventArgs e) + { + var isActiveDirectoryUserIsolated = ddlSite.SelectedItem.Text.Contains("ActiveDirectory"); + FtpRootRow.Visible = isActiveDirectoryUserIsolated; + txtAdFtpRootReqValidator.Enabled= isActiveDirectoryUserIsolated; + } } } \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx.designer.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx.designer.cs index 596afc56..b4f88c2a 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx.designer.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/MSFTP70_Settings.ascx.designer.cs @@ -1,22 +1,15 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.1378 // // Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// the code is regenerated. // //------------------------------------------------------------------------------ namespace WebsitePanel.Portal.ProviderControls { - /// - /// MSFTP70_Settings class. - /// - /// - /// Auto-generated class. - /// public partial class MSFTP70_Settings { /// @@ -47,13 +40,49 @@ namespace WebsitePanel.Portal.ProviderControls { protected global::System.Web.UI.WebControls.Label lblSite; /// - /// txtSiteId control. + /// ddlSite control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::System.Web.UI.WebControls.TextBox txtSiteId; + protected global::System.Web.UI.WebControls.DropDownList ddlSite; + + /// + /// FtpRootRow control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlTableRow FtpRootRow; + + /// + /// lblAdFtpRoot control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label lblAdFtpRoot; + + /// + /// txtAdFtpRoot control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.TextBox txtAdFtpRoot; + + /// + /// txtAdFtpRootReqValidator control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.RequiredFieldValidator txtAdFtpRootReqValidator; /// /// lblGroupName control. From d7ac9fa36fd5434ee560b1f009e8757aed1894fc Mon Sep 17 00:00:00 2001 From: Olov Karlsson Date: Fri, 3 Oct 2014 10:18:33 +0200 Subject: [PATCH 2/6] Changes to IIS70 provider, etc for changing PHP versions among installed versions. Mimics the behaviour of IIS PHP Manager and works with it, i.e. changes made in PHP Manager is visible in WSP and vice versa. --- .../Web/PhpVersion.cs | 42 +++++ .../Web/WebVirtualDirectory.cs | 9 +- .../WebsitePanel.Providers.Base.csproj | 1 + .../Handlers/HandlersModuleService.cs | 68 +++++++- .../WebsitePanel.Providers.Web.IIS70/IIs70.cs | 162 ++++++++++++++---- .../WebSitesExtensionsControl.ascx | 2 - .../WebSitesExtensionsControl.ascx.cs | 23 ++- ...WebSitesExtensionsControl.ascx.designer.cs | 3 +- 8 files changed, 266 insertions(+), 44 deletions(-) create mode 100644 WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/PhpVersion.cs diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/PhpVersion.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/PhpVersion.cs new file mode 100644 index 00000000..5648842e --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/PhpVersion.cs @@ -0,0 +1,42 @@ +// Copyright (c) 2014, Outercurve Foundation. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// - Neither the name of the Outercurve Foundation nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +using System; +using System.Net; +using System.Text; +using System.Xml.Serialization; + +namespace WebsitePanel.Providers.Web +{ + public class PhpVersion + { + public string HandlerName { get; set; } + public string Version { get; set; } + public string ExecutionPath { get; set; } + } +} diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebVirtualDirectory.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebVirtualDirectory.cs index 912d58f6..244b8940 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebVirtualDirectory.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/Web/WebVirtualDirectory.cs @@ -81,6 +81,7 @@ namespace WebsitePanel.Providers.Web private bool sharePointInstalled; private bool iis7; private string consoleUrl; + private string php5VersionsInstalled; public string AnonymousUsername { @@ -285,7 +286,13 @@ namespace WebsitePanel.Providers.Web set { consoleUrl = value; } } - #region Web Deploy Publishing Properties + public string Php5VersionsInstalled + { + get { return php5VersionsInstalled; } + set { php5VersionsInstalled = value; } + } + + #region Web Deploy Publishing Properties /// /// Gets or sets Web Deploy publishing account name /// diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj index 2ab48c12..3f7049a0 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj @@ -329,6 +329,7 @@ + diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Handlers/HandlersModuleService.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Handlers/HandlersModuleService.cs index 12a7b902..d2a7c783 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Handlers/HandlersModuleService.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Handlers/HandlersModuleService.cs @@ -26,6 +26,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +using System.Linq; + namespace WebsitePanel.Providers.Web.Handlers { using System; @@ -178,7 +180,7 @@ namespace WebsitePanel.Providers.Web.Handlers } } - internal void InheritScriptMapsFromParent(string fqPath) + internal void InheritScriptMapsFromParent(string fqPath) { if (String.IsNullOrEmpty(fqPath)) return; @@ -241,5 +243,69 @@ namespace WebsitePanel.Providers.Web.Handlers // return null; } + + + internal void CopyInheritedHandlers(string siteName, string vDirPath) + { + if (string.IsNullOrEmpty(siteName)) + { + return; + } + + if (string.IsNullOrEmpty(vDirPath)) + { + vDirPath = "/"; + } + + using (var srvman = GetServerManager()) + { + var config = srvman.GetWebConfiguration(siteName, vDirPath); + + var handlersSection = (HandlersSection)config.GetSection(Constants.HandlersSection, typeof(HandlersSection)); + + var handlersCollection = handlersSection.Handlers; + + var list = new HandlerAction[handlersCollection.Count]; + ((System.Collections.ICollection) handlersCollection).CopyTo(list, 0); + + handlersCollection.Clear(); + + foreach (var handler in list) + { + handlersCollection.AddCopy(handler); + } + + srvman.CommitChanges(); + } + } + + internal void MoveHandlerToTop(string handlerName, string siteName, string vDirPath) + { + if (string.IsNullOrEmpty(siteName)) + { + return; + } + + if (string.IsNullOrEmpty(vDirPath)) + { + vDirPath = "/"; + } + + using (var srvman = GetServerManager()) + { + var config = srvman.GetWebConfiguration(siteName, vDirPath); + + var handlersSection = (HandlersSection)config.GetSection(Constants.HandlersSection, typeof(HandlersSection)); + + var handlersCollection = handlersSection.Handlers; + + var handlerElement = handlersCollection[handlerName]; + + handlersCollection.Remove(handlerElement); + handlersCollection.AddCopyAt(0, handlerElement); + + srvman.CommitChanges(); + } + } } } diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs index 22f33a5b..bb0376a4 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs @@ -28,6 +28,8 @@ using System; using System.Collections; +using System.Diagnostics; +using System.Linq; using System.Management; using System.DirectoryServices; using System.DirectoryServices.ActiveDirectory; @@ -280,7 +282,7 @@ namespace WebsitePanel.Providers.Web Name = settings[Constants.IntegratedAspNet40Pool].Trim() }); } - #endregion + #endregion #region Populate Dedicated Application Pools // ASP.NET 1.1 @@ -711,9 +713,9 @@ namespace WebsitePanel.Providers.Web if (!String.IsNullOrEmpty(AspPath) && String.Equals(AspPath, processor, StringComparison.InvariantCultureIgnoreCase)) virtualDir.AspInstalled = true; - // Detect whether PHP 5 scripting is enabled - if (!String.IsNullOrEmpty(PhpExecutablePath) && String.Equals(PhpExecutablePath, processor, StringComparison.InvariantCultureIgnoreCase)) - virtualDir.PhpInstalled = PHP_5; + //// Detect whether PHP 5 scripting is enabled (non fast_cgi) + if (PhpMode != Constants.PhpMode.FastCGI && !String.IsNullOrEmpty(PhpExecutablePath) && String.Equals(PhpExecutablePath, processor, StringComparison.InvariantCultureIgnoreCase)) + virtualDir.PhpInstalled = PHP_5; // Detect whether PHP 4 scripting is enabled if (!String.IsNullOrEmpty(Php4Path) && String.Equals(Php4Path, processor, StringComparison.InvariantCultureIgnoreCase)) @@ -727,7 +729,18 @@ namespace WebsitePanel.Providers.Web if (!String.IsNullOrEmpty(PerlPath) && String.Equals(PerlPath, processor, StringComparison.InvariantCultureIgnoreCase)) virtualDir.PerlInstalled = true; } - + + // Detect PHP 5 Fast_cgi version(s) + var activePhp5Handler = GetActivePhpHandlerName(srvman, virtualDir); + if (!string.IsNullOrEmpty(activePhp5Handler)) + { + virtualDir.PhpInstalled = PHP_5 + "|" + activePhp5Handler; + var versions = GetPhpVersions(srvman, virtualDir); + // This versionstring is used in UI to view and change php5 version. + var versionString = string.Join("|", versions.Select(v => v.HandlerName + ";" + v.Version).ToArray()); + virtualDir.Php5VersionsInstalled = versionString; + } + // string fqPath = virtualDir.FullQualifiedPath; if (!fqPath.EndsWith(@"/")) @@ -865,32 +878,63 @@ namespace WebsitePanel.Providers.Web #endregion #region PHP 5 script mappings - if (!String.IsNullOrEmpty(PhpExecutablePath) && File.Exists(PhpExecutablePath)) - { - if (virtualDir.PhpInstalled == PHP_5) - { - switch (PhpMode) - { - case Constants.PhpMode.FastCGI: - handlersSvc.AddScriptMaps(virtualDir, PHP_EXTENSIONS, - PhpExecutablePath, Constants.HandlerAlias.PHP_FASTCGI, Constants.FastCgiModule); - break; - case Constants.PhpMode.CGI: - handlersSvc.AddScriptMaps(virtualDir, PHP_EXTENSIONS, - PhpExecutablePath, Constants.HandlerAlias.PHP_CGI, Constants.CgiModule); - break; - case Constants.PhpMode.ISAPI: - handlersSvc.AddScriptMaps(virtualDir, PHP_EXTENSIONS, - PhpExecutablePath, Constants.HandlerAlias.PHP_ISAPI, Constants.IsapiModule); - break; - } - } - else - { - handlersSvc.RemoveScriptMaps(virtualDir, PHP_EXTENSIONS, PhpExecutablePath); - } - } - // + if (virtualDir.PhpInstalled.StartsWith(PHP_5)) + { + if (PhpMode == Constants.PhpMode.FastCGI && virtualDir.PhpInstalled.Contains('|')) + { + var path = PhpExecutablePath; + var args = virtualDir.PhpInstalled.Split('|'); + if (args.Count() > 1) + { + // Handler name is present, let us try to find the corresponding path to executable + var phpVersion = GetPhpVersions(virtualDir).SingleOrDefault(p => p.HandlerName == args[1]); + if (phpVersion != null) + { + path = phpVersion.ExecutionPath; + } + } + + if (!String.IsNullOrEmpty(path) && File.Exists(path)) + { + handlersSvc.CopyInheritedHandlers(((WebSite)virtualDir).SiteId, virtualDir.VirtualPath); + handlersSvc.MoveHandlerToTop(args[1], ((WebSite) virtualDir).SiteId, virtualDir.VirtualPath); + } + } + else + { + if (!String.IsNullOrEmpty(PhpExecutablePath) && File.Exists(PhpExecutablePath)) + { + switch (PhpMode) + { + case Constants.PhpMode.FastCGI: + handlersSvc.AddScriptMaps(virtualDir, PHP_EXTENSIONS, + PhpExecutablePath, Constants.HandlerAlias.PHP_FASTCGI, Constants.FastCgiModule); + break; + case Constants.PhpMode.CGI: + handlersSvc.AddScriptMaps(virtualDir, PHP_EXTENSIONS, + PhpExecutablePath, Constants.HandlerAlias.PHP_CGI, Constants.CgiModule); + break; + case Constants.PhpMode.ISAPI: + handlersSvc.AddScriptMaps(virtualDir, PHP_EXTENSIONS, + PhpExecutablePath, Constants.HandlerAlias.PHP_ISAPI, Constants.IsapiModule); + break; + } + } + } + } + else + { + if (PhpMode == Constants.PhpMode.FastCGI && GetPhpVersions(virtualDir).Any()) + { + // Don't erase handler mappings, if we do, the virtualDir cannot see and choose what version of PHP to run later + } + else + { + handlersSvc.RemoveScriptMaps(virtualDir, PHP_EXTENSIONS, PhpExecutablePath); + } + } + + // #endregion #region PHP 4 script mappings (IsapiModule only) @@ -4437,5 +4481,59 @@ namespace WebsitePanel.Providers.Web #endregion - } + + #region Php Management + + protected PhpVersion[] GetPhpVersions(ServerManager srvman, WebVirtualDirectory virtualDir) + { + var config = srvman.GetWebConfiguration(((WebSite)virtualDir).SiteId, virtualDir.VirtualPath); + //var config = srvman.GetApplicationHostConfiguration(); + var handlersSection = config.GetSection(Constants.HandlersSection); + + var result = new List(); + + // Loop through available maps and fill installed processors + foreach (var handler in handlersSection.GetCollection()) + { + if (string.Equals(handler["path"].ToString(), "*.php", StringComparison.OrdinalIgnoreCase)) + { + var executable = handler["ScriptProcessor"].ToString().Split('|')[0]; + if (string.Equals(handler["Modules"].ToString(), "FastCgiModule", StringComparison.OrdinalIgnoreCase) && File.Exists(executable)) + { + var handlerName = handler["Name"].ToString(); + result.Add(new PhpVersion() {HandlerName = handlerName, Version = GetPhpExecutableVersion(executable), ExecutionPath = handler["ScriptProcessor"].ToString()}); + } + } + } + + return result.ToArray(); + } + + protected PhpVersion[] GetPhpVersions(WebVirtualDirectory virtualDir) + { + using (var srvman = new ServerManager()) + { + return GetPhpVersions(srvman, virtualDir); + } + } + + protected string GetActivePhpHandlerName(ServerManager srvman, WebVirtualDirectory virtualDir) + { + var config = srvman.GetWebConfiguration(((WebSite)virtualDir).SiteId, virtualDir.VirtualPath); + var handlersSection = config.GetSection(Constants.HandlersSection); + + // Find first handler for *.php + return (from handler in handlersSection.GetCollection() + where string.Equals(handler["path"].ToString(), "*.php", StringComparison.OrdinalIgnoreCase) && string.Equals(handler["Modules"].ToString(), "FastCgiModule", StringComparison.OrdinalIgnoreCase) + select handler["name"].ToString() + ).FirstOrDefault(); + } + + private static string GetPhpExecutableVersion(string phpexePath) + { + return FileVersionInfo.GetVersionInfo(phpexePath).ProductVersion; + } + + #endregion + } } diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx index fbf46c81..d725cd82 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx @@ -30,8 +30,6 @@ None - 4 - 5 diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx.cs index 74a074e5..6db36a40 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx.cs @@ -30,6 +30,7 @@ using System; using System.Data; using System.Configuration; using System.Collections; +using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; @@ -98,13 +99,23 @@ namespace WebsitePanel.Portal if (!IIs7 || !PackagesHelper.CheckGroupQuotaEnabled(packageId, ResourceGroups.Web, Quotas.WEB_ASPNET40)) ddlAspNet.Items.Remove(ddlAspNet.Items.FindByValue("4I")); - rowAspNet.Visible = ddlAspNet.Items.Count > 1; - // php - if (!PackagesHelper.CheckGroupQuotaEnabled(packageId, ResourceGroups.Web, Quotas.WEB_PHP4)) - ddlPhp.Items.Remove(ddlPhp.Items.FindByValue("4")); - if (!PackagesHelper.CheckGroupQuotaEnabled(packageId, ResourceGroups.Web, Quotas.WEB_PHP5)) - ddlPhp.Items.Remove(ddlPhp.Items.FindByValue("5")); + if (PackagesHelper.CheckGroupQuotaEnabled(packageId, ResourceGroups.Web, Quotas.WEB_PHP4)) + ddlPhp.Items.Add("4"); + if (PackagesHelper.CheckGroupQuotaEnabled(packageId, ResourceGroups.Web, Quotas.WEB_PHP5)) + { + if (!string.IsNullOrEmpty(item.Php5VersionsInstalled)) + { + // Add items from list + ddlPhp.Items.Remove(ddlPhp.Items.FindByValue("")); + ddlPhp.Items.AddRange(item.Php5VersionsInstalled.Split('|').Select(v => new ListItem(v.Split(';')[1], "5|" + v.Split(';')[0])).OrderBy(i => i.Text).ToArray()); + } + else + { + ddlPhp.Items.Add("5"); + } + } + Utils.SelectListItem(ddlPhp, item.PhpInstalled); rowPhp.Visible = ddlPhp.Items.Count > 1; rowPerl.Visible = PackagesHelper.CheckGroupQuotaEnabled(packageId, ResourceGroups.Web, Quotas.WEB_PERL); diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx.designer.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx.designer.cs index a9216e87..48e610df 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx.designer.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/WebSitesExtensionsControl.ascx.designer.cs @@ -1,10 +1,9 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.3053 // // Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// the code is regenerated. // //------------------------------------------------------------------------------ From 170b4da51d67efd30d2cd50b3ba4e261e9916483 Mon Sep 17 00:00:00 2001 From: Olov Karlsson Date: Thu, 9 Oct 2014 11:14:45 +0200 Subject: [PATCH 3/6] Some refactoring and small changes: - Use webObjectsSvc.GetServerManager() - Do not make any changes if the PHP5 handler is not changed in the UI - Added text on IIS70_Settings page to inform that the PHP5 Executable Path can be ignored --- .../Handlers/HandlersModuleService.cs | 29 ---------- .../WebsitePanel.Providers.Web.IIS70/IIs70.cs | 57 ++++++++++++++----- .../IIS70_Settings.ascx.resx | 7 ++- .../ProviderControls/IIS70_Settings.ascx | 5 ++ .../IIS70_Settings.ascx.designer.cs | 9 +++ 5 files changed, 62 insertions(+), 45 deletions(-) diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Handlers/HandlersModuleService.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Handlers/HandlersModuleService.cs index d2a7c783..bf283e54 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Handlers/HandlersModuleService.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/Handlers/HandlersModuleService.cs @@ -278,34 +278,5 @@ namespace WebsitePanel.Providers.Web.Handlers srvman.CommitChanges(); } } - - internal void MoveHandlerToTop(string handlerName, string siteName, string vDirPath) - { - if (string.IsNullOrEmpty(siteName)) - { - return; - } - - if (string.IsNullOrEmpty(vDirPath)) - { - vDirPath = "/"; - } - - using (var srvman = GetServerManager()) - { - var config = srvman.GetWebConfiguration(siteName, vDirPath); - - var handlersSection = (HandlersSection)config.GetSection(Constants.HandlersSection, typeof(HandlersSection)); - - var handlersCollection = handlersSection.Handlers; - - var handlerElement = handlersCollection[handlerName]; - - handlersCollection.Remove(handlerElement); - handlersCollection.AddCopyAt(0, handlerElement); - - srvman.CommitChanges(); - } - } } } diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs index bb0376a4..cdfbcf8c 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Web.IIS70/IIs70.cs @@ -882,22 +882,19 @@ namespace WebsitePanel.Providers.Web { if (PhpMode == Constants.PhpMode.FastCGI && virtualDir.PhpInstalled.Contains('|')) { - var path = PhpExecutablePath; var args = virtualDir.PhpInstalled.Split('|'); + if (args.Count() > 1) { - // Handler name is present, let us try to find the corresponding path to executable - var phpVersion = GetPhpVersions(virtualDir).SingleOrDefault(p => p.HandlerName == args[1]); - if (phpVersion != null) - { - path = phpVersion.ExecutionPath; - } - } + // Handler name is present, use it to set choosen version + var handlerName = args[1]; - if (!String.IsNullOrEmpty(path) && File.Exists(path)) - { - handlersSvc.CopyInheritedHandlers(((WebSite)virtualDir).SiteId, virtualDir.VirtualPath); - handlersSvc.MoveHandlerToTop(args[1], ((WebSite) virtualDir).SiteId, virtualDir.VirtualPath); + if (handlerName != GetActivePhpHandlerName(virtualDir)) + { + // Only change handler if it is different from the current one + handlersSvc.CopyInheritedHandlers(((WebSite)virtualDir).SiteId, virtualDir.VirtualPath); + MakeHandlerActive(handlerName, virtualDir); + } } } else @@ -4511,12 +4508,21 @@ namespace WebsitePanel.Providers.Web protected PhpVersion[] GetPhpVersions(WebVirtualDirectory virtualDir) { - using (var srvman = new ServerManager()) + using (var srvman = webObjectsSvc.GetServerManager()) { return GetPhpVersions(srvman, virtualDir); } } + protected string GetActivePhpHandlerName(WebVirtualDirectory virtualDir) + { + using (var srvman = webObjectsSvc.GetServerManager()) + { + return GetActivePhpHandlerName(srvman, virtualDir); + } + } + + protected string GetActivePhpHandlerName(ServerManager srvman, WebVirtualDirectory virtualDir) { var config = srvman.GetWebConfiguration(((WebSite)virtualDir).SiteId, virtualDir.VirtualPath); @@ -4529,11 +4535,34 @@ namespace WebsitePanel.Providers.Web ).FirstOrDefault(); } - private static string GetPhpExecutableVersion(string phpexePath) + protected static string GetPhpExecutableVersion(string phpexePath) { return FileVersionInfo.GetVersionInfo(phpexePath).ProductVersion; } + protected void MakeHandlerActive(string handlerName, WebVirtualDirectory virtualDir) + { + using (var srvman = webObjectsSvc.GetServerManager()) + { + var config = srvman.GetWebConfiguration(((WebSite)virtualDir).SiteId, virtualDir.VirtualPath); + + var handlersSection = (HandlersSection)config.GetSection(Constants.HandlersSection, typeof(HandlersSection)); + + var handlersCollection = handlersSection.Handlers; + + var handlerElement = handlersCollection[handlerName]; + var activeHandlerElement = handlersCollection[GetActivePhpHandlerName(srvman, virtualDir)]; + + var activeHandlerIndex = handlersCollection.IndexOf(activeHandlerElement); + + handlersCollection.Remove(handlerElement); + + handlersCollection.AddCopyAt(activeHandlerIndex, handlerElement); + + srvman.CommitChanges(); + } + } + #endregion } } diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/App_LocalResources/IIS70_Settings.ascx.resx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/App_LocalResources/IIS70_Settings.ascx.resx index 8c517294..377a2135 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/App_LocalResources/IIS70_Settings.ascx.resx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/App_LocalResources/IIS70_Settings.ascx.resx @@ -256,7 +256,10 @@ Web Sites Public Shared Address: - - Register Helicon Ape module globally: + + Register Helicon Ape module globally: + + + If any PHP5 FastCGI handlers are present on the server, the PHP 5.x Executable Path given above will be ignored and not used. \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/IIS70_Settings.ascx b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/IIS70_Settings.ascx index 3c44ec57..d3942659 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/IIS70_Settings.ascx +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/IIS70_Settings.ascx @@ -291,6 +291,11 @@ + + + + + diff --git a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/IIS70_Settings.ascx.designer.cs b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/IIS70_Settings.ascx.designer.cs index 5bba0914..b2bd278a 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/IIS70_Settings.ascx.designer.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebPortal/DesktopModules/WebsitePanel/ProviderControls/IIS70_Settings.ascx.designer.cs @@ -490,6 +490,15 @@ namespace WebsitePanel.Portal.ProviderControls { /// protected global::System.Web.UI.WebControls.DropDownList ddlPhpMode; + /// + /// litPHP5Info control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Literal litPHP5Info; + /// /// perlPath control. /// From 262d040575b84b463b1a38efc5a67527fa46e81b Mon Sep 17 00:00:00 2001 From: Virtuworks Date: Fri, 10 Oct 2014 19:36:51 -0400 Subject: [PATCH 4/6] Added tag build-2.1.0.431 for changeset b54b3d6d052a From 0c8f8024ddfa6c8a69a378457893d5a123cf9d4c Mon Sep 17 00:00:00 2001 From: Virtuworks Date: Fri, 10 Oct 2014 19:44:20 -0400 Subject: [PATCH 5/6] Added tag build-2.1.0.432 for changeset cf9aec09a754 From bb67d603e23bbe93441143717585d1223b07875a Mon Sep 17 00:00:00 2001 From: Virtuworks Date: Fri, 10 Oct 2014 19:51:42 -0400 Subject: [PATCH 6/6] Added tag build-2.1.0.433 for changeset a8b445030dd5