windows-nt/Source/XPSP1/NT/ds/security/services/ca/certmmc/certwrap.cpp

1586 lines
38 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// 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"
_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 = 0;
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:HRESULT_FROM_WIN32(GetLastError());
_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 = HRESULT_FROM_WIN32(GetLastError());
_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=HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "InitializeAcl");
}
fRet = GetAce(pDaclRead, 0, &pAce);
if(!fRet)
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "GetAce");
}
fRet = AddAce(pDaclWrite, ACL_REVISION_DS, 0, pAce, dwDaclSize-sizeof(ACL));
if(!fRet)
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "AddAce");
}
fRet = AddAccessAllowedAce(
pDaclWrite,
ACL_REVISION_DS,
ACTRL_CERTSRV_MANAGE_LESS_CONTROL_ACCESS,
pSid);
if(!fRet)
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "AddAccessAllowedAce");
}
fRet = SetSecurityDescriptorDacl(
pSDTemp,
TRUE,
pDaclWrite,
FALSE);
if(!fRet)
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "SetSecurityDescriptorDacl");
}
fRet = MakeSelfRelativeSD(
pSDTemp,
NULL,
&dwSDWriteSize);
if(fRet || ERROR_INSUFFICIENT_BUFFER!=GetLastError())
{
hr = fRet?E_FAIL:HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "MakeSelfRelativeSD");
}
pSDWrite = LocalAlloc(LMEM_FIXED, dwSDWriteSize);
_JumpIfAllocFailed(pSDWrite, error);
fRet = MakeSelfRelativeSD(
pSDTemp,
pSDWrite,
&dwSDWriteSize);
if(!fRet)
{
hr = HRESULT_FROM_WIN32(GetLastError());
_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;
}
BOOL CertSvrCA::FIsIncompleteInstallation()
{
DWORD dwStatus;
if (S_OK == GetSetupStatus(m_strSanitizedName, &dwStatus))
{
if(SETUP_SUSPEND_FLAG & dwStatus)
return TRUE;
}
return FALSE;
}
BOOL CertSvrCA::FIsRequestOutstanding()
{
DWORD dwStatus;
if (S_OK == GetSetupStatus(m_strSanitizedName, &dwStatus))
{
if(SETUP_REQUEST_FLAG & dwStatus)
return TRUE;
}
return FALSE;
}
BOOL CertSvrCA::FDoesSecurityNeedUpgrade()
{
DWORD dwStatus;
if (S_OK == GetSetupStatus(m_strSanitizedName, &dwStatus))
{
if(SETUP_W2K_SECURITY_NOT_UPGRADED_FLAG & dwStatus)
return TRUE;
}
return 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(
strConfig.GetBuffer(),
szConfigSubKey,
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(
strConfig.GetBuffer(),
szConfigSubKey,
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 += L"ROOT";
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;
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 = (V_I4(&varTmp) >= CSVER_WHISTLER); // bigger than or equal to major Whistler version? return TRUE!
m_fIsWhistlerMachineKnown = TRUE;
}
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(
strConfig.GetBuffer(),
NULL,
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;
DWORD dwAttempts = 0;
CWaitCursor cwait;
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;
__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"
LPWSTR szConfigFieldDescription[] =
{
L"Server",
L"CommonName",
L"OrgUnit",
L"Organization",
L"Locality",
L"State",
L"Country",
L"Config",
L"Comment",
};
DWORD
CertSvrMachine::RetrieveCertSvrCAs(
IN DWORD Flags)
{
HRESULT hr;
LONG i, iEntries;
LONG count=0, 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;
// 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
{
HKEY hBaseKey; // this is cached
DWORD cbOut, 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[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
CertSvrCA* 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;
}
LPWSTR pszString = NULL;
DWORD cbString = 0;
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);
}
// REG_MULTI_SZ: fwd to next string
szRegActive += wcslen(szRegActive)+1;
}
} while(0);
error:
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;
}