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

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: tmpllist.cpp
  7. //
  8. // Contents: certificate template list class
  9. //
  10. //---------------------------------------------------------------------------
  11. #include <pch.cpp>
  12. #pragma hdrstop
  13. #include "certadmd.h"
  14. #include "tmpllist.h"
  15. #define __dwFILE__ __dwFILE_CERTLIB_TMPLLIST_CPP__
  16. using namespace CertSrv;
  17. HRESULT CTemplateInfo::SetInfo(
  18. LPCWSTR pcwszTemplateName,
  19. LPCWSTR pcwszTemplateOID)
  20. {
  21. HRESULT hr = S_OK;
  22. if(pcwszTemplateName)
  23. {
  24. m_pwszTemplateName = (LPWSTR)LocalAlloc(
  25. LMEM_FIXED,
  26. sizeof(WCHAR)*(wcslen(pcwszTemplateName)+1));
  27. _JumpIfAllocFailed(m_pwszTemplateName, error);
  28. wcscpy(m_pwszTemplateName, pcwszTemplateName);
  29. }
  30. if(pcwszTemplateOID)
  31. {
  32. m_pwszTemplateOID = (LPWSTR)LocalAlloc(
  33. LMEM_FIXED,
  34. sizeof(WCHAR)*(wcslen(pcwszTemplateOID)+1));
  35. _JumpIfAllocFailed(m_pwszTemplateOID, error);
  36. wcscpy(m_pwszTemplateOID, pcwszTemplateOID);
  37. }
  38. error:
  39. return hr;
  40. }
  41. LPCWSTR CTemplateInfo::GetName()
  42. {
  43. if(!m_pwszTemplateName && m_hCertType)
  44. {
  45. FillInfoFromProperty(
  46. m_pwszTemplateName,
  47. CERTTYPE_PROP_CN);
  48. }
  49. return m_pwszTemplateName;
  50. }
  51. LPCWSTR CTemplateInfo::GetOID()
  52. {
  53. if(!m_pwszTemplateOID && m_hCertType)
  54. {
  55. FillInfoFromProperty(
  56. m_pwszTemplateOID,
  57. CERTTYPE_PROP_OID);
  58. }
  59. return m_pwszTemplateOID;
  60. }
  61. void CTemplateInfo::FillInfoFromProperty(
  62. LPWSTR& pwszProp,
  63. LPCWSTR pcwszPropName)
  64. {
  65. LPWSTR *ppwszProp = NULL;
  66. CAGetCertTypeProperty(
  67. m_hCertType,
  68. pcwszPropName,
  69. &ppwszProp);
  70. if(ppwszProp && ppwszProp[0])
  71. {
  72. pwszProp = (LPWSTR)LocalAlloc(
  73. LMEM_FIXED,
  74. sizeof(WCHAR)*(wcslen(ppwszProp[0])+1));
  75. if(pwszProp)
  76. wcscpy(pwszProp, ppwszProp[0]);
  77. }
  78. if(ppwszProp)
  79. {
  80. CAFreeCertTypeProperty(
  81. m_hCertType,
  82. ppwszProp);
  83. }
  84. }
  85. bool CTemplateInfo::operator==(CTemplateInfo& rh)
  86. {
  87. if(GetName() && rh.GetName())
  88. return 0==_wcsicmp(GetName(), rh.GetName());
  89. if(GetOID() && rh.GetOID())
  90. return 0==wcscmp(GetOID(), rh.GetOID());
  91. return false;
  92. }
  93. HRESULT CTemplateList::AddTemplateInfo(
  94. LPCWSTR pcwszTemplateName,
  95. LPCWSTR pcwszTemplateOID)
  96. {
  97. HRESULT hr = S_OK;
  98. CTemplateInfo *pTI = NULL;
  99. pTI = new CTemplateInfo;
  100. _JumpIfAllocFailed(pTI, error);
  101. hr = pTI->SetInfo(pcwszTemplateName, pcwszTemplateOID);
  102. _JumpIfError(hr, error, "SetInfo");
  103. if(!AddTail(pTI))
  104. {
  105. hr = E_OUTOFMEMORY;
  106. _JumpError(hr, error, "AddTail");
  107. }
  108. error:
  109. return hr;
  110. }
  111. HRESULT CTemplateList::AddTemplateInfo(
  112. IN HCERTTYPE hCertType,
  113. IN BOOL fTransientCertTypeHandle) // don't hang onto hCertType
  114. {
  115. HRESULT hr = S_OK;
  116. CTemplateInfo *pTI = NULL;
  117. WCHAR **apwszCertTypeCN = NULL;
  118. WCHAR **apwszCertTypeOID = NULL;
  119. WCHAR const *pwszCertTypeOID;
  120. pTI = new CTemplateInfo;
  121. _JumpIfAllocFailed(pTI, error);
  122. if (fTransientCertTypeHandle)
  123. {
  124. hr = CAGetCertTypeProperty(
  125. hCertType,
  126. CERTTYPE_PROP_CN,
  127. &apwszCertTypeCN);
  128. _JumpIfError(hr, error, "CAGetCertTypeProperty CERTTYPE_PROP_CN");
  129. if (NULL == apwszCertTypeCN || NULL == apwszCertTypeCN[0])
  130. {
  131. hr = CERTSRV_E_PROPERTY_EMPTY;
  132. _JumpError(hr, error, "CERTTYPE_PROP_CN");
  133. }
  134. hr = CAGetCertTypeProperty(
  135. hCertType,
  136. CERTTYPE_PROP_OID,
  137. &apwszCertTypeOID);
  138. // ignore errors, V1 templates don't have OIDs
  139. _PrintIfError2(hr, "CAGetCertTypeProperty CERTTYPE_PROP_OID", hr);
  140. pwszCertTypeOID = NULL != apwszCertTypeOID? apwszCertTypeCN[0] : NULL;
  141. pTI->SetInfo(apwszCertTypeCN[0], pwszCertTypeOID);
  142. _JumpIfErrorStr(hr, error, "SetInfr", apwszCertTypeCN[0]);
  143. }
  144. else
  145. {
  146. hr = pTI->SetInfo(hCertType);
  147. _JumpIfError(hr, error, "SetInfo");
  148. }
  149. if(!AddTail(pTI))
  150. {
  151. hr = E_OUTOFMEMORY;
  152. _JumpError(hr, error, "AddTail");
  153. }
  154. error:
  155. if (NULL != apwszCertTypeCN)
  156. {
  157. CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
  158. }
  159. if (NULL != apwszCertTypeOID)
  160. {
  161. CAFreeCertTypeProperty(hCertType, apwszCertTypeOID);
  162. }
  163. return hr;
  164. }
  165. DWORD CTemplateList::GetMarshalBufferSize() const
  166. {
  167. DWORD dwSize = sizeof(WCHAR); // at least a trailing zero
  168. CTemplateListEnum EnumList(*this);
  169. for(CTemplateInfo *pData=EnumList.Next();
  170. pData;
  171. pData=EnumList.Next())
  172. {
  173. dwSize += pData->GetMarshalBufferSize();
  174. }
  175. return dwSize;
  176. }
  177. // Marshals the template information into a buffer, strings separated
  178. // by new lines:
  179. //
  180. // "name1\nOID1\nname2\OID2...\nnameN\nOIDN\0"
  181. //
  182. // If the template doesn't have an OID (Win2k domain) there will
  183. // be an empty string in its place
  184. HRESULT CTemplateList::Marshal(BYTE*& rpBuffer, DWORD& rcBuffer) const
  185. {
  186. HRESULT hr = S_OK;
  187. DWORD dwBufferSize = GetMarshalBufferSize();
  188. CTemplateListEnum EnumList(*this);
  189. WCHAR *pb;
  190. rpBuffer = NULL;
  191. rcBuffer = 0;
  192. // build the marshaling buffer
  193. rpBuffer = (BYTE*) MIDL_user_allocate(dwBufferSize);
  194. _JumpIfAllocFailed(rpBuffer, error);
  195. pb=(WCHAR*)rpBuffer;
  196. for(CTemplateInfo *pData=EnumList.Next();
  197. pData;
  198. pData=EnumList.Next())
  199. {
  200. if(pData->GetName())
  201. {
  202. wcscpy(pb, pData->GetName());
  203. pb += wcslen(pData->GetName());
  204. }
  205. // replace trailing zero with the separator character
  206. *pb = m_gcchSeparator;
  207. // jump over to insert the OID
  208. pb++;
  209. if(pData->GetOID())
  210. {
  211. wcscpy(pb, pData->GetOID());
  212. pb += wcslen(pData->GetOID());
  213. }
  214. // replace trailing zero with the separator character
  215. *pb = m_gcchSeparator;
  216. // jump over to insert the OID
  217. pb++;
  218. }
  219. // add string terminator
  220. *pb = L'\0';
  221. rcBuffer = dwBufferSize;
  222. error:
  223. return hr;
  224. }
  225. HRESULT CTemplateList::ValidateMarshalBuffer(const BYTE *pBuffer, DWORD cBuffer) const
  226. {
  227. const hrError = E_INVALIDARG;
  228. if(cBuffer&1)
  229. {
  230. _PrintError(hrError,
  231. "ValidateMarshalBuffer: buffer contains unicode string, "
  232. "buffer size should be even");
  233. return hrError;
  234. }
  235. if(cBuffer==0)
  236. {
  237. return S_OK;
  238. }
  239. if(cBuffer==2)
  240. {
  241. if(*(WCHAR*)pBuffer==L'\0')
  242. return S_OK;
  243. else
  244. {
  245. _PrintErrorStr(hrError,
  246. "ValidateMarshalBuffer: buffer size is 2 but string is not empty",
  247. (WCHAR*)pBuffer);
  248. return hrError;
  249. }
  250. }
  251. if(L'\0' != *(WCHAR*)(pBuffer+cBuffer-sizeof(WCHAR)))
  252. {
  253. _PrintErrorStr(hrError,
  254. "ValidateMarshalBuffer: buffer doesn't end with a null string terminator",
  255. (WCHAR*)pBuffer);
  256. return hrError;
  257. }
  258. // should contain an even number of separators
  259. DWORD cSeparators = 0;
  260. for(WCHAR *pCrt = (WCHAR*)pBuffer;
  261. pCrt && *pCrt!=L'\0' && ((BYTE*)pCrt) < pBuffer+cBuffer;
  262. pCrt++, cSeparators++)
  263. {
  264. pCrt = wcschr(pCrt, m_gcchSeparator);
  265. if(!pCrt)
  266. break;
  267. }
  268. if(cSeparators&1)
  269. {
  270. _PrintErrorStr(hrError,
  271. "ValidateMarshalBuffer: buffer should contain an even number of separators",
  272. (WCHAR*)pBuffer);
  273. return hrError;
  274. }
  275. if(cBuffer>1 && cSeparators<2)
  276. {
  277. _PrintErrorStr(hrError,
  278. "ValidateMarshalBuffer: nonempty buffer should contain at least two separators",
  279. (WCHAR*)pBuffer);
  280. return hrError;
  281. }
  282. return S_OK;
  283. }
  284. HRESULT CTemplateList::Unmarshal(const BYTE *pBuffer, DWORD cBuffer)
  285. {
  286. HRESULT hr = S_OK;
  287. WCHAR *pCrt, *pNext, *pwszName, *pwszOID;
  288. hr = ValidateMarshalBuffer(pBuffer, cBuffer);
  289. _JumpIfError(hr, error, "CTemplateList::ValidateMarshalBuffer");
  290. for(pCrt = (WCHAR*)pBuffer; *pCrt!=L'\0';)
  291. {
  292. pwszName = pCrt;
  293. pNext = wcschr(pCrt, m_gcchSeparator);
  294. if(!pNext)
  295. break;
  296. *pNext++ = L'\0';
  297. pwszOID = pNext;
  298. pNext = wcschr(pNext, m_gcchSeparator);
  299. if(!pNext)
  300. break;
  301. *pNext++ = L'\0';
  302. hr = AddTemplateInfo(pwszName, pwszOID);
  303. _JumpIfError(hr, error, "CTemplateList::AddTemplateInfo");
  304. pCrt = pNext;
  305. }
  306. error:
  307. return hr;
  308. }
  309. HRESULT CTemplateList::RemoveTemplateInfo(HCERTTYPE hCertType)
  310. {
  311. HRESULT hr = S_OK;
  312. CTemplateListEnum EnumList(*this);
  313. CTemplateInfo *pData;
  314. DWORD dwPosition = 0;
  315. CTemplateInfo tempInfo;
  316. hr = tempInfo.SetInfo(hCertType);
  317. if(S_OK!=hr)
  318. return hr;
  319. for(pData = EnumList.Next();
  320. pData;
  321. pData = EnumList.Next(), dwPosition++)
  322. {
  323. if(*pData == tempInfo)
  324. break;
  325. }
  326. if(!pData)
  327. return S_FALSE;
  328. RemoveAt(dwPosition);
  329. return S_OK;
  330. }
  331. //
  332. // Loads the structure with all known templates from DS
  333. HRESULT CTemplateList::LoadTemplatesFromDS()
  334. {
  335. HRESULT hr;
  336. HCERTTYPE hCertType = NULL;
  337. WCHAR **apwszCertTypeCN = NULL;
  338. WCHAR **apwszCertTypeOID = NULL;
  339. hr = CAEnumCertTypes(
  340. CT_ENUM_USER_TYPES |
  341. CT_ENUM_MACHINE_TYPES |
  342. CT_FLAG_NO_CACHE_LOOKUP,
  343. &hCertType);
  344. _JumpIfError(hr, error, "CAEnumCertTypes");
  345. while (hCertType)
  346. {
  347. HCERTTYPE hCertTypeNext;
  348. CAGetCertTypeProperty(
  349. hCertType,
  350. CERTTYPE_PROP_DN,
  351. &apwszCertTypeCN);
  352. CAGetCertTypeProperty(
  353. hCertType,
  354. CERTTYPE_PROP_OID,
  355. &apwszCertTypeOID);
  356. if((apwszCertTypeCN && apwszCertTypeCN[0])||
  357. (apwszCertTypeOID && apwszCertTypeOID[0]))
  358. {
  359. hr = AddTemplateInfo(
  360. apwszCertTypeCN[0],
  361. apwszCertTypeOID[0]);
  362. _JumpIfError(hr, error, "AddTemplateInfo");
  363. }
  364. CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
  365. CAFreeCertTypeProperty(hCertType, apwszCertTypeOID);
  366. apwszCertTypeCN = NULL;
  367. apwszCertTypeOID = NULL;
  368. hr = CAEnumNextCertType(hCertType, &hCertTypeNext);
  369. _JumpIfError(hr, error, "CAEnumNextCertType");
  370. CACloseCertType(hCertType);
  371. hCertType = hCertTypeNext;
  372. }
  373. hr = S_OK;
  374. error:
  375. if (NULL != hCertType)
  376. {
  377. if (NULL != apwszCertTypeCN)
  378. {
  379. CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
  380. }
  381. if (NULL != apwszCertTypeOID)
  382. {
  383. CAFreeCertTypeProperty(hCertType, apwszCertTypeOID);
  384. }
  385. CACloseCertType(hCertType);
  386. }
  387. return hr;
  388. }
  389. HRESULT
  390. RetrieveCATemplateListFromCA(
  391. IN HCAINFO hCAInfo,
  392. OUT CTemplateList& list)
  393. {
  394. HRESULT hr = S_OK;
  395. LPWSTR *ppwszDNSName = NULL;
  396. LPWSTR *ppwszAuthority = NULL;
  397. ICertAdminD2 *pAdminD2 = NULL;
  398. DWORD dwServerVersion = 2;
  399. CERTTRANSBLOB ctbSD;
  400. ZeroMemory(&ctbSD, sizeof(CERTTRANSBLOB));
  401. hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &ppwszDNSName);
  402. _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_DNSNAME");
  403. hr = CAGetCAProperty(hCAInfo, CA_PROP_NAME, &ppwszAuthority);
  404. _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_NAME");
  405. ASSERT(ppwszDNSName[0]);
  406. hr = myOpenAdminDComConnection(
  407. ppwszDNSName[0],
  408. NULL,
  409. NULL,
  410. &dwServerVersion,
  411. &pAdminD2);
  412. _JumpIfError(hr, error, "myOpenAdminDComConnection");
  413. if (2 > dwServerVersion)
  414. {
  415. hr = RPC_E_VERSION_MISMATCH;
  416. _JumpError(hr, error, "old server");
  417. }
  418. CSASSERT(ppwszAuthority[0]);
  419. hr = pAdminD2->GetCAProperty(
  420. ppwszAuthority[0],
  421. CR_PROP_TEMPLATES,
  422. 0,
  423. PROPTYPE_STRING,
  424. &ctbSD);
  425. _JumpIfErrorStr(hr, error, "ICertAdminD2::GetCAProperty CR_PROP_TEMPLATES",
  426. ppwszDNSName[0]);
  427. hr = list.Unmarshal(ctbSD.pb, ctbSD.cb);
  428. _JumpIfError(hr, error, "CTemplateList::Unmarshal");
  429. error:
  430. if(ppwszDNSName)
  431. CAFreeCAProperty(hCAInfo, ppwszDNSName);
  432. if(ppwszAuthority)
  433. CAFreeCAProperty(hCAInfo, ppwszAuthority);
  434. if(pAdminD2)
  435. pAdminD2->Release();
  436. return hr;
  437. }
  438. HRESULT
  439. RetrieveCATemplateListFromDS(
  440. IN HCAINFO hCAInfo,
  441. IN BOOL fTransientCertTypeHandle, // don't hang onto hCertType
  442. OUT CTemplateList& list)
  443. {
  444. HRESULT hr;
  445. HCERTTYPE hCertType = NULL;
  446. hr = CAEnumCertTypesForCA(
  447. hCAInfo,
  448. CT_ENUM_MACHINE_TYPES |
  449. CT_ENUM_USER_TYPES |
  450. CT_FLAG_NO_CACHE_LOOKUP,
  451. &hCertType);
  452. _JumpIfError(hr, error, "CAEnumCertTypesForCA");
  453. while (hCertType != NULL)
  454. {
  455. HCERTTYPE hCertTypeNext;
  456. hr = list.AddTemplateInfo(hCertType, fTransientCertTypeHandle);
  457. _JumpIfError(hr, error, "CTemplateList::AddTemplate");
  458. hr = CAEnumNextCertType(hCertType, &hCertTypeNext);
  459. _JumpIfError(hr, error, "CAEnumNextCertType");
  460. if (fTransientCertTypeHandle)
  461. {
  462. CACloseCertType(hCertType);
  463. }
  464. hCertType = hCertTypeNext;
  465. }
  466. hr = S_OK;
  467. error:
  468. if (NULL != hCertType)
  469. {
  470. CACloseCertType(hCertType);
  471. }
  472. return hr;
  473. }
  474. HRESULT
  475. myRetrieveCATemplateList(
  476. IN HCAINFO hCAInfo,
  477. IN BOOL fTransientCertTypeHandle, // don't hang onto hCertType
  478. OUT CTemplateList& list)
  479. {
  480. HRESULT hr = S_OK;
  481. hr = RetrieveCATemplateListFromCA(hCAInfo, list);
  482. if(S_OK != hr)
  483. {
  484. // if failed to retrieve from the CA for any reason, try
  485. // fetching from DS
  486. hr = RetrieveCATemplateListFromDS(
  487. hCAInfo,
  488. fTransientCertTypeHandle,
  489. list);
  490. }
  491. return hr;
  492. }
  493. HRESULT
  494. myUpdateCATemplateListToDS(
  495. IN HCAINFO hCAInfo)
  496. {
  497. HRESULT hr = S_OK;
  498. hr = CAUpdateCA(hCAInfo);
  499. _JumpIfError(hr, error, "CAUpdateCA");
  500. error:
  501. return hr;
  502. }
  503. HRESULT
  504. myUpdateCATemplateListToCA(
  505. IN HCAINFO hCAInfo,
  506. IN const CTemplateList& list)
  507. {
  508. HRESULT hr = S_OK;
  509. LPWSTR *ppwszDNSName = NULL;
  510. LPWSTR *ppwszAuthority = NULL;
  511. ICertAdminD2 *pAdminD2 = NULL;
  512. DWORD dwServerVersion = 2;
  513. CERTTRANSBLOB ctbSD;
  514. ZeroMemory(&ctbSD, sizeof(CERTTRANSBLOB));
  515. hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &ppwszDNSName);
  516. _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_DNSNAME");
  517. hr = CAGetCAProperty(hCAInfo, CA_PROP_NAME, &ppwszAuthority);
  518. _JumpIfError(hr, error, "CAGetCAProperty CA_PROP_NAME");
  519. ASSERT(ppwszDNSName[0]);
  520. hr = myOpenAdminDComConnection(
  521. ppwszDNSName[0],
  522. NULL,
  523. NULL,
  524. &dwServerVersion,
  525. &pAdminD2);
  526. _JumpIfError(hr, error, "myOpenAdminDComConnection");
  527. if (2 > dwServerVersion)
  528. {
  529. hr = RPC_E_VERSION_MISMATCH;
  530. _JumpError(hr, error, "old server");
  531. }
  532. CSASSERT(ppwszAuthority[0]);
  533. hr = list.Marshal(ctbSD.pb, ctbSD.cb);
  534. _JumpIfError(hr, error, "CTemplateList::Marshal");
  535. CSASSERT(S_OK==list.ValidateMarshalBuffer(ctbSD.pb, ctbSD.cb));
  536. hr = pAdminD2->SetCAProperty(
  537. ppwszAuthority[0],
  538. CR_PROP_TEMPLATES,
  539. 0,
  540. PROPTYPE_STRING,
  541. &ctbSD);
  542. _JumpIfErrorStr(hr, error, "ICertAdminD2::SetCAProperty CR_PROP_TEMPLATES",
  543. ppwszDNSName[0]);
  544. error:
  545. if(ppwszDNSName)
  546. CAFreeCAProperty(hCAInfo, ppwszDNSName);
  547. if(ppwszAuthority)
  548. CAFreeCAProperty(hCAInfo, ppwszAuthority);
  549. if(pAdminD2)
  550. pAdminD2->Release();
  551. if(ctbSD.pb)
  552. MIDL_user_free(ctbSD.pb);
  553. return hr;
  554. }
  555. HRESULT
  556. myAddToCATemplateList(
  557. IN HCAINFO hCAInfo,
  558. IN OUT CTemplateList& list,
  559. IN HCERTTYPE hCertType,
  560. IN BOOL fTransientCertTypeHandle) // don't hang onto hCertType
  561. {
  562. HRESULT hr;
  563. hr = CAAddCACertificateType(hCAInfo, hCertType);
  564. _JumpIfError(hr, error, "CAAddCACertificateType");
  565. hr = list.AddTemplateInfo(hCertType, fTransientCertTypeHandle);
  566. _JumpIfError(hr, error, "CTemplateList::AddTemplateInfo HCERTTYPE");
  567. error:
  568. return hr;
  569. }
  570. HRESULT
  571. myRemoveFromCATemplateList(
  572. IN HCAINFO hCAInfo,
  573. IN OUT CTemplateList& list,
  574. IN HCERTTYPE hCertType)
  575. {
  576. HRESULT hr = S_OK;
  577. hr = CARemoveCACertificateType(hCAInfo, hCertType);
  578. _JumpIfError(hr, error, "CARemoveCACertificateType");
  579. hr = list.RemoveTemplateInfo(hCertType);
  580. _JumpIfError(hr, error, "CTemplateList::RemoveTemplateInfo HCERTTYPE");
  581. error:
  582. return hr;
  583. }