|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: certwrap.cpp
//
//--------------------------------------------------------------------------
#include <stdafx.h>
#include "csdisp.h"
#include "certsrv.h"
#include "genpage.h"
#include "progress.h"
#include "misc.h"
#include "certacl.h"
#include <dsgetdc.h>
#include <winldap.h>
#include "csldap.h"
#define __dwFILE__ __dwFILE_CERTMMC_CERTWRAP_CPP__
_COM_SMARTPTR_TYPEDEF(IADs, IID_IADs);
//////////////////////////
// CertSvrCA class
CertSvrCA::CertSvrCA(CertSvrMachine* pParent) : m_pParentMachine(pParent) { m_hCACertStore = NULL; m_fCertStoreOpenAttempted = FALSE; m_hrCACertStoreOpen = S_OK;
m_hRootCertStore = NULL; m_fRootStoreOpenAttempted = FALSE; m_hrRootCertStoreOpen = S_OK;
m_hKRACertStore = NULL; m_fKRAStoreOpenAttempted = FALSE; m_hrKRACertStoreOpen = S_OK;
m_bstrConfig = NULL;
m_enumCAType = ENUM_UNKNOWN_CA; m_fCATypeKnown = FALSE;
m_fIsUsingDS = FALSE; m_fIsUsingDSKnown = FALSE;
m_fAdvancedServer = FALSE; m_fAdvancedServerKnown = FALSE;
if(m_pParentMachine) m_pParentMachine->AddRef();
m_dwRoles = MAXDWORD; // assume all roles are enabled, in case we fail to retrieve them
m_fRolesKnown = FALSE; }
CertSvrCA::~CertSvrCA() { if (m_hCACertStore) { CertCloseStore(m_hCACertStore, 0); m_hCACertStore = NULL; }
if (m_hRootCertStore) { CertCloseStore(m_hRootCertStore, 0); m_hRootCertStore = NULL; }
if (m_hKRACertStore) { CertCloseStore(m_hKRACertStore, 0); m_hKRACertStore = NULL; }
if (m_bstrConfig) SysFreeString(m_bstrConfig);
if(m_pParentMachine) m_pParentMachine->Release(); }
BOOL CertSvrCA::AccessAllowed(DWORD dwAccess) { return (dwAccess & GetMyRoles())?TRUE:FALSE; }
DWORD CertSvrCA::GetMyRoles() { HRESULT hr = S_OK; ICertAdmin2Ptr pCertAdmin; LONG dwRoles;
if(!m_fRolesKnown) { hr = m_pParentMachine->GetAdmin2(&pCertAdmin); _JumpIfError(hr, error, "CertSvrMachine::GetAdmin2");
hr = pCertAdmin->GetMyRoles( m_bstrConfig, &dwRoles); _JumpIfError(hr, error, "ICertAdmin2::GetCAProperty");
m_dwRoles = dwRoles; m_fRolesKnown = TRUE; }
error: return m_dwRoles; }
HRESULT CertSvrCA::GetCAFlagsFromDS(PDWORD pdwFlags) { HRESULT hr = S_OK; LPWSTR pwszSanitizedDSName = NULL; HCAINFO hCAInfo = NULL;
hr = mySanitizedNameToDSName(m_strSanitizedName, &pwszSanitizedDSName); _JumpIfError(hr, error, "mySanitizedNameToDSName");
hr = CAFindByName( pwszSanitizedDSName, NULL, 0, &hCAInfo); _JumpIfErrorStr(hr, error, "CAFindByName", pwszSanitizedDSName);
hr = CAGetCAFlags( hCAInfo, pdwFlags); _JumpIfError(hr, error, "CAGetCAFlags");
error: LOCAL_FREE(pwszSanitizedDSName); if(hCAInfo) CACloseCA(hCAInfo);
return hr; }
// CA machine should have full control over the enrollment object in DS.
// This function checks if the machine has the rights and adds a new
// ace allowing CA machine obj (eg TESTDOMAIN\BOGDANTTEST$) full control
// over its enrollment object
// See bug# 193388.
HRESULT CertSvrCA::FixEnrollmentObject() { HRESULT hr = S_OK; IDirectoryObject *pADEnrollObj = NULL; LPWSTR pwszAttr = L"nTSecurityDescriptor"; PADS_ATTR_INFO paai = NULL; DWORD dwAttrReturned; LPWSTR pwszSanitizedDSName = NULL; CString strEnrollDN; HCAINFO hCAInfo = NULL; PSID pSid = NULL; bool fAllowed = false; PSECURITY_DESCRIPTOR pSDRead = NULL; // no free
PSECURITY_DESCRIPTOR pSDWrite = NULL;
hr = mySanitizedNameToDSName(m_strSanitizedName, &pwszSanitizedDSName); _JumpIfError(hr, error, "mySanitizedNameToDSName");
hr = CAFindByName( pwszSanitizedDSName, NULL, CA_FIND_INCLUDE_UNTRUSTED | CA_FIND_INCLUDE_NON_TEMPLATE_CA, &hCAInfo); _JumpIfErrorStr(hr, error, "CAFindByName", pwszSanitizedDSName);
strEnrollDN = L"LDAP://"; strEnrollDN += myCAGetDN(hCAInfo); if (strEnrollDN.IsEmpty()) { hr = myHLastError(); _JumpError(hr, error, "myCAGetDN"); }
hr = ADsGetObject(strEnrollDN, IID_IDirectoryObject, (void**)&pADEnrollObj); _JumpIfErrorStr(hr, error, "ADsGetObject", strEnrollDN);
hr = pADEnrollObj->GetObjectAttributes( &pwszAttr, 1, &paai, &dwAttrReturned); _JumpIfErrorStr(hr, error, "Get SD", strEnrollDN);
pSDRead = paai[0].pADsValues[0].SecurityDescriptor.lpValue;
CSASSERT(IsValidSecurityDescriptor(pSDRead));
hr = FindComputerObjectSid( m_strServer, pSid); _JumpIfErrorStr(hr, error, "FindCAComputerObjectSid", m_strServer);
// look in DACL for a ace allowing CA full control
hr = IsCAAllowedFullControl( pSDRead, pSid, fAllowed); _JumpIfError(hr, error, "IsCAAllowedFullControl");
if(!fAllowed) { // build new SD allowing CA full control and write it back
// to DS
ADSVALUE snValue; ADS_ATTR_INFO attrInfo[] = {{ pwszAttr, ADS_ATTR_UPDATE, ADSTYPE_NT_SECURITY_DESCRIPTOR, &snValue, 1} };
hr = AllowCAFullControl( pSDRead, pSid, pSDWrite); _JumpIfError(hr, error, "AllowCAFullControl");
CSASSERT(IsValidSecurityDescriptor(pSDWrite));
snValue.dwType = ADSTYPE_NT_SECURITY_DESCRIPTOR; snValue.SecurityDescriptor.dwLength = GetSecurityDescriptorLength(pSDWrite); snValue.SecurityDescriptor.lpValue = (LPBYTE)pSDWrite;
hr = pADEnrollObj->SetObjectAttributes( attrInfo, 1, &dwAttrReturned); _JumpIfErrorStr(hr, error, "Set SD", strEnrollDN); }
error:
if(paai) FreeADsMem(paai); if(pADEnrollObj) pADEnrollObj->Release(); if(hCAInfo) CACloseCA(hCAInfo); LOCAL_FREE(pwszSanitizedDSName); LOCAL_FREE(pSid); LOCAL_FREE(pSDWrite); return hr; }
HRESULT CertSvrCA::IsCAAllowedFullControl( PSECURITY_DESCRIPTOR pSDRead, PSID pSid, bool& fAllowed) { HRESULT hr = S_OK; PACL pDacl; // no free
ACL_SIZE_INFORMATION AclInfo; PACCESS_ALLOWED_ACE pAce; // no free
DWORD dwIndex; fAllowed = false;
hr = myGetSecurityDescriptorDacl( pSDRead, &pDacl); _JumpIfError(hr, error, "myGetSecurityDescriptorDacl");
if(!GetAclInformation(pDacl, &AclInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) { hr = myHLastError(); _JumpError(hr, error, "GetAclInformation"); }
for(dwIndex = 0; dwIndex < AclInfo.AceCount; dwIndex++) { if(!GetAce(pDacl, dwIndex, (LPVOID*)&pAce)) { hr = myHLastError(); _JumpError(hr, error, "GetAce"); }
if(pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && (pAce->Mask & ACTRL_CERTSRV_MANAGE) == ACTRL_CERTSRV_MANAGE && EqualSid((PSID)&pAce->SidStart, pSid)) { fAllowed = true; break; } }
error: return hr; }
HRESULT CertSvrCA::AllowCAFullControl( PSECURITY_DESCRIPTOR pSDRead, PSID pSid, PSECURITY_DESCRIPTOR& pSDWrite) { HRESULT hr = S_OK; BOOL fRet = 0; LPBYTE pSDTemp = NULL; PACL pDaclWrite = NULL; PACL pDaclRead = NULL; // no free
PVOID pAce = NULL; // no free
DWORD dwAbsoluteSDSize = 0; DWORD dwDaclSize = 0; DWORD dwSaclSize = 0; DWORD dwOwnerSize = 0; DWORD dwGroupSize = 0; DWORD dwSDWriteSize = 0; DWORD dwDaclWriteSize = 0;
hr = myGetSecurityDescriptorDacl( pSDRead, &pDaclRead); _JumpIfError(hr, error, "myGetSecurityDescriptorDacl"); fRet = MakeAbsoluteSD( pSDRead, NULL, &dwAbsoluteSDSize, NULL, &dwDaclSize, NULL, &dwSaclSize, NULL, &dwOwnerSize, NULL, &dwGroupSize); // should always fail with insufficient buffer
if(fRet || ERROR_INSUFFICIENT_BUFFER!=GetLastError()) { hr = fRet? E_FAIL : myHLastError(); _JumpError(hr, error, "MakeAbsoluteSD"); }
// alloc all buffers together
pSDTemp = (LPBYTE)LocalAlloc( LMEM_FIXED, dwAbsoluteSDSize+dwDaclSize+dwSaclSize+dwOwnerSize+dwGroupSize); _JumpIfAllocFailed(pSDTemp, error); fRet = MakeAbsoluteSD( pSDRead, (PSECURITY_DESCRIPTOR)pSDTemp, &dwAbsoluteSDSize, (PACL)(pSDTemp+dwAbsoluteSDSize), &dwDaclSize, (PACL)(pSDTemp+dwAbsoluteSDSize+dwDaclSize), &dwSaclSize, (PSID)(pSDTemp+dwAbsoluteSDSize+dwDaclSize+dwSaclSize), &dwOwnerSize, (PSID)(pSDTemp+dwAbsoluteSDSize+dwDaclSize+dwSaclSize+dwOwnerSize), &dwGroupSize); // should always fail with insufficient buffer
if(!fRet) { hr = myHLastError(); _JumpError(hr, error, "MakeAbsoluteSD"); }
dwDaclWriteSize = dwDaclSize+sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD)+ GetLengthSid(pSid);
pDaclWrite = (PACL) LocalAlloc(LMEM_FIXED, dwDaclWriteSize); _JumpIfAllocFailed(pDaclWrite, error);
fRet = InitializeAcl(pDaclWrite, dwDaclWriteSize, ACL_REVISION_DS); if(!fRet) { hr = myHLastError(); _JumpError(hr, error, "InitializeAcl"); }
fRet = GetAce(pDaclRead, 0, &pAce); if(!fRet) { hr = myHLastError(); _JumpError(hr, error, "GetAce"); }
fRet = AddAce(pDaclWrite, ACL_REVISION_DS, 0, pAce, dwDaclSize-sizeof(ACL)); if(!fRet) { hr = myHLastError(); _JumpError(hr, error, "AddAce"); }
fRet = AddAccessAllowedAce( pDaclWrite, ACL_REVISION_DS, ACTRL_CERTSRV_MANAGE_LESS_CONTROL_ACCESS, pSid); if(!fRet) { hr = myHLastError(); _JumpError(hr, error, "AddAccessAllowedAce"); }
fRet = SetSecurityDescriptorDacl( pSDTemp, TRUE, pDaclWrite, FALSE); if(!fRet) { hr = myHLastError(); _JumpError(hr, error, "SetSecurityDescriptorDacl"); }
fRet = MakeSelfRelativeSD( pSDTemp, NULL, &dwSDWriteSize); if(fRet || ERROR_INSUFFICIENT_BUFFER!=GetLastError()) { hr = fRet? E_FAIL : myHLastError(); _JumpError(hr, error, "MakeSelfRelativeSD"); }
pSDWrite = LocalAlloc(LMEM_FIXED, dwSDWriteSize); _JumpIfAllocFailed(pSDWrite, error);
fRet = MakeSelfRelativeSD( pSDTemp, pSDWrite, &dwSDWriteSize); if(!fRet) { hr = myHLastError(); _JumpError(hr, error, "MakeSelfRelativeSD"); }
error:
LOCAL_FREE(pSDTemp); LOCAL_FREE(pDaclWrite); return hr; }
BOOL CertSvrCA::FIsUsingDS() { DWORD dwRet; variant_t varUsingDS;
if (m_fIsUsingDSKnown) return m_fIsUsingDS;
dwRet = GetConfigEntry( NULL, wszREGCAUSEDS, &varUsingDS); _JumpIfError(dwRet, Ret, "GetConfigEntry");
CSASSERT ((V_VT(&varUsingDS)== VT_I4)); m_fIsUsingDS = V_I4(&varUsingDS);
Ret: m_fIsUsingDSKnown = TRUE; return m_fIsUsingDS; }
BOOL CertSvrCA::FIsAdvancedServer() { HRESULT hr = S_OK; variant_t var; ICertAdmin2Ptr pCertAdmin; CString strCADN, strCALDAP = L"LDAP://"; IADsPtr pADs;
if (!m_fAdvancedServerKnown) {
hr = m_pParentMachine->GetAdmin2(&pCertAdmin); if(S_OK==hr) {
hr = pCertAdmin->GetCAProperty( m_bstrConfig, CR_PROP_ADVANCEDSERVER, // PropId
0, // Index
PROPTYPE_LONG, // PropType
0, // Flags
&var); } if(S_OK != hr) { // couldn't figure it out from CA, try DS
DWORD dwFlags; hr = GetCAFlagsFromDS(&dwFlags); _JumpIfError(hr, error, "GetCAFlags"); m_fAdvancedServer = (dwFlags & CA_FLAG_CA_SERVERTYPE_ADVANCED)? TRUE: FALSE; m_fAdvancedServerKnown = TRUE; } else { CSASSERT ((V_VT(&var)== VT_I4)); m_fAdvancedServer = V_I4(&var); m_fAdvancedServerKnown = TRUE; } _JumpIfError(hr, error, "GetCAProperty"); }
error:
return m_fAdvancedServer; }
ENUM_CATYPES CertSvrCA::GetCAType() { DWORD dwRet; variant_t varCAType;
if (m_fCATypeKnown) return m_enumCAType;
dwRet = GetConfigEntry( NULL, wszREGCATYPE, &varCAType); _JumpIfError(dwRet, Ret, "GetConfigEntry");
CSASSERT ((V_VT(&varCAType)== VT_I4)); m_enumCAType = (ENUM_CATYPES)V_I4(&varCAType);
Ret: m_fCATypeKnown = TRUE; return m_enumCAType; }
HRESULT CertSvrCA::_GetSetupStatus(DWORD &rdwStatus) { HRESULT hr; variant_t varSetupStatus;
hr = GetConfigEntry( NULL, wszREGSETUPSTATUS, &varSetupStatus); _JumpIfErrorStr(hr, Ret, "GetConfigEntry", wszREGSETUPSTATUS);
CSASSERT ((V_VT(&varSetupStatus)== VT_I4)); rdwStatus = V_I4(&varSetupStatus);
Ret: return hr; }
HRESULT CertSvrCA::_SetSetupStatus(DWORD dwStatus) { HRESULT hr; variant_t varSetupStatus;
V_VT(&varSetupStatus) = VT_I4; V_I4(&varSetupStatus) = dwStatus;
hr = SetConfigEntry( NULL, wszREGSETUPSTATUS, &varSetupStatus); _JumpIfErrorStr(hr, Ret, "SetConfigEntry", wszREGSETUPSTATUS);
Ret: return hr; }
HRESULT CertSvrCA::CleanSetupStatusBits(DWORD dwBitsToClean) { HRESULT hr; DWORD dwStatus = 0;
hr = _GetSetupStatus(dwStatus); _JumpIfError(hr, Ret, "_GetSetupStatus");
dwStatus = dwStatus & ~dwBitsToClean;
hr = _SetSetupStatus(dwStatus); _JumpIfError(hr, Ret, "_SetSetupStatus");
Ret: return hr; }
BOOL CertSvrCA::FIsIncompleteInstallation() { DWORD dwStatus = 0; _GetSetupStatus(dwStatus); return ((SETUP_SUSPEND_FLAG & dwStatus)?TRUE:FALSE); }
BOOL CertSvrCA::FIsRequestOutstanding() { DWORD dwStatus = 0; _GetSetupStatus(dwStatus); return ((SETUP_REQUEST_FLAG & dwStatus)?TRUE:FALSE); }
BOOL CertSvrCA::FDoesSecurityNeedUpgrade() { DWORD dwStatus = 0; _GetSetupStatus(dwStatus); return ((SETUP_W2K_SECURITY_NOT_UPGRADED_FLAG & dwStatus)?TRUE:FALSE); }
BOOL CertSvrCA::FDoesServerAllowForeignCerts() { HRESULT hr; DWORD dwStatus; variant_t varKRAFlags;
hr = GetConfigEntry( NULL, wszREGKRAFLAGS, &varKRAFlags); _JumpIfError(hr, Ret, "GetConfigEntry");
CSASSERT ((V_VT(&varKRAFlags)== VT_I4)); dwStatus = V_I4(&varKRAFlags);
return ((dwStatus & KRAF_ENABLEFOREIGN) != 0);
Ret: return FALSE; }
DWORD CertSvrCA::GetCACertByKeyIndex(PCCERT_CONTEXT* ppCertCtxt, int iKeyIndex) { // don't cache CA cert
DWORD dwErr; ICertAdmin2* pCertAdmin = NULL; // must free this!!
VARIANT varPropertyValue; VariantInit(&varPropertyValue);
*ppCertCtxt = NULL;
dwErr = m_pParentMachine->GetAdmin2(&pCertAdmin); _JumpIfError(dwErr, Ret, "GetAdmin2"); // To get key's Cert
dwErr = pCertAdmin->GetCAProperty( m_bstrConfig, CR_PROP_CASIGCERT, // PropId
iKeyIndex, // PropIndex key index
PROPTYPE_BINARY, // PropType
CR_OUT_BINARY, // Flags
&varPropertyValue); _JumpIfError(dwErr, Ret, "GetCAProperty");
// varPropertyValue.vt will be VT_BSTR
if (VT_BSTR != varPropertyValue.vt) { dwErr = ERROR_INVALID_PARAMETER; _JumpError(dwErr, Ret, "GetCAProperty"); }
*ppCertCtxt = CertCreateCertificateContext( CRYPT_ASN_ENCODING, (PBYTE)varPropertyValue.bstrVal, SysStringByteLen(varPropertyValue.bstrVal)); if (*ppCertCtxt == NULL) { dwErr = GetLastError(); _JumpError(dwErr, Ret, "CertCreateCertContext"); }
dwErr = ERROR_SUCCESS; Ret: VariantClear(&varPropertyValue);
if (pCertAdmin) pCertAdmin->Release();
return dwErr; }
DWORD CertSvrCA::GetCurrentCRL(PCCRL_CONTEXT* ppCRLCtxt, BOOL fBaseCRL) { return GetCRLByKeyIndex(ppCRLCtxt, fBaseCRL, -1); }
DWORD CertSvrCA::GetCRLByKeyIndex(PCCRL_CONTEXT* ppCRLCtxt, BOOL fBaseCRL, int iKeyIndex) { // don't cache CRL
DWORD dwErr; ICertAdmin2* pCertAdmin = NULL; // must free this!!
VARIANT varPropertyValue; VariantInit(&varPropertyValue);
*ppCRLCtxt = NULL;
dwErr = m_pParentMachine->GetAdmin2(&pCertAdmin); _JumpIfError(dwErr, Ret, "GetAdmin2"); // To get each key's BASE CRL
dwErr = pCertAdmin->GetCAProperty( m_bstrConfig, fBaseCRL ? CR_PROP_BASECRL : CR_PROP_DELTACRL, // PropId
iKeyIndex, // PropIndex key index
PROPTYPE_BINARY, // PropType
CR_OUT_BINARY, // Flags
&varPropertyValue); _JumpIfError(dwErr, Ret, "GetCAProperty");
// varPropertyValue.vt will be VT_BSTR
if (VT_BSTR != varPropertyValue.vt) { dwErr = ERROR_INVALID_PARAMETER; _JumpError(dwErr, Ret, "GetCAProperty"); }
*ppCRLCtxt = CertCreateCRLContext( CRYPT_ASN_ENCODING, (PBYTE)varPropertyValue.bstrVal, SysStringByteLen(varPropertyValue.bstrVal)); if (*ppCRLCtxt == NULL) { dwErr = GetLastError(); _JumpError(dwErr, Ret, "CertCreateCRLContext"); }
dwErr = ERROR_SUCCESS; Ret: VariantClear(&varPropertyValue);
if (pCertAdmin) pCertAdmin->Release();
return dwErr; }
HRESULT CertSvrCA::GetConfigEntry( LPWSTR szConfigSubKey, LPWSTR szConfigEntry, VARIANT *pvarOut) { HRESULT hr = S_OK; ICertAdmin2Ptr pAdmin; LPWSTR pwszLocalMachine = NULL; CString strConfig = m_pParentMachine->m_strMachineName;
if(m_pParentMachine->m_strMachineName.IsEmpty()) { hr = myGetMachineDnsName(&pwszLocalMachine); _JumpIfError(hr, Err, "myGetMachineDnsName"); strConfig = pwszLocalMachine; } strConfig += L"\\"; strConfig += m_strSanitizedName;
VariantInit(pvarOut);
hr = m_pParentMachine->GetAdmin2(&pAdmin, true); _JumpIfError(hr, Err, "GetAdmin2");
hr = pAdmin->GetConfigEntry( _bstr_t(strConfig.GetBuffer()), _bstr_t(szConfigSubKey), _bstr_t(szConfigEntry), pvarOut); _JumpIfError2(hr, Err, "GetConfigEntry", HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
Err: LOCAL_FREE(pwszLocalMachine); return hr; }
HRESULT CertSvrCA::SetConfigEntry( LPWSTR szConfigSubKey, LPWSTR szConfigEntry, VARIANT *pvarIn) { HRESULT hr = S_OK; ICertAdmin2Ptr pAdmin; LPWSTR pwszLocalMachine = NULL; CString strConfig = m_pParentMachine->m_strMachineName;
if(m_pParentMachine->m_strMachineName.IsEmpty()) { hr = myGetMachineDnsName(&pwszLocalMachine); _JumpIfError(hr, Err, "myGetMachineDnsName"); strConfig = pwszLocalMachine; } strConfig += L"\\"; strConfig += m_strSanitizedName;
hr = m_pParentMachine->GetAdmin2(&pAdmin, true); _JumpIfError(hr, Err, "GetAdmin2");
hr = pAdmin->SetConfigEntry( _bstr_t(strConfig.GetBuffer()), _bstr_t(szConfigSubKey), _bstr_t(szConfigEntry), pvarIn); _JumpIfError(hr, Err, "SetConfigEntry");
Err: LOCAL_FREE(pwszLocalMachine); return hr; }
////////////////////////////////////////////////////////////////
// CertStor stub
DWORD CertSvrCA::GetRootCertStore(HCERTSTORE* phCertStore) { if (m_fRootStoreOpenAttempted) { *phCertStore = m_hRootCertStore; return m_hrRootCertStoreOpen; } m_fRootStoreOpenAttempted = TRUE;
LONG dwRet; CString cstrCertStorePath;
if (! m_pParentMachine->IsLocalMachine()) { // if remote, prefix with "\\mattt3\"
cstrCertStorePath = m_strServer; cstrCertStorePath += L"\\"; } cstrCertStorePath += wszROOT_CERTSTORE;
m_hRootCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, CRYPT_ASN_ENCODING, NULL, // hCryptProv
CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_MAXIMUM_ALLOWED_FLAG, (const void *)(LPCWSTR)cstrCertStorePath); if (m_hRootCertStore == NULL) { dwRet = GetLastError(); _JumpError(dwRet, Ret, "CertOpenStore"); } dwRet = ERROR_SUCCESS; Ret: *phCertStore = m_hRootCertStore; m_hrRootCertStoreOpen = HRESULT_FROM_WIN32(dwRet);
return dwRet; }
DWORD CertSvrCA::GetCACertStore(HCERTSTORE* phCertStore) { if (m_fCertStoreOpenAttempted) { *phCertStore = m_hCACertStore; return m_hrCACertStoreOpen; } m_fCertStoreOpenAttempted = TRUE;
LONG dwRet; CString cstrCertStorePath; if (! m_pParentMachine->IsLocalMachine()) { // if remote, prefix with "\\mattt3\"
cstrCertStorePath = m_strServer; cstrCertStorePath += L"\\"; } cstrCertStorePath += wszCA_CERTSTORE;
m_hCACertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, CRYPT_ASN_ENCODING, NULL, // hCryptProv
CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_MAXIMUM_ALLOWED_FLAG, (const void *)(LPCWSTR)cstrCertStorePath); if (m_hCACertStore == NULL) { dwRet = GetLastError(); _JumpError(dwRet, Ret, "CertOpenStore"); } dwRet = ERROR_SUCCESS; Ret:
*phCertStore = m_hCACertStore; m_hrCACertStoreOpen = HRESULT_FROM_WIN32(dwRet);
return dwRet; }
DWORD CertSvrCA::GetKRACertStore(HCERTSTORE* phCertStore) { if (m_fKRAStoreOpenAttempted) { *phCertStore = m_hKRACertStore; return m_hrKRACertStoreOpen; } m_fKRAStoreOpenAttempted = TRUE;
LONG dwRet; CString cstrCertStorePath; /*
if (! m_pParentMachine->IsLocalMachine()) { // if remote, prefix with "\\mattt3\"
cstrCertStorePath = m_strServer; cstrCertStorePath += L"\\"; } cstrCertStorePath += wszKRA_CERTSTORE; */ cstrCertStorePath = wszKRA_CERTSTORE;
m_hKRACertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, CRYPT_ASN_ENCODING, NULL, // hCryptProv
CERT_SYSTEM_STORE_LOCAL_MACHINE| CERT_STORE_MAXIMUM_ALLOWED_FLAG, (const void *)(LPCWSTR)cstrCertStorePath); if (m_hKRACertStore == NULL) { dwRet = GetLastError(); _JumpError(dwRet, Ret, "CertOpenStore"); } dwRet = ERROR_SUCCESS; Ret: *phCertStore = m_hKRACertStore; m_hrKRACertStoreOpen = HRESULT_FROM_WIN32(dwRet);
return dwRet; }
//////////////////////////
// CertSvrMachine class
CertSvrMachine::CertSvrMachine() { m_dwServiceStatus = ERROR_SERVICE_NOT_ACTIVE;
m_hCachedConfigBaseKey = NULL; m_bAttemptedBaseKeyOpen = FALSE; m_fLocalIsKnown = FALSE;
m_fIsWhistlerMachine = FALSE; m_fIsWhistlerMachineKnown = FALSE;
m_cRef = 1; // one "Release()" will initiate clean up
}
CertSvrMachine::~CertSvrMachine() { CSASSERT(m_cRef == 0); // delete any CAs that we still hold on to -- we own this memory
for (int i=0; i<m_CAList.GetSize(); i++) { delete m_CAList[i]; }
Init(); }
void CertSvrMachine::Init() { // on initialization, caller owns memory contents of m_CAList --
// we no longer do
m_dwServiceStatus = ERROR_SERVICE_NOT_ACTIVE;
if (m_hCachedConfigBaseKey) { RegCloseKey(m_hCachedConfigBaseKey); m_hCachedConfigBaseKey = NULL; } m_bAttemptedBaseKeyOpen = FALSE;
// clean other objects
m_CAList.Init(); // scope owns memory
m_strMachineNamePersist.Init(); m_strMachineName.Init(); }
BOOL CertSvrMachine::FIsWhistlerMachine() { HRESULT hr = S_OK; VARIANT varTmp; VariantInit(&varTmp);
if(!m_fIsWhistlerMachineKnown) { hr = GetRootConfigEntry( wszREGVERSION, &varTmp); _JumpIfError(hr, Err, "GetConfigEntry");
DBGPRINT((DBG_SS_INFO, "Found version: 0x%x", V_I4(&varTmp)));
CSASSERT ((V_VT(&varTmp)== VT_I4)); m_fIsWhistlerMachine = (CSVER_EXTRACT_MAJOR(V_I4(&varTmp)) >= CSVER_MAJOR_WHISTLER); // bigger than or equal to major Whistler version? return TRUE!
m_fIsWhistlerMachineKnown = TRUE; DBGPRINT((DBG_SS_INFO, m_fIsWhistlerMachine?"This is a Whistler CA":"This is a Win2k CA")); }
Err:
VariantClear(&varTmp); return m_fIsWhistlerMachine; }
HRESULT CertSvrMachine::GetRootConfigEntry( LPWSTR szConfigEntry, VARIANT *pvarOut) { HRESULT hr = S_OK; ICertAdmin2Ptr pAdmin; LPWSTR pwszLocalMachine = NULL; CString strConfig = m_strMachineName;
if(m_strMachineName.IsEmpty()) { hr = myGetMachineDnsName(&pwszLocalMachine); _JumpIfError(hr, Err, "myGetMachineDnsName"); strConfig = pwszLocalMachine; } VariantInit(pvarOut);
hr = GetAdmin2(&pAdmin, true); _JumpIfError(hr, Err, "GetAdmin2");
hr = pAdmin->GetConfigEntry( _bstr_t(strConfig.GetBuffer()), NULL, _bstr_t(szConfigEntry), pvarOut); _JumpIfError(hr, Err, "GetConfigEntry");
Err: LOCAL_FREE(pwszLocalMachine); return hr;
}
HRESULT CertSvrMachine::GetAdmin(ICertAdmin** ppAdmin) { HRESULT hr; BOOL fCoInit = FALSE;
if (!IsCertSvrServiceRunning()) { *ppAdmin = NULL; return RPC_S_NOT_LISTENING; }
// ensure this thread initialized
hr = CoInitialize(NULL); if ((S_OK == hr) || (S_FALSE == hr)) fCoInit = TRUE;
// create interface, pass back
hr = CoCreateInstance( CLSID_CCertAdmin, NULL, // pUnkOuter
CLSCTX_INPROC_SERVER, IID_ICertAdmin, (void **) ppAdmin); _PrintIfError(hr, "CoCreateInstance");
if (fCoInit) CoUninitialize();
return hr; }
HRESULT CertSvrMachine::GetAdmin2( ICertAdmin2** ppAdmin, bool fIgnoreServiceDown /* = false*/) { HRESULT hr = S_OK, hr1; BOOL fCoInit = FALSE;
if (!fIgnoreServiceDown && !IsCertSvrServiceRunning()) { *ppAdmin = NULL; return RPC_S_NOT_LISTENING; }
hr1 = CoInitialize(NULL); if ((S_OK == hr1) || (S_FALSE == hr1)) fCoInit = TRUE;
// create interface, pass back
hr = CoCreateInstance( CLSID_CCertAdmin, NULL, // pUnkOuter
CLSCTX_INPROC_SERVER, IID_ICertAdmin2, (void **) ppAdmin); _PrintIfError(hr, "CoCreateInstance");
if (fCoInit) CoUninitialize();
return hr; }
#define STARTSTOP_MAX_RETRY_SECONDS 30
DWORD CertSvrMachine::CertSvrStartStopService(HWND hwndParent, BOOL fStartSvc) { DWORD dwRet; SC_HANDLE schService = NULL; SC_HANDLE schSCManager = NULL; SERVICE_STATUS ServiceStatus; HANDLE hProgressDlg = NULL;
CWaitCursor cwait;
ServiceStatus.dwCurrentState = SERVICE_STOPPED; schSCManager = OpenSCManagerW( GetNullMachineName(&m_strMachineName),// machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_CONNECT // access required
); if ( NULL == schSCManager ) { dwRet = GetLastError(); _JumpError(dwRet, Ret, "OpenSCManagerW"); }
schService = OpenServiceW( schSCManager, wszSERVICE_NAME, ( fStartSvc ? SERVICE_START : SERVICE_STOP ) | SERVICE_QUERY_STATUS );
if (NULL == schService) { dwRet = GetLastError(); _JumpError(dwRet, Ret, "OpenServiceW"); }
// UNDONE: TRY/EXCEPT
hProgressDlg = StartProgressDlg( g_hInstance, hwndParent, STARTSTOP_MAX_RETRY_SECONDS, 0, fStartSvc ? IDS_STARTING_SVC : IDS_STOPPING_SVC);
//
// try to start the service
//
if (fStartSvc) { if (!StartService( schService, 0, NULL)) { dwRet = GetLastError(); if (dwRet == ERROR_SERVICE_ALREADY_RUNNING) dwRet = ERROR_SUCCESS; _JumpError2(dwRet, Ret, "StartService", ERROR_SUCCESS); } } else { if (! ControlService( schService, SERVICE_CONTROL_STOP, &ServiceStatus ) ) { dwRet = GetLastError(); if (dwRet == ERROR_SERVICE_NOT_ACTIVE) dwRet = ERROR_SUCCESS; _JumpError2(dwRet, Ret, "ControlService", ERROR_SUCCESS); } }
while( QueryServiceStatus( schService, &ServiceStatus ) ) { //
// FProgressDlgRunning sets upper time bound on loop
//
if( !FProgressDlgRunning() ) break;
if (fStartSvc) { // demorgan's on (pending OR (running AND !pausable))
if ((ServiceStatus.dwCurrentState != (DWORD) SERVICE_START_PENDING) && // not pending AND
((ServiceStatus.dwCurrentState != (DWORD) SERVICE_RUNNING) || // (not running OR is pausable)
(0 != (ServiceStatus.dwControlsAccepted & (DWORD) SERVICE_ACCEPT_PAUSE_CONTINUE) )) ) break; } else { if (ServiceStatus.dwCurrentState != (DWORD) SERVICE_STOP_PENDING) break; }
Sleep( 500 ); }
if ( ServiceStatus.dwCurrentState != (DWORD)(fStartSvc ? SERVICE_RUNNING : SERVICE_STOPPED)) { dwRet = ServiceStatus.dwWin32ExitCode;
if (ERROR_SERVICE_SPECIFIC_ERROR == dwRet) dwRet = ServiceStatus.dwServiceSpecificExitCode;
_JumpError(dwRet, Ret, "ServiceStatus.dwServiceSpecificExitCode"); } dwRet = ERROR_SUCCESS;
Ret: if (hProgressDlg) EndProgressDlg(hProgressDlg);
if (schService) CloseServiceHandle(schService); if (schSCManager) CloseServiceHandle(schSCManager);
if (ERROR_SUCCESS == dwRet) m_dwServiceStatus = ServiceStatus.dwCurrentState; else m_dwServiceStatus = SERVICE_STOPPED;
return dwRet; }
DWORD CertSvrMachine::RefreshServiceStatus() { DWORD dwRet; SC_HANDLE schService = NULL; SC_HANDLE schSCManager = NULL; SERVICE_STATUS ServiceStatus;
HCURSOR hPrevCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
m_dwServiceStatus = 0;
schSCManager = OpenSCManagerW( GetNullMachineName(&m_strMachineName),// machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_CONNECT // access required
); if ( NULL == schSCManager ) { dwRet = GetLastError(); _JumpError(dwRet, Ret, "OpenSCManagerW"); }
schService = OpenServiceW( schSCManager, wszSERVICE_NAME, SERVICE_INTERROGATE );
if (NULL == schService) { dwRet = GetLastError(); _JumpError(dwRet, Ret, "OpenServiceW"); }
if (!ControlService(schService, SERVICE_CONTROL_INTERROGATE, &ServiceStatus) ) { dwRet = GetLastError(); if (dwRet != ERROR_SERVICE_NOT_ACTIVE) { _JumpError(dwRet, Ret, "ControlService"); } }
m_dwServiceStatus = ServiceStatus.dwCurrentState;
dwRet = ERROR_SUCCESS; Ret: SetCursor(hPrevCur);
if (schService) CloseServiceHandle(schService); if (schSCManager) CloseServiceHandle(schSCManager);
return dwRet; }
LPCWSTR CertSvrMachine::GetCaCommonNameAtPos(DWORD iPos) { // if (iPos > (m_cCAList-1))
if (iPos > (DWORD)m_CAList.GetUpperBound()) return NULL;
return GetCaAtPos(iPos)->m_strCommonName; }
CertSvrCA* CertSvrMachine::GetCaAtPos(DWORD iPos) { // if (iPos > (m_cCAList-1))
if (iPos > (DWORD)m_CAList.GetUpperBound()) return NULL;
return m_CAList[iPos]; // return m_rgpCAList[iPos];
}
DWORD CertSvrMachine::PrepareData(HWND hwndParent) { // hwndParent: we will display a dlg describing what we're waiting for
HANDLE hDlg = NULL; DWORD dwRet; dwRet = ERROR_SUCCESS; __try { CSASSERT(hwndParent); hDlg = StartProgressDlg(g_hInstance, hwndParent, 10, 0, IDS_CA_REDISCOVER); // don't time out
dwRet = RefreshServiceStatus(); _LeaveIfError(dwRet, "RefreshServiceStatus"); dwRet = RetrieveCertSvrCAs(0); _LeaveIfError(dwRet, "RetrieveCertSvrCAs"); } __finally { if (hDlg) EndProgressDlg(hDlg); }
return dwRet; }
#include "csdisp.h"
DWORD CertSvrMachine::RetrieveCertSvrCAs( IN DWORD /* Flags */ ) { HRESULT hr; LONG Index; LPWSTR szTargetMachine = NULL; LPWSTR szTargetMachine2 = NULL; WCHAR* szRegActive; // no delete;
LPWSTR pwszzCAList = NULL; ICertAdmin2Ptr pAdmin; LPWSTR pwszSanitizedName = NULL; LPWSTR pwszCAList = NULL; size_t len; bool fNameIsAlreadySanitized = false; DWORD dwVersion; CertSvrCA *pIssuer = NULL;
// init var containing machine sans whacks
Index = sizeof(szTargetMachine); if (!m_strMachineName.IsEmpty()) { const WCHAR* pch = (LPCWSTR)m_strMachineName; // skip whack whack
if ((pch[0] == '\\') && (pch[1] == '\\')) pch+=2; szTargetMachine = (LPWSTR)LocalAlloc(LPTR, WSZ_BYTECOUNT(pch)); _JumpIfOutOfMemory(hr, error, szTargetMachine);
wcscpy(szTargetMachine, pch); } else { hr = myGetComputerNames(&szTargetMachine, &szTargetMachine2); _JumpIfError(hr, error, "myGetComputerNames"); }
// Don't go to DS for this, just RegConnect
// DS would give us: strConfig, szMachine, and Template info.
// we already can derive strConfig, szMachine; we weren't using template info here
// look for CAs that aren't yet completely set up
do { DWORD dwType;
hr = myPingCertSrv( szTargetMachine, NULL, &pwszzCAList, NULL, NULL, &dwVersion, NULL);
if(S_OK==hr) { if(dwVersion<2) hr = HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION); _JumpIfError(hr, error, "Whistler CA snapin cannot connect to older CAs"); }
// If for any reason we couldn't ping the CA, fail over to
// registry; we currently support only one CA per machine, if this
// changes in the future, replace the code below with an enumeration
// of nodes under configuration regkey.
if(S_OK!=hr) { hr = myGetCertRegValue( szTargetMachine, NULL, NULL, NULL, wszREGACTIVE, (BYTE**)&pwszCAList, NULL, &dwType); _JumpIfError(hr, error, "myGetCertRegValue");
CSASSERT(dwType==REG_SZ);
len = wcslen(pwszCAList)+1; pwszzCAList = (LPWSTR)LocalAlloc(LMEM_FIXED, (len+1)*sizeof(WCHAR)); _JumpIfAllocFailed(pwszzCAList, error);
wcscpy(pwszzCAList, pwszCAList); pwszzCAList[len] = L'\0';
// regactive gives us already sanitized ca name
fNameIsAlreadySanitized = true; } _JumpIfError(hr, error, "myPingCertSrv");
szRegActive = pwszzCAList;
while (szRegActive && szRegActive[0] != '\0') // while we don't hit end-of-string
{ for (int ii=0; ii<m_CAList.GetSize(); ii++) { // Common name match? break early
if (m_CAList[ii]->m_strCommonName.IsEqual(szRegActive)) break; }
// not found?
if (ii == m_CAList.GetSize()) { // and insert it into the list
pIssuer = new CertSvrCA(this); _JumpIfOutOfMemory(hr, error, pIssuer);
pIssuer->m_strServer = szTargetMachine;
if(!fNameIsAlreadySanitized) { hr = mySanitizeName(szRegActive, &pwszSanitizedName); _JumpIfError(hr, error, "mySanitizeName");
pIssuer->m_strSanitizedName = pwszSanitizedName; } else { pIssuer->m_strSanitizedName = szRegActive; }
variant_t varCommonName; // get prettified common name
hr = pIssuer->GetConfigEntry( NULL, wszREGCOMMONNAME, &varCommonName); _JumpIfError(hr, error, "GetConfigEntry");
if (V_VT(&varCommonName)!=VT_BSTR || V_BSTR(&varCommonName)==NULL) { hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); _JumpError(hr, error, "GetConfigEntry"); }
pIssuer->m_strCommonName = V_BSTR(&varCommonName); varCommonName.Clear();
// config is common name (not sanitized)
pIssuer->m_strConfig = szTargetMachine; pIssuer->m_strConfig += L"\\"; pIssuer->m_strConfig += pIssuer->m_strCommonName;
// Last: get description if exists
if (S_OK == pIssuer->GetConfigEntry( NULL, wszREGCADESCRIPTION, &varCommonName)) { if (V_VT(&varCommonName)==VT_BSTR && V_BSTR(&varCommonName)!=NULL) { pIssuer->m_strComment = V_BSTR(&varCommonName); } }
// create oft-used bstr
pIssuer->m_bstrConfig = pIssuer->m_strConfig.AllocSysString(); _JumpIfOutOfMemory(hr, error, pIssuer->m_bstrConfig);
m_CAList.Add(pIssuer); pIssuer = NULL; }
// REG_MULTI_SZ: fwd to next string
szRegActive += wcslen(szRegActive)+1; }
} while(0);
error: delete pIssuer; LOCAL_FREE(pwszzCAList); LOCAL_FREE(pwszSanitizedName); LOCAL_FREE(pwszCAList);
if (szTargetMachine) LocalFree(szTargetMachine);
if (szTargetMachine2) LocalFree(szTargetMachine2);
return(hr); }
STDMETHODIMP CertSvrMachine::Load(IStream *pStm) { CSASSERT(pStm); HRESULT hr;
// no header magic ?
// Read the string
hr = CStringLoad(m_strMachineNamePersist, pStm); m_strMachineName = m_strMachineNamePersist;
if (FAILED(hr)) return E_FAIL;
return S_OK; }
STDMETHODIMP CertSvrMachine::Save(IStream *pStm, BOOL fClearDirty) { CSASSERT(pStm); HRESULT hr;
// no header magic ?
// save the string
hr = CStringSave(m_strMachineNamePersist, pStm, fClearDirty); _PrintIfError(hr, "CStringSave");
// Verify that the write operation succeeded
if (FAILED(hr)) return STG_E_CANTSAVE;
return S_OK; }
STDMETHODIMP CertSvrMachine::GetSizeMax(int *pcbSize) { CSASSERT(pcbSize);
*pcbSize = (m_strMachineNamePersist.GetLength()+1)* sizeof(WCHAR);
return S_OK; }
|