//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: tmpllist.cpp // // Contents: certificate template list class // //--------------------------------------------------------------------------- #include #pragma hdrstop #include "certadmd.h" #include "tmpllist.h" #define __dwFILE__ __dwFILE_CERTLIB_TMPLLIST_CPP__ using namespace CertSrv; HRESULT CTemplateInfo::SetInfo( LPCWSTR pcwszTemplateName, LPCWSTR pcwszTemplateOID) { HRESULT hr = S_OK; if(pcwszTemplateName) { m_pwszTemplateName = (LPWSTR)LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(wcslen(pcwszTemplateName)+1)); _JumpIfAllocFailed(m_pwszTemplateName, error); wcscpy(m_pwszTemplateName, pcwszTemplateName); } if(pcwszTemplateOID) { m_pwszTemplateOID = (LPWSTR)LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(wcslen(pcwszTemplateOID)+1)); _JumpIfAllocFailed(m_pwszTemplateOID, error); wcscpy(m_pwszTemplateOID, pcwszTemplateOID); } error: return hr; } LPCWSTR CTemplateInfo::GetName() { if(!m_pwszTemplateName && m_hCertType) { FillInfoFromProperty( m_pwszTemplateName, CERTTYPE_PROP_CN); } return m_pwszTemplateName; } LPCWSTR CTemplateInfo::GetOID() { if(!m_pwszTemplateOID && m_hCertType) { FillInfoFromProperty( m_pwszTemplateOID, CERTTYPE_PROP_OID); } return m_pwszTemplateOID; } void CTemplateInfo::FillInfoFromProperty( LPWSTR& pwszProp, LPCWSTR pcwszPropName) { LPWSTR *ppwszProp = NULL; CAGetCertTypeProperty( m_hCertType, pcwszPropName, &ppwszProp); if(ppwszProp && ppwszProp[0]) { pwszProp = (LPWSTR)LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(wcslen(ppwszProp[0])+1)); if(pwszProp) wcscpy(pwszProp, ppwszProp[0]); } if(ppwszProp) { CAFreeCertTypeProperty( m_hCertType, ppwszProp); } } bool CTemplateInfo::operator==(CTemplateInfo& rh) { if(GetName() && rh.GetName()) return 0==_wcsicmp(GetName(), rh.GetName()); if(GetOID() && rh.GetOID()) return 0==wcscmp(GetOID(), rh.GetOID()); return false; } HRESULT CTemplateList::AddTemplateInfo( LPCWSTR pcwszTemplateName, LPCWSTR pcwszTemplateOID) { HRESULT hr = S_OK; CTemplateInfo *pTI = NULL; pTI = new CTemplateInfo; _JumpIfAllocFailed(pTI, error); hr = pTI->SetInfo(pcwszTemplateName, pcwszTemplateOID); _JumpIfError(hr, error, "SetInfo"); if(!AddTail(pTI)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "AddTail"); } error: return hr; } HRESULT CTemplateList::AddTemplateInfo( IN HCERTTYPE hCertType, IN BOOL fTransientCertTypeHandle) // don't hang onto hCertType { HRESULT hr = S_OK; CTemplateInfo *pTI = NULL; WCHAR **apwszCertTypeCN = NULL; WCHAR **apwszCertTypeOID = NULL; WCHAR const *pwszCertTypeOID; pTI = new CTemplateInfo; _JumpIfAllocFailed(pTI, error); if (fTransientCertTypeHandle) { hr = CAGetCertTypeProperty( hCertType, CERTTYPE_PROP_CN, &apwszCertTypeCN); _JumpIfError(hr, error, "CAGetCertTypeProperty CERTTYPE_PROP_CN"); if (NULL == apwszCertTypeCN || NULL == apwszCertTypeCN[0]) { hr = CERTSRV_E_PROPERTY_EMPTY; _JumpError(hr, error, "CERTTYPE_PROP_CN"); } hr = CAGetCertTypeProperty( hCertType, CERTTYPE_PROP_OID, &apwszCertTypeOID); // ignore errors, V1 templates don't have OIDs _PrintIfError2(hr, "CAGetCertTypeProperty CERTTYPE_PROP_OID", hr); pwszCertTypeOID = NULL != apwszCertTypeOID? apwszCertTypeCN[0] : NULL; pTI->SetInfo(apwszCertTypeCN[0], pwszCertTypeOID); _JumpIfErrorStr(hr, error, "SetInfr", apwszCertTypeCN[0]); } else { hr = pTI->SetInfo(hCertType); _JumpIfError(hr, error, "SetInfo"); } if(!AddTail(pTI)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "AddTail"); } error: if (NULL != apwszCertTypeCN) { CAFreeCertTypeProperty(hCertType, apwszCertTypeCN); } if (NULL != apwszCertTypeOID) { CAFreeCertTypeProperty(hCertType, apwszCertTypeOID); } return hr; } DWORD CTemplateList::GetMarshalBufferSize() const { DWORD dwSize = sizeof(WCHAR); // at least a trailing zero CTemplateListEnum EnumList(*this); for(CTemplateInfo *pData=EnumList.Next(); pData; pData=EnumList.Next()) { dwSize += pData->GetMarshalBufferSize(); } return dwSize; } // Marshals the template information into a buffer, strings separated // by new lines: // // "name1\nOID1\nname2\OID2...\nnameN\nOIDN\0" // // If the template doesn't have an OID (Win2k domain) there will // be an empty string in its place HRESULT CTemplateList::Marshal(BYTE*& rpBuffer, DWORD& rcBuffer) const { HRESULT hr = S_OK; DWORD dwBufferSize = GetMarshalBufferSize(); CTemplateListEnum EnumList(*this); WCHAR *pb; rpBuffer = NULL; rcBuffer = 0; // build the marshaling buffer rpBuffer = (BYTE*) MIDL_user_allocate(dwBufferSize); _JumpIfAllocFailed(rpBuffer, error); pb=(WCHAR*)rpBuffer; for(CTemplateInfo *pData=EnumList.Next(); pData; pData=EnumList.Next()) { if(pData->GetName()) { wcscpy(pb, pData->GetName()); pb += wcslen(pData->GetName()); } // replace trailing zero with the separator character *pb = m_gcchSeparator; // jump over to insert the OID pb++; if(pData->GetOID()) { wcscpy(pb, pData->GetOID()); pb += wcslen(pData->GetOID()); } // replace trailing zero with the separator character *pb = m_gcchSeparator; // jump over to insert the OID pb++; } // add string terminator *pb = L'\0'; rcBuffer = dwBufferSize; error: return hr; } HRESULT CTemplateList::ValidateMarshalBuffer(const BYTE *pBuffer, DWORD cBuffer) const { const hrError = E_INVALIDARG; if(cBuffer&1) { _PrintError(hrError, "ValidateMarshalBuffer: buffer contains unicode string, " "buffer size should be even"); return hrError; } if(cBuffer==0) { return S_OK; } if(cBuffer==2) { if(*(WCHAR*)pBuffer==L'\0') return S_OK; else { _PrintErrorStr(hrError, "ValidateMarshalBuffer: buffer size is 2 but string is not empty", (WCHAR*)pBuffer); return hrError; } } if(L'\0' != *(WCHAR*)(pBuffer+cBuffer-sizeof(WCHAR))) { _PrintErrorStr(hrError, "ValidateMarshalBuffer: buffer doesn't end with a null string terminator", (WCHAR*)pBuffer); return hrError; } // should contain an even number of separators DWORD cSeparators = 0; for(WCHAR *pCrt = (WCHAR*)pBuffer; pCrt && *pCrt!=L'\0' && ((BYTE*)pCrt) < pBuffer+cBuffer; pCrt++, cSeparators++) { pCrt = wcschr(pCrt, m_gcchSeparator); if(!pCrt) break; } if(cSeparators&1) { _PrintErrorStr(hrError, "ValidateMarshalBuffer: buffer should contain an even number of separators", (WCHAR*)pBuffer); return hrError; } if(cBuffer>1 && cSeparators<2) { _PrintErrorStr(hrError, "ValidateMarshalBuffer: nonempty buffer should contain at least two separators", (WCHAR*)pBuffer); return hrError; } return S_OK; } HRESULT CTemplateList::Unmarshal(const BYTE *pBuffer, DWORD cBuffer) { HRESULT hr = S_OK; WCHAR *pCrt, *pNext, *pwszName, *pwszOID; hr = ValidateMarshalBuffer(pBuffer, cBuffer); _JumpIfError(hr, error, "CTemplateList::ValidateMarshalBuffer"); for(pCrt = (WCHAR*)pBuffer; *pCrt!=L'\0';) { pwszName = pCrt; pNext = wcschr(pCrt, m_gcchSeparator); if(!pNext) break; *pNext++ = L'\0'; pwszOID = pNext; pNext = wcschr(pNext, m_gcchSeparator); if(!pNext) break; *pNext++ = L'\0'; hr = AddTemplateInfo(pwszName, pwszOID); _JumpIfError(hr, error, "CTemplateList::AddTemplateInfo"); pCrt = pNext; } error: return hr; } HRESULT CTemplateList::RemoveTemplateInfo(HCERTTYPE hCertType) { HRESULT hr = S_OK; CTemplateListEnum EnumList(*this); CTemplateInfo *pData; DWORD dwPosition = 0; CTemplateInfo tempInfo; hr = tempInfo.SetInfo(hCertType); if(S_OK!=hr) return hr; for(pData = EnumList.Next(); pData; pData = EnumList.Next(), dwPosition++) { if(*pData == tempInfo) break; } if(!pData) return S_FALSE; RemoveAt(dwPosition); return S_OK; } // // Loads the structure with all known templates from DS HRESULT CTemplateList::LoadTemplatesFromDS() { HRESULT hr; HCERTTYPE hCertType = NULL; WCHAR **apwszCertTypeCN = NULL; WCHAR **apwszCertTypeOID = NULL; hr = CAEnumCertTypes( CT_ENUM_USER_TYPES | CT_ENUM_MACHINE_TYPES | CT_FLAG_NO_CACHE_LOOKUP, &hCertType); _JumpIfError(hr, error, "CAEnumCertTypes"); while (hCertType) { HCERTTYPE hCertTypeNext; CAGetCertTypeProperty( hCertType, CERTTYPE_PROP_DN, &apwszCertTypeCN); CAGetCertTypeProperty( hCertType, CERTTYPE_PROP_OID, &apwszCertTypeOID); if((apwszCertTypeCN && apwszCertTypeCN[0])|| (apwszCertTypeOID && apwszCertTypeOID[0])) { hr = AddTemplateInfo( apwszCertTypeCN[0], apwszCertTypeOID[0]); _JumpIfError(hr, error, "AddTemplateInfo"); } CAFreeCertTypeProperty(hCertType, apwszCertTypeCN); CAFreeCertTypeProperty(hCertType, apwszCertTypeOID); apwszCertTypeCN = NULL; apwszCertTypeOID = NULL; hr = CAEnumNextCertType(hCertType, &hCertTypeNext); _JumpIfError(hr, error, "CAEnumNextCertType"); CACloseCertType(hCertType); hCertType = hCertTypeNext; } hr = S_OK; error: if (NULL != hCertType) { if (NULL != apwszCertTypeCN) { CAFreeCertTypeProperty(hCertType, apwszCertTypeCN); } if (NULL != apwszCertTypeOID) { CAFreeCertTypeProperty(hCertType, apwszCertTypeOID); } CACloseCertType(hCertType); } return hr; } HRESULT RetrieveCATemplateListFromCA( IN HCAINFO hCAInfo, OUT CTemplateList& list) { HRESULT hr = S_OK; LPWSTR *ppwszDNSName = NULL; LPWSTR *ppwszAuthority = NULL; ICertAdminD2 *pAdminD2 = NULL; DWORD dwServerVersion = 2; CERTTRANSBLOB ctbSD; ZeroMemory(&ctbSD, sizeof(CERTTRANSBLOB)); hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &ppwszDNSName); _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_DNSNAME"); hr = CAGetCAProperty(hCAInfo, CA_PROP_NAME, &ppwszAuthority); _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_NAME"); ASSERT(ppwszDNSName[0]); hr = myOpenAdminDComConnection( ppwszDNSName[0], NULL, NULL, &dwServerVersion, &pAdminD2); _JumpIfError(hr, error, "myOpenAdminDComConnection"); if (2 > dwServerVersion) { hr = RPC_E_VERSION_MISMATCH; _JumpError(hr, error, "old server"); } CSASSERT(ppwszAuthority[0]); hr = pAdminD2->GetCAProperty( ppwszAuthority[0], CR_PROP_TEMPLATES, 0, PROPTYPE_STRING, &ctbSD); _JumpIfErrorStr(hr, error, "ICertAdminD2::GetCAProperty CR_PROP_TEMPLATES", ppwszDNSName[0]); hr = list.Unmarshal(ctbSD.pb, ctbSD.cb); _JumpIfError(hr, error, "CTemplateList::Unmarshal"); error: if(ppwszDNSName) CAFreeCAProperty(hCAInfo, ppwszDNSName); if(ppwszAuthority) CAFreeCAProperty(hCAInfo, ppwszAuthority); if(pAdminD2) pAdminD2->Release(); return hr; } HRESULT RetrieveCATemplateListFromDS( IN HCAINFO hCAInfo, IN BOOL fTransientCertTypeHandle, // don't hang onto hCertType OUT CTemplateList& list) { HRESULT hr; HCERTTYPE hCertType = NULL; hr = CAEnumCertTypesForCA( hCAInfo, CT_ENUM_MACHINE_TYPES | CT_ENUM_USER_TYPES | CT_FLAG_NO_CACHE_LOOKUP, &hCertType); _JumpIfError(hr, error, "CAEnumCertTypesForCA"); while (hCertType != NULL) { HCERTTYPE hCertTypeNext; hr = list.AddTemplateInfo(hCertType, fTransientCertTypeHandle); _JumpIfError(hr, error, "CTemplateList::AddTemplate"); hr = CAEnumNextCertType(hCertType, &hCertTypeNext); _JumpIfError(hr, error, "CAEnumNextCertType"); if (fTransientCertTypeHandle) { CACloseCertType(hCertType); } hCertType = hCertTypeNext; } hr = S_OK; error: if (NULL != hCertType) { CACloseCertType(hCertType); } return hr; } HRESULT myRetrieveCATemplateList( IN HCAINFO hCAInfo, IN BOOL fTransientCertTypeHandle, // don't hang onto hCertType OUT CTemplateList& list) { HRESULT hr = S_OK; hr = RetrieveCATemplateListFromCA(hCAInfo, list); if(S_OK != hr) { // if failed to retrieve from the CA for any reason, try // fetching from DS hr = RetrieveCATemplateListFromDS( hCAInfo, fTransientCertTypeHandle, list); } return hr; } HRESULT myUpdateCATemplateListToDS( IN HCAINFO hCAInfo) { HRESULT hr = S_OK; hr = CAUpdateCA(hCAInfo); _JumpIfError(hr, error, "CAUpdateCA"); error: return hr; } HRESULT myUpdateCATemplateListToCA( IN HCAINFO hCAInfo, IN const CTemplateList& list) { HRESULT hr = S_OK; LPWSTR *ppwszDNSName = NULL; LPWSTR *ppwszAuthority = NULL; ICertAdminD2 *pAdminD2 = NULL; DWORD dwServerVersion = 2; CERTTRANSBLOB ctbSD; ZeroMemory(&ctbSD, sizeof(CERTTRANSBLOB)); hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &ppwszDNSName); _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_DNSNAME"); hr = CAGetCAProperty(hCAInfo, CA_PROP_NAME, &ppwszAuthority); _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_NAME"); ASSERT(ppwszDNSName[0]); hr = myOpenAdminDComConnection( ppwszDNSName[0], NULL, NULL, &dwServerVersion, &pAdminD2); _JumpIfError(hr, error, "myOpenAdminDComConnection"); if (2 > dwServerVersion) { hr = RPC_E_VERSION_MISMATCH; _JumpError(hr, error, "old server"); } CSASSERT(ppwszAuthority[0]); hr = list.Marshal(ctbSD.pb, ctbSD.cb); _JumpIfError(hr, error, "CTemplateList::Marshal"); CSASSERT(S_OK==list.ValidateMarshalBuffer(ctbSD.pb, ctbSD.cb)); hr = pAdminD2->SetCAProperty( ppwszAuthority[0], CR_PROP_TEMPLATES, 0, PROPTYPE_STRING, &ctbSD); _JumpIfErrorStr(hr, error, "ICertAdminD2::SetCAProperty CR_PROP_TEMPLATES", ppwszDNSName[0]); error: if(ppwszDNSName) CAFreeCAProperty(hCAInfo, ppwszDNSName); if(ppwszAuthority) CAFreeCAProperty(hCAInfo, ppwszAuthority); if(pAdminD2) pAdminD2->Release(); if(ctbSD.pb) MIDL_user_free(ctbSD.pb); return hr; } HRESULT myAddToCATemplateList( IN HCAINFO hCAInfo, IN OUT CTemplateList& list, IN HCERTTYPE hCertType, IN BOOL fTransientCertTypeHandle) // don't hang onto hCertType { HRESULT hr; hr = CAAddCACertificateType(hCAInfo, hCertType); _JumpIfError(hr, error, "CAAddCACertificateType"); hr = list.AddTemplateInfo(hCertType, fTransientCertTypeHandle); _JumpIfError(hr, error, "CTemplateList::AddTemplateInfo HCERTTYPE"); error: return hr; } HRESULT myRemoveFromCATemplateList( IN HCAINFO hCAInfo, IN OUT CTemplateList& list, IN HCERTTYPE hCertType) { HRESULT hr = S_OK; hr = CARemoveCACertificateType(hCAInfo, hCertType); _JumpIfError(hr, error, "CARemoveCACertificateType"); hr = list.RemoveTemplateInfo(hCertType); _JumpIfError(hr, error, "CTemplateList::RemoveTemplateInfo HCERTTYPE"); error: return hr; }