/*++ Copyright (c) 1994-1998 Microsoft Corporation Module Name : security.cpp Abstract: WWW Security Property Page Author: Ronald Meijer (ronaldm) Project: Internet Services Manager Revision History: --*/ // // Include Files // #include "stdafx.h" #include "wincrypt.h" #include "w3scfg.h" #include "security.h" #include "authent.h" #include "seccom.h" #include "ipdomdlg.h" #include "cryptui.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // // CW3SecurityPage property page // IMPLEMENT_DYNCREATE(CW3SecurityPage, CInetPropertyPage) CW3SecurityPage::CW3SecurityPage( IN CInetPropertySheet * pSheet, IN BOOL fHome, IN DWORD dwAttributes ) /*++ Routine Description: Constructor Arguments: CInetPropertySheet * pSheet : Sheet object BOOL fHome : TRUE if this is a home directory DWORD dwAttributes : Attributes Return Value: N/A --*/ : CInetPropertyPage(CW3SecurityPage::IDD, pSheet, IS_FILE(dwAttributes) ? IDS_TAB_FILE_SECURITY : IDS_TAB_DIR_SECURITY ), m_oblAccessList(), m_fU2Installed(FALSE), m_fIpDirty(FALSE), m_fHome(fHome), // // By default, we grant access // m_fOldDefaultGranted(TRUE), m_fDefaultGranted(TRUE) { #if 0 // Keep class wizard happy //{{AFX_DATA_INIT(CW3SecurityPage) m_fUseNTMapper = FALSE; //}}AFX_DATA_INIT #endif // 0 } CW3SecurityPage::~CW3SecurityPage() /*++ Routine Description: Destructor Arguments: N/A Return Value: N/A --*/ { } void CW3SecurityPage::DoDataExchange( IN CDataExchange * pDX ) /*++ Routine Description: Initialise/Store control data Arguments: CDataExchange * pDX - DDX/DDV control structure Return Value: None --*/ { CInetPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CW3SecurityPage) DDX_Check(pDX, IDC_CHECK_ENABLE_DS, m_fUseNTMapper); DDX_Control(pDX, IDC_ICON_SECURE, m_icon_Secure); DDX_Control(pDX, IDC_STATIC_SSL_PROMPT, m_static_SSLPrompt); DDX_Control(pDX, IDC_CHECK_ENABLE_DS, m_check_EnableDS); DDX_Control(pDX, IDC_BUTTON_GET_CERTIFICATES, m_button_GetCertificates); DDX_Control(pDX, IDC_VIEW_CERTIFICATE, m_button_ViewCertificates); DDX_Control(pDX, IDC_BUTTON_COMMUNICATIONS, m_button_Communications); //}}AFX_DATA_MAP } // // Message Map // BEGIN_MESSAGE_MAP(CW3SecurityPage, CInetPropertyPage) //{{AFX_MSG_MAP(CW3SecurityPage) ON_BN_CLICKED(IDC_BUTTON_AUTHENTICATION, OnButtonAuthentication) ON_BN_CLICKED(IDC_BUTTON_COMMUNICATIONS, OnButtonCommunications) ON_BN_CLICKED(IDC_BUTTON_IP_SECURITY, OnButtonIpSecurity) ON_BN_CLICKED(IDC_BUTTON_GET_CERTIFICATES, OnButtonGetCertificates) ON_BN_CLICKED(IDC_VIEW_CERTIFICATE, OnButtonViewCertificates) //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_CHECK_ENABLE_DS, OnItemChanged) END_MESSAGE_MAP() /* virtual */ HRESULT CW3SecurityPage::FetchLoadedValues() /*++ Routine Description: Move configuration data from sheet to dialog controls Arguments: None Return Value: HRESULT --*/ { CError err; BEGIN_META_DIR_READ(CW3Sheet) FETCH_DIR_DATA_FROM_SHEET(m_dwAuthFlags); FETCH_DIR_DATA_FROM_SHEET(m_dwSSLAccessPermissions); FETCH_DIR_DATA_FROM_SHEET(m_strBasicDomain); FETCH_DIR_DATA_FROM_SHEET(m_strAnonUserName); FETCH_DIR_DATA_FROM_SHEET(m_strAnonPassword); FETCH_DIR_DATA_FROM_SHEET(m_fPasswordSync); FETCH_DIR_DATA_FROM_SHEET(m_fU2Installed); FETCH_DIR_DATA_FROM_SHEET(m_fUseNTMapper); END_META_DIR_READ(err) // // First we need to read in the hash and the name of the store. If either // is not there then there is no certificate. // BEGIN_META_INST_READ(CW3Sheet) FETCH_INST_DATA_FROM_SHEET(m_strCertStoreName); FETCH_INST_DATA_FROM_SHEET(m_strCTLIdentifier); FETCH_INST_DATA_FROM_SHEET(m_strCTLStoreName); END_META_INST_READ(err) // // Build the IPL list // err = BuildIplOblistFromBlob( GetIPL(), m_oblAccessList, m_fDefaultGranted ); m_fOldDefaultGranted = m_fDefaultGranted; return err; } /* virtual */ HRESULT CW3SecurityPage::SaveInfo() /*++ Routine Description: Save the information on this property page Arguments: None Return Value: Error return code --*/ { ASSERT(IsDirty()); TRACEEOLID("Saving W3 security page now..."); CError err; // // Check to see if the ip access list needs saving. // BOOL fIplDirty = m_fIpDirty || (m_fOldDefaultGranted != m_fDefaultGranted); // // Use m_ notation because the message crackers require it // CBlob m_ipl; if (fIplDirty) { BuildIplBlob(m_oblAccessList, m_fDefaultGranted, m_ipl); } BeginWaitCursor(); BEGIN_META_DIR_WRITE(CW3Sheet) STORE_DIR_DATA_ON_SHEET(m_dwSSLAccessPermissions) STORE_DIR_DATA_ON_SHEET(m_dwAuthFlags) STORE_DIR_DATA_ON_SHEET(m_strBasicDomain) if (fIplDirty) { STORE_DIR_DATA_ON_SHEET(m_ipl) } STORE_DIR_DATA_ON_SHEET(m_strAnonUserName) STORE_DIR_DATA_ON_SHEET(m_fPasswordSync) STORE_DIR_DATA_ON_SHEET(m_fUseNTMapper) if (m_fPasswordSync) { // // Delete password // // CODEWORK: Shouldn't need to know ID number. // Implement m_fDelete flag in CMP template maybe? // FLAG_DIR_DATA_FOR_DELETION(MD_ANONYMOUS_PWD); } else { STORE_DIR_DATA_ON_SHEET(m_strAnonPassword); } END_META_DIR_WRITE(err) if (err.Succeeded()) { BEGIN_META_INST_WRITE(CW3Sheet) if ( m_strCTLIdentifier.IsEmpty() ) { FLAG_INST_DATA_FOR_DELETION( MD_SSL_CTL_IDENTIFIER ) } else { STORE_INST_DATA_ON_SHEET(m_strCTLIdentifier) } if ( m_strCTLStoreName.IsEmpty() ) { FLAG_INST_DATA_FOR_DELETION( MD_SSL_CTL_STORE_NAME ) } else { STORE_INST_DATA_ON_SHEET(m_strCTLStoreName) } END_META_INST_WRITE(err) } EndWaitCursor(); if (err.Succeeded()) { m_fIpDirty = FALSE; m_fOldDefaultGranted = m_fDefaultGranted; } return err; } BOOL CW3SecurityPage::FetchSSLState() /*++ Routine Description: Obtain the state of the dialog depending on whether certificates are installed or not. Arguments: None Return Value: TRUE if certificates are installed, FALSE otherwise --*/ { BeginWaitCursor(); m_fCertInstalled = ::IsCertInstalledOnServer( GetServerName(), QueryInstance() ); EndWaitCursor(); return m_fCertInstalled; } void CW3SecurityPage::SetSSLControlState() /*++ Routine Description: Enable/disable supported controls depending on what's installed. Only available on non-master instance nodes. Arguments: None Return Value: None --*/ { m_static_SSLPrompt.EnableWindow(!IsMasterInstance()); m_button_GetCertificates.EnableWindow( !IsMasterInstance() && m_fHome && IsLocal() ); m_button_Communications.EnableWindow( !IsMasterInstance() && IsSSLSupported() && FetchSSLState() ); m_button_ViewCertificates.EnableWindow(m_fCertInstalled); } // // Message Handlers // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< BOOL CW3SecurityPage::OnSetActive() /*++ Routine Description: Page got activated -- set the SSL state depending on whether a certificate is installed or not. Arguments: None Return Value: TRUE to activate the page, FALSE otherwise. --*/ { // // Enable/disable ssl controls // SetSSLControlState(); return CInetPropertyPage::OnSetActive(); } BOOL CW3SecurityPage::OnInitDialog() /*++ Routine Description: WM_INITDIALOG handler. Initialize the dialog. Arguments: None. Return Value: TRUE if no focus is to be set automatically, FALSE if the focus is already set. --*/ { CInetPropertyPage::OnInitDialog(); // // Initialize certificate authorities ocx // CRect rc(0, 0, 0, 0); m_ocx_CertificateAuthorities.Create( _T("CertWiz"), WS_BORDER, rc, this, IDC_APPSCTRL ); GetDlgItem(IDC_GROUP_IP)->EnableWindow(HasIPAccessCheck()); GetDlgItem(IDC_ICON_IP)->EnableWindow(HasIPAccessCheck()); GetDlgItem(IDC_STATIC_IP)->EnableWindow(HasIPAccessCheck()); GetDlgItem(IDC_BUTTON_IP_SECURITY)->EnableWindow(HasIPAccessCheck()); GetDlgItem(IDC_BUTTON_AUTHENTICATION)->EnableWindow(!m_fU2Installed); // // Configure for either master or non-master display. // m_check_EnableDS.ShowWindow(IsMasterInstance() ? SW_SHOW : SW_HIDE); m_check_EnableDS.EnableWindow( HasAdminAccess() && IsMasterInstance() && HasNTCertMapper() ); #define SHOW_NON_MASTER(x)\ (x).ShowWindow(IsMasterInstance() ? SW_HIDE : SW_SHOW) SHOW_NON_MASTER(m_static_SSLPrompt); SHOW_NON_MASTER(m_icon_Secure); SHOW_NON_MASTER(m_button_GetCertificates); SHOW_NON_MASTER(m_button_Communications); SHOW_NON_MASTER(m_button_ViewCertificates); #undef SHOW_NON_MASTER return TRUE; } void CW3SecurityPage::OnButtonAuthentication() /*++ Routine Description: 'Authentication' button hander Arguments: None Return Value: None --*/ { CAuthenticationDlg dlg( GetServerName(), QueryInstance(), m_strBasicDomain, m_dwAuthFlags, m_dwSSLAccessPermissions, m_strAnonUserName, m_strAnonPassword, m_fPasswordSync, HasAdminAccess(), HasDigest(), this ); DWORD dwOldAccess = m_dwSSLAccessPermissions; DWORD dwOldAuth = m_dwAuthFlags; CString strOldDomain = m_strBasicDomain; CString strOldUserName = m_strAnonUserName; CString strOldPassword = m_strAnonPassword; BOOL fOldPasswordSync = m_fPasswordSync; if (dlg.DoModal() == IDOK) { // // See if anything has changed // if (dwOldAccess != m_dwSSLAccessPermissions || dwOldAuth != m_dwAuthFlags || m_strBasicDomain != strOldDomain || m_strAnonUserName != strOldUserName || m_strAnonPassword != strOldPassword || m_fPasswordSync != fOldPasswordSync ) { // // Mark as dirty // OnItemChanged(); } } } void CW3SecurityPage::OnButtonCommunications() /*++ Routine Description: 'Communications' button handler Arguments: None Return Value: None --*/ { // // Prep the flag for if we can edit CTLs or not // BOOL fEditCTLs = IsMasterInstance() || m_fHome; // // Prep the communications dialog // CSecCommDlg dlg( GetServerName(), QueryInstanceMetaPath(), m_strBasicDomain, m_dwAuthFlags, m_dwSSLAccessPermissions, IsMasterInstance(), IsSSLSupported(), IsSSL128Supported(), m_fU2Installed, m_strCTLIdentifier, m_strCTLStoreName, fEditCTLs, IsLocal(), this ); DWORD dwOldAccess = m_dwSSLAccessPermissions; DWORD dwOldAuth = m_dwAuthFlags; if (dlg.DoModal() == IDOK) { // // See if anything has changed // if (dwOldAccess != m_dwSSLAccessPermissions || dwOldAuth != m_dwAuthFlags ) { // // Mark as dirty // OnItemChanged(); } // // See if the CTL information has changed // if (dlg.m_bCTLDirty) { m_strCTLIdentifier = dlg.m_strCTLIdentifier; m_strCTLStoreName = dlg.m_strCTLStoreName; OnItemChanged(); } } } void CW3SecurityPage::OnButtonIpSecurity() /*++ Routine Description: 'tcpip' button handler Arguments: None Return Value: None --*/ { CIPDomainDlg dlg( m_fIpDirty, m_fDefaultGranted, m_fOldDefaultGranted, m_oblAccessList, this ); if (dlg.DoModal() == IDOK) { // // Rebuild the list. Temporarily reset ownership, otherwise // RemoveAll() will destroy the pointers which are shared with the // new list. // BOOL fOwn = m_oblAccessList.SetOwnership(FALSE); m_oblAccessList.RemoveAll(); m_oblAccessList.AddTail(&dlg.GetAccessList()); m_oblAccessList.SetOwnership(fOwn); if (m_fIpDirty || m_fOldDefaultGranted != m_fDefaultGranted) { OnItemChanged(); } } } void CW3SecurityPage::OnButtonGetCertificates() /*++ Routine Description: "get certicate" button handler Arguments: None Return Value: None --*/ { m_ocx_CertificateAuthorities.SetMachineName(GetServerName()); m_ocx_CertificateAuthorities.SetServerInstance(QueryInstanceMetaPath()); m_ocx_CertificateAuthorities.DoClick(); // // There may now be a certificate. See if we should enable the edit button. // SetSSLControlState(); } void CW3SecurityPage::OnButtonViewCertificates() /*++ Routine Description: "view certicate" button handler Arguments: None Return Value: None --*/ { HCERTSTORE hStore = NULL; PCCERT_CONTEXT pCert = NULL; CMetaKey key(GetServerName(), METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE, METADATA_MASTER_ROOT_HANDLE, QueryInstanceMetaPath()); if (key.Succeeded()) { CString store_name; CBlob hash; if ( SUCCEEDED(key.QueryValue(MD_SSL_CERT_STORE_NAME, store_name)) && SUCCEEDED(key.QueryValue(MD_SSL_CERT_HASH, hash)) ) { hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE, store_name ); if (hStore != NULL) { // Now we need to find cert by hash CRYPT_HASH_BLOB crypt_hash; crypt_hash.cbData = hash.GetSize(); crypt_hash.pbData = hash.GetData(); pCert = CertFindCertificateInStore( hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_HASH, (LPVOID)&crypt_hash, NULL); } } } if (pCert) { BOOL fPropertiesChanged; CRYPTUI_VIEWCERTIFICATE_STRUCT vcs; HCERTSTORE hCertStore = ::CertDuplicateStore(hStore); ::ZeroMemory (&vcs, sizeof (vcs)); vcs.dwSize = sizeof (vcs); vcs.hwndParent = GetParent()->GetSafeHwnd(); vcs.dwFlags = 0; vcs.cStores = 1; vcs.rghStores = &hCertStore; vcs.pCertContext = pCert; ::CryptUIDlgViewCertificate(&vcs, &fPropertiesChanged); ::CertCloseStore (hCertStore, 0); } else { } if (pCert != NULL) ::CertFreeCertificateContext(pCert); if (hStore != NULL) ::CertCloseStore(hStore, 0); } void CW3SecurityPage::OnItemChanged() /*++ Routine Description: All EN_CHANGE messages map to this function Arguments: None Return Value: None --*/ { SetModified(TRUE); }