Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1029 lines
23 KiB

/*++
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;
}