File: MMCUI\WSATControl.cs
Project: ndp\cdf\src\WCF\Tools\WsatConfig\WsatUI.csproj (WsatUI)
//------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------
 
namespace Microsoft.Tools.ServiceModel.WsatConfig
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Data;
    using System.Text;
    using System.Security;
    using System.Security.Cryptography.X509Certificates;
    using System.Windows.Forms;
    using System.Globalization;
    using System.Security.Permissions;
    using System.Security.Principal;
 
    public partial class WsatControl : UserControl
    {
        bool changed = false;
        string machineName;
        string virtualServer;
        IntPtr propPage = IntPtr.Zero;
        IntPtr propSheetDialog = IntPtr.Zero;
        WsatPropertySheet propertySheetPage;
        WsatConfiguration previousConfig, config;
        MsdtcWrapper msdtc;
        bool oldNetworkSupportEnabledValue = false;
 
        [SecurityCritical]
        public WsatControl(IntPtr propPageParam, IntPtr propSheetDialogParam, WsatPropertySheet propertySheetPage)
        {
            if (propertySheetPage == null)
            {
                throw new ArgumentNullException("propSheetPage");
            }
 
            // The order of the following calls is important!
            InitializeComponent();
            this.propPage = propPageParam;
            this.propSheetDialog = propSheetDialogParam;
            this.propertySheetPage = propertySheetPage;
            this.machineName = this.propertySheetPage.MachineName;
            this.virtualServer = this.propertySheetPage.VirtualServer;
 
            InitializeConfig();
 
            if (config != null)
            {
                this.oldNetworkSupportEnabledValue = this.config.TransactionBridgeEnabled || this.config.TransactionBridge30Enabled;
                propertySheetPage.ShowPropertyPage += new ShowWindowEventHander(OnShowContainerPropertyPage);
                propertySheetPage.BeforeApplyChanges += new BeforeApplyChangesEventHandler(OnBeforeApplyChanges);
                propertySheetPage.ApplyChanges += new ApplyChangesEventHandler(OnApplyChanges);
            }
            Application.EnableVisualStyles();
        }
 
        [SecurityCritical]
        void InitializeConfig()
        {
            try
            {
                previousConfig = new WsatConfiguration(machineName, virtualServer, null, false);
                previousConfig.LoadFromRegistry();
 
                config = new WsatConfiguration(machineName, virtualServer, previousConfig, false);
                msdtc = config.GetMsdtcWrapper();
                ConfigurationToUI();
            }
            catch (WsatAdminException e)
            {
                HandleException(e);
            }
        }
        
        void CheckNetworkDtcAccessStatus()
        {
            Utilities.Log("CheckNetworkDtcAccessStatus");
 
            bool networkTransactionEnabled;
            try
            {
                networkTransactionEnabled = msdtc.GetNetworkTransactionAccess();
            }
            catch (WsatAdminException e)  
            {
                HandleException(e);
                networkTransactionEnabled = oldNetworkSupportEnabledValue;
            }
 
            if (!networkTransactionEnabled)
            {
                // If Msdtc network access is disabled, we'll disable the NetworkSupport checkbox anyway
                Utilities.Log("CheckNetworkDtcAccessStatus: msdtc.GetNetworkTransactionAccess = false");
                this.checkBoxEnableNetworkSupport.Checked = false;
                this.checkBoxEnableNetworkSupport.Enabled = false;
            }
            else
            {
                // Otherwise, we can't simply check it - we should use the original state saved before
                // navigating away from the tab
                Utilities.Log("CheckNetworkDtcAccessStatus: msdtc.GetNetworkTransactionAccess = true");
                this.checkBoxEnableNetworkSupport.Enabled = true;
                this.checkBoxEnableNetworkSupport.Checked = this.oldNetworkSupportEnabledValue;
            }
        }
 
        internal bool OnBeforeApplyChanges()
        {
            try
            {
                if (changed && Enabled)
                {
                    UIToConfiguration();
                    config.ValidateThrow();
                }
 
                return true;
            }
            catch (WsatAdminException e)
            {
                HandleException(e);
                return false;
            }
        }
 
        internal bool OnApplyChanges()
        {
            bool succeeded = true;
 
            try
            {
                if (changed && Enabled)
                {
                    DialogResult restart = MessageBox.Show(
                        SR.GetString(SR.PromptWhetherToRestartDTCMessage),
                        SR.GetString(SR.WSATUITitle),
                        MessageBoxButtons.YesNo,
                        MessageBoxIcon.Question,
                        MessageBoxDefaultButton.Button1,
                        (MessageBoxOptions)0);
 
                    config.Save(restart == DialogResult.Yes);
 
                    if (restart == DialogResult.Yes)
                    {
                        MessageBox.Show(SR.GetString(SR.PromptMSDTCRestartedMessage),
                                        SR.GetString(SR.WSATUITitle),
                                        MessageBoxButtons.OK,
                                        MessageBoxIcon.Information,
                                        MessageBoxDefaultButton.Button1,
                                        (MessageBoxOptions)0);
                    }
 
                    succeeded = true;
                    changed = false;
                }
            }
            catch (WsatAdminException e)
            {
                succeeded = false;
                HandleException(e);
            }
 
            return succeeded;
        }
 
        static bool IsLocalAdmin()
        {
            WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
            return principal.IsInRole(WindowsBuiltInRole.Administrator);
        }
 
        internal void OnShowContainerPropertyPage(bool show)
        {
            if (show)
            {
                if (Utilities.IsLocalMachineName(machineName) && !IsLocalAdmin())
                {
                    this.Enabled = false; 
                }
                else
                {
                    CheckNetworkDtcAccessStatus();
                }
            }
            else
            {
                this.oldNetworkSupportEnabledValue = this.checkBoxEnableNetworkSupport.Checked;
            }
        }
 
        string GetDisplayStringForCert(X509Certificate2 cert)
        {
            if (cert == null)
            {
                return SR.GetString(SR.WSATControlEndpointCertNotSelected);
            }
            string ret = cert.SubjectName.Name;
            if (string.IsNullOrEmpty(ret))
            {
                ret = cert.Thumbprint;
            }
            return ret;
        }
 
        void ComponentChanged()
        {
            changed = true;
            SafeNativeMethods.SendMessage(propSheetDialog, PSM.CHANGED, propPage, IntPtr.Zero);
        }
 
        void ConfigurationToUI()
        {
            this.checkBoxEnableNetworkSupport.Checked = this.config.TransactionBridgeEnabled || this.config.TransactionBridge30Enabled;
            this.textBoxHttpsPort.Text = this.config.HttpsPort.ToString(CultureInfo.InvariantCulture);
            this.textBoxEndpointCert.Text = GetDisplayStringForCert(config.X509Certificate);
            this.textBoxDefaultTimeout.Text = this.config.DefaultTimeout.ToString(CultureInfo.InvariantCulture);
            this.textBoxMaxTimeout.Text = this.config.MaxTimeout.ToString(CultureInfo.InvariantCulture);
            checkBoxEnableNetworkSupport_CheckedChanged(null, null);
        }
 
        void UIToConfiguration()
        {
            ushort shortTemp = 0;
            
            // Network Support
            this.config.TransactionBridgeEnabled = this.checkBoxEnableNetworkSupport.Checked;
 
            // Max Timeout
            if (UInt16.TryParse(this.textBoxMaxTimeout.Text, out shortTemp))
            {
                this.config.MaxTimeout = shortTemp;
            }
            else
            {
                this.textBoxMaxTimeout.Focus();
                throw new WsatAdminException(WsatAdminErrorCode.INVALID_MAXTIMEOUT_ARGUMENT,
                                                SR.GetString(SR.ErrorMaximumTimeoutRange));
            }
 
            // The following perperties only matter when network support is enabled
            if (this.config.TransactionBridgeEnabled)
            {
                // HTTPS port
                if (UInt16.TryParse(this.textBoxHttpsPort.Text, out shortTemp))
                {
                    this.config.HttpsPort = shortTemp;
                }
                else
                {
                    this.textBoxHttpsPort.Focus();
                    throw new WsatAdminException(WsatAdminErrorCode.INVALID_HTTPS_PORT,
                                                    SR.GetString(SR.ErrorHttpsPortRange));
                }
 
                // Default Timeout
                if (UInt16.TryParse(this.textBoxDefaultTimeout.Text, out shortTemp))
                {
                    this.config.DefaultTimeout = shortTemp;
                }
                else
                {
                    this.textBoxDefaultTimeout.Focus();
                    throw new WsatAdminException(WsatAdminErrorCode.INVALID_DEF_TIMEOUT,
                                                    SR.GetString(SR.ErrorDefaultTimeoutRange));
                }
 
                // The certs and Kerberos ACLs should have been validated and attached to configuration
                // when users perform the corresponding selection steps
            }
        }
 
        void checkBoxEnableNetworkSupport_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxEnableNetworkSupport.Enabled)
            {
                try
                {
                    QfeChecker.CheckQfe();
                }
                catch (WsatAdminException ex)
                {
                    HandleException(ex);
                }
            }
            groupBoxNetwork.Enabled = groupBoxTracing.Enabled = groupBoxTimeouts.Enabled = checkBoxEnableNetworkSupport.Checked;
            ComponentChanged();
        }
 
        void textBoxHttpsPort_TextChanged(object sender, EventArgs e)
        {
            ComponentChanged();
        }
 
        void textBoxDefaultTimeout_TextChanged(object sender, EventArgs e)
        {
            ComponentChanged();
        }
 
        void textBoxMaxTimeout_TextChanged(object sender, EventArgs e)
        {
            ComponentChanged();
        }
 
        void buttonSelectEndpointCert_Click(object sender, EventArgs e)
        {
            try
            {
                SafeCertificateStore storeHandle = CertificateManager.GetCertificateStorePointer(machineName);
 
                // do not display the Location column on the CryptUIDlgSelectCertificateFromStore
#pragma warning suppress 56523
                SafeCertificateContext certContext = SafeNativeMethods.CryptUIDlgSelectCertificateFromStore(
                        storeHandle,
                        propPage,
                        SR.GetString(SR.SSLBindingTitle),
                        SR.GetString(SR.SSLBindingMessage),
                        SafeNativeMethods.CRYPTUI_SELECT_LOCATION_COLUMN,
                        0, IntPtr.Zero);
 
                if (!certContext.IsInvalid)
                {
                    config.X509Certificate = certContext.GetNewX509Certificate();
                    textBoxEndpointCert.Text = GetDisplayStringForCert(config.X509Certificate);
                    ComponentChanged();
                }
 
                certContext.Close();
                storeHandle.Close();
            }
            catch (WsatAdminException ex)
            {
                HandleException(ex);
            }
        }
 
        void buttonSelectAuthorizedAccounts_Click(object sender, EventArgs e)
        {
            // popup a new ACL window, providing the WSATSecurityModel
            // and a handle for the parent window (this)
            if (ACLWrapper.EditACLSecurity(new WsatSecurityModel(Utilities.LocalHostName, config), this.Handle))
            {
                ComponentChanged();
            }
        }
 
        void buttonSelectAuthorizedCerts_Click(object sender, EventArgs e)
        {
            try
            {
                SafeCertificateStore storeHandle = CertificateManager.GetCertificateStorePointer(machineName);
 
                SafeCertificateContext prev = new SafeCertificateContext();
                SafeCertificateContext crt = new SafeCertificateContext();
 
                X509Certificate2Collection certificateCollection = new X509Certificate2Collection();
                do
                {
#pragma warning suppress 56523
                    crt = SafeNativeMethods.CertFindCertificateInStore(
                        storeHandle,
                        SafeNativeMethods.X509_ASN_ENCODING,
                        0,
                        SafeNativeMethods.CERT_FIND_ANY,
                        IntPtr.Zero,
                        prev);
                    prev = crt;
                    if (!crt.IsInvalid)
                    {
                        certificateCollection.Add(crt.GetNewX509Certificate());
                    }
                } while (!crt.IsInvalid);
 
                storeHandle.Close();
                prev.Close();
                crt.Close();
 
                AcceptedCertificatesForm dlg = new AcceptedCertificatesForm(certificateCollection, config.X509GlobalAcl);
                DialogResult dialogResult = dlg.ShowDialog(this);
 
                if (dialogResult == DialogResult.OK)
                {
                    this.config.X509GlobalAcl = dlg.AllowedCertificates;
                    if (this.config.X509GlobalAcl.Length > 0)
                    {
                        Utilities.Log("selected allowed client cert [0]: " + this.config.X509GlobalAcl[0]);
                    }
                    ComponentChanged();
                }
            }
            catch (WsatAdminException ex)
            {
                HandleException(ex);
            }
        }
 
        void buttonTracingOptions_Click(object sender, EventArgs e)
        {
            TraceOptionsForm form = new TraceOptionsForm(this.config);
            DialogResult result = form.ShowDialog();
            if (result == DialogResult.OK)
            {
                ComponentChanged();
            }
        }
 
        void HandleException(WsatAdminException ex)
        {
            if (ex.ErrorCode == WsatAdminErrorCode.REGISTRY_ACCESS
                || ex.ErrorCode == WsatAdminErrorCode.WRONG_WCF_INSTALLED 
                || ex.ErrorCode == WsatAdminErrorCode.CANNOT_ENABLE_NETWORK_SUPPORT_WHEN_QFE_IS_NOT_INSTALLED)
            {
                MessageBox.Show(ex.Message, SR.GetString(SR.WSATUITitle),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information,
                            MessageBoxDefaultButton.Button1,
                            (MessageBoxOptions)0);
                if (this.Enabled)
                {
                    this.Enabled = false;
                }
            }
            else
            {
                MessageBox.Show(ex.Message, SR.GetString(SR.ErrorMessageBoxTitle),
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error,
                                MessageBoxDefaultButton.Button1,
                                (MessageBoxOptions)0);
            }
        }
    }
}