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.

2251 lines
52 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000
  5. //
  6. // File: request.cpp
  7. //
  8. // Contents: Cert Server Policy Module implementation
  9. //
  10. //---------------------------------------------------------------------------
  11. #include "pch.cpp"
  12. #pragma hdrstop
  13. #include <ntdsapi.h>
  14. #include <lm.h>
  15. #include <winldap.h>
  16. #include <security.h>
  17. #include "cspelog.h"
  18. #include "pollog.h"
  19. #include "csprop.h"
  20. #include "csldap.h"
  21. #include "csdisp.h"
  22. #include "policy.h"
  23. #include "cainfop.h"
  24. #define __dwFILE__ __dwFILE_POLICY_DEFAULT_REQUEST_CPP__
  25. LDAP **g_rgGCCache = NULL;
  26. LONG g_cGCCacheCur;
  27. LONG g_cGCCacheMax;
  28. CRITICAL_SECTION g_GCCacheCriticalSection;
  29. BOOL g_fGCCacheCriticalSection = FALSE;
  30. VOID
  31. myLdapUnbind(
  32. IN OUT LDAP **ppld)
  33. {
  34. if (NULL != *ppld)
  35. {
  36. ldap_unbind(*ppld);
  37. *ppld = NULL;
  38. }
  39. }
  40. HRESULT
  41. myLdapBind(
  42. IN DWORD Flags,
  43. OPTIONAL IN WCHAR const *pwszClientDC, // require GC unless non-NULL
  44. IN OUT LDAP **ppld)
  45. {
  46. HRESULT hr;
  47. ULONG ldaperr;
  48. DWORD GetDSNameFlags;
  49. WCHAR *pwszDomainControllerName;
  50. BOOL fGC = NULL == pwszClientDC;
  51. BOOL fRediscover = FALSE;
  52. LDAP *pld = *ppld;
  53. GetDSNameFlags = DS_RETURN_DNS_NAME;
  54. if (fGC)
  55. {
  56. // We want to talk to a GC, so grab the GC name. Get the GC location.
  57. GetDSNameFlags |= DS_GC_SERVER_REQUIRED;
  58. }
  59. while (TRUE)
  60. {
  61. if (NULL != *ppld)
  62. {
  63. break;
  64. }
  65. // Clean up from previous loop execution
  66. if (NULL != pld)
  67. {
  68. ldap_unbind(pld);
  69. pld = NULL;
  70. }
  71. // Grab an LDAP handle for use during this instantiation
  72. pld = ldap_init(
  73. const_cast<WCHAR *>(pwszClientDC),
  74. fGC? LDAP_GC_PORT : LDAP_PORT);
  75. if (NULL == pld)
  76. {
  77. hr = myHLdapLastError(NULL, NULL);
  78. if (!fRediscover)
  79. {
  80. _PrintError2(hr, "Policy:ldap_init", hr);
  81. fRediscover = TRUE;
  82. continue;
  83. }
  84. _JumpError(hr, error, "Policy:ldap_init");
  85. }
  86. if (fRediscover && NULL == pwszClientDC)
  87. {
  88. GetDSNameFlags |= DS_FORCE_REDISCOVERY;
  89. }
  90. ldaperr = ldap_set_option(
  91. pld,
  92. LDAP_OPT_GETDSNAME_FLAGS,
  93. (VOID *) &GetDSNameFlags);
  94. if (LDAP_SUCCESS != ldaperr)
  95. {
  96. hr = myHLdapError(pld, ldaperr, NULL);
  97. if (!fRediscover)
  98. {
  99. _PrintError2(hr, "Policy:ldap_set_option", hr);
  100. fRediscover = TRUE;
  101. continue;
  102. }
  103. _JumpError(hr, error, "Policy:ldap_set_option");
  104. }
  105. if (NULL != pwszClientDC)
  106. {
  107. DWORD SSPIFlags;
  108. // Turn on mutual authentication -- just to make sure we can trust
  109. // the client-supplied DC name.
  110. ldaperr = ldap_get_option(
  111. pld,
  112. LDAP_OPT_SSPI_FLAGS,
  113. (VOID *) &SSPIFlags);
  114. if (LDAP_SUCCESS != ldaperr)
  115. {
  116. hr = myHLdapError(pld, ldaperr, NULL);
  117. if (!fRediscover)
  118. {
  119. _PrintError2(hr, "Policy:ldap_get_option", hr);
  120. fRediscover = TRUE;
  121. continue;
  122. }
  123. _JumpError(hr, error, "Policy:ldap_get_option");
  124. }
  125. SSPIFlags |= ISC_REQ_MUTUAL_AUTH;
  126. ldaperr = ldap_set_option(
  127. pld,
  128. LDAP_OPT_SSPI_FLAGS,
  129. (VOID *) &GetDSNameFlags);
  130. if (LDAP_SUCCESS != ldaperr)
  131. {
  132. hr = myHLdapError(pld, ldaperr, NULL);
  133. if (!fRediscover)
  134. {
  135. _PrintError2(hr, "Policy:ldap_set_option", hr);
  136. fRediscover = TRUE;
  137. continue;
  138. }
  139. _JumpError(hr, error, "Policy:ldap_set_option");
  140. }
  141. }
  142. ldaperr = ldap_set_option(pld, LDAP_OPT_SIGN, LDAP_OPT_ON);
  143. if (LDAP_SUCCESS != ldaperr)
  144. {
  145. hr = myHLdapError(pld, ldaperr, NULL);
  146. if (!fRediscover)
  147. {
  148. _PrintError2(hr, "Policy:ldap_set_option", hr);
  149. fRediscover = TRUE;
  150. continue;
  151. }
  152. _JumpError(hr, error, "Policy:ldap_set_option");
  153. }
  154. if (0 == (EDITF_ENABLELDAPREFERRALS & Flags) || NULL != pwszClientDC)
  155. {
  156. ldaperr = ldap_set_option(pld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
  157. if (LDAP_SUCCESS != ldaperr)
  158. {
  159. hr = myHLdapError(pld, ldaperr, NULL);
  160. if (!fRediscover)
  161. {
  162. _PrintError2(hr, "Policy:ldap_set_option LDAP_OPT_REFERRALS", hr);
  163. fRediscover = TRUE;
  164. continue;
  165. }
  166. _JumpError(hr, error, "Policy:ldap_set_option LDAP_OPT_REFERRALS");
  167. }
  168. }
  169. ldaperr = ldap_bind_s(pld, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  170. if (LDAP_SUCCESS != ldaperr)
  171. {
  172. hr = myHLdapError(pld, ldaperr, NULL);
  173. if (!fRediscover)
  174. {
  175. _PrintError2(hr, "Policy:ldap_bind_s", hr);
  176. fRediscover = TRUE;
  177. continue;
  178. }
  179. _JumpError(hr, error, "Policy:ldap_bind_s");
  180. }
  181. hr = myLdapGetDSHostName(pld, &pwszDomainControllerName);
  182. if (S_OK != hr)
  183. {
  184. if (!fRediscover)
  185. {
  186. _PrintError2(hr, "Policy:myLdapGetDSHostName", hr);
  187. fRediscover = TRUE;
  188. continue;
  189. }
  190. _JumpError(hr, error, "Policy:myLdapGetDSHostName");
  191. }
  192. DBGPRINT((
  193. DBG_SS_CERTPOLI,
  194. "DC name = %ws\n",
  195. pwszDomainControllerName));
  196. break;
  197. }
  198. hr = S_OK;
  199. error:
  200. if (S_OK != hr)
  201. {
  202. myLdapUnbind(&pld);
  203. }
  204. *ppld = pld;
  205. return(hr);
  206. }
  207. HRESULT
  208. reqGetLdapGC(
  209. IN DWORD Flags,
  210. OUT LDAP **ppldGC,
  211. OUT BOOL *pfCached)
  212. {
  213. HRESULT hr;
  214. LDAP *pldGC;
  215. *pfCached = TRUE;
  216. myLdapUnbind(ppldGC);
  217. if (!g_fGCCacheCriticalSection || NULL == g_rgGCCache)
  218. {
  219. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  220. _JumpError(hr, error, "InitializeCriticalSection");
  221. }
  222. pldGC = NULL;
  223. EnterCriticalSection(&g_GCCacheCriticalSection);
  224. if (0 != g_cGCCacheCur)
  225. {
  226. pldGC = g_rgGCCache[--g_cGCCacheCur];
  227. }
  228. LeaveCriticalSection(&g_GCCacheCriticalSection);
  229. if (NULL == pldGC)
  230. {
  231. hr = myLdapBind(Flags, NULL, &pldGC);
  232. _JumpIfError(hr, error, "myLdapBind");
  233. *pfCached = FALSE;
  234. }
  235. *ppldGC = pldGC;
  236. hr = S_OK;
  237. error:
  238. return(hr);
  239. }
  240. VOID
  241. reqReleaseLdapGC(
  242. IN OUT LDAP **ppldGC)
  243. {
  244. LDAP *pldGC = *ppldGC;
  245. if (NULL != pldGC)
  246. {
  247. *ppldGC = NULL;
  248. EnterCriticalSection(&g_GCCacheCriticalSection);
  249. CSASSERT(0 != g_cGCCacheMax);
  250. if (g_cGCCacheCur < g_cGCCacheMax)
  251. {
  252. g_rgGCCache[g_cGCCacheCur++] = pldGC;
  253. pldGC = NULL;
  254. }
  255. LeaveCriticalSection(&g_GCCacheCriticalSection);
  256. myLdapUnbind(&pldGC);
  257. }
  258. }
  259. WCHAR *
  260. reqCombineTemplates(
  261. OPTIONAL IN WCHAR const *pwszTemplateName,
  262. OPTIONAL IN WCHAR const *pwszTemplateObjId,
  263. OPTIONAL IN WCHAR const *pwszTemplateRA)
  264. {
  265. HRESULT hr;
  266. WCHAR const *apwszTemplate[3];
  267. WCHAR const *apwszDisplayName[3];
  268. DWORD i;
  269. DWORD cwc;
  270. WCHAR *pwszList = NULL;
  271. apwszTemplate[0] = pwszTemplateName;
  272. apwszTemplate[1] = pwszTemplateObjId;
  273. apwszTemplate[2] = pwszTemplateRA;
  274. ZeroMemory(apwszDisplayName, sizeof(apwszDisplayName));
  275. cwc = 0;
  276. for (i = 0; i < ARRAYSIZE(apwszTemplate); i++)
  277. {
  278. if (NULL != apwszTemplate[i])
  279. {
  280. if (0 != cwc)
  281. {
  282. cwc++;
  283. }
  284. cwc += wcslen(apwszTemplate[i]);
  285. hr = myVerifyObjId(apwszTemplate[i]);
  286. if (S_OK == hr)
  287. {
  288. WCHAR const *pwszDisplay = NULL;
  289. pwszDisplay = myGetOIDName(apwszTemplate[i]); // Static: do not free!
  290. if (NULL != pwszDisplay && L'\0' != *pwszDisplay)
  291. {
  292. apwszDisplayName[i] = pwszDisplay;
  293. cwc += 2 + wcslen(pwszDisplay);
  294. }
  295. }
  296. }
  297. }
  298. if (0 != cwc)
  299. {
  300. pwszList = (WCHAR *) LocalAlloc(LMEM_FIXED, (1 + cwc) * sizeof(WCHAR));
  301. if (NULL == pwszList)
  302. {
  303. hr = E_OUTOFMEMORY;
  304. _JumpError(hr, error, "Policy:LocalAlloc");
  305. }
  306. pwszList[0] = L'\0';
  307. for (i = 0; i < ARRAYSIZE(apwszTemplate); i++)
  308. {
  309. if (NULL != apwszTemplate[i])
  310. {
  311. if (L'\0' != pwszList[0])
  312. {
  313. wcscat(pwszList, L"/");
  314. }
  315. wcscat(pwszList, apwszTemplate[i]);
  316. if (NULL != apwszDisplayName[i])
  317. {
  318. wcscat(pwszList, wszLPAREN);
  319. wcscat(pwszList, apwszDisplayName[i]);
  320. wcscat(pwszList, wszRPAREN);
  321. }
  322. }
  323. }
  324. CSASSERT(wcslen(pwszList) == cwc);
  325. }
  326. error:
  327. return(pwszList);
  328. }
  329. // begin_sdksample
  330. HRESULT
  331. ReqInitialize(
  332. IN ICertServerPolicy *pServer)
  333. {
  334. HRESULT hr;
  335. // end_sdksample
  336. hr = S_OK;
  337. __try
  338. {
  339. InitializeCriticalSection(&g_GCCacheCriticalSection);
  340. g_fGCCacheCriticalSection = TRUE;
  341. }
  342. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  343. {
  344. }
  345. _JumpIfError(hr, error, "InitializeCriticalSection");
  346. hr = polGetCertificateLongProperty(
  347. pServer,
  348. wszPROPSESSIONCOUNT,
  349. &g_cGCCacheMax);
  350. if (S_OK != hr)
  351. {
  352. g_cGCCacheMax = DBSESSIONCOUNTDEFAULT;
  353. }
  354. g_rgGCCache = (LDAP **) LocalAlloc(
  355. LMEM_FIXED | LMEM_ZEROINIT,
  356. g_cGCCacheMax * sizeof(g_rgGCCache[0]));
  357. if (NULL == g_rgGCCache)
  358. {
  359. hr = E_OUTOFMEMORY;
  360. _JumpError(hr, error, "Policy:LocalAlloc");
  361. }
  362. g_cGCCacheCur = 0;
  363. // begin_sdksample
  364. hr = S_OK;
  365. error: // no_sdksample
  366. return(hr);
  367. }
  368. VOID
  369. ReqCleanup()
  370. {
  371. // end_sdksample
  372. if (g_fGCCacheCriticalSection)
  373. {
  374. EnterCriticalSection(&g_GCCacheCriticalSection);
  375. if (NULL != g_rgGCCache)
  376. {
  377. while (0 != g_cGCCacheCur)
  378. {
  379. myLdapUnbind(&g_rgGCCache[--g_cGCCacheCur]);
  380. }
  381. LocalFree(g_rgGCCache);
  382. }
  383. LeaveCriticalSection(&g_GCCacheCriticalSection);
  384. DeleteCriticalSection(&g_GCCacheCriticalSection);
  385. }
  386. // begin_sdksample
  387. }
  388. CRequestInstance::~CRequestInstance()
  389. {
  390. _Cleanup();
  391. }
  392. VOID
  393. CRequestInstance::_Cleanup()
  394. {
  395. if (NULL != m_strTemplateName)
  396. {
  397. SysFreeString(m_strTemplateName);
  398. m_strTemplateName = NULL;
  399. }
  400. if (NULL != m_strTemplateObjId)
  401. {
  402. SysFreeString(m_strTemplateObjId);
  403. m_strTemplateObjId = NULL;
  404. }
  405. // end_sdksample
  406. //+--------------------------------------
  407. _ReleasePrincipalObject();
  408. if (NULL != m_hToken)
  409. {
  410. CloseHandle(m_hToken);
  411. m_hToken = NULL;
  412. }
  413. if (NULL != m_strUserDN)
  414. {
  415. SysFreeString(m_strUserDN);
  416. m_strUserDN = NULL;
  417. }
  418. if (NULL != m_pwszUPN)
  419. {
  420. LocalFree(m_pwszUPN);
  421. m_pwszUPN = NULL;
  422. }
  423. delete m_pTemplate;
  424. m_pTemplate = NULL;
  425. if (NULL != m_pCreateErrorInfo)
  426. {
  427. m_pCreateErrorInfo->Release();
  428. m_pCreateErrorInfo = NULL;
  429. }
  430. //+--------------------------------------
  431. // begin_sdksample
  432. }
  433. // end_sdksample
  434. VOID
  435. CRequestInstance::SaveErrorInfo(
  436. OPTIONAL IN ICreateErrorInfo *pCreateErrorInfo)
  437. {
  438. if (NULL != pCreateErrorInfo)
  439. {
  440. if (NULL != m_pCreateErrorInfo)
  441. {
  442. m_pCreateErrorInfo->Release();
  443. }
  444. m_pCreateErrorInfo = pCreateErrorInfo;
  445. }
  446. }
  447. HRESULT
  448. CRequestInstance::SetErrorInfo()
  449. {
  450. HRESULT hr;
  451. if (NULL != m_pCreateErrorInfo)
  452. {
  453. hr = SetModuleErrorInfo(m_pCreateErrorInfo);
  454. _JumpIfError(hr, error, "Policy:SetErrorInfo");
  455. }
  456. hr = S_OK;
  457. error:
  458. return(hr);
  459. }
  460. HRESULT
  461. CRequestInstance::BuildErrorInfo(
  462. IN HRESULT hrLog,
  463. IN DWORD dwLogId,
  464. OPTIONAL IN WCHAR const * const *ppwszInsert)
  465. {
  466. HRESULT hr;
  467. hr = polBuildErrorInfo(
  468. hrLog,
  469. dwLogId,
  470. m_pPolicy->GetPolicyDescription(),
  471. ppwszInsert,
  472. &m_pCreateErrorInfo);
  473. _JumpIfError(hr, error, "polBuildErrorInfo");
  474. error:
  475. return(hr);
  476. }
  477. // begin_sdksample
  478. static WCHAR const *s_apwszCATypes[] =
  479. {
  480. wszCERTTYPE_SUBORDINATE_CA,
  481. wszCERTTYPE_CROSS_CA,
  482. };
  483. //+--------------------------------------------------------------------------
  484. // CRequestInstance::Initialize
  485. //
  486. // Returns S_OK on success.
  487. //+--------------------------------------------------------------------------
  488. HRESULT
  489. CRequestInstance::Initialize(
  490. IN CCertPolicyEnterprise *pPolicy,
  491. IN BOOL fEnterpriseCA, // no_sdksample
  492. IN BOOL bNewRequest, // no_sdksample
  493. IN ICertServerPolicy *pServer,
  494. OUT BOOL *pfEnableEnrolleeExtensions)
  495. {
  496. HRESULT hr;
  497. HRESULT hrTemplate = S_OK;
  498. CERT_TEMPLATE_EXT *pTemplate = NULL;
  499. CERT_NAME_VALUE *pName = NULL;
  500. BSTR strTemplateObjId = NULL; // from V2 template extension
  501. BSTR strTemplateName = NULL; // from V1 template extension
  502. BSTR strTemplateRA = NULL; // from request attributes
  503. WCHAR const *pwszTemplateName;
  504. WCHAR const *pwszTemplateObjId;
  505. WCHAR const *pwszV1TemplateClass;
  506. VARIANT varValue;
  507. DWORD cbType;
  508. DWORD i;
  509. BOOL fConflict;
  510. BOOL f;
  511. BOOL fTemplateMissing;
  512. BOOL fRAObjId = FALSE;
  513. CTemplatePolicy *ptp = NULL; // no_sdksample
  514. WCHAR *pwszTemplateList = NULL; // no_sdksample
  515. VariantInit(&varValue);
  516. *pfEnableEnrolleeExtensions = TRUE
  517. && !fEnterpriseCA // no_sdksample
  518. ;
  519. m_pPolicy = pPolicy;
  520. m_fCA = FALSE;
  521. m_fNewRequest = bNewRequest; // no_sdksample
  522. // end_sdksample
  523. //+--------------------------------------
  524. m_fUser = TRUE;
  525. m_fEnterpriseCA = fEnterpriseCA;
  526. if (m_fEnterpriseCA && bNewRequest)
  527. {
  528. hr = _InitToken(pServer);
  529. _JumpIfError(hr, error, "Policy:_InitToken");
  530. }
  531. hr = _InitClientOSVersionInfo(pServer);
  532. _JumpIfError(hr, error, "Policy:_InitClientOSVersionInfo");
  533. //+--------------------------------------
  534. // begin_sdksample
  535. // Retrieve the template ObjId from the V2 cert template info extension
  536. m_dwTemplateMajorVersion = 0;
  537. m_dwTemplateMinorVersion = 0;
  538. hr = polGetCertificateExtension(
  539. pServer,
  540. TEXT(szOID_CERTIFICATE_TEMPLATE),
  541. PROPTYPE_BINARY,
  542. &varValue);
  543. _PrintIfErrorStr2(
  544. hr,
  545. "Policy:polGetCertificateExtension",
  546. TEXT(szOID_CERTIFICATE_TEMPLATE),
  547. CERTSRV_E_PROPERTY_EMPTY);
  548. if (S_OK == hr)
  549. {
  550. // There was a cert type indicator.
  551. // varValue points to an encoded string
  552. if (VT_BSTR != varValue.vt)
  553. {
  554. hr = E_INVALIDARG;
  555. _JumpError(hr, error, "Policy:varValue.vt");
  556. }
  557. if (!myDecodeObject(
  558. X509_ASN_ENCODING,
  559. X509_CERTIFICATE_TEMPLATE,
  560. (BYTE *) varValue.bstrVal,
  561. SysStringByteLen(varValue.bstrVal),
  562. CERTLIB_USE_LOCALALLOC,
  563. (VOID **) &pTemplate,
  564. &cbType))
  565. {
  566. hr = myHLastError();
  567. _JumpError(hr, error, "Policy:myDecodeObject");
  568. }
  569. if (!myConvertSzToBstr(&strTemplateObjId, pTemplate->pszObjId, -1))
  570. {
  571. hr = E_OUTOFMEMORY;
  572. _JumpError(hr, error, "Policy:myConvertSzToBstr");
  573. }
  574. m_dwTemplateMajorVersion = pTemplate->dwMajorVersion;
  575. m_dwTemplateMinorVersion = pTemplate->dwMinorVersion;
  576. DBGPRINT((
  577. DBG_SS_CERTPOL,
  578. pTemplate->fMinorVersion?
  579. "Extension Template Info: %ws V%u.%u\n" :
  580. "Extension Template Info: %ws V%u%\n",
  581. strTemplateObjId,
  582. m_dwTemplateMajorVersion,
  583. m_dwTemplateMinorVersion));
  584. }
  585. VariantClear(&varValue);
  586. // Retrieve template Name from the V1 cert template name extension
  587. hr = polGetCertificateExtension(
  588. pServer,
  589. TEXT(szOID_ENROLL_CERTTYPE_EXTENSION),
  590. PROPTYPE_BINARY,
  591. &varValue);
  592. _PrintIfErrorStr2(
  593. hr,
  594. "Policy:polGetCertificateExtension",
  595. TEXT(szOID_ENROLL_CERTTYPE_EXTENSION),
  596. CERTSRV_E_PROPERTY_EMPTY);
  597. if (S_OK == hr)
  598. {
  599. // There was a cert type indicator.
  600. // varValue points to an encoded string
  601. if (VT_BSTR != varValue.vt)
  602. {
  603. hr = E_INVALIDARG;
  604. _JumpError(hr, error, "Policy:varValue.vt");
  605. }
  606. if (!myDecodeObject(
  607. X509_ASN_ENCODING,
  608. X509_UNICODE_ANY_STRING,
  609. (BYTE *) varValue.bstrVal,
  610. SysStringByteLen(varValue.bstrVal),
  611. CERTLIB_USE_LOCALALLOC,
  612. (VOID **) &pName,
  613. &cbType))
  614. {
  615. hr = myHLastError();
  616. _JumpError(hr, error, "Policy:myDecodeObject");
  617. }
  618. strTemplateName = SysAllocString((WCHAR *) pName->Value.pbData);
  619. if (NULL == strTemplateName)
  620. {
  621. hr = E_OUTOFMEMORY;
  622. _JumpError(hr, error, "Policy:SysAllocString");
  623. }
  624. DBGPRINT((DBG_SS_CERTPOL, "Extension Template: %ws\n", strTemplateName));
  625. }
  626. fConflict = FALSE;
  627. fTemplateMissing = FALSE;
  628. // Retrieve the template from the request attributes
  629. hr = polGetRequestAttribute(pServer, wszPROPCERTTEMPLATE, &strTemplateRA);
  630. if (S_OK != hr)
  631. {
  632. _PrintErrorStr2(
  633. hr,
  634. "Policy:polGetRequestAttribute",
  635. wszPROPCERTTEMPLATE,
  636. CERTSRV_E_PROPERTY_EMPTY);
  637. hr = S_OK;
  638. // end_sdksample
  639. if (m_fEnterpriseCA &&
  640. NULL == strTemplateObjId &&
  641. NULL == strTemplateName)
  642. {
  643. hrTemplate = CERTSRV_E_NO_CERT_TYPE;
  644. _PrintError(hrTemplate, "Policy:Request contains no template name");
  645. }
  646. // begin_sdksample
  647. }
  648. else
  649. {
  650. DBGPRINT((DBG_SS_CERTPOL, "Attribute Template: %ws\n", strTemplateRA));
  651. if (NULL != strTemplateObjId &&
  652. !_TemplateNamesMatch(strTemplateObjId, strTemplateRA, &f))
  653. {
  654. fConflict = TRUE;
  655. if (f)
  656. {
  657. fTemplateMissing = TRUE;
  658. }
  659. }
  660. if (NULL != strTemplateName &&
  661. !_TemplateNamesMatch(strTemplateName, strTemplateRA, &f))
  662. {
  663. fConflict = TRUE;
  664. if (f)
  665. {
  666. fTemplateMissing = TRUE;
  667. }
  668. }
  669. hr = myVerifyObjId(strTemplateRA);
  670. fRAObjId = S_OK == hr;
  671. }
  672. if (NULL != strTemplateObjId &&
  673. NULL != strTemplateName &&
  674. !_TemplateNamesMatch(strTemplateObjId, strTemplateName, &f))
  675. {
  676. fConflict = TRUE;
  677. if (f)
  678. {
  679. fTemplateMissing = TRUE;
  680. }
  681. }
  682. if (fConflict)
  683. {
  684. hrTemplate = CERTSRV_E_TEMPLATE_CONFLICT;
  685. if (NULL != strTemplateObjId)
  686. {
  687. _PrintErrorStr(
  688. hrTemplate,
  689. "Policy:Extension Template ObjId",
  690. strTemplateObjId);
  691. }
  692. if (NULL != strTemplateName)
  693. {
  694. _PrintErrorStr(
  695. hrTemplate,
  696. "Policy:Extension Template Name",
  697. strTemplateName);
  698. }
  699. if (NULL != strTemplateRA)
  700. {
  701. _PrintErrorStr(
  702. hrTemplate,
  703. "Policy:Attribute Template",
  704. strTemplateRA);
  705. }
  706. }
  707. pwszTemplateName = strTemplateName;
  708. pwszTemplateObjId = strTemplateObjId;
  709. if (fRAObjId)
  710. {
  711. if (NULL == pwszTemplateObjId)
  712. {
  713. pwszTemplateObjId = strTemplateRA;
  714. }
  715. }
  716. else
  717. {
  718. if (NULL == pwszTemplateName)
  719. {
  720. pwszTemplateName = strTemplateRA;
  721. }
  722. }
  723. // end_sdksample
  724. if (m_fEnterpriseCA)
  725. {
  726. DWORD dwFlags;
  727. hr = m_pPolicy->FindTemplate(
  728. pwszTemplateName,
  729. pwszTemplateObjId,
  730. &ptp);
  731. if (S_OK != hr)
  732. {
  733. _PrintErrorStr(
  734. hr,
  735. "FindTemplate",
  736. NULL != pwszTemplateName? pwszTemplateName : pwszTemplateObjId);
  737. if (S_OK == hrTemplate || fTemplateMissing)
  738. {
  739. hrTemplate = hr;
  740. }
  741. }
  742. else
  743. {
  744. hr = ptp->GetFlags(CERTTYPE_GENERAL_FLAG, &dwFlags);
  745. _JumpIfError(hr, error, "Policy:GetFlags");
  746. if ((CT_FLAG_IS_CA | CT_FLAG_IS_CROSS_CA) & dwFlags)
  747. {
  748. m_fCA = TRUE;
  749. }
  750. hr = ptp->GetFlags(CERTTYPE_ENROLLMENT_FLAG, &dwFlags);
  751. _JumpIfError(hr, error, "Policy:GetFlags");
  752. hr = _SetFlagsProperty(
  753. pServer,
  754. wszPROPCERTIFICATEENROLLMENTFLAGS,
  755. dwFlags);
  756. _JumpIfError(hr, error, "Policy:_SetFlagsProperty");
  757. hr = ptp->GetFlags(CERTTYPE_GENERAL_FLAG, &dwFlags);
  758. _JumpIfError(hr, error, "Policy:GetFlags");
  759. hr = _SetFlagsProperty(
  760. pServer,
  761. wszPROPCERTIFICATEGENERALFLAGS,
  762. dwFlags);
  763. _JumpIfError(hr, error, "Policy:_SetFlagsProperty");
  764. if (CT_FLAG_MACHINE_TYPE & dwFlags)
  765. {
  766. m_fUser = FALSE;
  767. }
  768. pwszTemplateName = ptp->GetTemplateName();
  769. pwszTemplateObjId = ptp->GetTemplateObjId();
  770. }
  771. }
  772. else
  773. // begin_sdksample
  774. {
  775. if (NULL != pwszTemplateName)
  776. {
  777. for (i = 0; i < ARRAYSIZE(s_apwszCATypes); i++)
  778. {
  779. if (0 == mylstrcmpiL(s_apwszCATypes[i], pwszTemplateName))
  780. {
  781. m_fCA = TRUE;
  782. break;
  783. }
  784. }
  785. }
  786. }
  787. hr = SetTemplateName(pServer, pwszTemplateName, pwszTemplateObjId);
  788. _JumpIfError(hr, error, "Policy:SetTemplateName");
  789. pwszV1TemplateClass = pwszTemplateName;
  790. // end_sdksample
  791. if (NULL != ptp)
  792. {
  793. DWORD dwSubjectNameFlags;
  794. // on resubmitted requests we don't have the requester's token
  795. if (bNewRequest)
  796. {
  797. CSASSERT(NULL != m_hToken);
  798. hr = ptp->AccessCheck(m_hToken);
  799. _JumpIfError(hr, error, "Policy:AccessCheck");
  800. }
  801. hr = ptp->GetV1TemplateClass(&pwszV1TemplateClass);
  802. _JumpIfError(hr, error, "AddTemplateNameExtension");
  803. hr = ptp->GetFlags(CERTTYPE_SUBJECT_NAME_FLAG, &dwSubjectNameFlags);
  804. _JumpIfError(hr, error, "GetFlags");
  805. if (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT & dwSubjectNameFlags)
  806. {
  807. *pfEnableEnrolleeExtensions = TRUE;
  808. }
  809. hr = ptp->Clone(&m_pTemplate);
  810. _JumpIfError(hr, error, "Clone");
  811. }
  812. // begin_sdksample
  813. hr = pPolicy->AddV1TemplateNameExtension(pServer, pwszV1TemplateClass);
  814. _JumpIfError(hr, error, "AddTemplateNameExtension");
  815. error:
  816. if (S_OK != hrTemplate)
  817. {
  818. hr = hrTemplate; // override secondary errors
  819. // end_sdksample
  820. WCHAR const *apwsz[2];
  821. DWORD cpwsz = 0;
  822. DWORD LogMsg;
  823. switch (hrTemplate)
  824. {
  825. default:
  826. case CERTSRV_E_NO_CERT_TYPE:
  827. LogMsg = MSG_MISSING_CERT_TYPE;
  828. apwsz[cpwsz++] = wszPROPCERTTEMPLATE;
  829. break;
  830. // The request specifies conflicting certificate templates: %1.
  831. case CERTSRV_E_TEMPLATE_CONFLICT:
  832. LogMsg = MSG_CONFLICTING_CERT_TYPE;
  833. break;
  834. // The request was for a certificate template that is not
  835. // supported by the Certificate Services policy: %1.
  836. case CERTSRV_E_UNSUPPORTED_CERT_TYPE:
  837. LogMsg = MSG_UNSUPPORTED_CERT_TYPE;
  838. break;
  839. }
  840. if (0 == cpwsz)
  841. {
  842. WCHAR const *pwsz;
  843. pwszTemplateList = reqCombineTemplates(
  844. strTemplateName,
  845. strTemplateObjId,
  846. strTemplateRA);
  847. pwsz = pwszTemplateList;
  848. if (NULL == pwsz)
  849. {
  850. pwsz = strTemplateName;
  851. if (NULL == pwsz)
  852. {
  853. pwsz = strTemplateObjId;
  854. if (NULL == pwsz)
  855. {
  856. pwsz = strTemplateRA;
  857. if (NULL == pwsz)
  858. {
  859. pwsz = L"???";
  860. }
  861. }
  862. }
  863. }
  864. apwsz[cpwsz++] = pwsz;
  865. }
  866. CSASSERT(ARRAYSIZE(apwsz) > cpwsz);
  867. apwsz[cpwsz] = NULL;
  868. BuildErrorInfo(hr, LogMsg, apwsz);
  869. // begin_sdksample
  870. }
  871. VariantClear(&varValue);
  872. // end_sdksample
  873. if (NULL != pwszTemplateList)
  874. {
  875. LocalFree(pwszTemplateList);
  876. }
  877. // begin_sdksample
  878. if (NULL != pName)
  879. {
  880. LocalFree(pName);
  881. }
  882. if (NULL != pTemplate)
  883. {
  884. LocalFree(pTemplate);
  885. }
  886. if (NULL != strTemplateObjId)
  887. {
  888. SysFreeString(strTemplateObjId);
  889. }
  890. if (NULL != strTemplateName)
  891. {
  892. SysFreeString(strTemplateName);
  893. }
  894. if (NULL != strTemplateRA)
  895. {
  896. SysFreeString(strTemplateRA);
  897. }
  898. return(hr);
  899. }
  900. // end_sdksample
  901. //+--------------------------------------------------------------------------
  902. // CRequestInstance::ApplyTemplate
  903. //
  904. // Returns S_OK on success.
  905. //+--------------------------------------------------------------------------
  906. HRESULT
  907. CRequestInstance::ApplyTemplate(
  908. IN ICertServerPolicy *pServer,
  909. OUT BOOL *pfReenroll,
  910. OUT DWORD *pdwEnrollmentFlags,
  911. OUT DWORD *pcCriticalExtensions,
  912. OUT WCHAR const * const **papwszCriticalExtensions)
  913. {
  914. HRESULT hr;
  915. *pdwEnrollmentFlags = 0;
  916. *pfReenroll = FALSE;
  917. *pcCriticalExtensions = 0;
  918. *papwszCriticalExtensions = NULL;
  919. if (NULL == m_pTemplate)
  920. {
  921. hr = CERTSRV_E_UNSUPPORTED_CERT_TYPE;
  922. _JumpErrorStr(
  923. hr,
  924. error,
  925. "Policy:ApplyTemplate:no cert template",
  926. m_strTemplateName);
  927. }
  928. hr = m_pTemplate->Apply(pServer, this, pfReenroll);
  929. _JumpIfError(hr, error, "Apply");
  930. hr = m_pTemplate->GetFlags(CERTTYPE_ENROLLMENT_FLAG, pdwEnrollmentFlags);
  931. _JumpIfError(hr, error, "GetFlags");
  932. hr = m_pTemplate->GetCriticalExtensions(
  933. pcCriticalExtensions,
  934. papwszCriticalExtensions);
  935. _JumpIfError(hr, error, "GetCriticalExtension");
  936. error:
  937. DBGPRINT((DBG_SS_CERTPOLI, "Policy:_ApplyTemplate: %x\n", hr));
  938. return(hr);
  939. }
  940. // begin_sdksample
  941. BOOL
  942. CRequestInstance::_TemplateNamesMatch(
  943. IN WCHAR const *pwszTemplateName1,
  944. IN WCHAR const *pwszTemplateName2,
  945. OUT BOOL *pfTemplateMissing)
  946. {
  947. HRESULT hr1;
  948. HRESULT hr2;
  949. BOOL fMatch = TRUE;
  950. *pfTemplateMissing = FALSE;
  951. if (0 == mylstrcmpiL(pwszTemplateName1, pwszTemplateName2))
  952. {
  953. goto done; // identical names
  954. }
  955. // end_sdksample
  956. if (m_fEnterpriseCA)
  957. {
  958. CTemplatePolicy *pTemplate1;
  959. CTemplatePolicy *pTemplate2;
  960. hr1 = m_pPolicy->FindTemplate(pwszTemplateName1, NULL, &pTemplate1);
  961. hr2 = m_pPolicy->FindTemplate(pwszTemplateName2, NULL, &pTemplate2);
  962. if (S_OK == hr1 && S_OK == hr2)
  963. {
  964. if (pTemplate1 == pTemplate2)
  965. {
  966. goto done;
  967. }
  968. }
  969. else
  970. {
  971. *pfTemplateMissing = TRUE;
  972. }
  973. }
  974. else
  975. // begin_sdksample
  976. {
  977. hr1 = myVerifyObjId(pwszTemplateName1);
  978. hr2 = myVerifyObjId(pwszTemplateName2);
  979. if ((S_OK == hr1) ^ (S_OK == hr2))
  980. {
  981. goto done;
  982. }
  983. }
  984. fMatch = FALSE;
  985. done:
  986. return(fMatch);
  987. }
  988. //+--------------------------------------------------------------------------
  989. // CRequestInstance::SetTemplateName
  990. //
  991. // Returns S_OK on success.
  992. //+--------------------------------------------------------------------------
  993. HRESULT
  994. CRequestInstance::SetTemplateName(
  995. IN ICertServerPolicy *pServer,
  996. IN OPTIONAL WCHAR const *pwszTemplateName,
  997. IN OPTIONAL WCHAR const *pwszTemplateObjId)
  998. {
  999. HRESULT hr;
  1000. BSTR strProp = NULL;
  1001. BSTR strTemplateName = NULL;
  1002. if (NULL != pwszTemplateName)
  1003. {
  1004. m_strTemplateName = SysAllocString(pwszTemplateName);
  1005. if (NULL == m_strTemplateName)
  1006. {
  1007. hr = E_OUTOFMEMORY;
  1008. _JumpError(hr, error, "Policy:SysAllocString");
  1009. }
  1010. strTemplateName = m_strTemplateName;
  1011. }
  1012. if (NULL != pwszTemplateObjId)
  1013. {
  1014. m_strTemplateObjId = SysAllocString(pwszTemplateObjId);
  1015. if (NULL == m_strTemplateObjId)
  1016. {
  1017. hr = E_OUTOFMEMORY;
  1018. _JumpError(hr, error, "Policy:SysAllocString");
  1019. }
  1020. strTemplateName = m_strTemplateObjId;
  1021. }
  1022. if (NULL != strTemplateName)
  1023. {
  1024. VARIANT var;
  1025. strProp = SysAllocString(wszPROPCERTIFICATETEMPLATE);
  1026. if (NULL == strProp)
  1027. {
  1028. hr = E_OUTOFMEMORY;
  1029. _JumpError(hr, error, "Policy:SysAllocString");
  1030. }
  1031. var.vt = VT_BSTR;
  1032. var.bstrVal = strTemplateName;
  1033. hr = pServer->SetCertificateProperty(strProp, PROPTYPE_STRING, &var);
  1034. _JumpIfError(hr, error, "Policy:SetCertificateProperty");
  1035. }
  1036. hr = S_OK;
  1037. error:
  1038. if (NULL != strProp)
  1039. {
  1040. SysFreeString(strProp);
  1041. }
  1042. return(hr);
  1043. }
  1044. // end_sdksample
  1045. HRESULT
  1046. CRequestInstance::_SetFlagsProperty(
  1047. IN ICertServerPolicy *pServer,
  1048. IN WCHAR const *pwszPropName,
  1049. IN DWORD dwFlags)
  1050. {
  1051. HRESULT hr;
  1052. BSTR strPropName = NULL;
  1053. VARIANT var;
  1054. strPropName = SysAllocString(pwszPropName);
  1055. if (NULL == strPropName)
  1056. {
  1057. hr = E_OUTOFMEMORY;
  1058. _JumpError(hr, error, "Policy:SysAllocString");
  1059. }
  1060. var.vt = VT_I4;
  1061. var.lVal = dwFlags;
  1062. hr = pServer->SetCertificateProperty(strPropName, PROPTYPE_LONG, &var);
  1063. _JumpIfError(hr, error, "Policy:SetCertificateProperty");
  1064. error:
  1065. if (NULL != strPropName)
  1066. {
  1067. SysFreeString(strPropName);
  1068. }
  1069. return(hr);
  1070. }
  1071. VOID
  1072. CRequestInstance::GetTemplateVersion(
  1073. OUT DWORD *pdwTemplateMajorVersion,
  1074. OUT DWORD *pdwTemplateMinorVersion)
  1075. {
  1076. *pdwTemplateMajorVersion = m_dwTemplateMajorVersion;
  1077. *pdwTemplateMinorVersion = m_dwTemplateMinorVersion;
  1078. }
  1079. //+--------------------------------------------------------------------------
  1080. // CRequestInstance::_InitToken
  1081. //
  1082. // Returns S_OK on success.
  1083. //+--------------------------------------------------------------------------
  1084. HRESULT
  1085. CRequestInstance::_InitToken(
  1086. IN ICertServerPolicy *pServer)
  1087. {
  1088. HRESULT hr;
  1089. VARIANT varValue;
  1090. HANDLE hToken;
  1091. VariantInit(&varValue);
  1092. hr = polGetProperty(
  1093. pServer,
  1094. FALSE, // fRequest
  1095. wszPROPREQUESTERTOKEN,
  1096. PROPTYPE_BINARY,
  1097. &varValue);
  1098. if(CERTSRV_E_PROPERTY_EMPTY == hr)
  1099. {
  1100. _PrintIfError(hr, "polGetProperty(PROPREQUESTERTOKEN)");
  1101. hr = S_OK;
  1102. }
  1103. _JumpIfError(hr, error, "polGetProperty(PROPREQUESTERTOKEN)");
  1104. // Got a token value
  1105. if (sizeof(hToken) != SysStringByteLen(varValue.bstrVal) ||
  1106. NULL == *(HANDLE *) varValue.bstrVal)
  1107. {
  1108. hr = E_HANDLE;
  1109. BuildErrorInfo(hr, MSG_NO_REQUESTER_TOKEN, NULL);
  1110. _JumpError(hr, error, "Policy:Token/Length");
  1111. }
  1112. hToken = *(HANDLE *) varValue.bstrVal;
  1113. if (!DuplicateToken(hToken, SecurityIdentification, &m_hToken))
  1114. {
  1115. hr = myHLastError();
  1116. BuildErrorInfo(hr, MSG_NO_REQUESTER_TOKEN, NULL);
  1117. _JumpError(hr, error, "Policy:DuplicateToken");
  1118. }
  1119. hr = S_OK;
  1120. error:
  1121. VariantClear(&varValue);
  1122. return(hr);
  1123. }
  1124. //+--------------------------------------------------------------------------
  1125. // CRequestInstance::_InitClientOSVersionInfo
  1126. //
  1127. // Returns S_OK on success.
  1128. //+--------------------------------------------------------------------------
  1129. HRESULT
  1130. CRequestInstance::_InitClientOSVersionInfo(
  1131. IN ICertServerPolicy *pServer)
  1132. {
  1133. HRESULT hr;
  1134. VARIANT varValue;
  1135. DWORD dwFormat = 0;
  1136. LONG l;
  1137. BSTR strVersionInfo = NULL;
  1138. BSTR strCSPProvider = NULL;
  1139. VariantInit(&varValue);
  1140. // In the following code, we also attempt to determine if the
  1141. // request came from an xenroll.dll, so we know whether to put
  1142. // the UPN in the subject name. We put the UPN in the subject name
  1143. // for old xenroll requests, as we know that autoenrollment on those
  1144. // machines will need it to prevent enrollment loops.
  1145. // Get the optional OS version information. Ignore failure.
  1146. hr = polGetRequestAttribute(pServer, wszPROPREQUESTOSVERSION, &strVersionInfo);
  1147. if (S_OK == hr && NULL != strVersionInfo)
  1148. {
  1149. DWORD dwMajor, dwMinor, dwBuild, dwPlatform;
  1150. if (4 == swscanf(
  1151. strVersionInfo,
  1152. L"%d.%d.%d.%d",
  1153. &dwMajor,
  1154. &dwMinor,
  1155. &dwBuild,
  1156. &dwPlatform))
  1157. {
  1158. m_RequestOsVersion.dwMajorVersion = dwMajor;
  1159. m_RequestOsVersion.dwMinorVersion = dwMinor;
  1160. m_RequestOsVersion.dwBuildNumber = dwBuild;
  1161. m_RequestOsVersion.dwPlatformId = dwPlatform;
  1162. }
  1163. // We know this is an xenroll request,
  1164. // as it has a OSVERSIONINFO property
  1165. m_fIsXenrollRequest = TRUE;
  1166. m_fClientVersionSpecified = TRUE;
  1167. }
  1168. hr = polGetRequestLongProperty(pServer, wszPROPREQUESTTYPE, &l);
  1169. if (S_OK == hr)
  1170. {
  1171. dwFormat = CR_IN_FORMATMASK & l;
  1172. }
  1173. if (dwFormat == CR_IN_KEYGEN)
  1174. {
  1175. // KEYGEN requests only come from netscape, not xenroll,
  1176. // so we know it's not an xenroll request.
  1177. m_fIsXenrollRequest = FALSE;
  1178. }
  1179. else if (!m_fIsXenrollRequest)
  1180. {
  1181. hr = polGetRequestAttribute(
  1182. pServer,
  1183. wszPROPREQUESTCSPPROVIDER,
  1184. &strCSPProvider);
  1185. if (S_OK == hr && NULL != strCSPProvider)
  1186. {
  1187. // xenroll includes a CSPPROVIDER attribute
  1188. m_fIsXenrollRequest = TRUE;
  1189. }
  1190. }
  1191. hr = S_OK;
  1192. //error:
  1193. if (NULL != strVersionInfo)
  1194. {
  1195. SysFreeString(strVersionInfo);
  1196. }
  1197. if (NULL != strCSPProvider)
  1198. {
  1199. SysFreeString(strCSPProvider);
  1200. }
  1201. VariantClear(&varValue);
  1202. return(hr);
  1203. }
  1204. //+--------------------------------------------------------------------------
  1205. // CRequestInstance::_LoadPrincipalObject
  1206. //
  1207. // Returns S_OK on success.
  1208. //+--------------------------------------------------------------------------
  1209. HRESULT
  1210. CRequestInstance::_LoadPrincipalObject(
  1211. IN ICertServerPolicy *pServer,
  1212. IN CTemplatePolicy *pTemplate,
  1213. IN BOOL fDNSNameRequired)
  1214. {
  1215. HRESULT hr;
  1216. BSTR strProp = NULL;
  1217. LPWSTR *awszUPN = NULL;
  1218. BSTR strSamName = NULL;
  1219. BSTR strClientDC = NULL;
  1220. WCHAR *pwszUserName;
  1221. DWORD dwFlags;
  1222. VARIANT var;
  1223. VariantInit(&var);
  1224. // Get the name of the user or machine
  1225. hr = polGetRequestStringProperty(
  1226. pServer,
  1227. wszPROPREQUESTERNAME,
  1228. &strSamName);
  1229. _JumpIfErrorStr(
  1230. hr,
  1231. error,
  1232. "Policy:polGetRequestStringProperty",
  1233. wszPROPREQUESTERNAME);
  1234. if (L'\0' == *strSamName)
  1235. {
  1236. // can't have a zero length name
  1237. hr = E_ACCESSDENIED;
  1238. _JumpError(hr, error, "Policy:zero length name");
  1239. }
  1240. // See if there's a domain, as well
  1241. pwszUserName = wcschr(strSamName, L'\\');
  1242. if (NULL == pwszUserName)
  1243. {
  1244. WCHAR wszDN[MAX_PATH];
  1245. DWORD cwc = ARRAYSIZE(wszDN);
  1246. // No domain portion, so assume part of the current domain.
  1247. if (GetUserNameEx(NameSamCompatible, wszDN, &cwc))
  1248. {
  1249. pwszUserName = wcschr(wszDN, L'\\');
  1250. if (NULL != pwszUserName)
  1251. {
  1252. BSTR strT;
  1253. DWORD cwcT;
  1254. pwszUserName[1] = L'\0';
  1255. cwcT = wcslen(wszDN) + wcslen(strSamName);
  1256. strT = SysAllocStringLen(NULL, cwcT);
  1257. if (NULL == strT)
  1258. {
  1259. hr = E_OUTOFMEMORY;
  1260. _JumpError(hr, error, "Policy:SysAllocString");
  1261. }
  1262. wcscpy(strT, wszDN);
  1263. wcscat(strT, strSamName);
  1264. CSASSERT(wcslen(strT) == cwcT);
  1265. CSASSERT(SysStringLen(strT) == cwcT);
  1266. SysFreeString(strSamName);
  1267. strSamName = strT;
  1268. }
  1269. }
  1270. }
  1271. pwszUserName = wcschr(strSamName, L'\\');
  1272. if (NULL == pwszUserName)
  1273. {
  1274. pwszUserName = strSamName;
  1275. }
  1276. else
  1277. {
  1278. pwszUserName++;
  1279. }
  1280. DBGPRINT((DBG_SS_CERTPOL, "pwszUserName = %ws\n", pwszUserName));
  1281. DBGPRINT((DBG_SS_CERTPOL, "strSamName = %ws\n", strSamName));
  1282. // If the user name ends in $, it's a hint that this is a machine account.
  1283. if (pwszUserName[wcslen(pwszUserName) - 1] == L'$')
  1284. {
  1285. if (m_fUser)
  1286. {
  1287. DBGPRINT((
  1288. DBG_SS_CERTPOL,
  1289. "USER TEMPLATE w/ '$': %ws\n",
  1290. pwszUserName));
  1291. }
  1292. }
  1293. else
  1294. {
  1295. if (!m_fUser)
  1296. {
  1297. DBGPRINT((
  1298. DBG_SS_CERTPOL,
  1299. "MACHINE TEMPLATE w/o '$': %ws\n",
  1300. pwszUserName));
  1301. }
  1302. }
  1303. hr = polGetCertificateStringProperty(pServer, wszPROPUSERDN, &m_strUserDN);
  1304. _JumpIfErrorStr(
  1305. hr,
  1306. error,
  1307. "Policy:polGetCertificateStringProperty",
  1308. wszPROPUSERDN);
  1309. hr = _GetDSObject(pServer, fDNSNameRequired, NULL);
  1310. // If we couldn't find the DS object or the DNS name is missing or out of
  1311. // date, it is a machine object and the client specified his DC name, chase
  1312. // the client supplied DC in hopes of finding more current information.
  1313. if ((CERTSRV_E_SUBJECT_DNS_REQUIRED == hr ||
  1314. HRESULT_FROM_WIN32(DNS_ERROR_NAME_DOES_NOT_EXIST) == hr ||
  1315. (HRESULT) ERROR_DS_OBJ_NOT_FOUND == hr ||
  1316. HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND) == hr) &&
  1317. fDNSNameRequired &&
  1318. (EDITF_ENABLECHASECLIENTDC & m_pPolicy->GetEditFlags()) &&
  1319. !m_fUser)
  1320. {
  1321. HRESULT hr2;
  1322. _PrintError(hr, "_GetDSObject");
  1323. hr2 = polGetRequestAttribute(pServer, wszPROPCLIENTDCDNS, &strClientDC);
  1324. _PrintIfErrorStr(
  1325. hr2,
  1326. "Policy:polGetRequestAttribute",
  1327. wszPROPCLIENTDCDNS);
  1328. if (S_OK == hr2 && NULL != strClientDC)
  1329. {
  1330. _PrintErrorStr(hr, "_GetDSObject", strClientDC);
  1331. hr = _GetDSObject(pServer, TRUE, strClientDC);
  1332. _JumpIfErrorStr(hr, error, "_GetDSObject", strClientDC);
  1333. }
  1334. }
  1335. _JumpIfError(hr, error, "_GetDSObject");
  1336. hr = pTemplate->GetFlags(CERTTYPE_GENERAL_FLAG, &dwFlags);
  1337. _JumpIfError(hr, error, "Policy:GetFlags");
  1338. if (!m_fUser ^ (0 != (CT_FLAG_MACHINE_TYPE & dwFlags)))
  1339. {
  1340. // if m_fUser state no longer agrees with the template machine flag,
  1341. // toggle the flag and store the corrected value in the database.
  1342. dwFlags ^= CT_FLAG_MACHINE_TYPE;
  1343. hr = _SetFlagsProperty(
  1344. pServer,
  1345. wszPROPCERTIFICATEGENERALFLAGS,
  1346. dwFlags);
  1347. _JumpIfError(hr, error, "Policy:_SetFlagsProperty");
  1348. }
  1349. // Build the UPN value.
  1350. // If a machine, the UPN must be the DNS name.
  1351. hr = _GetValues(m_fUser? DS_ATTR_UPN : DS_ATTR_DNS_NAME, &awszUPN);
  1352. if (S_OK == hr && NULL != awszUPN && NULL != awszUPN[0])
  1353. {
  1354. hr = myDupString(awszUPN[0], &m_pwszUPN);
  1355. _JumpIfError(hr, error, "myDupString");
  1356. }
  1357. else
  1358. {
  1359. if (m_fUser)
  1360. {
  1361. WCHAR **awszExplodedDN;
  1362. WCHAR **ppwszCurrent;
  1363. DWORD cwcT;
  1364. // Build a UPN from the username -- without the SAM domain.
  1365. // Get a buffer that will be big enough.
  1366. cwcT = wcslen(pwszUserName) + 1 + wcslen(m_strUserDN);
  1367. m_pwszUPN = (WCHAR *) LocalAlloc(
  1368. LMEM_FIXED,
  1369. (1 + cwcT) * sizeof(WCHAR));
  1370. if (NULL == m_pwszUPN)
  1371. {
  1372. hr = E_OUTOFMEMORY;
  1373. _JumpError(hr, error, "Policy:LocalAlloc");
  1374. }
  1375. wcscpy(m_pwszUPN, pwszUserName);
  1376. awszExplodedDN = ldap_explode_dn(m_strUserDN, 0);
  1377. if (NULL != awszExplodedDN)
  1378. {
  1379. wcscat(m_pwszUPN, L"@");
  1380. for (ppwszCurrent = awszExplodedDN;
  1381. NULL != *ppwszCurrent;
  1382. ppwszCurrent++)
  1383. {
  1384. WCHAR wszDC[4];
  1385. wcsncpy(wszDC, *ppwszCurrent, ARRAYSIZE(wszDC) - 1);
  1386. wszDC[ARRAYSIZE(wszDC) - 1] = L'\0';
  1387. if (0 == LSTRCMPIS(wszDC, L"DC="))
  1388. {
  1389. wcscat(
  1390. m_pwszUPN,
  1391. (*ppwszCurrent) + ARRAYSIZE(wszDC) - 1);
  1392. wcscat(m_pwszUPN, L".");
  1393. CSASSERT(wcslen(m_pwszUPN) < cwcT);
  1394. }
  1395. }
  1396. // remove the trailing '.' or "@" if there was no DC=
  1397. m_pwszUPN[wcslen(m_pwszUPN) - 1] = L'\0';
  1398. // We're done referencing awszExplodedDN, so free it.
  1399. // ldap_value_free frees the ldap_explode_dn return value
  1400. ldap_value_free(awszExplodedDN);
  1401. }
  1402. }
  1403. else
  1404. {
  1405. if (CERTSRV_E_PROPERTY_EMPTY == hr || S_OK == hr)
  1406. {
  1407. hr = CERTSRV_E_SUBJECT_DNS_REQUIRED;
  1408. }
  1409. BuildErrorInfo(hr, MSG_NO_DNS_NAME, &m_strUserDN);
  1410. _JumpErrorStr(hr, error, "No DNS Name", m_strUserDN);
  1411. }
  1412. }
  1413. DBGPRINT((DBG_SS_CERTPOL, "m_pwszUPN = %ws\n", m_pwszUPN));
  1414. strProp = SysAllocString(wszPROPCERTIFICATEUPN);
  1415. if (NULL == strProp)
  1416. {
  1417. hr = E_OUTOFMEMORY;
  1418. _JumpError(hr, error, "Policy:SysAllocString");
  1419. }
  1420. var.bstrVal = NULL;
  1421. if (!myConvertWszToBstr(&var.bstrVal, m_pwszUPN, -1))
  1422. {
  1423. hr = E_OUTOFMEMORY;
  1424. _JumpError(hr, error, "Policy:myConvertWszToBstr");
  1425. }
  1426. var.vt = VT_BSTR;
  1427. hr = pServer->SetCertificateProperty(strProp, PROPTYPE_STRING, &var);
  1428. _JumpIfError(hr, error, "Policy:SetCertificateProperty");
  1429. error:
  1430. if (NULL != strClientDC)
  1431. {
  1432. SysFreeString(strClientDC);
  1433. }
  1434. if (NULL != strSamName)
  1435. {
  1436. SysFreeString(strSamName);
  1437. }
  1438. if (NULL != awszUPN)
  1439. {
  1440. _FreeValues(awszUPN);
  1441. }
  1442. if (NULL != strProp)
  1443. {
  1444. SysFreeString(strProp);
  1445. }
  1446. VariantClear(&var);
  1447. return(hr);
  1448. }
  1449. VOID
  1450. CRequestInstance::_ReleasePrincipalObject()
  1451. {
  1452. if (NULL != m_pldGC)
  1453. {
  1454. if (NULL != m_SearchResult)
  1455. {
  1456. ldap_msgfree(m_SearchResult);
  1457. m_SearchResult = NULL;
  1458. }
  1459. reqReleaseLdapGC(&m_pldGC);
  1460. myLdapUnbind(&m_pldClientDC);
  1461. }
  1462. }
  1463. #define wszHOSTPREFIX L"HOST/"
  1464. #define DS_ATTR_SPN L"servicePrincipalName"
  1465. #define DS_ATTR_BACKLINK L"serverReferenceBL"
  1466. #define wszSEARCHUSER L"(objectCategory=user)"
  1467. #define wszSEARCHCOMPUTER L"(objectCategory=computer)"
  1468. #define wszSEARCHNTDSDSA L"(objectCategory=nTDSDSA)"
  1469. #define wszSEARCHUSERCOMPUTER L"(|" wszSEARCHUSER wszSEARCHCOMPUTER L")"
  1470. #define wszSEARCHSPN L"(" DS_ATTR_SPN L"=" wszHOSTPREFIX L"%ws)"
  1471. #define wszSEARCHCOMPUTERSPN L"(&" wszSEARCHCOMPUTER wszSEARCHSPN L")"
  1472. #define wszDSOBJECTCATEGORYATTRIBUTE L"objectCategory"
  1473. WCHAR *s_apwszAttrsClientDC[] = {
  1474. DS_ATTR_DNS_NAME,
  1475. DS_ATTR_SPN,
  1476. DS_ATTR_BACKLINK,
  1477. NULL,
  1478. };
  1479. // Use the ldap GC handle to verify the client-supplied DC DNS name is a valid
  1480. // DC in our forest. If it is, bind to the client supplied DC.
  1481. HRESULT
  1482. reqFindClientDC(
  1483. IN LDAP *pldGC,
  1484. IN WCHAR const *pwszClientDC,
  1485. OUT LDAP **ppldClientDC)
  1486. {
  1487. HRESULT hr;
  1488. ULONG ldaperr;
  1489. struct l_timeval timeout;
  1490. WCHAR *pwszSearch = NULL;
  1491. DWORD cwc;
  1492. WCHAR *pwszError = NULL;
  1493. LDAPMessage *pSearchResult = NULL;
  1494. LDAPMessage *pEntry = NULL;
  1495. WCHAR **ppwszValues = NULL;
  1496. WCHAR *pwszServiceDN = NULL;
  1497. myLdapUnbind(ppldClientDC);
  1498. cwc = WSZARRAYSIZE(wszSEARCHCOMPUTERSPN) + wcslen(pwszClientDC);
  1499. pwszSearch = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
  1500. if (NULL == pwszSearch)
  1501. {
  1502. hr = E_OUTOFMEMORY;
  1503. _JumpError(hr, error, "SysAllocStringByteLen");
  1504. }
  1505. wsprintf(pwszSearch, wszSEARCHCOMPUTERSPN, pwszClientDC);
  1506. CSASSERT(wcslen(pwszSearch) <= cwc);
  1507. timeout.tv_sec = csecLDAPTIMEOUT;
  1508. timeout.tv_usec = 0;
  1509. // ldap_search the GC for a Computer object with matching SPN.
  1510. // Fetch the service object back link attribute from the Computer object.
  1511. // Make sure the service object has a child object of class NTDSDSA
  1512. ldaperr = ldap_search_ext_s(
  1513. pldGC,
  1514. NULL,
  1515. LDAP_SCOPE_SUBTREE,
  1516. pwszSearch,
  1517. s_apwszAttrsClientDC,
  1518. 0,
  1519. NULL,
  1520. NULL,
  1521. &timeout,
  1522. 10000,
  1523. &pSearchResult);
  1524. if (LDAP_SUCCESS != ldaperr)
  1525. {
  1526. hr = myHLdapError(pldGC, ldaperr, &pwszError);
  1527. _PrintErrorStr(hr, "Policy:ldap_search_ext_s", pwszError);
  1528. _JumpErrorStr(hr, error, "Policy:ldap_search_ext_s", pwszSearch);
  1529. }
  1530. if (0 == ldap_count_entries(pldGC, pSearchResult))
  1531. {
  1532. hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);
  1533. _JumpError(hr, error, "Policy:ldap_count_entries");
  1534. }
  1535. pEntry = ldap_first_entry(pldGC, pSearchResult);
  1536. if (NULL == pEntry)
  1537. {
  1538. hr = myHLdapLastError(pldGC, NULL);
  1539. _JumpError(hr, error, "Policy:ldap_first_entry");
  1540. }
  1541. ppwszValues = ldap_get_values(pldGC, pEntry, DS_ATTR_BACKLINK);
  1542. if (NULL == ppwszValues || NULL == ppwszValues[0])
  1543. {
  1544. hr = CERTSRV_E_PROPERTY_EMPTY;
  1545. _JumpErrorStr(hr, error, "Policy:ldap_get_values", DS_ATTR_BACKLINK);
  1546. }
  1547. hr = myDupString(ppwszValues[0], &pwszServiceDN);
  1548. _JumpIfError(hr, error, "myDupString");
  1549. if (NULL != ppwszValues)
  1550. {
  1551. ldap_value_free(ppwszValues);
  1552. ppwszValues = NULL;
  1553. }
  1554. if (NULL != pSearchResult)
  1555. {
  1556. ldap_msgfree(pSearchResult);
  1557. pSearchResult = NULL;
  1558. }
  1559. if (NULL != pwszError)
  1560. {
  1561. LocalFree(pwszError);
  1562. pwszError = NULL;
  1563. }
  1564. // ldap_search the GC for a child of the Service object with class NTDSDSA.
  1565. ldaperr = ldap_search_ext_s(
  1566. pldGC,
  1567. pwszServiceDN,
  1568. LDAP_SCOPE_ONELEVEL,
  1569. wszSEARCHNTDSDSA,
  1570. NULL,
  1571. 0,
  1572. NULL,
  1573. NULL,
  1574. &timeout,
  1575. 10000,
  1576. &pSearchResult);
  1577. if (LDAP_SUCCESS != ldaperr)
  1578. {
  1579. hr = myHLdapError(pldGC, ldaperr, &pwszError);
  1580. _PrintErrorStr(hr, "Policy:ldap_search_ext_s", pwszError);
  1581. _JumpErrorStr(hr, error, "Policy:ldap_search_ext_s", pwszServiceDN);
  1582. }
  1583. if (0 == ldap_count_entries(pldGC, pSearchResult))
  1584. {
  1585. hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);
  1586. _JumpError(hr, error, "Policy:ldap_count_entries");
  1587. }
  1588. hr = myLdapBind(0, pwszClientDC, ppldClientDC);
  1589. _JumpIfError(hr, error, "myLdapBind");
  1590. error:
  1591. if (NULL != ppwszValues)
  1592. {
  1593. ldap_value_free(ppwszValues);
  1594. }
  1595. if (NULL != pSearchResult)
  1596. {
  1597. ldap_msgfree(pSearchResult);
  1598. }
  1599. if (NULL != pwszError)
  1600. {
  1601. LocalFree(pwszError);
  1602. }
  1603. if (NULL != pwszServiceDN)
  1604. {
  1605. LocalFree(pwszServiceDN);
  1606. }
  1607. if (NULL != pwszSearch)
  1608. {
  1609. LocalFree(pwszSearch);
  1610. }
  1611. return(hr);
  1612. }
  1613. WCHAR *s_apwszAttrs[] = {
  1614. wszDSOBJECTCLASSATTRIBUTE,
  1615. //wszDSOBJECTCATEGORYATTRIBUTE,
  1616. DS_ATTR_COMMON_NAME,
  1617. DS_ATTR_DNS_NAME,
  1618. DS_ATTR_EMAIL_ADDR,
  1619. DS_ATTR_OBJECT_GUID,
  1620. DS_ATTR_UPN,
  1621. NULL,
  1622. };
  1623. HRESULT
  1624. CRequestInstance::_GetDSObject(
  1625. IN ICertServerPolicy *pServer,
  1626. IN BOOL fDNSNameRequired,
  1627. OPTIONAL IN WCHAR const *pwszClientDC)
  1628. {
  1629. HRESULT hr;
  1630. ULONG ldaperr;
  1631. struct l_timeval timeout;
  1632. WCHAR **ppwszValues = NULL;
  1633. BOOL fUser;
  1634. LONG cRetry;
  1635. WCHAR *pwszError = NULL;
  1636. BSTR strDNS = NULL;
  1637. timeout.tv_sec = csecLDAPTIMEOUT;
  1638. timeout.tv_usec = 0;
  1639. cRetry = 0;
  1640. while (TRUE)
  1641. {
  1642. BOOL fCached;
  1643. if (NULL != m_SearchResult)
  1644. {
  1645. ldap_msgfree(m_SearchResult);
  1646. m_SearchResult = NULL;
  1647. }
  1648. hr = reqGetLdapGC(m_pPolicy->GetEditFlags(), &m_pldGC, &fCached);
  1649. _JumpIfError(hr, error, "reqGetLdapGC");
  1650. m_pldT = m_pldGC;
  1651. if (NULL != pwszClientDC)
  1652. {
  1653. hr = reqFindClientDC(m_pldGC, pwszClientDC, &m_pldClientDC);
  1654. _JumpIfError(hr, error, "reqFindClientDC");
  1655. m_pldT = m_pldClientDC;
  1656. }
  1657. ldaperr = ldap_search_ext_s(
  1658. m_pldT,
  1659. m_strUserDN,
  1660. LDAP_SCOPE_BASE,
  1661. wszSEARCHUSERCOMPUTER,
  1662. s_apwszAttrs,
  1663. 0,
  1664. NULL,
  1665. NULL,
  1666. &timeout,
  1667. 10000,
  1668. &m_SearchResult);
  1669. if (LDAP_SUCCESS != ldaperr)
  1670. {
  1671. if (NULL != pwszError)
  1672. {
  1673. LocalFree(pwszError);
  1674. pwszError = NULL;
  1675. }
  1676. hr = myHLdapError(m_pldT, ldaperr, &pwszError);
  1677. // only retry for cached GC handle & when hr != object not found
  1678. if (fCached &&
  1679. (HRESULT) ERROR_DS_OBJ_NOT_FOUND != hr &&
  1680. NULL == pwszClientDC &&
  1681. cRetry++ < g_cGCCacheMax)
  1682. {
  1683. // get rid of GC handle we have, it might be stale
  1684. _PrintError2(hr, "Policy:ldap_search_ext_s", hr);
  1685. myLdapUnbind(&m_pldGC);
  1686. myLdapUnbind(&m_pldClientDC);
  1687. continue;
  1688. }
  1689. _JumpErrorStr(hr, error, "Policy:ldap_search_ext_s", m_strUserDN);
  1690. }
  1691. break;
  1692. }
  1693. if (0 == ldap_count_entries(m_pldT, m_SearchResult))
  1694. {
  1695. hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);
  1696. _JumpError(hr, error, "Policy:ldap_count_entries");
  1697. }
  1698. m_PrincipalAttributes = ldap_first_entry(m_pldT, m_SearchResult);
  1699. if (NULL == m_PrincipalAttributes)
  1700. {
  1701. hr = myHLdapLastError(m_pldT, NULL);
  1702. _JumpError(hr, error, "Policy:ldap_first_entry");
  1703. }
  1704. #if DBG_CERTSRV
  1705. {
  1706. DWORD i;
  1707. for (i = 0; NULL != s_apwszAttrs[i]; i++)
  1708. {
  1709. if (0 == LSTRCMPIS(s_apwszAttrs[i], DS_ATTR_OBJECT_GUID))
  1710. {
  1711. BSTR strGuid = NULL;
  1712. hr = _GetObjectGUID(&strGuid);
  1713. if (S_OK == hr)
  1714. {
  1715. WCHAR *pwsz;
  1716. hr = myCLSIDToWsz((CLSID const *) strGuid, &pwsz);
  1717. if (S_OK == hr)
  1718. {
  1719. DBGPRINT((
  1720. DBG_SS_CERTPOL,
  1721. "%ws = %ws\n",
  1722. s_apwszAttrs[i],
  1723. pwsz));
  1724. LocalFree(pwsz);
  1725. }
  1726. SysFreeString(strGuid);
  1727. }
  1728. }
  1729. else
  1730. {
  1731. hr = _GetValues(s_apwszAttrs[i], &ppwszValues);
  1732. if (S_OK == hr)
  1733. {
  1734. DWORD j;
  1735. for (j = 0; NULL != ppwszValues[j]; j++)
  1736. {
  1737. DBGPRINT((
  1738. DBG_SS_CERTPOL,
  1739. "%ws[%u] = %ws\n",
  1740. s_apwszAttrs[i],
  1741. j,
  1742. ppwszValues[j]));
  1743. }
  1744. _FreeValues(ppwszValues);
  1745. ppwszValues = NULL;
  1746. }
  1747. }
  1748. if (S_OK != hr)
  1749. {
  1750. DBGPRINT((DBG_SS_CERTPOL, "%ws = NULL\n", s_apwszAttrs[i]));
  1751. }
  1752. }
  1753. }
  1754. #endif
  1755. hr = _GetValues(wszDSOBJECTCLASSATTRIBUTE, &ppwszValues);
  1756. _JumpIfErrorStr(hr, error, "Policy:_GetValues", wszDSOBJECTCLASSATTRIBUTE);
  1757. fUser = TRUE;
  1758. if (NULL != ppwszValues)
  1759. {
  1760. DWORD i;
  1761. for (i = 0; NULL != ppwszValues[i]; i++)
  1762. {
  1763. DBGPRINT((
  1764. DBG_SS_CERTPOLI,
  1765. "%ws[%u] = %ws\n",
  1766. wszDSOBJECTCLASSATTRIBUTE,
  1767. i,
  1768. ppwszValues[i]));
  1769. if (0 == LSTRCMPIS(ppwszValues[i], L"computer"))
  1770. {
  1771. fUser = FALSE;
  1772. break;
  1773. }
  1774. }
  1775. }
  1776. if (fUser != m_fUser)
  1777. {
  1778. DBGPRINT((
  1779. DBG_SS_CERTPOL,
  1780. fUser? "MACHINE -> USER: %ws\n" : "USER -> MACHINE: %ws\n",
  1781. m_strUserDN));
  1782. m_fUser = fUser;
  1783. }
  1784. if (!m_fUser && fDNSNameRequired)
  1785. {
  1786. if (NULL != ppwszValues)
  1787. {
  1788. _FreeValues(ppwszValues);
  1789. ppwszValues = NULL;
  1790. }
  1791. hr = _GetValues(DS_ATTR_DNS_NAME, &ppwszValues);
  1792. if (S_OK != hr || NULL == ppwszValues || NULL == ppwszValues[0])
  1793. {
  1794. _PrintIfError(hr, "Policy:_GetValues");
  1795. hr = CERTSRV_E_SUBJECT_DNS_REQUIRED;
  1796. }
  1797. _JumpIfErrorStr(hr, error, "Policy:_GetValues", DS_ATTR_DNS_NAME);
  1798. hr = polGetRequestAttribute(pServer, wszPROPREQUESTMACHINEDNS, &strDNS);
  1799. _PrintIfErrorStr(
  1800. hr,
  1801. "Policy:polGetRequestAttribute",
  1802. wszPROPREQUESTMACHINEDNS);
  1803. if (S_OK == hr &&
  1804. NULL != strDNS &&
  1805. 0 != mylstrcmpiL(ppwszValues[0], strDNS))
  1806. {
  1807. hr = HRESULT_FROM_WIN32(DNS_ERROR_NAME_DOES_NOT_EXIST);
  1808. _PrintErrorStr(hr, "Policy:DNS name changed", ppwszValues[0]);
  1809. _JumpErrorStr(hr, error, "Policy:DNS name changed", strDNS);
  1810. }
  1811. }
  1812. hr = S_OK;
  1813. error:
  1814. if (S_OK != hr && NULL != pwszError)
  1815. {
  1816. WCHAR *apwsz[2];
  1817. apwsz[0] = m_strUserDN;
  1818. apwsz[1] = pwszError;
  1819. BuildErrorInfo(
  1820. hr,
  1821. HRESULT_FROM_WIN32(ERROR_DS_REFERRAL) == hr?
  1822. MSG_DS_REFERRAL :
  1823. MSG_DS_SEARCH_ERROR,
  1824. apwsz);
  1825. }
  1826. if (NULL != strDNS)
  1827. {
  1828. SysFreeString(strDNS);
  1829. }
  1830. if (NULL != pwszError)
  1831. {
  1832. LocalFree(pwszError);
  1833. }
  1834. if (NULL != ppwszValues)
  1835. {
  1836. _FreeValues(ppwszValues);
  1837. }
  1838. return(hr);
  1839. }
  1840. HRESULT
  1841. CRequestInstance::_GetValues(
  1842. IN WCHAR const *pwszName,
  1843. OUT WCHAR ***pppwszValues)
  1844. {
  1845. HRESULT hr;
  1846. WCHAR **ppwszValues = NULL;
  1847. ppwszValues = ldap_get_values(
  1848. m_pldT,
  1849. m_PrincipalAttributes,
  1850. const_cast<WCHAR *>(pwszName));
  1851. if (NULL == ppwszValues || NULL == ppwszValues[0])
  1852. {
  1853. hr = CERTSRV_E_PROPERTY_EMPTY;
  1854. _JumpErrorStr2(hr, error, "Policy:ldap_get_values", pwszName, hr);
  1855. }
  1856. *pppwszValues = ppwszValues;
  1857. ppwszValues = NULL;
  1858. hr = S_OK;
  1859. error:
  1860. if (NULL != ppwszValues)
  1861. {
  1862. ldap_value_free(ppwszValues);
  1863. }
  1864. return(hr);
  1865. }
  1866. HRESULT
  1867. CRequestInstance::_GetObjectGUID(
  1868. OUT BSTR *pstrGuid)
  1869. {
  1870. struct berval **pGuidVal = NULL;
  1871. HRESULT hr;
  1872. *pstrGuid = NULL;
  1873. pGuidVal = ldap_get_values_len(
  1874. m_pldT,
  1875. m_PrincipalAttributes,
  1876. DS_ATTR_OBJECT_GUID);
  1877. if (NULL == pGuidVal || NULL == pGuidVal[0])
  1878. {
  1879. hr = CERTSRV_E_PROPERTY_EMPTY;
  1880. _JumpError2(hr, error, "Policy:ldap_get_values_len", hr);
  1881. }
  1882. *pstrGuid = SysAllocStringByteLen(
  1883. pGuidVal[0]->bv_val,
  1884. ~(sizeof(WCHAR) - 1) & pGuidVal[0]->bv_len);
  1885. if (NULL == *pstrGuid)
  1886. {
  1887. hr = E_OUTOFMEMORY;
  1888. _JumpError(hr, error, "SysAllocStringByteLen");
  1889. }
  1890. hr = S_OK;
  1891. error:
  1892. if (NULL != pGuidVal)
  1893. {
  1894. ldap_value_free_len(pGuidVal);
  1895. }
  1896. return(hr);
  1897. }
  1898. HRESULT
  1899. CRequestInstance::_FreeValues(
  1900. IN WCHAR **ppwszValues)
  1901. {
  1902. if (NULL != ppwszValues)
  1903. {
  1904. ldap_value_free(ppwszValues);
  1905. }
  1906. return(S_OK);
  1907. }
  1908. HRESULT
  1909. CRequestInstance::_GetValueString(
  1910. IN WCHAR const *pwszName,
  1911. OUT BSTRC *pstrValue)
  1912. {
  1913. HRESULT hr;
  1914. WCHAR **ppwszValues = NULL;
  1915. BSTR strReturn;
  1916. DWORD i;
  1917. DWORD cwc;
  1918. *pstrValue = NULL;
  1919. hr = _GetValues(pwszName, &ppwszValues);
  1920. _JumpIfErrorStr(hr, error, "Policy:_GetValues", pwszName);
  1921. if (NULL == ppwszValues || NULL == ppwszValues[0])
  1922. {
  1923. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1924. _JumpErrorStr(hr, error, "Policy:ppwszValues", pwszName);
  1925. }
  1926. cwc = 0;
  1927. for (i = 0; NULL != ppwszValues[i]; i++)
  1928. {
  1929. if (0 != i)
  1930. {
  1931. cwc++;
  1932. }
  1933. cwc += wcslen(ppwszValues[i]);
  1934. }
  1935. strReturn = SysAllocStringLen(NULL, cwc);
  1936. if (NULL == strReturn)
  1937. {
  1938. hr = E_OUTOFMEMORY;
  1939. _JumpError(hr, error, "Policy:SysAllocStringLen");
  1940. }
  1941. strReturn[0] = L'\0';
  1942. for (i = 0; NULL != ppwszValues[i]; i++)
  1943. {
  1944. if (0 != i)
  1945. {
  1946. wcscat(strReturn, L",");
  1947. }
  1948. wcscat(strReturn, ppwszValues[i]);
  1949. }
  1950. CSASSERT(SysStringByteLen(strReturn) == cwc * sizeof(WCHAR));
  1951. CSASSERT(wcslen(strReturn) == cwc);
  1952. *pstrValue = strReturn;
  1953. error:
  1954. if (NULL != ppwszValues)
  1955. {
  1956. _FreeValues(ppwszValues);
  1957. }
  1958. return(hr);
  1959. }