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.
 
 
 
 
 
 

721 lines
17 KiB

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: tmpllist.cpp
//
// Contents: certificate template list class
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#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;
}