|
|
/*++
Copyright (c) 1994-2001 Microsoft Corporation
Module Name : security.cpp
Abstract: WWW Security Property Page
Author: Ronald Meijer (ronaldm) Sergei Antonov (sergeia)
Project: Internet Services Manager
Revision History:
--*/ #include "stdafx.h"
#include "common.h"
#include "inetprop.h"
#include "InetMgrApp.h"
#include "supdlgs.h"
#include "shts.h"
#include "w3sht.h"
#include "wincrypt.h"
#include "resource.h"
#include "wsecure.h"
#include "authent.h"
#include "seccom.h"
#include "ipdomdlg.h"
#include <schannel.h>
#include "cryptui.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
extern CInetmgrApp theApp;
//
// 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), m_fPasswordSync(FALSE), m_fPasswordSyncInitial(FALSE), //
// 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_strRealm); FETCH_DIR_DATA_FROM_SHEET(m_strAnonUserName); FETCH_DIR_DATA_FROM_SHEET_PASSWORD(m_strAnonPassword); if (GetSheet()->QueryMajorVersion() < 6) { 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) m_fPasswordSyncInitial = m_fPasswordSync; //
// 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) // BUGBUG we are not fetching the hash right now because it needs a new
// copy constructor. Otherwise it does a bitwise copy of the pointer value.
// Then this one desctructs, freeing the pointer. Then the other one desctucts
// freeing it again.
// FETCH_INST_DATA_FROM_SHEET(m_CertHash);
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) STORE_DIR_DATA_ON_SHEET(m_strRealm)
if (fIplDirty) { STORE_DIR_DATA_ON_SHEET(m_ipl) } STORE_DIR_DATA_ON_SHEET(m_strAnonUserName) STORE_DIR_DATA_ON_SHEET(m_fUseNTMapper) if (GetSheet()->QueryMajorVersion() < 6) { STORE_DIR_DATA_ON_SHEET(m_fPasswordSync) if (m_fPasswordSync != m_fPasswordSyncInitial && m_fPasswordSync) { FLAG_DIR_DATA_FOR_DELETION(MD_ANONYMOUS_PWD); } else { STORE_DIR_DATA_ON_SHEET(m_strAnonPassword); } } 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; err = ((CW3Sheet *)GetSheet())->SetKeyType(); }
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( QueryAuthInfo(), QueryMetaPath() ); 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
--*/ { // only enable these buttons on the local system!
FetchSSLState();
m_static_SSLPrompt.EnableWindow(!IsMasterInstance()); m_button_GetCertificates.EnableWindow( !IsMasterInstance() && m_fHome && IsLocal() );
m_button_Communications.EnableWindow( !IsMasterInstance() && IsSSLSupported() // && FetchSSLState()
&& IsLocal() );
m_button_ViewCertificates.EnableWindow(IsLocal() ? m_fCertInstalled: FALSE); }
//
// 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( QueryServerName(), QueryInstance(), m_strBasicDomain, m_strRealm, 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 strOldRealm = m_strRealm; CString strOldUserName = m_strAnonUserName; CStrPassword strOldPassword = m_strAnonPassword; BOOL fOldPasswordSync = m_fPasswordSync; dlg.m_dwVersionMajor = GetSheet()->QueryMajorVersion(); dlg.m_dwVersionMinor = GetSheet()->QueryMinorVersion();
if (dlg.DoModal() == IDOK) { //
// See if anything has changed
//
if (dwOldAccess != m_dwSSLAccessPermissions || dwOldAuth != m_dwAuthFlags || m_strBasicDomain != strOldDomain || m_strRealm != strOldRealm || 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( QueryServerName(), QueryInstanceMetaPath(), m_strBasicDomain, m_dwAuthFlags, QueryAuthInfo(), 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(QueryServerName()); m_ocx_CertificateAuthorities.SetServerInstance(QueryInstanceMetaPath()); CThemeContextActivator activator(theApp.GetFusionInitHandle()); 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; PCCERT_CONTEXT pNewCertificate = NULL; CMetaKey key(QueryAuthInfo(), QueryInstanceMetaPath(), METADATA_PERMISSION_READ, METADATA_MASTER_ROOT_HANDLE); 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)) ) { // We got our information already...
// so don't keep the handle open...
key.Close();
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);
// check if this cert has been renewed and is actually
// pointing to another cert... if it is then display the other cert.
if (pCert) { DWORD dwProtocol = SP_PROT_SERVERS; if (TRUE == CheckForCertificateRenewal(dwProtocol,pCert,&pNewCertificate)) { TRACEEOLID(_T("Cert has been renewed:display new cert\r\n")); if (pCert != NULL) { // free the one we already had.
::CertFreeCertificateContext(pCert);pCert=NULL; }
pCert = pNewCertificate; } }
} } } 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); }
if (pCert != NULL) { ::CertFreeCertificateContext(pCert);pCert=NULL; } 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); }
#define CB_SHA_DIGEST_LEN 20
BOOL CheckForCertificateRenewal( DWORD dwProtocol, PCCERT_CONTEXT pCertContext, PCCERT_CONTEXT *ppNewCertificate) { BYTE rgbThumbprint[CB_SHA_DIGEST_LEN]; DWORD cbThumbprint = sizeof(rgbThumbprint); CRYPT_HASH_BLOB HashBlob; PCCERT_CONTEXT pNewCert; BOOL fMachineCert; PCRYPT_KEY_PROV_INFO pProvInfo = NULL; DWORD cbSize; HCERTSTORE hMyCertStore = 0; BOOL fRenewed = FALSE;
HCERTSTORE g_hMyCertStore;
if(dwProtocol & SP_PROT_SERVERS) { fMachineCert = TRUE; } else { fMachineCert = FALSE; }
//
// Loop through the linked list of renewed certificates, looking
// for the last one.
//
while(TRUE) { //
// Check for renewal property.
//
if(!CertGetCertificateContextProperty(pCertContext, CERT_RENEWAL_PROP_ID, rgbThumbprint, &cbThumbprint)) { // Certificate has not been renewed.
break; } //DebugLog((DEB_TRACE, "Certificate has renewal property\n"));
//
// Determine whether to look in the local machine MY store
// or the current user MY store.
//
if(!hMyCertStore) { if(CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbSize)) { //SafeAllocaAllocate(pProvInfo, cbSize);
pProvInfo = (PCRYPT_KEY_PROV_INFO) LocalAlloc(LPTR,cbSize); if(pProvInfo == NULL) { break; }
if(CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, pProvInfo, &cbSize)) { if(pProvInfo->dwFlags & CRYPT_MACHINE_KEYSET) { fMachineCert = TRUE; } else { fMachineCert = FALSE; } } if (pProvInfo) { LocalFree(pProvInfo);pProvInfo=NULL; } //SafeAllocaFree(pProvInfo);
} }
//
// Open up the appropriate MY store, and attempt to find
// the new certificate.
//
if(!hMyCertStore) { if(fMachineCert) { g_hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,X509_ASN_ENCODING,0,CERT_SYSTEM_STORE_LOCAL_MACHINE,L"MY"); if(g_hMyCertStore) { hMyCertStore = g_hMyCertStore; } } else { hMyCertStore = CertOpenSystemStore(0, _T("MY")); }
if(!hMyCertStore) { //DebugLog((DEB_ERROR, "Error 0x%x opening %s MY certificate store!\n", GetLastError(),(fMachineCert ? "local machine" : "current user") ));
break; } }
HashBlob.cbData = cbThumbprint; HashBlob.pbData = rgbThumbprint;
pNewCert = CertFindCertificateInStore(hMyCertStore, X509_ASN_ENCODING, 0, CERT_FIND_HASH, &HashBlob, NULL); if(pNewCert == NULL) { // Certificate has been renewed, but the new certificate
// cannot be found.
//DebugLog((DEB_ERROR, "New certificate cannot be found: 0x%x\n", GetLastError()));
break; }
//
// Return the new certificate, but first loop back and see if it's been
// renewed itself.
//
pCertContext = pNewCert; *ppNewCertificate = pNewCert;
//DebugLog((DEB_TRACE, "Certificate has been renewed\n"));
fRenewed = TRUE; }
//
// Cleanup.
//
if(hMyCertStore && hMyCertStore != g_hMyCertStore) { CertCloseStore(hMyCertStore, 0); }
return fRenewed; }
|