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.

6020 lines
138 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: ds.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include <pch.cpp>
  11. #pragma hdrstop
  12. #include <winldap.h>
  13. #include <autoenr.h>
  14. #include <ntdsapi.h>
  15. #include <dsgetdc.h>
  16. #include <lmaccess.h>
  17. #include <lmapibuf.h>
  18. #include "csldap.h"
  19. #include "certtype.h"
  20. #include "csber.h"
  21. #include "tmpllist.h"
  22. #define __dwFILE__ __dwFILE_CERTUTIL_DS_CPP__
  23. HRESULT
  24. cuGetTemplateNames(
  25. IN WCHAR const *pwszTemplate,
  26. OUT WCHAR **ppwszCN,
  27. OUT WCHAR **ppwszDisplayName)
  28. {
  29. HRESULT hr;
  30. WCHAR *pwszCN = NULL;
  31. WCHAR *pwszDisplayName = NULL;
  32. HCERTTYPE hCertType = NULL;
  33. DWORD dwFlags;
  34. WCHAR **apwszCertTypeName = NULL;
  35. WCHAR **apwszCertTypeCN = NULL;
  36. *ppwszCN = NULL;
  37. *ppwszDisplayName = NULL;
  38. dwFlags = CT_ENUM_USER_TYPES | CT_ENUM_MACHINE_TYPES;
  39. if (!g_fUserRegistry)
  40. {
  41. dwFlags |= CT_FIND_LOCAL_SYSTEM;
  42. }
  43. if (g_fForce)
  44. {
  45. dwFlags |= CT_FLAG_NO_CACHE_LOOKUP;
  46. }
  47. hr = CAFindCertTypeByName(pwszTemplate, NULL, dwFlags, &hCertType);
  48. if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == hr)
  49. {
  50. hr = CAFindCertTypeByName(
  51. pwszTemplate,
  52. NULL,
  53. CT_FIND_BY_OID | dwFlags,
  54. &hCertType);
  55. }
  56. _JumpIfErrorStr(hr, error, "CAFindCertTypeByName", pwszTemplate);
  57. hr = CAGetCertTypeProperty(
  58. hCertType,
  59. CERTTYPE_PROP_CN,
  60. &apwszCertTypeCN);
  61. _JumpIfError(hr, error, "CAGetCertTypeProperty");
  62. if (NULL != apwszCertTypeCN && NULL != apwszCertTypeCN[0])
  63. {
  64. hr = myDupString(apwszCertTypeCN[0], &pwszCN);
  65. _JumpIfError(hr, error, "myDupString");
  66. }
  67. hr = CAGetCertTypeProperty(
  68. hCertType,
  69. CERTTYPE_PROP_FRIENDLY_NAME,
  70. &apwszCertTypeName);
  71. _JumpIfError(hr, error, "CAGetCertTypeProperty");
  72. if (NULL != apwszCertTypeName && NULL != apwszCertTypeName[0])
  73. {
  74. hr = myDupString(apwszCertTypeName[0], &pwszDisplayName);
  75. _JumpIfError(hr, error, "myDupString");
  76. }
  77. if (NULL != pwszCN)
  78. {
  79. *ppwszCN = pwszCN;
  80. pwszCN = NULL;
  81. }
  82. if (NULL != pwszDisplayName)
  83. {
  84. *ppwszDisplayName = pwszDisplayName;
  85. pwszDisplayName = NULL;
  86. }
  87. hr = S_OK;
  88. error:
  89. if (NULL != hCertType)
  90. {
  91. if (NULL != apwszCertTypeName)
  92. {
  93. CAFreeCertTypeProperty(hCertType, apwszCertTypeName);
  94. }
  95. if (NULL != apwszCertTypeCN)
  96. {
  97. CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
  98. }
  99. CACloseCertType(hCertType);
  100. }
  101. if (NULL != pwszCN)
  102. {
  103. LocalFree(pwszCN);
  104. }
  105. if (NULL != pwszDisplayName)
  106. {
  107. LocalFree(pwszDisplayName);
  108. }
  109. return(hr);
  110. }
  111. HRESULT
  112. DumpDSStore(
  113. OPTIONAL IN WCHAR const *pwszDN,
  114. IN BOOL fCRL,
  115. IN BOOL fDeltaCRL,
  116. IN DWORD iCert,
  117. IN DWORD iCRL,
  118. OPTIONAL IN WCHAR const *pwszfnOut)
  119. {
  120. HRESULT hr;
  121. HCERTSTORE hStoreDS = NULL;
  122. WCHAR *pwszServer = NULL;
  123. WCHAR *pwszCAName = NULL;
  124. WCHAR *pwszSanitizedName = NULL;
  125. WCHAR *pwszURL = NULL;
  126. WCHAR *pwszTemplateAlloc = NULL;
  127. WCHAR const *pwszTemplate;
  128. BSTR strDomainDN = NULL;
  129. BSTR strConfigDN = NULL;
  130. LDAP *pld = NULL;
  131. DWORD Mode;
  132. //if (NULL != pwszDN) wprintf(L"pwszDN = \"%ws\"\n", pwszDN);
  133. // Get the object name and open its cert or CRL store
  134. if (NULL == pwszDN)
  135. {
  136. if (NULL == g_pwszConfig)
  137. {
  138. hr = cuSetConfig();
  139. _JumpIfError(hr, error, "cuSetConfig");
  140. }
  141. pwszTemplate = fCRL?
  142. g_wszzLDAPRevocationURLTemplate : g_wszzLDAPIssuerCertURLTemplate;
  143. hr = mySplitConfigString(g_pwszConfig, &pwszServer, &pwszCAName);
  144. _JumpIfError(hr, error, "mySplitConfigString");
  145. hr = mySanitizeName(pwszCAName, &pwszSanitizedName);
  146. _JumpIfError(hr, error, "mySanitizeName");
  147. hr = myLdapOpen(g_pwszDC, 0, &pld, &strDomainDN, &strConfigDN);
  148. _JumpIfError(hr, error, "myLdapOpen");
  149. }
  150. else
  151. {
  152. pwszTemplate = fCRL?
  153. wszFCSAPARM_DSCRLATTRIBUTE :
  154. (g_fEnterpriseRegistry?
  155. wszFCSAPARM_DSCROSSCERTPAIRATTRIBUTE :
  156. (g_fUserRegistry?
  157. wszFCSAPARM_DSUSERCERTATTRIBUTE :
  158. wszFCSAPARM_DSCACERTATTRIBUTE));
  159. pwszTemplateAlloc = (WCHAR *) LocalAlloc(
  160. LMEM_FIXED,
  161. (wcslen(pwszDN) +
  162. wcslen(pwszTemplate) + 1) * sizeof(WCHAR));
  163. if (NULL == pwszTemplateAlloc)
  164. {
  165. hr = E_OUTOFMEMORY;
  166. _JumpError(hr, error, "LocalAlloc");
  167. }
  168. wcscpy(pwszTemplateAlloc, pwszDN);
  169. wcscat(pwszTemplateAlloc, pwszTemplate);
  170. pwszTemplate = pwszTemplateAlloc;
  171. }
  172. hr = myFormatCertsrvStringArray(
  173. FALSE, // fURL
  174. NULL != pwszServer? pwszServer : g_wszEmpty, // pwszServerName_p1_2
  175. NULL != pwszSanitizedName? pwszSanitizedName : g_wszEmpty,
  176. // pwszSanitizedName_p3_7
  177. 0, // iCert_p4
  178. MAXDWORD, // iCertTarget_p4
  179. NULL != strDomainDN? strDomainDN : g_wszEmpty, // pwszDomainDN_p5
  180. NULL != strConfigDN? strConfigDN : g_wszEmpty, // pwszConfigDN_p6
  181. iCRL, // iCRL_p8
  182. fDeltaCRL, // fDeltaCRL_p9
  183. TRUE, // fDSAttrib_p10_11
  184. 1, // cStrings
  185. &pwszTemplate, // apwszStringsIn
  186. &pwszURL); // apwszStringsOut
  187. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  188. wprintf(L"\n%ws:\n", pwszURL);
  189. Mode = DVNS_DUMP;
  190. hr = cuOpenCertStore(pwszURL, &Mode, NULL, &hStoreDS);
  191. _JumpIfError(hr, error, "cuOpenCertStore");
  192. if (fCRL)
  193. {
  194. iCRL = MAXDWORD;
  195. if (NULL != pwszfnOut)
  196. {
  197. iCRL = 0;
  198. }
  199. }
  200. hr = cuDumpAndVerifyStore(
  201. hStoreDS,
  202. DVNS_VERIFYCERT | DVNS_CASTORE | DVNS_DUMPPROPERTIES,
  203. NULL, // pwszCertName
  204. iCert,
  205. iCRL,
  206. MAXDWORD, // iCTL
  207. pwszfnOut,
  208. NULL);
  209. _JumpIfError(hr, error, "cuDumpAndVerifyStore");
  210. error:
  211. if (NULL != pwszTemplateAlloc)
  212. {
  213. LocalFree(pwszTemplateAlloc);
  214. }
  215. if (NULL != pwszSanitizedName)
  216. {
  217. LocalFree(pwszSanitizedName);
  218. }
  219. if (NULL != pwszServer)
  220. {
  221. LocalFree(pwszServer);
  222. }
  223. if (NULL != pwszCAName)
  224. {
  225. LocalFree(pwszCAName);
  226. }
  227. if (NULL != pwszURL)
  228. {
  229. LocalFree(pwszURL);
  230. }
  231. if (NULL != hStoreDS)
  232. {
  233. CertCloseStore(hStoreDS, CERT_CLOSE_STORE_CHECK_FLAG);
  234. }
  235. myLdapClose(pld, strDomainDN, strConfigDN);
  236. return(hr);
  237. }
  238. HRESULT
  239. verbDSCert(
  240. IN WCHAR const *pwszOption,
  241. OPTIONAL IN WCHAR const *pwszCertIndex,
  242. OPTIONAL IN WCHAR const *pwszfnOut,
  243. IN WCHAR const *pwszArg3,
  244. IN WCHAR const *pwszArg4)
  245. {
  246. HRESULT hr;
  247. DWORD iCert = MAXDWORD;
  248. WCHAR const *pwszDN = NULL;
  249. if (NULL != pwszCertIndex)
  250. {
  251. hr = myGetLong(pwszCertIndex, (LONG *) &iCert);
  252. if (S_OK != hr)
  253. {
  254. if (NULL != pwszfnOut)
  255. {
  256. _JumpError(hr, error, "CertIndex must be a number");
  257. }
  258. pwszDN = pwszCertIndex;
  259. iCert = MAXDWORD;
  260. }
  261. }
  262. hr = DumpDSStore(pwszDN, FALSE, FALSE, iCert, MAXDWORD, pwszfnOut);
  263. _JumpIfError(hr, error, "DumpDSStore");
  264. error:
  265. return(hr);
  266. }
  267. HRESULT
  268. GetCACertCount(
  269. IN DISPATCHINTERFACE *pdiRequest,
  270. OUT DWORD *pcCACerts)
  271. {
  272. HRESULT hr;
  273. BSTR str = NULL;
  274. DWORD cwc;
  275. WCHAR const *pwc;
  276. CAINFO CAInfo;
  277. hr = Request_GetCACertificate(
  278. pdiRequest,
  279. GETCERT_CAINFO, // fExchangeCertificate
  280. g_pwszConfig,
  281. CR_OUT_BINARY,
  282. &str);
  283. _JumpIfError(hr, error, "Request_GetCACertificate(CAInfo)");
  284. cwc = wcslen(str);
  285. pwc = str;
  286. if (!cuParseDecimal(&pwc, &cwc, (DWORD *) &CAInfo.CAType) ||
  287. !cuParseDecimal(&pwc, &cwc, &CAInfo.cCASignatureCerts))
  288. {
  289. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  290. _JumpError(hr, error, "cuParseDecimal");
  291. }
  292. *pcCACerts = CAInfo.cCASignatureCerts;
  293. error:
  294. if (NULL != str)
  295. {
  296. SysFreeString(str);
  297. }
  298. return(hr);
  299. }
  300. HRESULT
  301. GetCRLState(
  302. IN DISPATCHINTERFACE *pdiRequest,
  303. IN DWORD iCRL,
  304. OUT DWORD *pState)
  305. {
  306. HRESULT hr;
  307. BSTR str = NULL;
  308. DWORD cwc;
  309. WCHAR const *pwc;
  310. hr = Request_GetCACertificate(
  311. pdiRequest,
  312. GETCERT_CRLSTATEBYINDEX | iCRL, // fExchangeCertificate
  313. g_pwszConfig,
  314. CR_OUT_BINARY,
  315. &str);
  316. _JumpIfError(hr, error, "Request_GetCACertificate");
  317. cwc = wcslen(str);
  318. pwc = str;
  319. if (!cuParseDecimal(&pwc, &cwc, pState))
  320. {
  321. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  322. _JumpError(hr, error, "cuParseDecimal");
  323. }
  324. error:
  325. if (NULL != str)
  326. {
  327. SysFreeString(str);
  328. }
  329. return(hr);
  330. }
  331. HRESULT
  332. DSCRLSub(
  333. IN BOOL fDeltaCRL,
  334. OPTIONAL IN WCHAR const *pwszCRLIndex,
  335. OPTIONAL IN WCHAR const *pwszfnOut)
  336. {
  337. HRESULT hr;
  338. DWORD iCRL = MAXDWORD;
  339. DISPATCHINTERFACE diRequest;
  340. BOOL fMustRelease = FALSE;
  341. WCHAR const *pwszDN = NULL;
  342. if (NULL != pwszCRLIndex)
  343. {
  344. hr = myGetLong(pwszCRLIndex, (LONG *) &iCRL);
  345. if (S_OK != hr)
  346. {
  347. if (NULL != pwszfnOut)
  348. {
  349. _JumpError(hr, error, "CRLIndex must be a number");
  350. }
  351. pwszDN = pwszCRLIndex;
  352. iCRL = MAXDWORD;
  353. }
  354. }
  355. if (NULL == pwszDN)
  356. {
  357. hr = cuSetConfig();
  358. _JumpIfError(hr, error, "cuSetConfig");
  359. }
  360. if (MAXDWORD == iCRL && NULL == pwszDN)
  361. {
  362. DWORD cCACerts;
  363. DWORD State;
  364. hr = Request_Init(g_DispatchFlags, &diRequest);
  365. _JumpIfError(hr, error, "Request_Init");
  366. fMustRelease = TRUE;
  367. hr = GetCACertCount(&diRequest, &cCACerts);
  368. _JumpIfError(hr, error, "GetCACertCount");
  369. for (iCRL = 0; iCRL < cCACerts; iCRL++)
  370. {
  371. hr = GetCRLState(&diRequest, iCRL, &State);
  372. _JumpIfError(hr, error, "GetCRLState");
  373. if (CA_DISP_VALID != State)
  374. {
  375. //wprintf(L"Skipping CRL.%u\n", iCRL);
  376. continue;
  377. }
  378. hr = DumpDSStore(NULL, TRUE, fDeltaCRL, MAXDWORD, iCRL, NULL);
  379. _JumpIfError(hr, error, "DumpDSStore");
  380. }
  381. }
  382. else
  383. {
  384. hr = DumpDSStore(pwszDN, TRUE, fDeltaCRL, MAXDWORD, iCRL, pwszfnOut);
  385. _JumpIfError(hr, error, "DumpDSStore");
  386. }
  387. error:
  388. if (fMustRelease)
  389. {
  390. Request_Release(&diRequest);
  391. }
  392. return(hr);
  393. }
  394. HRESULT
  395. verbDSCRL(
  396. IN WCHAR const *pwszOption,
  397. OPTIONAL IN WCHAR const *pwszCRLIndex,
  398. OPTIONAL IN WCHAR const *pwszfnOut,
  399. IN WCHAR const *pwszArg3,
  400. IN WCHAR const *pwszArg4)
  401. {
  402. HRESULT hr;
  403. hr = DSCRLSub(FALSE, pwszCRLIndex, pwszfnOut);
  404. _JumpIfError(hr, error, "DSCRLSub");
  405. error:
  406. return(hr);
  407. }
  408. HRESULT
  409. verbDSDeltaCRL(
  410. IN WCHAR const *pwszOption,
  411. OPTIONAL IN WCHAR const *pwszCRLIndex,
  412. OPTIONAL IN WCHAR const *pwszfnOut,
  413. IN WCHAR const *pwszArg3,
  414. IN WCHAR const *pwszArg4)
  415. {
  416. HRESULT hr;
  417. hr = DSCRLSub(TRUE, pwszCRLIndex, pwszfnOut);
  418. _JumpIfError(hr, error, "DSCRLSub");
  419. error:
  420. return(hr);
  421. }
  422. #define wszCOMMA L","
  423. #define wszCNEQUALS L"CN="
  424. DWORD
  425. dsGetNumericSuffix(
  426. IN WCHAR const *pwszName)
  427. {
  428. HRESULT hr;
  429. DWORD cwcPrefix;
  430. BOOL fDigit;
  431. WCHAR const *pwsz;
  432. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  433. cwcPrefix = MAXDWORD;
  434. if (NULL == pwszName || L'\0' == *pwszName)
  435. {
  436. _JumpError2(hr, error, "empty", hr);
  437. }
  438. pwsz = &pwszName[wcslen(pwszName) - 1];
  439. if (wcRPAREN == *pwsz)
  440. {
  441. pwsz--;
  442. fDigit = FALSE;
  443. while (pwsz > pwszName && iswdigit(*pwsz))
  444. {
  445. fDigit = TRUE;
  446. pwsz--;
  447. }
  448. if (!fDigit || pwsz <= pwszName || wcLPAREN != *pwsz)
  449. {
  450. _JumpError2(hr, error, "fDigit or wcLPAREN", hr);
  451. }
  452. cwcPrefix = SAFE_SUBTRACT_POINTERS(pwsz, pwszName);
  453. }
  454. error:
  455. return(cwcPrefix);
  456. }
  457. BOOL
  458. CACNBaseNameMatch(
  459. IN WCHAR const *pwszCNMatch,
  460. IN WCHAR const *pwszCN)
  461. {
  462. HRESULT hr;
  463. WCHAR *pwszDup = NULL;
  464. BOOL fMatch = FALSE;
  465. DWORD iSuffix;
  466. WCHAR *pwsz;
  467. hr = myDupString(pwszCN, &pwszDup);
  468. _JumpIfError(hr, error, "myDupString");
  469. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  470. iSuffix = dsGetNumericSuffix(pwszDup);
  471. if (MAXDWORD != iSuffix)
  472. {
  473. pwszDup[iSuffix] = L'\0'; // truncate trailing "(#)"
  474. }
  475. pwsz = &pwszDup[wcslen(pwszDup) - WSZARRAYSIZE(L"-CDP") + 1];
  476. if (pwsz > pwszDup && 0 == LSTRCMPIS(pwsz, L"-CDP"))
  477. {
  478. *pwsz = '\0'; // truncate trailing L"-CDP"
  479. }
  480. if (0 != mylstrcmpiL(pwszCNMatch, pwszDup)) // compare base name
  481. {
  482. _JumpError2(hr, error, "no base name match", hr);
  483. }
  484. fMatch = TRUE;
  485. error:
  486. if (NULL != pwszDup)
  487. {
  488. LocalFree(pwszDup);
  489. }
  490. return(fMatch);
  491. }
  492. BOOL
  493. CACNMatches(
  494. OPTIONAL IN WCHAR const *pwszCNMatch,
  495. OPTIONAL IN WCHAR const *pwszOIDCN,
  496. IN WCHAR const *pwszRevertCN,
  497. IN WCHAR const *pwszSanitizedCN,
  498. OPTIONAL IN WCHAR const *pwszDisplayName,
  499. OPTIONAL IN WCHAR const *pwszAlternateCN)
  500. {
  501. BOOL fMatch = TRUE;
  502. // If no match criteria, match everything
  503. if (NULL == pwszCNMatch)
  504. {
  505. goto match;
  506. }
  507. // Check against the Desanitized short name or Sanitized short name.
  508. if (0 == mylstrcmpiL(pwszCNMatch, pwszRevertCN) ||
  509. 0 == mylstrcmpiL(pwszCNMatch, pwszSanitizedCN))
  510. {
  511. goto match;
  512. }
  513. // Check against the displayName
  514. if (NULL != pwszDisplayName && 0 == mylstrcmpiL(pwszCNMatch, pwszDisplayName))
  515. {
  516. goto match;
  517. }
  518. // Check against the alternate CN (msPKI-Cert-Template-OID)
  519. if (NULL != pwszAlternateCN && 0 == mylstrcmpiL(pwszCNMatch, pwszAlternateCN))
  520. {
  521. goto match;
  522. }
  523. // Check against the OID converted to a CN
  524. if (NULL != pwszOIDCN &&
  525. 0 == mylstrcmpiL(pwszOIDCN, pwszRevertCN))
  526. {
  527. goto match;
  528. }
  529. // Check against the Desanitized short name or Sanitized short name,
  530. // stripped of the key index and CDP tags.
  531. if (CACNBaseNameMatch(pwszCNMatch, pwszRevertCN) ||
  532. CACNBaseNameMatch(pwszCNMatch, pwszSanitizedCN))
  533. {
  534. goto match;
  535. }
  536. fMatch = FALSE; // can't say we didn't try...
  537. match:
  538. return(fMatch);
  539. }
  540. HRESULT
  541. BuildDN(
  542. IN WCHAR const *pwszRDN,
  543. IN WCHAR const *pwszContainer,
  544. IN BOOL fAddCNEquals,
  545. OUT WCHAR **ppwszDN)
  546. {
  547. HRESULT hr;
  548. WCHAR *pwszDN = NULL;
  549. DWORD cwc;
  550. *ppwszDN = NULL;
  551. cwc = wcslen(pwszRDN) + 1 + wcslen(pwszContainer) + 1;
  552. if (fAddCNEquals)
  553. {
  554. cwc += WSZARRAYSIZE(wszCNEQUALS);
  555. }
  556. pwszDN = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
  557. if (NULL == pwszDN)
  558. {
  559. hr = E_OUTOFMEMORY;
  560. _JumpError(hr, error, "LocalAlloc");
  561. }
  562. *pwszDN = L'\0';
  563. if (fAddCNEquals)
  564. {
  565. wcscpy(pwszDN, wszCNEQUALS);
  566. }
  567. wcscat(pwszDN, pwszRDN);
  568. wcscat(pwszDN, wszCOMMA);
  569. wcscat(pwszDN, pwszContainer);
  570. *ppwszDN = pwszDN;
  571. pwszDN = NULL;
  572. hr = S_OK;
  573. error:
  574. if (NULL != pwszDN)
  575. {
  576. LocalFree(pwszDN);
  577. }
  578. return(hr);
  579. }
  580. HRESULT
  581. DeleteDN(
  582. IN LDAP *pld,
  583. OPTIONAL IN WCHAR const *pwszRDN,
  584. IN WCHAR const *pwszContainer)
  585. {
  586. WCHAR *pwszDNAlloc = NULL;
  587. WCHAR const *pwszDN;
  588. HRESULT hr;
  589. pwszDN = pwszContainer;
  590. if (NULL != pwszRDN)
  591. {
  592. hr = BuildDN(pwszRDN, pwszContainer, TRUE, &pwszDNAlloc);
  593. _JumpIfError(hr, error, "BuildDN");
  594. pwszDN = pwszDNAlloc;
  595. }
  596. hr = ldap_delete_s(pld, const_cast<WCHAR *>(pwszDN));
  597. if (S_OK != hr)
  598. {
  599. hr = myHLdapError(pld, hr, NULL);
  600. _JumpErrorStr(hr, error, "ldap_delete_s", pwszDN);
  601. }
  602. error:
  603. if (NULL != pwszDNAlloc)
  604. {
  605. LocalFree(pwszDNAlloc);
  606. }
  607. return(hr);
  608. }
  609. #define DSAF_STRING 0x00000001
  610. #define DSAF_FLAGS 0x00000002
  611. #define DSAF_BINARY 0x00000003
  612. #define DSAF_GUID 0x00000004
  613. #define DSAF_ASNDATE 0x00000005
  614. #define DSAF_ASN 0x00000006
  615. #define DSAF_FILETIME 0x00000007
  616. #define DSAF_EXTENSION 0x00000008 // see pszObjId
  617. typedef struct _EXTTEMPLATE
  618. {
  619. WCHAR const *pwszObjId; // wszOID_*
  620. BYTE const *pbTemplate; // Template
  621. DWORD cbTemplate; // Template length
  622. DWORD cbAdd; // Additional encoded length
  623. } EXTTEMPLATE;
  624. typedef struct _DSATTR
  625. {
  626. WCHAR const *pwszName; // Attribute name
  627. DWORD Flags; // DSAF_*
  628. UINT idMsg; // IDS_FORMAT_*
  629. EXTTEMPLATE *pExtension;
  630. } DSATTR;
  631. BYTE s_abTemplateKeyUsage[] = { BER_BIT_STRING, 0x00, 0x00 };
  632. EXTTEMPLATE s_ExtKeyUsage =
  633. {
  634. TEXT(szOID_KEY_USAGE),
  635. s_abTemplateKeyUsage,
  636. sizeof(s_abTemplateKeyUsage),
  637. 1
  638. };
  639. DSATTR s_DSAttrBinary =
  640. {
  641. L"",
  642. DSAF_BINARY,
  643. 0,
  644. NULL,
  645. };
  646. DSATTR s_DSAttrString =
  647. {
  648. L"",
  649. DSAF_STRING,
  650. 0,
  651. NULL,
  652. };
  653. DSATTR s_aDSAttr[] =
  654. {
  655. { wszDSUSERCERTATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CERT_INDEX, NULL, },
  656. { wszDSCACERTATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CERT_INDEX, NULL, },
  657. { wszDSCROSSCERTPAIRATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CERT_INDEX, NULL, },
  658. { wszDSAUTHORITYCRLATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CRL_INDEX, NULL, },
  659. { wszDSBASECRLATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CRL_INDEX, NULL, },
  660. { wszDSDELTACRLATTRIBUTE, DSAF_ASN, IDS_FORMAT_DUMP_CRL_INDEX, NULL, },
  661. { L"teletexTerminalIdentifier", DSAF_ASN, 0, NULL, },
  662. { L"kCCStatus", DSAF_ASN, 0, NULL, },
  663. { CERTTYPE_PROP_CN, DSAF_STRING, 0, NULL, },
  664. { CERTTYPE_PROP_DN, DSAF_STRING, 0, NULL, },
  665. { L"name", DSAF_STRING, 0, NULL, },
  666. { L"showInAdvancedViewOnly", DSAF_STRING, 0, NULL, },
  667. { L"memberOf", DSAF_STRING, 0, NULL, },
  668. { L"operatingSystem", DSAF_STRING, 0, NULL, },
  669. { L"operatingSystemVersion", DSAF_STRING, 0, NULL, },
  670. { L"servicePrincipalName", DSAF_STRING, 0, NULL, },
  671. { L"sAMAccountName", DSAF_STRING, 0, NULL, },
  672. { L"description", DSAF_STRING, 0, NULL, },
  673. { L"isCriticalSystemObject", DSAF_STRING, 0, NULL, },
  674. //{ L"uSNChanged", DSAF_STRING, 0, NULL, },
  675. //{ L"uSNCreated", DSAF_STRING, 0, NULL, },
  676. //{ L"instanceType", DSAF_STRING, 0, NULL, },
  677. { L"objectCategory", DSAF_STRING, 0, NULL, },
  678. { wszDSOBJECTCLASSATTRIBUTE, DSAF_STRING, 0, NULL, },
  679. { L"objectGUID", DSAF_GUID, 0, NULL, },
  680. { L"whenChanged", DSAF_ASNDATE, 0, NULL, },
  681. { L"whenCreated", DSAF_ASNDATE, 0, NULL, },
  682. { L"dSCorePropagationData", DSAF_ASNDATE, 0, NULL, },
  683. { CA_PROP_CERT_DN, DSAF_STRING, 0, NULL, },
  684. { CA_PROP_CERT_TYPES, DSAF_STRING, 0, NULL, },
  685. { CERTTYPE_PROP_FRIENDLY_NAME, DSAF_STRING, 0, NULL, },
  686. { CA_PROP_DNSNAME, DSAF_STRING, 0, NULL, },
  687. { OID_PROP_LOCALIZED_NAME, DSAF_STRING, 0, NULL, },
  688. { OID_PROP_CPS, DSAF_STRING, 0, NULL, },
  689. { L"legacyExchangeDN", DSAF_STRING, 0, NULL, },
  690. { L"msExchADCGlobalNames", DSAF_STRING, 0, NULL, },
  691. { L"domainDefAltRecip", DSAF_STRING, 0, NULL, },
  692. { L"dXAAdminForward", DSAF_STRING, 0, NULL, },
  693. { L"kMServer", DSAF_STRING, 0, NULL, },
  694. { L"sendEMailMessage", DSAF_STRING, 0, NULL, },
  695. { L"serverReferenceBL", DSAF_STRING, 0, NULL, },
  696. { L"rIDSetReferences", DSAF_STRING, 0, NULL, },
  697. { L"frsComputerReferenceBL", DSAF_STRING, 0, NULL, },
  698. { L"serverReference", DSAF_STRING, 0, NULL, },
  699. { L"mailAddress", DSAF_STRING, 0, NULL, },
  700. { L"msDS-HasInstantiatedNCs", DSAF_STRING, 0, NULL, },
  701. { L"msDS-HasDomainNCs", DSAF_STRING, 0, NULL, },
  702. { L"msDS-hasMasterNCs", DSAF_STRING, 0, NULL, },
  703. { L"hasMasterNCs", DSAF_STRING, 0, NULL, },
  704. { L"dMDLocation", DSAF_STRING, 0, NULL, },
  705. { L"userPrincipalName", DSAF_STRING, 0, NULL, },
  706. { L"mail", DSAF_STRING, 0, NULL, },
  707. { L"givenName", DSAF_STRING, 0, NULL, },
  708. { L"sn", DSAF_STRING, 0, NULL, },
  709. // Template Schema Version 1 properties:
  710. { CERTTYPE_PROP_FLAGS, DSAF_FLAGS, 0, NULL, },
  711. { CERTTYPE_PROP_CSP_LIST, DSAF_STRING, 0, NULL, },
  712. //{ CERTTYPE_PROP_DEFAULT_KEYSPEC, DSAF_STRING, 0, NULL, },
  713. //{ CERTTYPE_PROP_EXTENDED_KEY_USAGE, DSAF_STRING, 0, NULL, },
  714. //{ CERTTYPE_PROP_CRITICAL_EXTENSIONS, DSAF_STRING, 0, NULL, },
  715. //{ CERTTYPE_PROP_MAX_DEPTH, DSAF_STRING, 0, NULL, },
  716. //{ CERTTYPE_PROP_REVISION, DSAF_STRING, 0, NULL, },
  717. { CERTTYPE_PROP_EXPIRATION, DSAF_FILETIME, 0, NULL, },
  718. { CERTTYPE_PROP_OVERLAP, DSAF_FILETIME, 0, NULL, },
  719. { CERTTYPE_PROP_KU, DSAF_EXTENSION, 0, &s_ExtKeyUsage, },
  720. // Template Schema Version 2 properties:
  721. { CERTTYPE_RPOP_ENROLLMENT_FLAG, DSAF_FLAGS, 0, NULL, },
  722. { CERTTYPE_PROP_NAME_FLAG, DSAF_FLAGS, 0, NULL, },
  723. { CERTTYPE_PROP_PRIVATE_KEY_FLAG, DSAF_FLAGS, 0, NULL, },
  724. { CERTTYPE_PROP_SCHEMA_VERSION, DSAF_STRING, 0, NULL, },
  725. { CERTTYPE_PROP_MINOR_REVISION, DSAF_STRING, 0, NULL, },
  726. { CERTTYPE_PROP_RA_SIGNATURE, DSAF_STRING, 0, NULL, },
  727. { CERTTYPE_PROP_MIN_KEY_SIZE, DSAF_STRING, 0, NULL, },
  728. { CERTTYPE_PROP_OID, DSAF_STRING, 0, NULL, },
  729. { CERTTYPE_PROP_SUPERSEDE, DSAF_STRING, 0, NULL, },
  730. { CERTTYPE_PROP_RA_POLICY, DSAF_STRING, 0, NULL, },
  731. { CERTTYPE_PROP_RA_APPLICATION_POLICY, DSAF_STRING, 0, NULL, },
  732. { CERTTYPE_PROP_POLICY, DSAF_STRING, 0, NULL, },
  733. { CERTTYPE_PROP_APPLICATION_POLICY, DSAF_STRING, 0, NULL, },
  734. };
  735. #define ISEMPTYATTR(pberval) \
  736. (0 == (pberval)->bv_len || \
  737. (1 == (pberval)->bv_len && 0 == *(BYTE const *) (pberval)->bv_val))
  738. WCHAR const s_wszPad0[] = L" ";
  739. WCHAR const s_wszPad1[] = L"\t";
  740. #define wszPUBLICKEYSERVICESCONTAINER \
  741. L"CN=Public Key Services," \
  742. L"CN=Services"
  743. WCHAR const g_wszCNAuthoritiesOld[] =
  744. L"CN=Certification Authorities";
  745. WCHAR const g_wszCNAuthorities[] =
  746. L"CN=Certification Authorities,"
  747. wszPUBLICKEYSERVICESCONTAINER;
  748. WCHAR const g_wszEnterpriseCAs[] =
  749. //L"CN=NTAuthCertificates,"
  750. wszPUBLICKEYSERVICESCONTAINER;
  751. WCHAR const g_wszCNKRA[] =
  752. L"CN=KRA,"
  753. wszPUBLICKEYSERVICESCONTAINER;
  754. WCHAR const g_wszCNEnrollment[] =
  755. L"CN=Enrollment Services,"
  756. wszPUBLICKEYSERVICESCONTAINER;
  757. WCHAR const g_wszCNAIA[] =
  758. L"CN=AIA,"
  759. wszPUBLICKEYSERVICESCONTAINER;
  760. WCHAR const g_wszCNOID[] =
  761. L"CN=OID,"
  762. wszPUBLICKEYSERVICESCONTAINER;
  763. WCHAR const g_wszCNCDP[] =
  764. L"CN=CDP,"
  765. wszPUBLICKEYSERVICESCONTAINER;
  766. WCHAR const g_wszCNTemplates[] =
  767. L"CN=Certificate Templates,"
  768. wszPUBLICKEYSERVICESCONTAINER;
  769. typedef struct _DSDN
  770. {
  771. DWORD Flags;
  772. WCHAR const *pwszCN;
  773. WCHAR const *pwszChild;
  774. WCHAR const *pwszAlternateCNAttribute;
  775. } DSDN;
  776. #define DSDF_ADDCNEQUALS 0x00000001
  777. #define DSDF_RECURSEONELEVEL 0x00000002
  778. #define DSDF_DELETE 0x00000004
  779. #define DSDF_INFDUMP 0x00000008
  780. #define DSDF_DOMAINDN 0x00000010
  781. #define DSDF_BASE 0x00000020
  782. #define DSDF_CA 0x00000100
  783. #define DSDF_TEMPLATE 0x00000200
  784. #define DSDF_OID 0x00000400
  785. #define DSDF_TYPEMASK 0x00000700
  786. DSDN s_aDSDN[] =
  787. {
  788. { 0, wszPUBLICKEYSERVICESCONTAINER, L"NTAuthCertificates", NULL },
  789. { DSDF_CA | DSDF_DOMAINDN, g_wszCNAuthoritiesOld, NULL, NULL },
  790. { DSDF_CA, g_wszCNAuthorities, NULL, NULL },
  791. { 0, g_wszCNKRA, NULL, NULL },
  792. { DSDF_CA, g_wszCNEnrollment, NULL, NULL },
  793. { DSDF_CA, g_wszCNAIA, NULL, NULL },
  794. { DSDF_CA | DSDF_RECURSEONELEVEL, g_wszCNCDP, NULL, NULL },
  795. { DSDF_OID, g_wszCNOID, NULL, OID_PROP_OID },
  796. { DSDF_TEMPLATE, g_wszCNTemplates, NULL, CERTTYPE_PROP_OID },
  797. };
  798. HRESULT
  799. dumpDSStringAttribute(
  800. IN LDAP *pld,
  801. IN LDAPMessage *pres,
  802. IN DWORD dwFlags,
  803. IN WCHAR const *pwszAttrName,
  804. IN DSATTR const *pdsa)
  805. {
  806. HRESULT hr;
  807. WCHAR **rgpwszval = NULL;
  808. BOOL fInfDump = 0 != (DSDF_INFDUMP & dwFlags);
  809. rgpwszval = ldap_get_values(pld, pres, (WCHAR * const) pwszAttrName);
  810. if (NULL != rgpwszval)
  811. {
  812. LONG lVal;
  813. BOOL fValidNumber;
  814. WCHAR const *pwszVal;
  815. BOOL fCompact;
  816. DWORD i;
  817. WCHAR const *pwszSep;
  818. fCompact = fInfDump ||
  819. (1 >= g_fVerbose && (NULL == rgpwszval[0] || NULL == rgpwszval[1]));
  820. if (!fCompact)
  821. {
  822. wprintf(L"%ws%ws\n", s_wszPad0, pwszAttrName);
  823. }
  824. for (i = 0; NULL != (pwszVal = rgpwszval[i]); i++)
  825. {
  826. pwszSep = L"";
  827. if (fCompact)
  828. {
  829. if (0 == i)
  830. {
  831. wprintf(L"%ws%ws =", s_wszPad0, pwszAttrName);
  832. }
  833. else
  834. {
  835. pwszSep = L",";
  836. }
  837. }
  838. else
  839. {
  840. wprintf(s_wszPad1);
  841. wprintf(
  842. myLoadResourceString(IDS_FORMAT_ELEMENT), // "Element %u:"
  843. i);
  844. }
  845. wprintf(L"%ws \"%ws\"", pwszSep, pwszVal);
  846. if (iswdigit(pwszVal[0]) || L'-' == pwszVal[0])
  847. {
  848. if (L'-' == pwszVal[0])
  849. {
  850. lVal = myWtoI(&pwszVal[1], &fValidNumber);
  851. lVal = -lVal;
  852. }
  853. else
  854. {
  855. lVal = myWtoI(pwszVal, &fValidNumber);
  856. }
  857. if (!fInfDump || g_fVerbose)
  858. {
  859. if (fValidNumber)
  860. {
  861. if (0 > lVal || 9 < lVal)
  862. {
  863. wprintf(L" 0x%x", lVal);
  864. }
  865. if (DSAF_FLAGS == pdsa->Flags)
  866. {
  867. WCHAR const *pwsz;
  868. pwsz = pdsa->pwszName;
  869. if (0 == LSTRCMPIS(pwsz, CERTTYPE_PROP_FLAGS))
  870. {
  871. if (DSDF_CA & dwFlags)
  872. {
  873. pwsz = wszCUREGDSCAFLAGS;
  874. }
  875. else if (DSDF_TEMPLATE & dwFlags)
  876. {
  877. pwsz = wszCUREGDSTEMPLATEFLAGS;
  878. }
  879. else if (DSDF_OID & dwFlags)
  880. {
  881. pwsz = wszCUREGDSOIDFLAGS;
  882. }
  883. }
  884. wprintf(wszNewLine);
  885. cuRegPrintDwordValue(FALSE, pwsz, pwsz, lVal);
  886. }
  887. }
  888. else
  889. {
  890. cuPrintPossibleObjectIdName(pwszVal);
  891. }
  892. }
  893. }
  894. if (DSAF_ASNDATE == pdsa->Flags)
  895. {
  896. WCHAR const *pwszT;
  897. FILETIME ft;
  898. DWORD cbft;
  899. DWORD cb;
  900. BYTE ab[MAX_PATH];
  901. cb = 0;
  902. ab[cb++] = BER_GENERALIZED_TIME;
  903. ab[cb++] = (BYTE) wcslen(pwszVal);
  904. for (pwszT = pwszVal; L'\0' != *pwszT; pwszT++)
  905. {
  906. ab[cb++] = (BYTE) *pwszT;
  907. }
  908. cbft = sizeof(FILETIME);
  909. if (!CryptDecodeObject(
  910. X509_ASN_ENCODING,
  911. X509_CHOICE_OF_TIME,
  912. ab,
  913. cb,
  914. 0,
  915. &ft,
  916. &cbft))
  917. {
  918. wprintf(L"\n");
  919. hr = myHLastError();
  920. _PrintIfError(hr, "CryptDecodeObject");
  921. }
  922. else if (!fInfDump || g_fVerbose)
  923. {
  924. cuDumpFileTime(0, NULL, &ft);
  925. }
  926. }
  927. else if (!fInfDump)
  928. {
  929. wprintf(L"\n");
  930. }
  931. if (1 < g_fVerbose)
  932. {
  933. DumpHex(
  934. DH_NOADDRESS | DH_NOTABPREFIX | 12,
  935. (BYTE const *) pwszVal,
  936. wcslen(pwszVal) * sizeof(WCHAR));
  937. }
  938. }
  939. if (fInfDump)
  940. {
  941. wprintf(L"\n");
  942. }
  943. }
  944. hr = S_OK;
  945. //error:
  946. if (NULL != rgpwszval)
  947. {
  948. ldap_value_free(rgpwszval);
  949. }
  950. return(hr);
  951. }
  952. BOOL
  953. isStringAttribute(
  954. berval **rgpberval)
  955. {
  956. BOOL fString = FALSE;
  957. DWORD i;
  958. DWORD cbTotal = 0;
  959. for (i = 0; NULL != rgpberval[i]; i++)
  960. {
  961. BYTE const *pb = (BYTE const *) rgpberval[i]->bv_val;
  962. DWORD cb = rgpberval[i]->bv_len;
  963. cbTotal += cb;
  964. if (0 < cb && '-' == *pb)
  965. {
  966. pb++;
  967. cb--;
  968. }
  969. while (0 < cb--)
  970. {
  971. if (('0' > *pb || '9' < *pb) && '.' != *pb)
  972. {
  973. goto error;
  974. }
  975. pb++;
  976. }
  977. }
  978. if (0 < cbTotal)
  979. {
  980. fString = TRUE;
  981. }
  982. error:
  983. return(fString);
  984. }
  985. HRESULT
  986. dumpDSBinaryAttribute(
  987. IN LDAP *pld,
  988. IN LDAPMessage *pres,
  989. IN DWORD dwFlags,
  990. IN WCHAR const *pwszAttrName,
  991. IN DSATTR const *pdsa)
  992. {
  993. HRESULT hr;
  994. berval **rgpberval = NULL;
  995. BOOL fNewLine = FALSE;
  996. BOOL fInfDump = 0 != (DSDF_INFDUMP & dwFlags);
  997. rgpberval = ldap_get_values_len(pld, pres, (WCHAR * const) pwszAttrName);
  998. if (NULL != rgpberval)
  999. {
  1000. BOOL fCompact;
  1001. DWORD i;
  1002. WCHAR const *pwszInfQuote = fInfDump? L"\"" : L"";
  1003. if (&s_DSAttrBinary == pdsa && isStringAttribute(rgpberval))
  1004. {
  1005. hr = dumpDSStringAttribute(
  1006. pld,
  1007. pres,
  1008. dwFlags,
  1009. pwszAttrName,
  1010. &s_DSAttrString);
  1011. _PrintIfError(hr, "dumpDSStringAttribute");
  1012. goto error;
  1013. }
  1014. fCompact = fInfDump ||
  1015. (1 >= g_fVerbose && (NULL == rgpberval[0] || NULL == rgpberval[1]));
  1016. if (!fCompact)
  1017. {
  1018. wprintf(L"%ws%ws\n", s_wszPad0, pwszAttrName);
  1019. }
  1020. for (i = 0; NULL != rgpberval[i]; i++)
  1021. {
  1022. BOOL fEmpty = ISEMPTYATTR(rgpberval[i]);
  1023. WCHAR const *pwszSep;
  1024. if (fCompact)
  1025. {
  1026. wprintf(L"%ws%ws", s_wszPad0, pwszAttrName);
  1027. pwszSep = L" = ";
  1028. }
  1029. else
  1030. {
  1031. wprintf(s_wszPad1);
  1032. wprintf(
  1033. myLoadResourceString(IDS_FORMAT_ELEMENT), // "Element %u:"
  1034. i);
  1035. wprintf(
  1036. L" %u %ws",
  1037. rgpberval[i]->bv_len,
  1038. myLoadResourceString(IDS_BYTES)); // "Bytes"
  1039. pwszSep = L" ";
  1040. }
  1041. if (fEmpty)
  1042. {
  1043. wprintf(
  1044. L"%ws%ws\n",
  1045. pwszSep,
  1046. fInfDump?
  1047. L"\"\"" :
  1048. myLoadResourceString(IDS_PROP_EMPTY)); // "EMPTY"
  1049. }
  1050. else
  1051. {
  1052. BOOL fHex = TRUE;
  1053. if (DSAF_ASN == pdsa->Flags)
  1054. {
  1055. if (!fInfDump)
  1056. {
  1057. BOOL fVerboseOld = g_fVerbose;
  1058. BYTE const *pb;
  1059. DWORD cb;
  1060. wprintf(wszNewLine);
  1061. CSASSERT(g_fVerbose);
  1062. g_fVerbose--;
  1063. g_fQuiet = !g_fVerbose;
  1064. if (g_fVerbose)
  1065. {
  1066. g_fVerbose--;
  1067. }
  1068. if (0 != pdsa->idMsg)
  1069. {
  1070. wprintf(
  1071. myLoadResourceString(pdsa->idMsg),
  1072. i);
  1073. wprintf(wszNewLine);
  1074. }
  1075. cb = rgpberval[i]->bv_len;
  1076. pb = (BYTE const *) rgpberval[i]->bv_val;
  1077. if (0 == cb ||
  1078. (1 == cb && (0 == *pb || ' ' == *pb)))
  1079. {
  1080. hr = S_FALSE;
  1081. }
  1082. else
  1083. {
  1084. if (SZARRAYSIZE(szPROPASNTAG) < cb &&
  1085. 0 == _strnicmp(
  1086. (char const *) pb,
  1087. szPROPASNTAG,
  1088. SZARRAYSIZE(szPROPASNTAG)))
  1089. {
  1090. pb += SZARRAYSIZE(szPROPASNTAG);
  1091. cb -= SZARRAYSIZE(szPROPASNTAG);
  1092. }
  1093. hr = cuDumpAsnBinary(pb, cb, MAXDWORD);
  1094. _PrintIfError(hr, "cuDumpAsnBinary");
  1095. }
  1096. if (S_OK == hr)
  1097. {
  1098. fHex = FALSE;
  1099. }
  1100. g_fVerbose = fVerboseOld;
  1101. fNewLine = TRUE;
  1102. }
  1103. }
  1104. else if (DSAF_FILETIME == pdsa->Flags)
  1105. {
  1106. FILETIME ft;
  1107. if (sizeof(ft) == rgpberval[i]->bv_len)
  1108. {
  1109. wprintf(pwszSep);
  1110. CopyMemory(&ft, rgpberval[i]->bv_val, sizeof(ft));
  1111. hr = cuDumpFileTimeOrPeriod(0, pwszInfQuote, &ft);
  1112. if (S_OK == hr)
  1113. {
  1114. fHex = FALSE;
  1115. }
  1116. }
  1117. }
  1118. else if (DSAF_EXTENSION == pdsa->Flags)
  1119. {
  1120. if (!fInfDump)
  1121. {
  1122. BOOL fQuietOld = g_fQuiet;
  1123. DWORD cb;
  1124. BYTE ab[MAX_PATH];
  1125. cb = pdsa->pExtension->cbTemplate;
  1126. CopyMemory(
  1127. ab,
  1128. pdsa->pExtension->pbTemplate,
  1129. cb);
  1130. CopyMemory(
  1131. &ab[cb],
  1132. rgpberval[i]->bv_val,
  1133. rgpberval[i]->bv_len);
  1134. ab[1] = (BYTE) (pdsa->pExtension->cbAdd + rgpberval[i]->bv_len);
  1135. cb += rgpberval[i]->bv_len;
  1136. wprintf(pwszSep);
  1137. g_fQuiet = TRUE;
  1138. if (!cuDumpFormattedExtension(
  1139. pdsa->pExtension->pwszObjId,
  1140. ab,
  1141. cb))
  1142. {
  1143. hr = myHLastError();
  1144. _PrintError(hr, "cuDumpFormattedExtension");
  1145. }
  1146. else
  1147. {
  1148. fHex = FALSE;
  1149. }
  1150. g_fQuiet = fQuietOld;
  1151. wprintf(wszNewLine);
  1152. }
  1153. }
  1154. else if (DSAF_GUID == pdsa->Flags)
  1155. {
  1156. if (sizeof(GUID) == rgpberval[i]->bv_len)
  1157. {
  1158. WCHAR *pwszGUID;
  1159. hr = myCLSIDToWsz(
  1160. (GUID *) rgpberval[i]->bv_val,
  1161. &pwszGUID);
  1162. _PrintIfError(hr, "myCLSIDToWsz");
  1163. if (S_OK == hr)
  1164. {
  1165. wprintf(
  1166. L"%ws%ws%ws%ws",
  1167. pwszSep,
  1168. pwszInfQuote,
  1169. pwszGUID,
  1170. pwszInfQuote);
  1171. LocalFree(pwszGUID);
  1172. fHex = FALSE;
  1173. }
  1174. }
  1175. wprintf(wszNewLine);
  1176. }
  1177. else
  1178. {
  1179. wprintf(wszNewLine);
  1180. }
  1181. if (fHex || 1 < g_fVerbose)
  1182. {
  1183. if (fInfDump)
  1184. {
  1185. BSTR strHex = NULL;
  1186. hr = MultiByteIntegerToBstr(
  1187. TRUE,
  1188. rgpberval[i]->bv_len,
  1189. (BYTE const *) rgpberval[i]->bv_val,
  1190. &strHex);
  1191. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  1192. wprintf(L"%ws\"%ws\"\n", pwszSep, strHex);
  1193. SysFreeString(strHex);
  1194. }
  1195. else
  1196. {
  1197. DumpHex(
  1198. DH_NOADDRESS | DH_NOTABPREFIX | 12,
  1199. (BYTE const *) rgpberval[i]->bv_val,
  1200. rgpberval[i]->bv_len);
  1201. }
  1202. }
  1203. }
  1204. }
  1205. }
  1206. if (fNewLine)
  1207. {
  1208. wprintf(wszNewLine);
  1209. }
  1210. hr = S_OK;
  1211. error:
  1212. if (NULL != rgpberval)
  1213. {
  1214. ldap_value_free_len(rgpberval);
  1215. }
  1216. return(hr);
  1217. }
  1218. HRESULT
  1219. dumpDSAttributes(
  1220. IN LDAP *pld,
  1221. IN LDAPMessage *pres,
  1222. IN DWORD dwFlags)
  1223. {
  1224. HRESULT hr;
  1225. WCHAR *pwszAttrName;
  1226. BerElement *pber = NULL;
  1227. for (pwszAttrName = ldap_first_attribute(pld, pres, &pber);
  1228. pwszAttrName != NULL;
  1229. pwszAttrName = ldap_next_attribute(pld, pres, pber))
  1230. {
  1231. DSATTR const *pdsa;
  1232. for (pdsa = s_aDSAttr; ; pdsa++)
  1233. {
  1234. if (pdsa >= &s_aDSAttr[ARRAYSIZE(s_aDSAttr)])
  1235. {
  1236. pdsa = &s_DSAttrBinary; // Unknown attribute
  1237. break;
  1238. }
  1239. if (0 == mylstrcmpiS(pwszAttrName, pdsa->pwszName))
  1240. {
  1241. break;
  1242. }
  1243. }
  1244. switch (pdsa->Flags)
  1245. {
  1246. case DSAF_ASNDATE:
  1247. case DSAF_STRING:
  1248. case DSAF_FLAGS:
  1249. hr = dumpDSStringAttribute(
  1250. pld,
  1251. pres,
  1252. dwFlags,
  1253. pwszAttrName,
  1254. pdsa);
  1255. _PrintIfError(hr, "dumpDSStringAttribute");
  1256. break;
  1257. case DSAF_GUID:
  1258. case DSAF_FILETIME:
  1259. case DSAF_EXTENSION:
  1260. case DSAF_BINARY:
  1261. case DSAF_ASN:
  1262. hr = dumpDSBinaryAttribute(
  1263. pld,
  1264. pres,
  1265. dwFlags,
  1266. pwszAttrName,
  1267. pdsa);
  1268. _PrintIfError(hr, "dumpDSBinaryAttribute");
  1269. break;
  1270. default:
  1271. CSASSERT(FALSE && pdsa->Flags);
  1272. break;
  1273. }
  1274. ldap_memfree(pwszAttrName);
  1275. pwszAttrName = NULL;
  1276. }
  1277. wprintf(L"\n");
  1278. hr = S_OK;
  1279. //error:
  1280. if (NULL != pber)
  1281. {
  1282. //ber_free(pber, 0);
  1283. }
  1284. return(hr);
  1285. }
  1286. HRESULT
  1287. AddCNList(
  1288. IN WCHAR const *pwszCN,
  1289. IN OUT WCHAR ***pppwsz)
  1290. {
  1291. HRESULT hr;
  1292. DWORD cpwsz = 0;
  1293. WCHAR **ppwsz = *pppwsz;
  1294. WCHAR **ppwszAlloc = NULL;
  1295. WCHAR *pwszDup = NULL;
  1296. hr = myDupString(pwszCN, &pwszDup);
  1297. _JumpIfError(hr, error, "myDupString");
  1298. if (NULL != ppwsz)
  1299. {
  1300. for ( ; NULL != ppwsz[cpwsz]; cpwsz++)
  1301. ;
  1302. }
  1303. if (NULL == ppwsz)
  1304. {
  1305. ppwszAlloc = (WCHAR **) LocalAlloc(
  1306. LMEM_FIXED,
  1307. 2 * sizeof(*ppwszAlloc));
  1308. }
  1309. else
  1310. {
  1311. ppwszAlloc = (WCHAR **) LocalReAlloc(
  1312. ppwsz,
  1313. (cpwsz + 2) * sizeof(*ppwszAlloc),
  1314. LMEM_MOVEABLE | LMEM_ZEROINIT);
  1315. }
  1316. if (NULL == ppwszAlloc)
  1317. {
  1318. hr = E_OUTOFMEMORY;
  1319. _JumpError(
  1320. hr,
  1321. error,
  1322. NULL == ppwsz? "LocalAlloc" : "LocalReAlloc");
  1323. }
  1324. ppwszAlloc[cpwsz] = pwszDup;
  1325. ppwszAlloc[cpwsz + 1] = NULL;
  1326. pwszDup = NULL;
  1327. *pppwsz = ppwszAlloc;
  1328. hr = S_OK;
  1329. error:
  1330. if (NULL != pwszDup)
  1331. {
  1332. LocalFree(pwszDup);
  1333. }
  1334. return(hr);
  1335. }
  1336. HRESULT
  1337. dumpDSDNs(
  1338. IN LDAP *pld,
  1339. IN DWORD dwFlags,
  1340. IN WCHAR const *pwszAlternateCNAttribute,
  1341. IN WCHAR const *pwszCNMatch,
  1342. IN WCHAR const *pwszRDN,
  1343. OPTIONAL IN WCHAR const *pwszContainer,
  1344. OPTIONAL OUT WCHAR ***pppwsz)
  1345. {
  1346. HRESULT hr;
  1347. WCHAR *pwszDNAlloc = NULL;
  1348. WCHAR const *pwszDN;
  1349. DWORD cwc;
  1350. DWORD cres;
  1351. LDAP_TIMEVAL timeval;
  1352. LDAPMessage *pmsg = NULL;
  1353. LDAPMessage *pres;
  1354. WCHAR *pwszOIDCN = NULL;
  1355. WCHAR *pwszAlternateCN = NULL;
  1356. WCHAR *pwszDisplayName = NULL;
  1357. WCHAR *pwszRevertCN = NULL;
  1358. BOOL fFirst = TRUE;
  1359. WCHAR **ppwszLdapVal = NULL;
  1360. if (NULL != pppwsz)
  1361. {
  1362. *pppwsz = NULL;
  1363. }
  1364. if (NULL == pwszContainer)
  1365. {
  1366. pwszDN = pwszRDN;
  1367. }
  1368. else
  1369. {
  1370. hr = BuildDN(
  1371. pwszRDN,
  1372. pwszContainer,
  1373. 0 != (DSDF_ADDCNEQUALS & dwFlags),
  1374. &pwszDNAlloc);
  1375. _JumpIfError(hr, error, "BuildDN");
  1376. pwszDN = pwszDNAlloc;
  1377. }
  1378. if (NULL != pwszCNMatch && iswdigit(*pwszCNMatch))
  1379. {
  1380. hr = myOIDHashOIDToString(pwszCNMatch, &pwszOIDCN);
  1381. //_PrintIfError2(hr, "myOIDHashOIDToString", hr);
  1382. _PrintIfError2(hr, "myOIDHashOIDToString", E_INVALIDARG);
  1383. }
  1384. timeval.tv_sec = csecLDAPTIMEOUT;
  1385. timeval.tv_usec = 0;
  1386. hr = ldap_search_st(
  1387. pld, // ld
  1388. const_cast<WCHAR *>(pwszDN), // base
  1389. (DSDF_BASE & dwFlags)? LDAP_SCOPE_BASE : LDAP_SCOPE_ONELEVEL,
  1390. NULL, // filter
  1391. NULL, // attrs
  1392. FALSE, // attrsonly
  1393. &timeval, // timeout
  1394. &pmsg); // res
  1395. if (S_OK != hr)
  1396. {
  1397. hr = myHLdapError2(pld, hr, LDAP_NO_SUCH_OBJECT, NULL);
  1398. _JumpErrorStr2(
  1399. hr,
  1400. error,
  1401. "ldap_search_st",
  1402. pwszDN,
  1403. HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND));
  1404. }
  1405. cres = ldap_count_entries(pld, pmsg);
  1406. if (0 == cres)
  1407. {
  1408. // No entries were found.
  1409. goto error;
  1410. }
  1411. for (pres = ldap_first_entry(pld, pmsg);
  1412. NULL != pres;
  1413. pres = ldap_next_entry(pld, pres))
  1414. {
  1415. if (NULL != pwszDisplayName)
  1416. {
  1417. LocalFree(pwszDisplayName);
  1418. pwszDisplayName = NULL;
  1419. }
  1420. if (NULL != pwszAlternateCN)
  1421. {
  1422. LocalFree(pwszAlternateCN);
  1423. pwszAlternateCN = NULL;
  1424. }
  1425. if (NULL != pwszRevertCN)
  1426. {
  1427. LocalFree(pwszRevertCN);
  1428. pwszRevertCN = NULL;
  1429. }
  1430. CSASSERT(NULL == ppwszLdapVal);
  1431. ppwszLdapVal = ldap_get_values(pld, pres, CA_PROP_DISPLAY_NAME);
  1432. if (NULL != ppwszLdapVal)
  1433. {
  1434. if (NULL != ppwszLdapVal[0])
  1435. {
  1436. hr = myDupString(ppwszLdapVal[0], &pwszDisplayName);
  1437. _JumpIfError(hr, error, "myDupString");
  1438. }
  1439. ldap_value_free(ppwszLdapVal);
  1440. ppwszLdapVal = NULL;
  1441. }
  1442. CSASSERT(NULL == ppwszLdapVal);
  1443. if (NULL != pwszAlternateCNAttribute)
  1444. {
  1445. ppwszLdapVal = ldap_get_values(
  1446. pld,
  1447. pres,
  1448. const_cast<WCHAR *>(pwszAlternateCNAttribute));
  1449. if (NULL != ppwszLdapVal)
  1450. {
  1451. if (NULL != ppwszLdapVal[0])
  1452. {
  1453. hr = myDupString(ppwszLdapVal[0], &pwszAlternateCN);
  1454. _JumpIfError(hr, error, "myDupString");
  1455. }
  1456. ldap_value_free(ppwszLdapVal);
  1457. ppwszLdapVal = NULL;
  1458. }
  1459. }
  1460. CSASSERT(NULL == ppwszLdapVal);
  1461. ppwszLdapVal = ldap_get_values(pld, pres, CERTTYPE_PROP_CN);
  1462. if (NULL != ppwszLdapVal)
  1463. {
  1464. if (NULL != ppwszLdapVal[0])
  1465. {
  1466. hr = myRevertSanitizeName(ppwszLdapVal[0], &pwszRevertCN);
  1467. _JumpIfError(hr, error, "myRevertSanitizeName");
  1468. if (CACNMatches(
  1469. pwszCNMatch,
  1470. pwszOIDCN,
  1471. pwszRevertCN,
  1472. ppwszLdapVal[0],
  1473. pwszDisplayName,
  1474. pwszAlternateCN))
  1475. {
  1476. if (NULL != pppwsz)
  1477. {
  1478. hr = AddCNList(ppwszLdapVal[0], pppwsz);
  1479. _JumpIfError(hr, error, "AddCNList");
  1480. }
  1481. if (DSDF_INFDUMP & dwFlags)
  1482. {
  1483. wprintf(L"\n[%ws]\n", ppwszLdapVal[0]);
  1484. }
  1485. else
  1486. {
  1487. if (fFirst)
  1488. {
  1489. wprintf(L"%ws:\n", pwszDN);
  1490. }
  1491. wprintf(
  1492. L" %ws%ws%ws",
  1493. (DSDF_DELETE & dwFlags)?
  1494. myLoadResourceString(IDS_DELETING) : // "Deleting"
  1495. L"",
  1496. (DSDF_DELETE & dwFlags)? L" " : L"",
  1497. pwszRevertCN);
  1498. if (0 != mylstrcmpiL(pwszRevertCN, ppwszLdapVal[0]))
  1499. {
  1500. wprintf(L" -- %ws", ppwszLdapVal[0]);
  1501. }
  1502. wprintf(L"\n");
  1503. if (!g_fVerbose &&
  1504. NULL != pwszAlternateCN &&
  1505. 0 != mylstrcmpiL(pwszRevertCN, pwszAlternateCN))
  1506. {
  1507. wprintf(L" %ws\n", pwszAlternateCN);
  1508. }
  1509. if (!g_fVerbose &&
  1510. NULL != pwszDisplayName &&
  1511. 0 != mylstrcmpiL(pwszRevertCN, pwszDisplayName))
  1512. {
  1513. wprintf(L" %ws\n", pwszDisplayName);
  1514. }
  1515. }
  1516. if (DSDF_DELETE & dwFlags)
  1517. {
  1518. DeleteDN(
  1519. pld,
  1520. (DSDF_BASE & dwFlags)? NULL : ppwszLdapVal[0],
  1521. pwszDN);
  1522. }
  1523. else if (g_fVerbose || (DSDF_INFDUMP & dwFlags))
  1524. {
  1525. dumpDSAttributes(pld, pres, dwFlags);
  1526. }
  1527. fFirst = FALSE;
  1528. }
  1529. }
  1530. ldap_value_free(ppwszLdapVal);
  1531. ppwszLdapVal = NULL;
  1532. }
  1533. }
  1534. if (!fFirst)
  1535. {
  1536. wprintf(wszNewLine);
  1537. }
  1538. if (DSDF_RECURSEONELEVEL & dwFlags)
  1539. {
  1540. for (pres = ldap_first_entry(pld, pmsg);
  1541. NULL != pres;
  1542. pres = ldap_next_entry(pld, pres))
  1543. {
  1544. CSASSERT(NULL == ppwszLdapVal);
  1545. ppwszLdapVal = ldap_get_values(pld, pres, CERTTYPE_PROP_CN);
  1546. if (NULL != ppwszLdapVal)
  1547. {
  1548. if (NULL != ppwszLdapVal[0])
  1549. {
  1550. hr = dumpDSDNs(
  1551. pld,
  1552. DSDF_ADDCNEQUALS |
  1553. (~DSDF_RECURSEONELEVEL & dwFlags),
  1554. pwszAlternateCNAttribute,
  1555. pwszCNMatch,
  1556. ppwszLdapVal[0],
  1557. pwszDN,
  1558. NULL);
  1559. _PrintIfError(hr, "dumpDSDNs");
  1560. }
  1561. ldap_value_free(ppwszLdapVal);
  1562. ppwszLdapVal = NULL;
  1563. }
  1564. }
  1565. }
  1566. error:
  1567. if (NULL != ppwszLdapVal)
  1568. {
  1569. ldap_value_free(ppwszLdapVal);
  1570. }
  1571. if (NULL != pmsg)
  1572. {
  1573. ldap_msgfree(pmsg);
  1574. }
  1575. if (NULL != pwszOIDCN)
  1576. {
  1577. LocalFree(pwszOIDCN);
  1578. }
  1579. if (NULL != pwszDisplayName)
  1580. {
  1581. LocalFree(pwszDisplayName);
  1582. }
  1583. if (NULL != pwszAlternateCN)
  1584. {
  1585. LocalFree(pwszAlternateCN);
  1586. }
  1587. if (NULL != pwszRevertCN)
  1588. {
  1589. LocalFree(pwszRevertCN);
  1590. }
  1591. if (NULL != pwszDNAlloc)
  1592. {
  1593. LocalFree(pwszDNAlloc);
  1594. }
  1595. return(hr);
  1596. }
  1597. HRESULT
  1598. DumpOrDeleteFromDS(
  1599. OPTIONAL IN WCHAR const *pwszCN,
  1600. IN BOOL fDelete)
  1601. {
  1602. HRESULT hr;
  1603. BSTR strDomainDN = NULL;
  1604. BSTR strConfigDN = NULL;
  1605. LDAP *pld = NULL;
  1606. DSDN *pDSDN;
  1607. BOOL fFullDN = FALSE;
  1608. WCHAR awcType[4]; // for "CN=\0"
  1609. hr = myLdapOpen(g_pwszDC, 0, &pld, &strDomainDN, &strConfigDN);
  1610. _JumpIfError(hr, error, "myLdapOpen");
  1611. if (NULL != pwszCN && ARRAYSIZE(awcType) - 1 <= wcslen(pwszCN))
  1612. {
  1613. CopyMemory(awcType, pwszCN, sizeof(awcType) - sizeof(WCHAR));
  1614. awcType[ARRAYSIZE(awcType) - 1] = L'\0';
  1615. if (0 == LSTRCMPIS(awcType, L"CN="))
  1616. {
  1617. dumpDSDNs(
  1618. pld,
  1619. DSDF_BASE | (fDelete? DSDF_DELETE : 0),
  1620. NULL,
  1621. NULL,
  1622. pwszCN,
  1623. NULL,
  1624. NULL);
  1625. fFullDN = TRUE;
  1626. }
  1627. }
  1628. if (!fFullDN)
  1629. {
  1630. for (pDSDN = s_aDSDN; pDSDN < &s_aDSDN[ARRAYSIZE(s_aDSDN)]; pDSDN++)
  1631. {
  1632. DWORD dwFlags = (DSDF_TYPEMASK | DSDF_RECURSEONELEVEL) & pDSDN->Flags;
  1633. if (fDelete)
  1634. {
  1635. dwFlags |= DSDF_DELETE;
  1636. }
  1637. if (NULL == pDSDN->pwszChild || !fDelete)
  1638. {
  1639. dumpDSDNs(
  1640. pld,
  1641. dwFlags,
  1642. pDSDN->pwszAlternateCNAttribute,
  1643. NULL != pwszCN? pwszCN : pDSDN->pwszChild,
  1644. pDSDN->pwszCN,
  1645. (DSDF_DOMAINDN & pDSDN->Flags)? strDomainDN : strConfigDN,
  1646. NULL);
  1647. }
  1648. }
  1649. }
  1650. error:
  1651. myLdapClose(pld, strDomainDN, strConfigDN);
  1652. return(hr);
  1653. }
  1654. HRESULT
  1655. verbDS(
  1656. IN WCHAR const *pwszOption,
  1657. OPTIONAL IN WCHAR const *pwszCN,
  1658. IN WCHAR const *pwszArg2,
  1659. IN WCHAR const *pwszArg3,
  1660. IN WCHAR const *pwszArg4)
  1661. {
  1662. HRESULT hr;
  1663. hr = DumpOrDeleteFromDS(pwszCN, FALSE);
  1664. _JumpIfError(hr, error, "DumpOrDeleteFromDS");
  1665. error:
  1666. return(hr);
  1667. }
  1668. HRESULT
  1669. verbDSDel(
  1670. IN WCHAR const *pwszOption,
  1671. IN WCHAR const *pwszCN,
  1672. IN WCHAR const *pwszArg2,
  1673. IN WCHAR const *pwszArg3,
  1674. IN WCHAR const *pwszArg4)
  1675. {
  1676. HRESULT hr;
  1677. CSASSERT(NULL != pwszCN);
  1678. hr = DumpOrDeleteFromDS(pwszCN, TRUE);
  1679. _JumpIfError(hr, error, "DumpOrDeleteFromDS");
  1680. error:
  1681. return(hr);
  1682. }
  1683. #define wszINFSECTION_TEMPLATELIST L"TemplateList"
  1684. #define wszINFKEY_TEMPLATE L"Template"
  1685. HRESULT
  1686. verbDSTemplate(
  1687. IN WCHAR const *pwszOption,
  1688. IN WCHAR const *pwszTemplate,
  1689. IN WCHAR const *pwszArg2,
  1690. IN WCHAR const *pwszArg3,
  1691. IN WCHAR const *pwszArg4)
  1692. {
  1693. HRESULT hr;
  1694. BSTR strDomainDN = NULL;
  1695. BSTR strConfigDN = NULL;
  1696. LDAP *pld = NULL;
  1697. WCHAR **ppwszTemplates = NULL;
  1698. WCHAR **ppwsz;
  1699. hr = myLdapOpen(g_pwszDC, 0, &pld, &strDomainDN, &strConfigDN);
  1700. _JumpIfError(hr, error, "myLdapOpen");
  1701. wprintf(
  1702. L"[Version]\n"
  1703. L"Signature = \"$Windows NT$\"\n"
  1704. L"\n");
  1705. dumpDSDNs(
  1706. pld,
  1707. DSDF_TEMPLATE | DSDF_INFDUMP,
  1708. CERTTYPE_PROP_OID,
  1709. pwszTemplate,
  1710. g_wszCNTemplates,
  1711. strConfigDN,
  1712. &ppwszTemplates);
  1713. if (NULL != ppwszTemplates)
  1714. {
  1715. wprintf(L"[%ws]\n", wszINFSECTION_TEMPLATELIST);
  1716. for (ppwsz = ppwszTemplates; NULL != *ppwsz; ppwsz++)
  1717. {
  1718. wprintf(L" %ws = \"%ws\"\n", wszINFKEY_TEMPLATE, *ppwsz);
  1719. }
  1720. }
  1721. error:
  1722. if (NULL != ppwszTemplates)
  1723. {
  1724. for (ppwsz = ppwszTemplates; NULL != *ppwsz; ppwsz++)
  1725. {
  1726. LocalFree(*ppwsz);
  1727. }
  1728. LocalFree(ppwszTemplates);
  1729. }
  1730. myLdapClose(pld, strDomainDN, strConfigDN);
  1731. return(hr);
  1732. }
  1733. typedef struct _CTFLAGS {
  1734. DWORD dwOption;
  1735. WCHAR const *pwszLookupName;
  1736. WCHAR const *pwszPropName;
  1737. } CTFLAGS;
  1738. // The last entry has a prefix added to distinguish the name enough to display
  1739. // the correct symbolic names for its bit fields. "flags" is too generic.
  1740. CTFLAGS g_actf[] = {
  1741. {
  1742. CERTTYPE_ENROLLMENT_FLAG,
  1743. CERTTYPE_RPOP_ENROLLMENT_FLAG,
  1744. CERTTYPE_RPOP_ENROLLMENT_FLAG,
  1745. },
  1746. {
  1747. CERTTYPE_SUBJECT_NAME_FLAG,
  1748. CERTTYPE_PROP_NAME_FLAG,
  1749. CERTTYPE_PROP_NAME_FLAG,
  1750. },
  1751. {
  1752. CERTTYPE_PRIVATE_KEY_FLAG,
  1753. CERTTYPE_PROP_PRIVATE_KEY_FLAG,
  1754. CERTTYPE_PROP_PRIVATE_KEY_FLAG,
  1755. },
  1756. {
  1757. CERTTYPE_GENERAL_FLAG,
  1758. wszCUREGDSTEMPLATEFLAGS,
  1759. CERTTYPE_PROP_FLAGS,
  1760. },
  1761. };
  1762. typedef struct _CTPROP {
  1763. BOOL fString;
  1764. WCHAR const *pwszPropName;
  1765. } CTPROP;
  1766. CTPROP g_actProp[] = {
  1767. { TRUE, CERTTYPE_PROP_CN, },
  1768. { TRUE, CERTTYPE_PROP_DN, },
  1769. { TRUE, CERTTYPE_PROP_FRIENDLY_NAME, },
  1770. { TRUE, CERTTYPE_PROP_EXTENDED_KEY_USAGE, },
  1771. { TRUE, CERTTYPE_PROP_CSP_LIST, },
  1772. { TRUE, CERTTYPE_PROP_CRITICAL_EXTENSIONS, },
  1773. { FALSE, CERTTYPE_PROP_REVISION, },
  1774. { FALSE, CERTTYPE_PROP_SCHEMA_VERSION, },
  1775. { FALSE, CERTTYPE_PROP_MINOR_REVISION, },
  1776. { FALSE, CERTTYPE_PROP_RA_SIGNATURE, },
  1777. { FALSE, CERTTYPE_PROP_MIN_KEY_SIZE, },
  1778. { TRUE, CERTTYPE_PROP_OID, },
  1779. { TRUE, CERTTYPE_PROP_SUPERSEDE, },
  1780. { TRUE, CERTTYPE_PROP_RA_POLICY, },
  1781. { TRUE, CERTTYPE_PROP_RA_APPLICATION_POLICY, },
  1782. { TRUE, CERTTYPE_PROP_POLICY, },
  1783. { TRUE, CERTTYPE_PROP_APPLICATION_POLICY, },
  1784. };
  1785. # if 0
  1786. BYTE ab0[sizeof(FILETIME)] =
  1787. { 0x00, 0x80, 0x37, 0xae, 0xff, 0xf4, 0xff, 0xff }; // 2 Weeks
  1788. BYTE ab1[sizeof(FILETIME)] =
  1789. { 0x00, 0x40, 0x39, 0x87, 0x2e, 0xe1, 0xfe, 0xff }; // 1 Years
  1790. BYTE ab2[sizeof(FILETIME)] =
  1791. { 0x00, 0x80, 0x72, 0x0e, 0x5d, 0xc2, 0xfd, 0xff }; // 2 Years
  1792. BYTE ab3[sizeof(FILETIME)] =
  1793. { 0x00, 0x40, 0x1e, 0xa4, 0xe8, 0x65, 0xfa, 0xff }; // 5 Years
  1794. void
  1795. dumpConstantValidityPeriod(
  1796. FILETIME const *pft)
  1797. {
  1798. if (1 < g_fVerbose)
  1799. {
  1800. wprintf(wszNewLine);
  1801. cuDumpFileTimeOrPeriod(0, NULL, pft);
  1802. DumpHex(
  1803. DH_NOADDRESS | DH_NOASCIIHEX | DH_NOTABPREFIX | 4,
  1804. (BYTE const *) pft,
  1805. sizeof(*pft));
  1806. wprintf(wszNewLine);
  1807. }
  1808. }
  1809. void
  1810. dumpConstantValidityPeriods()
  1811. {
  1812. dumpConstantValidityPeriod((FILETIME const *) ab0);
  1813. dumpConstantValidityPeriod((FILETIME const *) ab1);
  1814. dumpConstantValidityPeriod((FILETIME const *) ab2);
  1815. dumpConstantValidityPeriod((FILETIME const *) ab3);
  1816. }
  1817. #endif
  1818. HRESULT
  1819. dsDumpTemplateInfo(
  1820. IN HCERTTYPE hCertType)
  1821. {
  1822. HRESULT hr;
  1823. DWORD i;
  1824. DWORD j;
  1825. DWORD dwValue;
  1826. DWORD dwKeySpec;
  1827. FILETIME ftExpiration;
  1828. FILETIME ftOverlap;
  1829. CERT_EXTENSIONS *pCertExtensions;
  1830. for (i = 0; i < ARRAYSIZE(g_actf); i++)
  1831. {
  1832. hr = CAGetCertTypeFlagsEx(hCertType, g_actf[i].dwOption, &dwValue);
  1833. if (S_OK != hr)
  1834. {
  1835. _PrintError(hr, "CAGetCertTypeFlagsEx");
  1836. }
  1837. else
  1838. {
  1839. cuRegPrintDwordValue(
  1840. TRUE,
  1841. g_actf[i].pwszLookupName,
  1842. g_actf[i].pwszPropName,
  1843. dwValue);
  1844. }
  1845. }
  1846. for (i = 0; i < ARRAYSIZE(g_actProp); i++)
  1847. {
  1848. WCHAR **rgpwszPropValues;
  1849. hr = CAGetCertTypePropertyEx(
  1850. hCertType,
  1851. g_actProp[i].pwszPropName,
  1852. g_actProp[i].fString?
  1853. (VOID *) &rgpwszPropValues : &dwValue);
  1854. if (S_OK != hr)
  1855. {
  1856. _PrintError(hr, "CAGetCertTypePropertyEx");
  1857. }
  1858. else
  1859. {
  1860. if (g_actProp[i].fString)
  1861. {
  1862. cuRegPrintAwszValue(
  1863. g_actProp[i].pwszPropName,
  1864. rgpwszPropValues);
  1865. CAFreeCertTypeProperty(hCertType, rgpwszPropValues);
  1866. }
  1867. else
  1868. {
  1869. cuRegPrintDwordValue(
  1870. TRUE,
  1871. g_actProp[i].pwszPropName,
  1872. g_actProp[i].pwszPropName,
  1873. dwValue);
  1874. }
  1875. }
  1876. }
  1877. hr = CAGetCertTypeKeySpec(hCertType, &dwKeySpec);
  1878. if (S_OK != hr)
  1879. {
  1880. _PrintError(hr, "CAGetCertTypeKeySpec");
  1881. }
  1882. else
  1883. {
  1884. WCHAR const *pwsz = NULL;
  1885. switch (dwKeySpec)
  1886. {
  1887. case AT_SIGNATURE: pwsz = L"AT_SIGNATURE"; break;
  1888. case AT_KEYEXCHANGE: pwsz = L"AT_KEYEXCHANGE"; break;
  1889. }
  1890. if (NULL != pwsz)
  1891. {
  1892. wprintf(L" dwKeySpec = %ws\n", pwsz);
  1893. }
  1894. }
  1895. hr = CAGetCertTypeExpiration(hCertType, &ftExpiration, &ftOverlap);
  1896. if (S_OK != hr)
  1897. {
  1898. _PrintError(hr, "CAGetCertTypeExpiration");
  1899. }
  1900. else
  1901. {
  1902. wprintf(L" " CERTTYPE_PROP_EXPIRATION L" = ");
  1903. cuDumpFileTimeOrPeriod(0, NULL, &ftExpiration);
  1904. if (g_fVerbose)
  1905. {
  1906. DumpHex(
  1907. DH_NOADDRESS | DH_NOASCIIHEX | DH_NOTABPREFIX | 8,
  1908. (BYTE const *) &ftExpiration,
  1909. sizeof(ftExpiration));
  1910. }
  1911. wprintf(L" " CERTTYPE_PROP_OVERLAP L" = ");
  1912. cuDumpFileTimeOrPeriod(0, NULL, &ftOverlap);
  1913. if (g_fVerbose)
  1914. {
  1915. DumpHex(
  1916. DH_NOADDRESS | DH_NOASCIIHEX | DH_NOTABPREFIX | 8,
  1917. (BYTE const *) &ftOverlap,
  1918. sizeof(ftOverlap));
  1919. }
  1920. }
  1921. hr = CAGetCertTypeExtensions(hCertType, &pCertExtensions);
  1922. if (S_OK != hr)
  1923. {
  1924. _PrintError(hr, "CAGetCertTypeExtensions");
  1925. }
  1926. else
  1927. {
  1928. wprintf(wszNewLine);
  1929. hr = cuDumpExtensionArray(
  1930. IDS_TEMPLATE_EXTENSIONS,
  1931. pCertExtensions->cExtension,
  1932. pCertExtensions->rgExtension);
  1933. _PrintIfError(hr, "cuDumpExtensionArray");
  1934. CAFreeCertTypeExtensions(hCertType, pCertExtensions);
  1935. }
  1936. hr = S_OK;
  1937. //error:
  1938. return(hr);
  1939. }
  1940. HRESULT
  1941. dsDumpTemplate(
  1942. OPTIONAL IN HCAINFO hCAInfo,
  1943. OPTIONAL IN WCHAR const *pwszTemplate,
  1944. OPTIONAL OUT WCHAR **ppwszTemplate)
  1945. {
  1946. HRESULT hr;
  1947. BOOL fFound = FALSE;
  1948. WCHAR const *pwszDisplayName = NULL;
  1949. HCERTTYPE hCertType = NULL;
  1950. DWORD dwFlags = 0;
  1951. WCHAR **apwszCertTypeName = NULL;
  1952. WCHAR **apwszCertTypeCN = NULL;
  1953. if (NULL != ppwszTemplate)
  1954. {
  1955. *ppwszTemplate = NULL;
  1956. }
  1957. if (!g_fUserTemplates && !g_fMachineTemplates)
  1958. {
  1959. g_fUserTemplates = TRUE;
  1960. g_fMachineTemplates = TRUE;
  1961. }
  1962. if (g_fUserTemplates)
  1963. {
  1964. dwFlags |= CT_ENUM_USER_TYPES;
  1965. }
  1966. if (g_fMachineTemplates)
  1967. {
  1968. dwFlags |= CT_ENUM_MACHINE_TYPES;
  1969. }
  1970. if (!g_fUserRegistry)
  1971. {
  1972. dwFlags |= CT_FIND_LOCAL_SYSTEM;
  1973. }
  1974. if (g_fForce)
  1975. {
  1976. dwFlags |= CT_FLAG_NO_CACHE_LOOKUP;
  1977. }
  1978. if (NULL != pwszTemplate)
  1979. {
  1980. hr = CAFindCertTypeByName(pwszTemplate, hCAInfo, dwFlags, &hCertType);
  1981. if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == hr)
  1982. {
  1983. hr = CAFindCertTypeByName(
  1984. pwszTemplate,
  1985. hCAInfo,
  1986. CT_FIND_BY_OID | dwFlags,
  1987. &hCertType);
  1988. }
  1989. if (S_OK != hr)
  1990. {
  1991. _PrintErrorStr2(
  1992. hr,
  1993. "CAFindCertTypeByName",
  1994. pwszTemplate,
  1995. HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
  1996. pwszDisplayName = pwszTemplate;
  1997. }
  1998. else
  1999. {
  2000. fFound = TRUE;
  2001. }
  2002. }
  2003. if (NULL == pwszTemplate || NULL != pwszDisplayName)
  2004. {
  2005. if (NULL != hCAInfo)
  2006. {
  2007. hr = CAEnumCertTypesForCA(hCAInfo, dwFlags, &hCertType);
  2008. _JumpIfError(hr, error, "CAEnumCertTypesForCA");
  2009. if (NULL == hCertType)
  2010. {
  2011. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  2012. _JumpError(hr, error, "CAEnumCertTypesForCA");
  2013. }
  2014. }
  2015. else
  2016. {
  2017. hr = CAEnumCertTypes(dwFlags, &hCertType);
  2018. _JumpIfError(hr, error, "CAEnumCertTypes");
  2019. if (NULL == hCertType)
  2020. {
  2021. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  2022. _JumpError(hr, error, "CAEnumCertTypes");
  2023. }
  2024. }
  2025. }
  2026. while (TRUE)
  2027. {
  2028. HCERTTYPE hCertTypeNext;
  2029. WCHAR const *pwszError = NULL;
  2030. hr = CAGetCertTypeProperty(
  2031. hCertType,
  2032. CERTTYPE_PROP_FRIENDLY_NAME,
  2033. &apwszCertTypeName);
  2034. _JumpIfError(hr, error, "CAGetCertTypeProperty");
  2035. hr = CAGetCertTypeProperty(
  2036. hCertType,
  2037. CERTTYPE_PROP_CN,
  2038. &apwszCertTypeCN);
  2039. _JumpIfError(hr, error, "CAGetCertTypeProperty");
  2040. if (NULL != pwszDisplayName &&
  2041. (0 == mylstrcmpiL(pwszDisplayName, apwszCertTypeName[0]) ||
  2042. 0 == mylstrcmpiL(pwszDisplayName, apwszCertTypeCN[0])))
  2043. {
  2044. fFound = TRUE;
  2045. if (NULL != ppwszTemplate)
  2046. {
  2047. hr = myDupString(apwszCertTypeCN[0], ppwszTemplate);
  2048. _JumpIfError(hr, error, "myDupString");
  2049. break;
  2050. }
  2051. }
  2052. if (NULL == ppwszTemplate && (fFound || NULL == pwszDisplayName))
  2053. {
  2054. hr = CACertTypeAccessCheck(hCertType, NULL);
  2055. if (S_OK != hr)
  2056. {
  2057. pwszError = myGetErrorMessageText(hr, FALSE);
  2058. }
  2059. wprintf(L"%ws: %ws", apwszCertTypeCN[0], apwszCertTypeName[0]);
  2060. if (NULL != pwszError)
  2061. {
  2062. wprintf(L" -- %ws", pwszError);
  2063. LocalFree(const_cast<WCHAR *>(pwszError));
  2064. }
  2065. wprintf(wszNewLine);
  2066. if (g_fVerbose)
  2067. {
  2068. BOOL fVerboseOld = g_fVerbose;
  2069. g_fVerbose--;
  2070. dsDumpTemplateInfo(hCertType);
  2071. g_fVerbose = fVerboseOld;
  2072. }
  2073. }
  2074. CAFreeCertTypeProperty(hCertType, apwszCertTypeName);
  2075. apwszCertTypeName = NULL;
  2076. CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
  2077. apwszCertTypeCN = NULL;
  2078. if (fFound)
  2079. {
  2080. break;
  2081. }
  2082. hr = CAEnumNextCertType(hCertType, &hCertTypeNext);
  2083. _JumpIfError(hr, error, "CAEnumNextCertType");
  2084. CACloseCertType(hCertType);
  2085. hCertType = hCertTypeNext;
  2086. if (NULL == hCertType)
  2087. {
  2088. break;
  2089. }
  2090. }
  2091. hr = S_OK;
  2092. error:
  2093. if (NULL != hCertType)
  2094. {
  2095. if (NULL != apwszCertTypeName)
  2096. {
  2097. CAFreeCertTypeProperty(hCertType, apwszCertTypeName);
  2098. }
  2099. if (NULL != apwszCertTypeCN)
  2100. {
  2101. CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
  2102. }
  2103. CACloseCertType(hCertType);
  2104. }
  2105. return(hr);
  2106. }
  2107. HRESULT
  2108. verbTemplate(
  2109. IN WCHAR const *pwszOption,
  2110. OPTIONAL IN WCHAR const *pwszTemplate,
  2111. IN WCHAR const *pwszArg2,
  2112. IN WCHAR const *pwszArg3,
  2113. IN WCHAR const *pwszArg4)
  2114. {
  2115. HRESULT hr;
  2116. hr = dsDumpTemplate(NULL, pwszTemplate, NULL);
  2117. _JumpIfError(hr, error, "dsDumpTemplate");
  2118. error:
  2119. return(hr);
  2120. }
  2121. int
  2122. dsCompareMachineNames(
  2123. IN WCHAR const *pwszServer,
  2124. IN WCHAR const *pwszDnsName)
  2125. {
  2126. HRESULT hr;
  2127. WCHAR const *pwsz;
  2128. WCHAR *pwszMachine = NULL;
  2129. int rc;
  2130. rc = mylstrcmpiL(pwszServer, pwszDnsName);
  2131. if (0 != rc)
  2132. {
  2133. pwsz = wcschr(pwszDnsName, '.');
  2134. if (NULL != pwsz)
  2135. {
  2136. DWORD cb;
  2137. cb = SAFE_SUBTRACT_POINTERS(pwsz, pwszDnsName) * sizeof(WCHAR);
  2138. pwszMachine = (WCHAR *) LocalAlloc(LMEM_FIXED, cb + sizeof(WCHAR));
  2139. if (NULL == pwszMachine)
  2140. {
  2141. _PrintError(E_OUTOFMEMORY, "LocalAlloc");
  2142. goto error;
  2143. }
  2144. CopyMemory(pwszMachine, pwszDnsName, cb);
  2145. pwszMachine[cb / sizeof(WCHAR)] = L'\0';
  2146. rc = mylstrcmpiL(pwszServer, pwszMachine);
  2147. }
  2148. }
  2149. error:
  2150. if (NULL != pwszMachine)
  2151. {
  2152. LocalFree(pwszMachine);
  2153. }
  2154. return(rc);
  2155. }
  2156. // Enumerate matching CAs
  2157. typedef HRESULT (FNENUMCA)(
  2158. IN HCAINFO hCAInfo,
  2159. IN OUT VOID *pvArgs);
  2160. HRESULT
  2161. dsEnumCA(
  2162. IN FNENUMCA *pfnEnumCA,
  2163. IN VOID *pvArgs)
  2164. {
  2165. HRESULT hr;
  2166. WCHAR *pwszCAName = NULL;
  2167. WCHAR *pwszServer = NULL;
  2168. WCHAR *pwszCANameRevert = NULL;
  2169. WCHAR *pwszCANameSanitized = NULL;
  2170. WCHAR *pwszCANameSanitizedDS = NULL;
  2171. HCAINFO hCAInfo = NULL;
  2172. DWORD dwFlags = CA_FIND_INCLUDE_NON_TEMPLATE_CA | CA_FIND_INCLUDE_UNTRUSTED;
  2173. WCHAR **apwszMachine = NULL;
  2174. BOOL fFound = FALSE;
  2175. hr = mySplitConfigString(g_pwszConfig, &pwszServer, &pwszCAName);
  2176. _JumpIfError(hr, error, "mySplitConfigString");
  2177. hr = myRevertSanitizeName(pwszCAName, &pwszCANameRevert);
  2178. _JumpIfError(hr, error, "myRevertSanitizeName");
  2179. hr = mySanitizeName(pwszCANameRevert, &pwszCANameSanitized);
  2180. _JumpIfError(hr, error, "mySanitizeName");
  2181. hr = mySanitizedNameToDSName(pwszCANameSanitized, &pwszCANameSanitizedDS);
  2182. _JumpIfError(hr, error, "mySanitizedNameToDSName");
  2183. if (!g_fUserRegistry)
  2184. {
  2185. dwFlags |= CA_FIND_LOCAL_SYSTEM;
  2186. }
  2187. if (NULL != g_pwszDC)
  2188. {
  2189. dwFlags |= CA_FLAG_SCOPE_DNS;
  2190. }
  2191. if (g_fForce)
  2192. {
  2193. dwFlags |= CT_FLAG_NO_CACHE_LOOKUP;
  2194. }
  2195. hr = CAFindByName(
  2196. pwszCANameSanitizedDS,
  2197. g_pwszDC, // wszScope
  2198. dwFlags,
  2199. &hCAInfo);
  2200. _JumpIfErrorStr(hr, error, "CAFindByName", pwszCAName);
  2201. while (TRUE)
  2202. {
  2203. HCAINFO hCAInfoNext;
  2204. hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &apwszMachine);
  2205. _JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_DNSNAME)");
  2206. if (0 == dsCompareMachineNames(pwszServer, apwszMachine[0]))
  2207. {
  2208. fFound = TRUE;
  2209. hr = (*pfnEnumCA)(hCAInfo, pvArgs);
  2210. _JumpIfError(hr, error, "*pfnEnumCA");
  2211. }
  2212. CAFreeCAProperty(hCAInfo, apwszMachine);
  2213. apwszMachine = NULL;
  2214. hr = CAEnumNextCA(hCAInfo, &hCAInfoNext);
  2215. _JumpIfError(hr, error, "CAEnumNextCA");
  2216. CACloseCA(hCAInfo);
  2217. hCAInfo = hCAInfoNext;
  2218. if (NULL == hCAInfo)
  2219. {
  2220. break;
  2221. }
  2222. }
  2223. if (!fFound)
  2224. {
  2225. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  2226. _JumpError(hr, error, "CAEnumNextCA");
  2227. }
  2228. hr = S_OK;
  2229. error:
  2230. if (NULL != apwszMachine)
  2231. {
  2232. CAFreeCAProperty(hCAInfo, apwszMachine);
  2233. }
  2234. if (NULL != hCAInfo)
  2235. {
  2236. CACloseCA(hCAInfo);
  2237. }
  2238. if (NULL != pwszServer)
  2239. {
  2240. LocalFree(pwszServer);
  2241. }
  2242. if (NULL != pwszCAName)
  2243. {
  2244. LocalFree(pwszCAName);
  2245. }
  2246. if (NULL != pwszCANameRevert)
  2247. {
  2248. LocalFree(pwszCANameRevert);
  2249. }
  2250. if (NULL != pwszCANameSanitized)
  2251. {
  2252. LocalFree(pwszCANameSanitized);
  2253. }
  2254. if (NULL != pwszCANameSanitizedDS)
  2255. {
  2256. LocalFree(pwszCANameSanitizedDS);
  2257. }
  2258. return(hr);
  2259. }
  2260. // Display Templates for specified CA
  2261. typedef struct _CATEMPLATESARGS {
  2262. OPTIONAL IN WCHAR const *pwszTemplate;
  2263. } CATEMPLATESARGS;
  2264. HRESULT
  2265. dsEnumCADumpTemplate(
  2266. IN HCAINFO hCAInfo,
  2267. IN OUT VOID *pvArgs)
  2268. {
  2269. HRESULT hr;
  2270. CATEMPLATESARGS *pArgs = (CATEMPLATESARGS *) pvArgs;
  2271. hr = dsDumpTemplate(hCAInfo, pArgs->pwszTemplate, NULL);
  2272. _JumpIfError(hr, error, "dsDumpTemplate");
  2273. error:
  2274. return(hr);
  2275. }
  2276. HRESULT
  2277. verbCATemplates(
  2278. IN WCHAR const *pwszOption,
  2279. OPTIONAL IN WCHAR const *pwszTemplate,
  2280. IN WCHAR const *pwszArg2,
  2281. IN WCHAR const *pwszArg3,
  2282. IN WCHAR const *pwszArg4)
  2283. {
  2284. HRESULT hr;
  2285. CATEMPLATESARGS Args;
  2286. Args.pwszTemplate = pwszTemplate;
  2287. hr = dsEnumCA(dsEnumCADumpTemplate, &Args);
  2288. _JumpIfError(hr, error, "dsEnumCA");
  2289. error:
  2290. return(hr);
  2291. }
  2292. // Set Templates for specified CA
  2293. typedef struct _CASETTEMPLATESARGS {
  2294. IN WCHAR const *pwszTemplateList;
  2295. } CASETTEMPLATESARGS;
  2296. #define SCTOP_SET 0
  2297. #define SCTOP_ADD 1
  2298. #define SCTOP_REMOVE 2
  2299. HRESULT
  2300. dsAddCATemplates(
  2301. IN HCAINFO hCAInfo,
  2302. IN DWORD Op,
  2303. IN WCHAR const * const *ppwszList)
  2304. {
  2305. HRESULT hr;
  2306. CTemplateList CATemplateList;
  2307. CTemplateListEnum CATemplateListEnum(CATemplateList);
  2308. BOOL fSkipCache = g_fForce;
  2309. BOOL fChanged = FALSE;
  2310. WCHAR const * const *ppwsz;
  2311. HCERTTYPE hCertType = NULL;
  2312. HCERTTYPE hCertTypeT;
  2313. WCHAR **apwszCertTypeCN = NULL;
  2314. WCHAR *pwszT = NULL;
  2315. hr = myRetrieveCATemplateList(hCAInfo, TRUE, CATemplateList);
  2316. _JumpIfError(hr, error, "myRetrieveCATemplateList");
  2317. CATemplateListEnum.Reset();
  2318. while (TRUE)
  2319. {
  2320. CTemplateInfo *pTemplateInfo;
  2321. pTemplateInfo = CATemplateListEnum.Next();
  2322. if (NULL == pTemplateInfo)
  2323. {
  2324. break;
  2325. }
  2326. hCertTypeT = pTemplateInfo->GetCertType();
  2327. if (NULL == hCertTypeT)
  2328. {
  2329. CSASSERT(NULL != pTemplateInfo->GetName());
  2330. hr = CAFindCertTypeByName(
  2331. pTemplateInfo->GetName(),
  2332. NULL,
  2333. CT_ENUM_MACHINE_TYPES |
  2334. CT_ENUM_USER_TYPES |
  2335. (fSkipCache? CT_FLAG_NO_CACHE_LOOKUP : 0),
  2336. &hCertType);
  2337. hCertTypeT = hCertType;
  2338. // continue on errors
  2339. _PrintIfErrorStr(
  2340. hr,
  2341. "CAFindCertTypeByName",
  2342. NULL != pTemplateInfo->GetName()?
  2343. pTemplateInfo->GetName() : pTemplateInfo->GetOID());
  2344. if (S_OK == hr)
  2345. {
  2346. fSkipCache = FALSE;
  2347. }
  2348. }
  2349. if (NULL != hCertTypeT)
  2350. {
  2351. if (SCTOP_SET == Op)
  2352. {
  2353. BOOL fFound;
  2354. fFound = FALSE;
  2355. for (ppwsz = ppwszList; NULL != *ppwsz; ppwsz++)
  2356. {
  2357. if (0 == mylstrcmpiL(*ppwsz, pTemplateInfo->GetName()) ||
  2358. 0 == lstrcmp(*ppwsz, pTemplateInfo->GetOID()))
  2359. {
  2360. fFound = TRUE;
  2361. break;
  2362. }
  2363. }
  2364. if (!fFound)
  2365. {
  2366. // can't reference pTemplateInfo after it's been removed
  2367. hr = myDupString(
  2368. NULL != pTemplateInfo->GetName()?
  2369. pTemplateInfo->GetName() :
  2370. pTemplateInfo->GetOID(),
  2371. &pwszT);
  2372. _JumpIfError(hr, error, "myDupString");
  2373. pTemplateInfo = NULL;
  2374. hr = myRemoveFromCATemplateList(
  2375. hCAInfo,
  2376. CATemplateList,
  2377. hCertTypeT);
  2378. _JumpIfError(hr, error, "myRemoveFromCATemplateList");
  2379. fChanged = TRUE;
  2380. wprintf(
  2381. L"%ws: %ws\n",
  2382. pwszT,
  2383. myLoadResourceString(IDS_REMOVING)); // "Removing"
  2384. LocalFree(pwszT);
  2385. pwszT = NULL;
  2386. CATemplateListEnum.Reset(); // start over to avoid faulting
  2387. }
  2388. }
  2389. if (NULL != hCertType)
  2390. {
  2391. CACloseCertType(hCertType);
  2392. hCertType = NULL;
  2393. }
  2394. }
  2395. }
  2396. if (fChanged)
  2397. {
  2398. wprintf(wszNewLine);
  2399. }
  2400. for (ppwsz = ppwszList; NULL != *ppwsz; ppwsz++)
  2401. {
  2402. UINT idmsg;
  2403. hr = CAFindCertTypeByName(
  2404. *ppwsz,
  2405. NULL,
  2406. CT_ENUM_MACHINE_TYPES |
  2407. CT_ENUM_USER_TYPES |
  2408. (fSkipCache? CT_FLAG_NO_CACHE_LOOKUP : 0),
  2409. &hCertType);
  2410. if (S_OK != hr)
  2411. {
  2412. _PrintErrorStr2(hr, "CAFindCertTypeByName", *ppwsz, hr);
  2413. hr = CAFindCertTypeByName(
  2414. *ppwsz,
  2415. NULL,
  2416. CT_ENUM_MACHINE_TYPES |
  2417. CT_ENUM_USER_TYPES |
  2418. CT_FIND_BY_OID |
  2419. (fSkipCache? CT_FLAG_NO_CACHE_LOOKUP : 0),
  2420. &hCertType);
  2421. if (S_OK != hr)
  2422. {
  2423. cuPrintAPIError(*ppwsz, hr);
  2424. _JumpErrorStr(hr, error, "CAFindCertTypeByName", *ppwsz);
  2425. }
  2426. }
  2427. fSkipCache = FALSE;
  2428. hCertTypeT = hCertType;
  2429. hr = CAGetCertTypeProperty(
  2430. hCertTypeT,
  2431. CERTTYPE_PROP_CN,
  2432. &apwszCertTypeCN);
  2433. _JumpIfErrorStr(hr, error, "CAGetCertTypeProperty", *ppwsz);
  2434. idmsg = 0;
  2435. if (SCTOP_REMOVE == Op)
  2436. {
  2437. if (CATemplateList.TemplateExistsOID(*ppwsz) ||
  2438. CATemplateList.TemplateExistsName(*ppwsz))
  2439. {
  2440. idmsg = IDS_REMOVING; // "Removing"
  2441. hr = myRemoveFromCATemplateList(
  2442. hCAInfo,
  2443. CATemplateList,
  2444. hCertTypeT);
  2445. _JumpIfError(hr, error, "myRemoveFromCATemplateList");
  2446. fChanged = TRUE;
  2447. }
  2448. else
  2449. {
  2450. idmsg = IDS_NOTPRESENT; // "Not present"
  2451. }
  2452. }
  2453. else
  2454. {
  2455. if (!CATemplateList.TemplateExistsOID(*ppwsz) &&
  2456. !CATemplateList.TemplateExistsName(*ppwsz))
  2457. {
  2458. idmsg = IDS_ADDING; // "Adding"
  2459. hr = myAddToCATemplateList(
  2460. hCAInfo,
  2461. CATemplateList,
  2462. hCertTypeT,
  2463. TRUE);
  2464. _JumpIfError(hr, error, "myAddToCATemplateList");
  2465. fChanged = TRUE;
  2466. }
  2467. else
  2468. {
  2469. idmsg = IDS_ALREADYPRESENT; // "Already present"
  2470. }
  2471. }
  2472. if (0 != idmsg)
  2473. {
  2474. hr = myVerifyObjId(*ppwsz);
  2475. if (S_OK == hr &&
  2476. NULL != apwszCertTypeCN &&
  2477. NULL != apwszCertTypeCN[0])
  2478. {
  2479. wprintf(L"%ws: ", apwszCertTypeCN[0]);
  2480. }
  2481. wprintf(L"%ws: %ws\n", *ppwsz, myLoadResourceString(idmsg));
  2482. }
  2483. if (NULL != apwszCertTypeCN)
  2484. {
  2485. CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
  2486. apwszCertTypeCN = NULL;
  2487. }
  2488. if (NULL != hCertType)
  2489. {
  2490. CACloseCertType(hCertType);
  2491. hCertType = NULL;
  2492. }
  2493. }
  2494. if (fChanged || g_fForce)
  2495. {
  2496. hr = myUpdateCATemplateListToCA(hCAInfo, CATemplateList);
  2497. _PrintIfError2(hr, "myUpdateCATemplateListToCA", hr);
  2498. if (S_OK != hr && g_fForce)
  2499. {
  2500. // if failed to update through the CA for any reason, try writing
  2501. // directly to DS
  2502. hr = myUpdateCATemplateListToDS(hCAInfo);
  2503. _JumpIfError(hr, error, "myUpdateCATemplateListToDS");
  2504. }
  2505. _JumpIfError(hr, error, "myUpdateCATemplateListToCA");
  2506. }
  2507. hr = S_OK;
  2508. error:
  2509. if (NULL != pwszT)
  2510. {
  2511. LocalFree(pwszT);
  2512. }
  2513. if (NULL != hCertType)
  2514. {
  2515. if (NULL != apwszCertTypeCN)
  2516. {
  2517. CAFreeCertTypeProperty(hCertType, apwszCertTypeCN);
  2518. }
  2519. CACloseCertType(hCertType);
  2520. }
  2521. return(hr);
  2522. }
  2523. HRESULT
  2524. dsEnumCASetTemplates(
  2525. IN HCAINFO hCAInfo,
  2526. IN OUT VOID *pvArgs)
  2527. {
  2528. HRESULT hr;
  2529. CASETTEMPLATESARGS *pArgs = (CASETTEMPLATESARGS *) pvArgs;
  2530. DWORD Op = SCTOP_SET;
  2531. WCHAR const *pwszList;
  2532. WCHAR **ppwszList = NULL;
  2533. pwszList = pArgs->pwszTemplateList;
  2534. if (myIsMinusSign(*pwszList))
  2535. {
  2536. pwszList++;
  2537. Op = SCTOP_REMOVE;
  2538. }
  2539. else if (L'+' == *pwszList)
  2540. {
  2541. pwszList++;
  2542. Op = SCTOP_ADD;
  2543. }
  2544. hr = cuParseStrings(pwszList, FALSE, NULL, NULL, &ppwszList, NULL);
  2545. _JumpIfError(hr, error, "cuParseStrings");
  2546. hr = dsAddCATemplates(hCAInfo, Op, ppwszList);
  2547. _JumpIfError(hr, error, "dsAddCATemplates");
  2548. error:
  2549. cuFreeStringArray(ppwszList);
  2550. return(hr);
  2551. }
  2552. HRESULT
  2553. verbSetCATemplates(
  2554. IN WCHAR const *pwszOption,
  2555. IN WCHAR const *pwszTemplateList,
  2556. IN WCHAR const *pwszArg2,
  2557. IN WCHAR const *pwszArg3,
  2558. IN WCHAR const *pwszArg4)
  2559. {
  2560. HRESULT hr;
  2561. CASETTEMPLATESARGS Args;
  2562. Args.pwszTemplateList = pwszTemplateList;
  2563. hr = dsEnumCA(dsEnumCASetTemplates, &Args);
  2564. _JumpIfError(hr, error, "dsEnumCA");
  2565. error:
  2566. return(hr);
  2567. }
  2568. HRESULT
  2569. dsCAFindByCertType(
  2570. IN WCHAR const *pwszTemplate,
  2571. OPTIONAL WCHAR const *pwszDC,
  2572. IN DWORD dwFlags,
  2573. OUT HCAINFO *phCAInfo)
  2574. {
  2575. HRESULT hr;
  2576. WCHAR const *pwszCertType = pwszTemplate;
  2577. WCHAR *pwszAlloc = NULL;
  2578. while (TRUE)
  2579. {
  2580. hr = CAFindByCertType(
  2581. pwszCertType,
  2582. pwszDC, // wszScope
  2583. dwFlags,
  2584. phCAInfo);
  2585. if (S_OK == hr)
  2586. {
  2587. if (NULL == *phCAInfo)
  2588. {
  2589. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  2590. _JumpError(hr, error, "CAFindByCertType");
  2591. }
  2592. break;
  2593. }
  2594. _PrintErrorStr2(
  2595. hr,
  2596. "CAFindByCertType",
  2597. pwszCertType,
  2598. HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
  2599. if (NULL != pwszAlloc)
  2600. {
  2601. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  2602. _JumpError(hr, error, "CAFindByCertType");
  2603. }
  2604. hr = dsDumpTemplate(NULL, pwszTemplate, &pwszAlloc);
  2605. _JumpIfError(hr, error, "dsDumpTemplate");
  2606. if (NULL == pwszAlloc)
  2607. {
  2608. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  2609. _JumpError(hr, error, "dsDumpTemplate");
  2610. }
  2611. pwszCertType = pwszAlloc;
  2612. }
  2613. error:
  2614. if (NULL != pwszAlloc)
  2615. {
  2616. LocalFree(pwszAlloc);
  2617. }
  2618. return(hr);
  2619. }
  2620. // Display CAs for specified Template
  2621. HRESULT
  2622. verbTemplateCAs(
  2623. IN WCHAR const *pwszOption,
  2624. IN WCHAR const *pwszTemplate,
  2625. IN WCHAR const *pwszArg2,
  2626. IN WCHAR const *pwszArg3,
  2627. IN WCHAR const *pwszArg4)
  2628. {
  2629. HRESULT hr;
  2630. HCAINFO hCAInfo = NULL;
  2631. DWORD dwFlags = CA_FIND_INCLUDE_NON_TEMPLATE_CA | CA_FIND_INCLUDE_UNTRUSTED;
  2632. WCHAR **apwszMachine = NULL;
  2633. WCHAR **apwszCommonName = NULL;
  2634. if (!g_fUserRegistry)
  2635. {
  2636. dwFlags |= CA_FIND_LOCAL_SYSTEM;
  2637. }
  2638. if (NULL != g_pwszDC)
  2639. {
  2640. dwFlags |= CA_FLAG_SCOPE_DNS;
  2641. }
  2642. hr = dsCAFindByCertType(pwszTemplate, g_pwszDC, dwFlags, &hCAInfo);
  2643. _JumpIfError(hr, error, "dsCAFindByCertType");
  2644. while (TRUE)
  2645. {
  2646. HCAINFO hCAInfoNext;
  2647. WCHAR const *pwszError = NULL;
  2648. hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &apwszMachine);
  2649. _JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_DNSNAME)");
  2650. hr = CAGetCAProperty(
  2651. hCAInfo,
  2652. CA_PROP_DISPLAY_NAME,
  2653. &apwszCommonName);
  2654. _JumpIfError(hr, error, "CAGetCAProperty(CA_PROP_DISPLAY_NAME)");
  2655. hr = CAAccessCheck(hCAInfo, NULL);
  2656. if (S_OK != hr)
  2657. {
  2658. pwszError = myGetErrorMessageText(hr, FALSE);
  2659. }
  2660. wprintf(L"%ws\\%ws", apwszMachine[0], apwszCommonName[0]);
  2661. if (NULL != pwszError)
  2662. {
  2663. wprintf(L" -- %ws", pwszError);
  2664. LocalFree(const_cast<WCHAR *>(pwszError));
  2665. }
  2666. wprintf(wszNewLine);
  2667. CAFreeCAProperty(hCAInfo, apwszMachine);
  2668. apwszMachine = NULL;
  2669. CAFreeCAProperty(hCAInfo, apwszCommonName);
  2670. apwszCommonName = NULL;
  2671. hr = CAEnumNextCA(hCAInfo, &hCAInfoNext);
  2672. _JumpIfError(hr, error, "CAEnumNextCA");
  2673. CACloseCA(hCAInfo);
  2674. hCAInfo = hCAInfoNext;
  2675. if (NULL == hCAInfo)
  2676. {
  2677. break;
  2678. }
  2679. }
  2680. hr = S_OK;
  2681. error:
  2682. if (NULL != apwszMachine)
  2683. {
  2684. CAFreeCAProperty(hCAInfo, apwszMachine);
  2685. }
  2686. if (NULL != apwszCommonName)
  2687. {
  2688. CAFreeCAProperty(hCAInfo, apwszCommonName);
  2689. }
  2690. if (NULL != hCAInfo)
  2691. {
  2692. CACloseCA(hCAInfo);
  2693. }
  2694. return(hr);
  2695. }
  2696. typedef struct _MODTYPE
  2697. {
  2698. WCHAR const *pwszAttributeName;
  2699. DWORD dwType;
  2700. } MODTYPE;
  2701. #define MT_STRING 0
  2702. #define MT_IGNORE 1
  2703. #define MT_TIMEPERIOD 2
  2704. #define MT_BINARY 3
  2705. const MODTYPE s_amtTemplateAttributes[] =
  2706. {
  2707. { CERTTYPE_PROP_CN, MT_IGNORE },
  2708. { L"instanceType", MT_IGNORE },
  2709. { CERTTYPE_PROP_DN, MT_IGNORE },
  2710. { L"objectCategory", MT_IGNORE },
  2711. { L"objectGUID", MT_IGNORE },
  2712. { L"name", MT_IGNORE },
  2713. { L"showInAdvancedViewOnly",MT_IGNORE },
  2714. { L"uSNChanged", MT_IGNORE },
  2715. { L"uSNCreated", MT_IGNORE },
  2716. { L"whenChanged", MT_IGNORE },
  2717. { L"whenCreated", MT_IGNORE },
  2718. { L"dSCorePropagationData", MT_IGNORE },
  2719. { CERTTYPE_PROP_EXPIRATION, MT_TIMEPERIOD },
  2720. { CERTTYPE_PROP_OVERLAP, MT_TIMEPERIOD },
  2721. { CERTTYPE_PROP_KU, MT_BINARY },
  2722. { NULL, MT_STRING }
  2723. };
  2724. DWORD
  2725. ModType(
  2726. IN WCHAR const *pwszName)
  2727. {
  2728. MODTYPE const *pmt;
  2729. for (pmt = s_amtTemplateAttributes; NULL != pmt->pwszAttributeName; pmt++)
  2730. {
  2731. if (0 == mylstrcmpiS(pwszName, pmt->pwszAttributeName))
  2732. {
  2733. break;
  2734. }
  2735. }
  2736. return(pmt->dwType);
  2737. }
  2738. HRESULT
  2739. ConvertBinaryValue(
  2740. IN WCHAR const *pwszValue,
  2741. OUT BERVAL **ppber)
  2742. {
  2743. HRESULT hr;
  2744. BYTE *pb = NULL;
  2745. DWORD cb;
  2746. hr = WszToMultiByteInteger(TRUE, pwszValue, &cb, &pb);
  2747. _JumpIfError(hr, error, "WszToMultiByteInteger");
  2748. *ppber = (BERVAL *) LocalAlloc(LMEM_FIXED, sizeof(**ppber));
  2749. if (NULL == *ppber)
  2750. {
  2751. hr = E_OUTOFMEMORY;
  2752. _JumpError(hr, error, "LocalAlloc");
  2753. }
  2754. (*ppber)->bv_len = cb;
  2755. (*ppber)->bv_val = (char *) pb;
  2756. pb = NULL;
  2757. error:
  2758. if (NULL != pb)
  2759. {
  2760. LocalFree(pb);
  2761. }
  2762. return(hr);
  2763. }
  2764. HRESULT
  2765. ParseTimePeriod(
  2766. IN WCHAR const *pwszValue,
  2767. OUT LONGLONG *pll)
  2768. {
  2769. HRESULT hr;
  2770. WCHAR *pwszDup = NULL;
  2771. WCHAR *pwszCount;
  2772. WCHAR *pwszNext;
  2773. LONGLONG ll;
  2774. DWORD lHours;
  2775. DWORD lMinutes;
  2776. DWORD lSeconds;
  2777. ll = 0;
  2778. hr = myDupString(pwszValue, &pwszDup);
  2779. _JumpIfError(hr, error, "myDupString");
  2780. pwszCount = pwszDup;
  2781. while (TRUE)
  2782. {
  2783. BOOL fValid;
  2784. WCHAR *pwszString;
  2785. DWORD dwCount;
  2786. enum ENUM_PERIOD enumPeriod;
  2787. LONG lCount;
  2788. while (L' ' == *pwszCount)
  2789. {
  2790. pwszCount++;
  2791. }
  2792. pwszNext = wcschr(pwszCount, L',');
  2793. if (NULL == pwszNext)
  2794. {
  2795. if (L'\0' == *pwszCount || NULL != wcschr(pwszCount, L':'))
  2796. {
  2797. break;
  2798. }
  2799. pwszNext = &pwszCount[wcslen(pwszCount)];
  2800. pwszString = pwszNext;
  2801. }
  2802. else
  2803. {
  2804. pwszString = pwszNext;
  2805. *pwszNext++ = L'\0';
  2806. }
  2807. while (pwszString > pwszCount && L' ' == *--pwszString)
  2808. {
  2809. *pwszString = L'\0';
  2810. }
  2811. pwszString = wcschr(pwszCount, L' ');
  2812. if (NULL == pwszString)
  2813. {
  2814. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2815. _JumpErrorStr(hr, error, "bad time period", pwszCount);
  2816. }
  2817. *pwszString++ = L'\0';
  2818. while (L' ' == *pwszString)
  2819. {
  2820. pwszString++;
  2821. }
  2822. //wprintf(L"Period: '%ws' '%ws'\n", pwszCount, pwszString);
  2823. dwCount = myWtoI(pwszCount, &fValid);
  2824. if (!fValid)
  2825. {
  2826. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2827. _JumpError(hr, error, "bad time period digit");
  2828. }
  2829. hr = myTranslatePeriodUnits(pwszString, dwCount, &enumPeriod, &lCount);
  2830. _JumpIfError(hr, error, "myTranslatePeriodUnits");
  2831. if (0 != dwCount)
  2832. {
  2833. if (ENUM_PERIOD_YEARS == enumPeriod)
  2834. {
  2835. // "Years" is implemented without considering leap years.
  2836. ll += (LONGLONG) (lCount * 365 * CVT_DAYS) * CVT_BASE;
  2837. }
  2838. else if (ENUM_PERIOD_MONTHS == enumPeriod)
  2839. {
  2840. // "Months" is implemented assuming 30 days per month
  2841. ll += (LONGLONG) (lCount * 30 * CVT_DAYS) * CVT_BASE;
  2842. }
  2843. else if (ENUM_PERIOD_WEEKS == enumPeriod)
  2844. {
  2845. // "Months" is implemented assuming 7 days per week
  2846. ll += (LONGLONG) (lCount * 7 * CVT_DAYS) * CVT_BASE;
  2847. }
  2848. else
  2849. {
  2850. myMakeExprDateTime((FILETIME *) &ll, lCount, enumPeriod);
  2851. }
  2852. }
  2853. pwszCount = pwszNext;
  2854. }
  2855. if (3 == swscanf(pwszCount, L"%u:%02u:%02u", &lHours, &lMinutes, &lSeconds))
  2856. {
  2857. if (0 != lHours)
  2858. {
  2859. myMakeExprDateTime((FILETIME *) &ll, lHours, ENUM_PERIOD_HOURS);
  2860. }
  2861. if (0 != lMinutes)
  2862. {
  2863. myMakeExprDateTime((FILETIME *) &ll, lMinutes, ENUM_PERIOD_MINUTES);
  2864. }
  2865. if (0 != lSeconds)
  2866. {
  2867. myMakeExprDateTime((FILETIME *) &ll, lSeconds, ENUM_PERIOD_SECONDS);
  2868. }
  2869. }
  2870. *pll = -ll;
  2871. hr = S_OK;
  2872. error:
  2873. if (NULL != pwszDup)
  2874. {
  2875. LocalFree(pwszDup);
  2876. }
  2877. return(hr);
  2878. }
  2879. HRESULT
  2880. ConvertTimePeriodValue(
  2881. IN WCHAR const *pwszValue,
  2882. OUT BERVAL **ppber)
  2883. {
  2884. HRESULT hr;
  2885. LONGLONG ll;
  2886. BYTE *pb = NULL;
  2887. hr = ParseTimePeriod(pwszValue, &ll);
  2888. _JumpIfError(hr, error, "ParseTimePeriod");
  2889. pb = (BYTE *) LocalAlloc(LMEM_FIXED, sizeof(ll));
  2890. if (NULL == pb)
  2891. {
  2892. hr = E_OUTOFMEMORY;
  2893. _JumpError(hr, error, "LocalAlloc");
  2894. }
  2895. CopyMemory(pb, &ll, sizeof(ll));
  2896. *ppber = (BERVAL *) LocalAlloc(LMEM_FIXED, sizeof(**ppber));
  2897. if (NULL == *ppber)
  2898. {
  2899. hr = E_OUTOFMEMORY;
  2900. _JumpError(hr, error, "LocalAlloc");
  2901. }
  2902. (*ppber)->bv_len = sizeof(ll);
  2903. (*ppber)->bv_val = (char *) pb;
  2904. pb = NULL;
  2905. error:
  2906. if (NULL != pb)
  2907. {
  2908. LocalFree(pb);
  2909. }
  2910. return(hr);
  2911. }
  2912. VOID
  2913. FreeMods(
  2914. IN DWORD cmod,
  2915. LDAPMod *rgmod)
  2916. {
  2917. DWORD imod;
  2918. DWORD ival;
  2919. if (NULL != rgmod)
  2920. {
  2921. for (imod = 0; imod < cmod; imod++)
  2922. {
  2923. if (LDAP_MOD_BVALUES & rgmod[imod].mod_op)
  2924. {
  2925. BERVAL **rgpber = rgmod[imod].mod_bvalues;
  2926. if (NULL != rgpber)
  2927. {
  2928. for (ival = 0; NULL != rgpber[ival]; ival++)
  2929. {
  2930. if (rgpber[ival]->bv_val)
  2931. {
  2932. LocalFree(rgpber[ival]->bv_val);
  2933. }
  2934. LocalFree(rgpber[ival]);
  2935. }
  2936. LocalFree(rgpber);
  2937. }
  2938. }
  2939. else
  2940. {
  2941. WCHAR **rgpwsz = rgmod[imod].mod_values;
  2942. if (NULL != rgpwsz)
  2943. {
  2944. for (ival = 0; NULL != rgpwsz[ival]; ival++)
  2945. {
  2946. LocalFree(rgpwsz[ival]);
  2947. }
  2948. LocalFree(rgpwsz);
  2949. }
  2950. }
  2951. }
  2952. LocalFree(rgmod);
  2953. }
  2954. }
  2955. HRESULT
  2956. ConvertInfValuesToMods(
  2957. IN DWORD cInfValues,
  2958. INFVALUES const *rgInfValues,
  2959. OUT WCHAR **ppwszCN,
  2960. OUT DWORD *pcmod,
  2961. OUT LDAPMod **prgmod)
  2962. {
  2963. HRESULT hr;
  2964. LDAPMod *rgmod = NULL;
  2965. DWORD cmod = 0;
  2966. DWORD imod;
  2967. DWORD i;
  2968. WCHAR *pwszCN = NULL;
  2969. *ppwszCN = NULL;
  2970. *prgmod = NULL;
  2971. for (i = 0; i < cInfValues; i++)
  2972. {
  2973. if (MT_IGNORE != ModType(rgInfValues[i].pwszKey))
  2974. {
  2975. cmod++;
  2976. }
  2977. }
  2978. rgmod = (LDAPMod *) LocalAlloc(
  2979. LMEM_FIXED | LMEM_ZEROINIT,
  2980. cmod * sizeof(rgmod[0]));
  2981. if (NULL == rgmod)
  2982. {
  2983. hr = E_OUTOFMEMORY;
  2984. _JumpError(hr, error, "LocalAlloc");
  2985. }
  2986. imod = 0;
  2987. for (i = 0; i < cInfValues; i++)
  2988. {
  2989. INFVALUES const *pInfValues = &rgInfValues[i];
  2990. DWORD dwType = ModType(pInfValues->pwszKey);
  2991. WCHAR **ppwsz = NULL;
  2992. BERVAL **ppber = NULL;
  2993. DWORD ival;
  2994. if (NULL != ppwszCN &&
  2995. NULL == pwszCN &&
  2996. 0 == LSTRCMPIS(pInfValues->pwszKey, CERTTYPE_PROP_CN))
  2997. {
  2998. hr = myDupString(pInfValues->rgpwszValues[0], &pwszCN);
  2999. _JumpIfError(hr, error, "myDupString");
  3000. }
  3001. if (MT_IGNORE != dwType)
  3002. {
  3003. rgmod[imod].mod_op = LDAP_MOD_REPLACE;
  3004. rgmod[imod].mod_type = pInfValues->pwszKey;
  3005. if (MT_STRING == dwType)
  3006. {
  3007. ppwsz = (WCHAR **) LocalAlloc(
  3008. LMEM_FIXED | LMEM_ZEROINIT,
  3009. (pInfValues->cValues + 1) * sizeof(ppwsz[0]));
  3010. if (NULL == ppwsz)
  3011. {
  3012. hr = E_OUTOFMEMORY;
  3013. _JumpError(hr, error, "LocalAlloc");
  3014. }
  3015. rgmod[imod].mod_values = ppwsz;
  3016. }
  3017. else
  3018. {
  3019. ppber = (BERVAL **) LocalAlloc(
  3020. LMEM_FIXED | LMEM_ZEROINIT,
  3021. (pInfValues->cValues + 1) * sizeof(ppber[0]));
  3022. if (NULL == ppber)
  3023. {
  3024. hr = E_OUTOFMEMORY;
  3025. _JumpError(hr, error, "LocalAlloc");
  3026. }
  3027. rgmod[imod].mod_op |= LDAP_MOD_BVALUES;
  3028. rgmod[imod].mod_bvalues = ppber;
  3029. }
  3030. for (ival = pInfValues->cValues; ival > 0; ival--)
  3031. {
  3032. WCHAR const *pwszValue = pInfValues->rgpwszValues[ival - 1];
  3033. switch (dwType)
  3034. {
  3035. case MT_BINARY:
  3036. hr = ConvertBinaryValue(pwszValue, ppber);
  3037. _JumpIfErrorStr(
  3038. hr,
  3039. error,
  3040. "ConvertBinaryValue",
  3041. pInfValues->pwszKey);
  3042. ppber++;
  3043. CSASSERT(NULL == *ppber);
  3044. break;
  3045. case MT_TIMEPERIOD:
  3046. hr = ConvertTimePeriodValue(pwszValue, ppber);
  3047. _JumpIfErrorStr(
  3048. hr,
  3049. error,
  3050. "ConvertTimePeriodValue",
  3051. pInfValues->pwszKey);
  3052. ppber++;
  3053. CSASSERT(NULL == *ppber);
  3054. break;
  3055. default:
  3056. CSASSERT(MT_STRING == dwType);
  3057. hr = myDupString(pwszValue, ppwsz);
  3058. _JumpIfErrorStr(
  3059. hr,
  3060. error,
  3061. "myDupString",
  3062. pInfValues->pwszKey);
  3063. ppwsz++;
  3064. CSASSERT(NULL == *ppwsz);
  3065. break;
  3066. }
  3067. }
  3068. imod++;
  3069. }
  3070. }
  3071. CSASSERT(imod == cmod);
  3072. *pcmod = cmod;
  3073. *prgmod = rgmod;
  3074. rgmod = NULL;
  3075. if (NULL != ppwszCN)
  3076. {
  3077. *ppwszCN = pwszCN;
  3078. pwszCN = NULL;
  3079. }
  3080. hr = S_OK;
  3081. error:
  3082. if (NULL != pwszCN)
  3083. {
  3084. LocalFree(pwszCN);
  3085. }
  3086. if (NULL != rgmod)
  3087. {
  3088. FreeMods(cmod, rgmod);
  3089. }
  3090. return(hr);
  3091. }
  3092. HRESULT
  3093. dsAddTemplate(
  3094. IN HINF hInf,
  3095. IN WCHAR const *pwszTemplate,
  3096. IN OUT BSTR *pstrConfigDN,
  3097. IN OUT LDAP **ppld)
  3098. {
  3099. HRESULT hr;
  3100. ULONG ldaperr;
  3101. DWORD cInfValues;
  3102. INFVALUES *rgInfValues = NULL;
  3103. DWORD cmod;
  3104. LDAPMod *rgmod = NULL;
  3105. LDAPMod **rgpmod = NULL;
  3106. DWORD imod;
  3107. DWORD ival;
  3108. WCHAR *pwszDNContainer = NULL;
  3109. WCHAR *pwszDNTemplate = NULL;
  3110. WCHAR *pwszCNAlloc = NULL;
  3111. WCHAR const *pwszCN;
  3112. UINT idmsg;
  3113. WCHAR *pwszError = NULL;
  3114. hr = myInfGetSectionValues(
  3115. hInf,
  3116. pwszTemplate,
  3117. &cInfValues,
  3118. &rgInfValues);
  3119. _JumpIfError(hr, error, "myInfGetSectionValues");
  3120. hr = ConvertInfValuesToMods(
  3121. cInfValues,
  3122. rgInfValues,
  3123. &pwszCNAlloc,
  3124. &cmod,
  3125. &rgmod);
  3126. _JumpIfError(hr, error, "ConvertInfValuesToMods");
  3127. rgpmod = (LDAPMod **) LocalAlloc(
  3128. LMEM_FIXED,
  3129. (cmod + 3) * sizeof(rgpmod[0]));
  3130. if (NULL == rgpmod)
  3131. {
  3132. hr = E_OUTOFMEMORY;
  3133. _JumpError(hr, error, "LocalAlloc");
  3134. }
  3135. for (imod = 0; imod < cmod; imod++)
  3136. {
  3137. rgpmod[imod] = &rgmod[imod];
  3138. }
  3139. rgpmod[imod] = NULL;
  3140. pwszCN = pwszCNAlloc;
  3141. if (NULL == pwszCN)
  3142. {
  3143. pwszCN = pwszTemplate;
  3144. }
  3145. if (g_fVerbose)
  3146. {
  3147. for (imod = 0; NULL != rgpmod[imod]; imod++)
  3148. {
  3149. WCHAR const *pwszSep = L"";
  3150. wprintf(L"%ws =", rgpmod[imod]->mod_type);
  3151. if (LDAP_MOD_BVALUES & rgmod[imod].mod_op)
  3152. {
  3153. BERVAL **ppber = rgpmod[imod]->mod_bvalues;
  3154. wprintf(wszNewLine);
  3155. for (ival = 0; NULL != ppber[ival]; ival++)
  3156. {
  3157. DumpHex(
  3158. DH_NOADDRESS | DH_NOTABPREFIX | 8,
  3159. (BYTE const *) ppber[ival]->bv_val,
  3160. ppber[ival]->bv_len);
  3161. wprintf(wszNewLine);
  3162. }
  3163. }
  3164. else
  3165. {
  3166. WCHAR **ppwsz = rgpmod[imod]->mod_values;
  3167. for (ival = 0; NULL != ppwsz[ival]; ival++)
  3168. {
  3169. wprintf(L"%ws \"%ws\"", pwszSep, ppwsz[ival]);
  3170. pwszSep = L",";
  3171. }
  3172. wprintf(wszNewLine);
  3173. }
  3174. if (1 < ival)
  3175. {
  3176. wprintf(wszNewLine);
  3177. }
  3178. }
  3179. }
  3180. if (NULL == *pstrConfigDN)
  3181. {
  3182. hr = myLdapOpen(
  3183. g_pwszDC,
  3184. RLBF_REQUIRE_SECURE_LDAP,
  3185. ppld,
  3186. NULL,
  3187. pstrConfigDN);
  3188. _JumpIfError(hr, error, "myLdapOpen");
  3189. }
  3190. CSASSERT(NULL != *pstrConfigDN);
  3191. CSASSERT(NULL != *ppld);
  3192. hr = BuildDN(g_wszCNTemplates, *pstrConfigDN, FALSE, &pwszDNContainer);
  3193. _JumpIfError(hr, error, "BuildDN");
  3194. hr = BuildDN(pwszCN, pwszDNContainer, TRUE, &pwszDNTemplate);
  3195. _JumpIfError(hr, error, "BuildDN");
  3196. DBGPRINT((DBG_SS_CERTUTILI, "Template DN: %ws\n", pwszDNTemplate));
  3197. idmsg = IDS_CREATED_TEMPLATE; // "Created DS Template"
  3198. ldaperr = ldap_add_ext_s(*ppld, pwszDNTemplate, rgpmod, NULL, NULL);
  3199. hr = myHLdapError3(
  3200. *ppld,
  3201. ldaperr,
  3202. LDAP_ALREADY_EXISTS,
  3203. LDAP_OBJECT_CLASS_VIOLATION,
  3204. &pwszError);
  3205. _PrintIfErrorStr(hr, "ldap_add_ext_s", pwszCN);
  3206. if (LDAP_ALREADY_EXISTS == ldaperr ||
  3207. LDAP_OBJECT_CLASS_VIOLATION == ldaperr)
  3208. {
  3209. if (NULL != pwszError)
  3210. {
  3211. LocalFree(pwszError);
  3212. pwszError = NULL;
  3213. }
  3214. for (imod = 0; NULL != rgpmod[imod]; imod++)
  3215. {
  3216. rgmod[imod].mod_op =
  3217. LDAP_MOD_REPLACE | (LDAP_MOD_BVALUES & rgmod[imod].mod_op);
  3218. }
  3219. idmsg = IDS_UPDATED_TEMPLATE; // "Updated DS Template"
  3220. ldaperr = ldap_modify_ext_s(*ppld, pwszDNTemplate, rgpmod, NULL, NULL);
  3221. if (LDAP_ATTRIBUTE_OR_VALUE_EXISTS == ldaperr)
  3222. {
  3223. ldaperr = LDAP_SUCCESS;
  3224. }
  3225. hr = myHLdapError(*ppld, ldaperr, &pwszError);
  3226. _PrintIfErrorStr(hr, "ldap_modify_ext_s", pwszCN);
  3227. }
  3228. _JumpIfErrorStr(hr, error, "Add/Update", pwszCN);
  3229. wprintf(L"%ws: %ws\n", myLoadResourceString(idmsg), pwszCN);
  3230. if (NULL != pwszError)
  3231. {
  3232. wprintf(L"%ws\n", pwszError);
  3233. }
  3234. hr = S_OK;
  3235. error:
  3236. if (NULL != pwszError)
  3237. {
  3238. LocalFree(pwszError);
  3239. }
  3240. if (NULL != pwszCNAlloc)
  3241. {
  3242. LocalFree(pwszCNAlloc);
  3243. }
  3244. if (NULL != pwszDNContainer)
  3245. {
  3246. LocalFree(pwszDNContainer);
  3247. }
  3248. if (NULL != pwszDNTemplate)
  3249. {
  3250. LocalFree(pwszDNTemplate);
  3251. }
  3252. if (NULL != rgpmod)
  3253. {
  3254. LocalFree(rgpmod);
  3255. }
  3256. if (NULL != rgmod)
  3257. {
  3258. FreeMods(cmod, rgmod);
  3259. }
  3260. if (NULL != rgInfValues)
  3261. {
  3262. myInfFreeSectionValues(cInfValues, rgInfValues);
  3263. }
  3264. return(hr);
  3265. }
  3266. HRESULT
  3267. verbDSAddTemplate(
  3268. IN WCHAR const *pwszOption,
  3269. IN WCHAR const *pwszfnTemplateInf,
  3270. IN WCHAR const *pwszArg2,
  3271. IN WCHAR const *pwszArg3,
  3272. IN WCHAR const *pwszArg4)
  3273. {
  3274. HRESULT hr;
  3275. HINF hInf = INVALID_HANDLE_VALUE;
  3276. DWORD ErrorLine;
  3277. BOOL fCritical;
  3278. WCHAR *pwszzTemplateList = NULL;
  3279. WCHAR const *pwsz;
  3280. BSTR strConfigDN = NULL;
  3281. LDAP *pld = NULL;
  3282. static WCHAR const * const s_apwszKeys[] =
  3283. { wszINFKEY_TEMPLATE, NULL };
  3284. hr = myInfOpenFile(pwszfnTemplateInf, &hInf, &ErrorLine);
  3285. _JumpIfError(hr, error, "myInfOpenFIle");
  3286. hr = myInfGetKeyList(
  3287. hInf,
  3288. wszINFSECTION_TEMPLATELIST,
  3289. wszINFKEY_TEMPLATE,
  3290. s_apwszKeys,
  3291. &fCritical,
  3292. &pwszzTemplateList);
  3293. _JumpIfErrorStr(hr, error, "myInfGetKeyList", wszINFKEY_TEMPLATE);
  3294. for (pwsz = pwszzTemplateList; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
  3295. {
  3296. wprintf(L"[%ws]\n", pwsz);
  3297. hr = dsAddTemplate(hInf, pwsz, &strConfigDN, &pld);
  3298. _JumpIfError(hr, error, "dsAddTemplate");
  3299. }
  3300. error:
  3301. if (NULL != pwszzTemplateList)
  3302. {
  3303. LocalFree(pwszzTemplateList);
  3304. }
  3305. if (INVALID_HANDLE_VALUE != hInf)
  3306. {
  3307. WCHAR *pwszT = myInfGetError();
  3308. if (NULL != pwszT)
  3309. {
  3310. wprintf(L"%ws\n", pwszT);
  3311. }
  3312. myInfCloseFile(hInf);
  3313. }
  3314. myLdapClose(pld, NULL, strConfigDN);
  3315. return(hr);
  3316. }
  3317. #define DSP_OBJECT_NTAUTHCERT 0x00000001
  3318. #define DSP_OBJECT_ROOTTRUST 0x00000002
  3319. #define DSP_OBJECT_AIA 0x00000004
  3320. #define DSP_OBJECT_KRA 0x00000008
  3321. #define DSP_OBJECT_MACHINE 0x00000010
  3322. #define DSP_OBJECT_USER 0x00000020
  3323. #define DSP_OBJECT_MASK 0x000000ff
  3324. #define DSP_ATTRIBUTE_CACERTIFICATE 0x00000100
  3325. #define DSP_ATTRIBUTE_USERCERTIFICATE 0x00000200
  3326. #define DSP_ATTRIBUTE_CROSSCERTPAIR 0x00000400
  3327. #define DSP_ATTRIBUTE_MASK 0x0000ff00
  3328. #define DSP_TYPE_KRACERT 0x00010000
  3329. #define DSP_TYPE_EECERT 0x00020000
  3330. #define DSP_TYPE_ROOTCACERT 0x00040000
  3331. #define DSP_TYPE_SUBCACERT 0x00080000
  3332. #define DSP_TYPE_MASK 0x00ff0000
  3333. typedef struct _DSOBJECTMAP {
  3334. DWORD ObjectFlags;
  3335. WCHAR const *pwszTemplate;
  3336. } DSOBJECTMAP;
  3337. DSOBJECTMAP s_rgObjectMap[] = {
  3338. { DSP_OBJECT_NTAUTHCERT, g_wszLDAPNTAuthURLTemplate },
  3339. { DSP_OBJECT_ROOTTRUST, g_wszLDAPRootTrustURLTemplate },
  3340. { DSP_OBJECT_AIA, g_wszzLDAPIssuerCertURLTemplate },
  3341. { DSP_OBJECT_KRA, g_wszzLDAPKRACertURLTemplate },
  3342. { DSP_OBJECT_USER, NULL },
  3343. { DSP_OBJECT_MACHINE, NULL },
  3344. };
  3345. HRESULT GetSubjectAltNameEntry(
  3346. CERT_CONTEXT const *pccCert,
  3347. DWORD dwAltNameChoice,
  3348. LPCSTR pcszOID,
  3349. LPWSTR *ppwszValue)
  3350. {
  3351. HRESULT hr;
  3352. PCERT_INFO pCertInfo = pccCert->pCertInfo;
  3353. CERT_ALT_NAME_INFO *pInfo = NULL;
  3354. CERT_NAME_VALUE *pNameValue = NULL;
  3355. DWORD cb;
  3356. bool fFound = false;
  3357. *ppwszValue = NULL;
  3358. for (DWORD i = 0; !fFound && i < pCertInfo->cExtension; i++)
  3359. {
  3360. if (0 == strcmp(pCertInfo->rgExtension[i].pszObjId, szOID_SUBJECT_ALT_NAME2))
  3361. {
  3362. // Decode to plain text
  3363. if (!myDecodeObject(
  3364. X509_ASN_ENCODING,
  3365. X509_ALTERNATE_NAME,
  3366. pCertInfo->rgExtension[i].Value.pbData,
  3367. pCertInfo->rgExtension[i].Value.cbData,
  3368. CERTLIB_USE_LOCALALLOC,
  3369. (VOID **) &pInfo,
  3370. &cb))
  3371. {
  3372. hr = myHLastError();
  3373. _JumpError(hr, error, "myDecodeObject");
  3374. }
  3375. for(DWORD j=0; !fFound && j<pInfo->cAltEntry; j++)
  3376. {
  3377. if(dwAltNameChoice== pInfo->rgAltEntry[j].dwAltNameChoice)
  3378. {
  3379. switch(dwAltNameChoice)
  3380. {
  3381. case CERT_ALT_NAME_OTHER_NAME:
  3382. if(0==_stricmp(pcszOID, pInfo->rgAltEntry[j].pOtherName->pszObjId))
  3383. {
  3384. if (!myDecodeObject(
  3385. X509_ASN_ENCODING,
  3386. X509_UNICODE_ANY_STRING,
  3387. pInfo->rgAltEntry[j].pOtherName->Value.pbData,
  3388. pInfo->rgAltEntry[j].pOtherName->Value.cbData,
  3389. CERTLIB_USE_LOCALALLOC,
  3390. (VOID **) &pNameValue,
  3391. &cb))
  3392. {
  3393. hr = myHLastError();
  3394. _JumpError(hr, error, "Policy:myDecodeObject");
  3395. }
  3396. hr = myDupString((LPWSTR)pNameValue->Value.pbData, ppwszValue);
  3397. _JumpIfError(hr, error, "myDupString");
  3398. fFound = true;
  3399. }
  3400. break;
  3401. case CERT_ALT_NAME_RFC822_NAME:
  3402. hr = myDupString(pInfo->rgAltEntry[j].pwszRfc822Name, ppwszValue);
  3403. _JumpIfError(hr, error, "myDupString");
  3404. fFound = true;
  3405. break;
  3406. case CERT_ALT_NAME_DNS_NAME:
  3407. hr = myDupString(pInfo->rgAltEntry[j].pwszDNSName, ppwszValue);
  3408. _JumpIfError(hr, error, "myDupString");
  3409. fFound = true;
  3410. break;
  3411. }
  3412. }
  3413. }
  3414. }
  3415. }
  3416. if(!fFound)
  3417. {
  3418. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  3419. }
  3420. else
  3421. {
  3422. hr = S_OK;
  3423. }
  3424. error:
  3425. if (NULL != pInfo)
  3426. {
  3427. LocalFree(pInfo);
  3428. }
  3429. if(pNameValue)
  3430. {
  3431. LocalFree(pNameValue);
  3432. }
  3433. return hr;
  3434. }
  3435. HRESULT
  3436. LocateUserOrMachineInDS(
  3437. IN CERT_CONTEXT const *pccCert,
  3438. IN DWORD dwObjectType,
  3439. OUT LPWSTR *ppwszURL)
  3440. {
  3441. HRESULT hr = S_FALSE;
  3442. HANDLE hDS = NULL;
  3443. PDOMAIN_CONTROLLER_INFO pDCI = NULL;
  3444. PDS_NAME_RESULT pName = NULL;
  3445. LPCWSTR pwszDC;
  3446. LPWSTR pwszSearchName = NULL;
  3447. LPCWSTR pcwszAttribute;
  3448. LPCWSTR pcwszObjectCategory =
  3449. (LPC_USEROBJECT==dwObjectType)?wszDSUSERCLASSNAME:wszDSMACHINECLASSNAME;
  3450. LDAP *pld = NULL;
  3451. LPCWSTR pcwszFormat = L"(&(objectCategory=%s)(%s=%s))";
  3452. LPWSTR pwszUserFilter = NULL;
  3453. CSASSERT(dwObjectType==LPC_USEROBJECT || dwObjectType==LPC_MACHINEOBJECT);
  3454. // DSCrackNames first
  3455. if(dwObjectType == LPC_USEROBJECT)
  3456. {
  3457. // look for UPN is subject alt name
  3458. hr = GetSubjectAltNameEntry(
  3459. pccCert,
  3460. CERT_ALT_NAME_OTHER_NAME,
  3461. szOID_NT_PRINCIPAL_NAME,
  3462. &pwszSearchName);
  3463. if(S_OK==hr)
  3464. {
  3465. hr = DsGetDcName(
  3466. NULL,
  3467. NULL,
  3468. NULL,
  3469. NULL,
  3470. DS_GC_SERVER_REQUIRED,
  3471. &pDCI);
  3472. _JumpIfError(hr, error, "DsGetDCName");
  3473. pwszDC = pDCI->DomainControllerName;
  3474. while (*pwszDC == L'\\')
  3475. {
  3476. pwszDC++;
  3477. }
  3478. hr = DsBind(pwszDC, NULL, &hDS);
  3479. _JumpIfError(hr, error, "DSBind");
  3480. hr = DsCrackNames(
  3481. hDS,
  3482. DS_NAME_NO_FLAGS,
  3483. DS_USER_PRINCIPAL_NAME,
  3484. DS_FQDN_1779_NAME,
  3485. 1,
  3486. &pwszSearchName,
  3487. &pName);
  3488. if(S_OK==hr && pName->cItems>0 && pName->rItems[0].pName)
  3489. {
  3490. hr = myDupString(pName->rItems[0].pName, ppwszURL);
  3491. _JumpIfError(hr, error, "myDupString");
  3492. }
  3493. }
  3494. }
  3495. // Not found yet? Try other fields
  3496. if(NULL == *ppwszURL)
  3497. {
  3498. if(dwObjectType == LPC_USEROBJECT)
  3499. {
  3500. // look for email is subject alt name
  3501. hr = GetSubjectAltNameEntry(
  3502. pccCert,
  3503. CERT_ALT_NAME_RFC822_NAME,
  3504. NULL,
  3505. &pwszSearchName);
  3506. _PrintIfError(hr, "GetSubjectAltNameEntry");
  3507. if(S_OK != hr)
  3508. {
  3509. hr = myGetRDNAttributeFromNameBlob(
  3510. &pccCert->pCertInfo->Subject,
  3511. szOID_RSA_emailAddr,
  3512. &pwszSearchName);
  3513. _PrintIfError(hr, "myGetRDNAttributeFromNameBlob");
  3514. }
  3515. if(S_OK==hr)
  3516. {
  3517. pcwszAttribute = wszDSMAILATTRIBUTE;
  3518. }
  3519. }
  3520. else // LPC_MACHINEOBJECT
  3521. {
  3522. // look for DNS name in subject alt name
  3523. hr = GetSubjectAltNameEntry(
  3524. pccCert,
  3525. CERT_ALT_NAME_DNS_NAME,
  3526. NULL,
  3527. &pwszSearchName);
  3528. _PrintIfError(hr, "GetSubjectAltNameEntry");
  3529. if(S_OK != hr)
  3530. {
  3531. hr = myGetCommonName(
  3532. &pccCert->pCertInfo->Subject,
  3533. FALSE,
  3534. &pwszSearchName);
  3535. _PrintIfError(hr, "myGetCommonName");
  3536. }
  3537. if(S_OK==hr)
  3538. {
  3539. pcwszAttribute = wszDSDNSHOSTNAMEATTRIBUTE;
  3540. }
  3541. }
  3542. // Found a suitable name? Search the global catalog for the matching object.
  3543. if(NULL != pwszSearchName)
  3544. {
  3545. hr = myLdapOpen(
  3546. NULL, // pwszDomainName
  3547. RLBF_REQUIRE_GC | RLBF_REQUIRE_SECURE_LDAP,
  3548. &pld,
  3549. NULL, // pstrDomainDN
  3550. NULL); // pstrConfigDN
  3551. _JumpIfError(hr, error, "myLdapOpen");
  3552. if(dwObjectType == LPC_USEROBJECT)
  3553. {
  3554. // build the search filter, e.g.
  3555. // (&(objectCategory=user)([email protected]))
  3556. pwszUserFilter = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*
  3557. (wcslen(pcwszFormat)+wcslen(pcwszObjectCategory)+
  3558. wcslen(pcwszAttribute)+wcslen(pwszSearchName)+1));
  3559. _JumpIfAllocFailed(pwszUserFilter, error);
  3560. wsprintf(pwszUserFilter, pcwszFormat,
  3561. pcwszObjectCategory, pcwszAttribute, pwszSearchName);
  3562. hr = myLdapFindObjectInForest(
  3563. pld,
  3564. pwszUserFilter,
  3565. ppwszURL);
  3566. _PrintIfErrorStr(hr, "myLdapFindObjectInForest", pwszUserFilter);
  3567. }
  3568. else
  3569. {
  3570. hr = myLdapFindComputerInForest(
  3571. pld,
  3572. pwszSearchName,
  3573. ppwszURL);
  3574. _PrintIfErrorStr(hr, "myLdapFindMachineInForest", pwszSearchName);
  3575. }
  3576. }
  3577. }
  3578. if(NULL == *ppwszURL)
  3579. {
  3580. hr = CRYPT_E_NOT_FOUND;
  3581. _JumpError(hr, error, "Could not find a matching DS object to publish to");
  3582. }
  3583. hr = S_OK;
  3584. error:
  3585. if (NULL != hDS)
  3586. {
  3587. DsUnBind(&hDS);
  3588. }
  3589. if(pDCI)
  3590. {
  3591. NetApiBufferFree(pDCI);
  3592. }
  3593. if(pName)
  3594. {
  3595. DsFreeNameResult(pName);
  3596. }
  3597. if(pwszSearchName)
  3598. {
  3599. LocalFree(pwszSearchName);
  3600. }
  3601. myLdapClose(pld, NULL, NULL);
  3602. if(pwszUserFilter)
  3603. {
  3604. LocalFree(pwszUserFilter);
  3605. }
  3606. return hr;
  3607. }
  3608. HRESULT
  3609. dsPublishCert(
  3610. IN CERT_CONTEXT const *pccPublish,
  3611. IN WCHAR const *pwszSanitizedCN,
  3612. IN DWORD dspFlags,
  3613. IN DWORD dwObjectType)
  3614. {
  3615. HRESULT hr;
  3616. WCHAR const *pwszAttribute;
  3617. WCHAR *pwszServerName = NULL; // Shouldn't be necessary
  3618. WCHAR *pwszURL = NULL;
  3619. LDAP *pld = NULL;
  3620. BSTR strDomainDN = NULL;
  3621. BSTR strConfigDN = NULL;
  3622. DWORD dwDisposition;
  3623. DWORD i;
  3624. WCHAR *pwszError = NULL;
  3625. hr = myGetMachineDnsName(&pwszServerName);
  3626. _JumpIfError(hr, error, "myGetMachineDnsName");
  3627. hr = myLdapOpen(
  3628. g_pwszDC,
  3629. RLBF_REQUIRE_SECURE_LDAP,
  3630. &pld,
  3631. &strDomainDN,
  3632. &strConfigDN);
  3633. _JumpIfError(hr, error, "myLdapOpen");
  3634. switch (DSP_ATTRIBUTE_MASK & dspFlags)
  3635. {
  3636. case DSP_ATTRIBUTE_CACERTIFICATE:
  3637. pwszAttribute = wszDSCACERTATTRIBUTE;
  3638. break;
  3639. case DSP_ATTRIBUTE_USERCERTIFICATE:
  3640. pwszAttribute = wszDSUSERCERTATTRIBUTE;
  3641. break;
  3642. case DSP_ATTRIBUTE_CROSSCERTPAIR:
  3643. pwszAttribute = wszDSCROSSCERTPAIRATTRIBUTE;
  3644. break;
  3645. default:
  3646. hr = E_INVALIDARG;
  3647. _JumpError(hr, error, "bad attribute indicator");
  3648. }
  3649. for (i = 0; i < ARRAYSIZE(s_rgObjectMap); i++)
  3650. {
  3651. WCHAR const *pwszTemplate;
  3652. if (0 == (s_rgObjectMap[i].ObjectFlags & DSP_OBJECT_MASK & dspFlags))
  3653. {
  3654. continue;
  3655. }
  3656. pwszTemplate = s_rgObjectMap[i].pwszTemplate;
  3657. if (NULL != pwszTemplate)
  3658. {
  3659. hr = myFormatCertsrvStringArray(
  3660. FALSE, // fURL
  3661. pwszServerName, // pwszServerName_p1_2
  3662. pwszSanitizedCN,// pwszSanitizedName_p3_7
  3663. 0, // iCert_p4
  3664. MAXDWORD, // iCertTarget_p4
  3665. strDomainDN, // pwszDomainDN_p5
  3666. strConfigDN, // pwszConfigDN_p6
  3667. 0, // iCRL_p8
  3668. FALSE, // fDeltaCRL_p9
  3669. FALSE, // fDSAttrib_p10_11
  3670. 1, // cStrings
  3671. &pwszTemplate, // apwszStringsIn
  3672. &pwszURL); // apwszStringsOut
  3673. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  3674. }
  3675. else
  3676. {
  3677. // user and machine objects don't have predefined DS location, we
  3678. // need to search for it based on information from the cert
  3679. hr = LocateUserOrMachineInDS(pccPublish, dwObjectType, &pwszURL);
  3680. if (S_OK != hr)
  3681. {
  3682. wprintf(
  3683. myLoadResourceString(IDS_ERR_CANNOT_FIND_MATCHING_OBJ));
  3684. }
  3685. _JumpIfError(hr, error, "LocateObjectInDS");
  3686. }
  3687. wprintf(L"%ws?%ws\n\n", pwszURL, pwszAttribute);
  3688. if (g_fForce)
  3689. {
  3690. dwObjectType |= LPC_CREATECONTAINER | LPC_CREATEOBJECT;
  3691. }
  3692. hr = myLdapPublishCertToDS(
  3693. pld,
  3694. pccPublish,
  3695. pwszURL,
  3696. pwszAttribute,
  3697. dwObjectType,
  3698. FALSE, // fDelete
  3699. &dwDisposition,
  3700. &pwszError);
  3701. _JumpIfError(hr, error, "myLdapPublishCertToDS");
  3702. if (LDAP_SUCCESS == dwDisposition)
  3703. {
  3704. wprintf(
  3705. myLoadResourceString(IDS_FORMAT_ADDED_TO_DS_STORE), // "%ws added to DS store."
  3706. myLoadResourceString(IDS_CERTIFICATE)); // "Certificate"
  3707. }
  3708. else
  3709. {
  3710. CSASSERT(LDAP_ATTRIBUTE_OR_VALUE_EXISTS == dwDisposition);
  3711. wprintf(
  3712. myLoadResourceString(IDS_FORMAT_ALREADY_IN_DS_STORE), // "%ws already in DS store."
  3713. myLoadResourceString(IDS_CERTIFICATE)); // "Certificate"
  3714. }
  3715. wprintf(wszNewLine);
  3716. wprintf(wszNewLine);
  3717. if (dspFlags & DSP_OBJECT_AIA)
  3718. {
  3719. hr = myLdapFilterCertificates(
  3720. pld,
  3721. pwszURL,
  3722. pwszAttribute,
  3723. &dwDisposition,
  3724. &pwszError);
  3725. _JumpIfErrorStr(hr, error, "myLdapFilterCertificates", pwszURL);
  3726. }
  3727. LocalFree(pwszURL);
  3728. pwszURL = NULL;
  3729. }
  3730. hr = S_OK;
  3731. error:
  3732. if (NULL != pwszError)
  3733. {
  3734. wprintf(L"%ws\n", pwszError);
  3735. LocalFree(pwszError);
  3736. }
  3737. if (NULL != pwszServerName)
  3738. {
  3739. LocalFree(pwszServerName);
  3740. }
  3741. if (NULL != pwszURL)
  3742. {
  3743. LocalFree(pwszURL);
  3744. }
  3745. myLdapClose(pld, strDomainDN, strConfigDN);
  3746. return(hr);
  3747. }
  3748. HRESULT
  3749. dsPublishCRL(
  3750. OPTIONAL IN LDAP *pld,
  3751. IN CRL_CONTEXT const *pCRLPublish,
  3752. IN BOOL fDelta,
  3753. IN WCHAR const *pwszURL)
  3754. {
  3755. HRESULT hr;
  3756. WCHAR const *pwszAttribute;
  3757. LDAP *pldT = NULL;
  3758. DWORD dwDisposition;
  3759. UINT idMsg = fDelta? IDS_PROP_DELTACRL : IDS_PROP_BASECRL;
  3760. WCHAR *pwszError = NULL;
  3761. pwszAttribute = fDelta? wszDSDELTACRLATTRIBUTE : wszDSBASECRLATTRIBUTE;
  3762. wprintf(L"%ws?%ws\n\n", pwszURL, pwszAttribute);
  3763. if (NULL == pld)
  3764. {
  3765. hr = myLdapOpen(
  3766. g_pwszDC,
  3767. RLBF_REQUIRE_SECURE_LDAP,
  3768. &pldT,
  3769. NULL,
  3770. NULL);
  3771. _JumpIfError(hr, error, "myLdapOpen");
  3772. pld = pldT;
  3773. }
  3774. hr = myLdapPublishCRLToDS(
  3775. pld,
  3776. pCRLPublish,
  3777. pwszURL,
  3778. pwszAttribute,
  3779. &dwDisposition,
  3780. &pwszError);
  3781. _JumpIfError(hr, error, "myLdapPublishCRLToDS");
  3782. if (LDAP_SUCCESS == dwDisposition)
  3783. {
  3784. wprintf(
  3785. myLoadResourceString(IDS_FORMAT_ADDED_TO_DS_STORE), // "%ws added to DS store."
  3786. myLoadResourceString(idMsg));
  3787. }
  3788. else
  3789. {
  3790. CSASSERT(LDAP_ATTRIBUTE_OR_VALUE_EXISTS == dwDisposition);
  3791. wprintf(
  3792. myLoadResourceString(IDS_FORMAT_ALREADY_IN_DS_STORE), // "%ws already in DS store."
  3793. myLoadResourceString(idMsg));
  3794. }
  3795. wprintf(wszNewLine);
  3796. wprintf(wszNewLine);
  3797. hr = S_OK;
  3798. error:
  3799. if (NULL != pwszError)
  3800. {
  3801. wprintf(L"%ws\n", pwszError);
  3802. LocalFree(pwszError);
  3803. }
  3804. myLdapClose(pldT, NULL, NULL);
  3805. return(hr);
  3806. }
  3807. HRESULT
  3808. IsCrossCACert(
  3809. IN CERT_CONTEXT const *pCertContext,
  3810. OUT BOOL *pfCrossCA)
  3811. {
  3812. HRESULT hr;
  3813. WCHAR *pwszObjId = NULL;
  3814. HCERTTYPE hCertType = NULL;
  3815. DWORD dwValue;
  3816. CAutoLPWSTR pwszCertTypeNameV1;
  3817. *pfCrossCA = FALSE;
  3818. // CrossCA is a V2 template, so only fetch the template OID
  3819. hr = cuGetCertType(
  3820. pCertContext->pCertInfo,
  3821. &pwszCertTypeNameV1,// ppwszCertTypeNameV1
  3822. NULL, // ppwszDisplayNameV1
  3823. &pwszObjId, // ppwszCertTypeObjId
  3824. NULL, // ppwszCertTypeName
  3825. NULL); // ppwszDisplayName
  3826. if (S_OK != hr || NULL == pwszObjId)
  3827. {
  3828. _PrintIfError2(hr, "cuGetCertType", CRYPT_E_NOT_FOUND);
  3829. if (CRYPT_E_NOT_FOUND == hr)
  3830. {
  3831. hr = S_OK;
  3832. }
  3833. goto error;
  3834. }
  3835. if(((LPWSTR)NULL)!=pwszCertTypeNameV1&&
  3836. 0 == LSTRCMPIS(pwszCertTypeNameV1, wszCERTTYPE_CROSS_CA))
  3837. {
  3838. *pfCrossCA = TRUE;
  3839. }
  3840. else
  3841. {
  3842. hr = CAFindCertTypeByName(
  3843. pwszObjId,
  3844. NULL,
  3845. CT_ENUM_USER_TYPES | CT_ENUM_MACHINE_TYPES | CT_FIND_BY_OID,
  3846. &hCertType);
  3847. if (S_OK != hr)
  3848. {
  3849. _PrintErrorStr2(hr, "CAFindCertTypeByName", pwszObjId, hr);
  3850. if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) != hr)
  3851. {
  3852. _JumpErrorStr(hr, error, "CAFindCertTypeByName", pwszObjId);
  3853. }
  3854. }
  3855. else
  3856. {
  3857. hr = CAGetCertTypeFlagsEx(hCertType, CERTTYPE_GENERAL_FLAG, &dwValue);
  3858. _JumpIfError(hr, error, "CAGetCertTypeFlagsEx");
  3859. if (CT_FLAG_IS_CROSS_CA & dwValue)
  3860. {
  3861. *pfCrossCA = TRUE;
  3862. }
  3863. }
  3864. }
  3865. hr = S_OK;
  3866. error:
  3867. if (NULL != hCertType)
  3868. {
  3869. CACloseCertType(hCertType);
  3870. }
  3871. if (NULL != pwszObjId)
  3872. {
  3873. LocalFree(pwszObjId);
  3874. }
  3875. return(hr);
  3876. }
  3877. HRESULT
  3878. IsCACert(
  3879. IN CERT_CONTEXT const *pCertContext,
  3880. OUT BOOL *pfCA)
  3881. {
  3882. HRESULT hr;
  3883. CERT_EXTENSION *pExt;
  3884. *pfCA = FALSE;
  3885. pExt = CertFindExtension(
  3886. szOID_BASIC_CONSTRAINTS2,
  3887. pCertContext->pCertInfo->cExtension,
  3888. pCertContext->pCertInfo->rgExtension);
  3889. if (NULL != pExt)
  3890. {
  3891. CERT_BASIC_CONSTRAINTS2_INFO Constraints;
  3892. DWORD cb;
  3893. cb = sizeof(Constraints);
  3894. if (!CryptDecodeObject(
  3895. X509_ASN_ENCODING,
  3896. X509_BASIC_CONSTRAINTS2,
  3897. pExt->Value.pbData,
  3898. pExt->Value.cbData,
  3899. 0,
  3900. &Constraints,
  3901. &cb))
  3902. {
  3903. hr = myHLastError();
  3904. _JumpError(hr, error, "CryptDecodeObject");
  3905. }
  3906. *pfCA = Constraints.fCA;
  3907. }
  3908. hr = S_OK;
  3909. error:
  3910. return(hr);
  3911. }
  3912. char const *g_apszKRAObjIds[] = {
  3913. szOID_KP_KEY_RECOVERY_AGENT,
  3914. szOID_EFS_RECOVERY,
  3915. };
  3916. HRESULT
  3917. IsKRACert(
  3918. IN CERT_CONTEXT const *pCertContext,
  3919. OUT BOOL *pfKRA)
  3920. {
  3921. HRESULT hr;
  3922. CERT_EXTENSION *pExt;
  3923. CERT_ENHKEY_USAGE *pKeyUsage = NULL;
  3924. CERT_POLICIES_INFO *pPolicies = NULL;
  3925. DWORD cb;
  3926. DWORD i;
  3927. DWORD j;
  3928. *pfKRA = FALSE;
  3929. pExt = CertFindExtension(
  3930. szOID_ENHANCED_KEY_USAGE,
  3931. pCertContext->pCertInfo->cExtension,
  3932. pCertContext->pCertInfo->rgExtension);
  3933. if (NULL != pExt)
  3934. {
  3935. if (!myDecodeObject(
  3936. X509_ASN_ENCODING,
  3937. X509_ENHANCED_KEY_USAGE,
  3938. pExt->Value.pbData,
  3939. pExt->Value.cbData,
  3940. CERTLIB_USE_LOCALALLOC,
  3941. (VOID **) &pKeyUsage,
  3942. &cb))
  3943. {
  3944. hr = myHLastError();
  3945. _JumpIfError(hr, error, "myDecodeObject");
  3946. }
  3947. for (i = 0; i < pKeyUsage->cUsageIdentifier; i++)
  3948. {
  3949. char const *pszObjId = pKeyUsage->rgpszUsageIdentifier[i];
  3950. for (j = 0; j < ARRAYSIZE(g_apszKRAObjIds); j++)
  3951. {
  3952. if (0 == strcmp(
  3953. pszObjId,
  3954. g_apszKRAObjIds[j]))
  3955. {
  3956. *pfKRA = TRUE;
  3957. hr = S_OK;
  3958. goto error;
  3959. }
  3960. }
  3961. }
  3962. }
  3963. pExt = CertFindExtension(
  3964. szOID_APPLICATION_CERT_POLICIES,
  3965. pCertContext->pCertInfo->cExtension,
  3966. pCertContext->pCertInfo->rgExtension);
  3967. if (NULL != pExt)
  3968. {
  3969. if (!myDecodeObject(
  3970. X509_ASN_ENCODING,
  3971. X509_CERT_POLICIES,
  3972. pExt->Value.pbData,
  3973. pExt->Value.cbData,
  3974. CERTLIB_USE_LOCALALLOC,
  3975. (VOID **) &pPolicies,
  3976. &cb))
  3977. {
  3978. hr = myHLastError();
  3979. _JumpIfError(hr, error, "myDecodeObject");
  3980. }
  3981. for (i = 0; i < pPolicies->cPolicyInfo; i++)
  3982. {
  3983. CERT_POLICY_INFO *pPolicyInfo = &pPolicies->rgPolicyInfo[i];
  3984. for (j = 0; j < ARRAYSIZE(g_apszKRAObjIds); j++)
  3985. {
  3986. if (0 == strcmp(
  3987. pPolicyInfo->pszPolicyIdentifier,
  3988. g_apszKRAObjIds[j]))
  3989. {
  3990. *pfKRA = TRUE;
  3991. hr = S_OK;
  3992. goto error;
  3993. }
  3994. }
  3995. }
  3996. }
  3997. hr = S_OK;
  3998. error:
  3999. if (NULL != pKeyUsage)
  4000. {
  4001. LocalFree(pKeyUsage);
  4002. }
  4003. if (NULL != pPolicies)
  4004. {
  4005. LocalFree(pPolicies);
  4006. }
  4007. return(hr);
  4008. }
  4009. HRESULT
  4010. IsMachineCert(
  4011. IN CERT_CONTEXT const *pCertContext,
  4012. OUT BOOL *pfMachine)
  4013. {
  4014. HRESULT hr;
  4015. HCERTTYPE hCertType = NULL;
  4016. CERT_EXTENSION *pExt;
  4017. CERT_TEMPLATE_EXT *pTemplate = NULL;
  4018. CERT_NAME_VALUE *pbName = NULL;
  4019. LPWSTR pwszTemplate = NULL;
  4020. DWORD dwTemplateFlags;
  4021. DWORD cb;
  4022. bool fNameIsOID;
  4023. *pfMachine = FALSE;
  4024. pExt = CertFindExtension(
  4025. szOID_CERTIFICATE_TEMPLATE,
  4026. pCertContext->pCertInfo->cExtension,
  4027. pCertContext->pCertInfo->rgExtension);
  4028. if (NULL != pExt)
  4029. {
  4030. if (!myDecodeObject(
  4031. X509_ASN_ENCODING,
  4032. X509_CERTIFICATE_TEMPLATE,
  4033. pExt->Value.pbData,
  4034. pExt->Value.cbData,
  4035. CERTLIB_USE_LOCALALLOC,
  4036. (VOID **) &pTemplate,
  4037. &cb))
  4038. {
  4039. hr = myHLastError();
  4040. _JumpError(hr, error, "myDecodeObject");
  4041. }
  4042. if (!ConvertSzToWsz(&pwszTemplate, pTemplate->pszObjId, -1))
  4043. {
  4044. hr = E_OUTOFMEMORY;
  4045. _JumpError(hr, error, "ConvertSzToWsz");
  4046. }
  4047. fNameIsOID = true;
  4048. }
  4049. else
  4050. {
  4051. // try v1 template extension
  4052. pExt = CertFindExtension(
  4053. szOID_ENROLL_CERTTYPE_EXTENSION,
  4054. pCertContext->pCertInfo->cExtension,
  4055. pCertContext->pCertInfo->rgExtension);
  4056. if(pExt)
  4057. {
  4058. if (!myDecodeObject(
  4059. X509_ASN_ENCODING,
  4060. X509_UNICODE_ANY_STRING,
  4061. pExt->Value.pbData,
  4062. pExt->Value.cbData,
  4063. CERTLIB_USE_LOCALALLOC,
  4064. (VOID **) &pbName,
  4065. &cb))
  4066. {
  4067. hr = myHLastError();
  4068. _JumpError(hr, error, "myDecodeObject");
  4069. }
  4070. hr = myDupString((LPWSTR)pbName->Value.pbData, &pwszTemplate);
  4071. _JumpIfError(hr, error, "myDupString");
  4072. fNameIsOID = false;
  4073. }
  4074. }
  4075. if(pwszTemplate)
  4076. {
  4077. hr = CAFindCertTypeByName(
  4078. pwszTemplate,
  4079. NULL,
  4080. (fNameIsOID?CT_FIND_BY_OID:0) |
  4081. CT_ENUM_MACHINE_TYPES |
  4082. CT_ENUM_USER_TYPES,
  4083. &hCertType);
  4084. if(S_OK==hr)
  4085. {
  4086. hr = CAGetCertTypeFlagsEx(
  4087. hCertType,
  4088. CERTTYPE_GENERAL_FLAG,
  4089. &dwTemplateFlags);
  4090. }
  4091. if(S_OK==hr)
  4092. {
  4093. *pfMachine = (dwTemplateFlags & CT_FLAG_MACHINE_TYPE)?TRUE:FALSE;
  4094. }
  4095. }
  4096. hr = S_OK;
  4097. error:
  4098. if (NULL != hCertType)
  4099. {
  4100. CACloseCertType(hCertType);
  4101. }
  4102. LOCAL_FREE(pTemplate);
  4103. LOCAL_FREE(pbName);
  4104. LOCAL_FREE(pwszTemplate);
  4105. return(hr);
  4106. }
  4107. HRESULT
  4108. dsPublishCertFromContext(
  4109. IN CERT_CONTEXT const *pCertContext,
  4110. OPTIONAL IN WCHAR const *pwszType)
  4111. {
  4112. HRESULT hr;
  4113. BOOL fCrossCA;
  4114. BOOL fCA;
  4115. BOOL fKRA;
  4116. BOOL fRoot;
  4117. BOOL fMachine;
  4118. DWORD dspFlags;
  4119. DWORD dwObjectType;
  4120. WCHAR *pwszCN = NULL;
  4121. WCHAR const *pwszSanitizedCN = NULL;
  4122. WCHAR *pwszSanitizedCNAlloc = NULL;
  4123. // If a CrossCA cert, publish to the Subject CN's AIA container.
  4124. // If a CA cert, publish to the Subject CN's AIA container.
  4125. // If a KRA cert, publish to the Issuer CN's KRA container.
  4126. hr = IsCrossCACert(pCertContext, &fCrossCA);
  4127. if (S_OK != hr)
  4128. {
  4129. _PrintError(hr, "IsCrossCACert");
  4130. if (NULL == pwszType && !g_fForce)
  4131. {
  4132. goto error;
  4133. }
  4134. }
  4135. hr = IsCACert(pCertContext, &fCA);
  4136. _JumpIfError(hr, error, "IsCACert");
  4137. hr = IsKRACert(pCertContext, &fKRA);
  4138. _JumpIfError(hr, error, "IsKRACert");
  4139. hr = IsMachineCert(pCertContext, &fMachine);
  4140. _JumpIfError(hr, error, "IsMachineCert");
  4141. fRoot = CertCompareCertificateName(
  4142. X509_ASN_ENCODING,
  4143. &pCertContext->pCertInfo->Subject,
  4144. &pCertContext->pCertInfo->Issuer);
  4145. dwObjectType = LPC_CAOBJECT;
  4146. if (NULL == pwszType || myIsMinusSignString(pwszType))
  4147. {
  4148. if (fCrossCA)
  4149. {
  4150. // Don't publish to "Certification Authorities" (root CAs)
  4151. // because Win2k crypt32 can't handle zero byte cACertificate
  4152. // attributes, and aborts processing valid roots.
  4153. dspFlags = DSP_OBJECT_AIA |
  4154. //DSP_OBJECT_ROOTTRUST |
  4155. DSP_ATTRIBUTE_CROSSCERTPAIR |
  4156. DSP_TYPE_SUBCACERT;
  4157. }
  4158. else
  4159. if (fCA)
  4160. {
  4161. dspFlags = DSP_OBJECT_AIA | DSP_ATTRIBUTE_CACERTIFICATE;
  4162. if (fRoot)
  4163. {
  4164. dspFlags |= DSP_OBJECT_ROOTTRUST;
  4165. }
  4166. }
  4167. else
  4168. if (fKRA)
  4169. {
  4170. dspFlags = DSP_OBJECT_KRA | DSP_ATTRIBUTE_USERCERTIFICATE;
  4171. dwObjectType = LPC_KRAOBJECT;
  4172. }
  4173. else
  4174. if(fMachine)
  4175. {
  4176. dspFlags =
  4177. DSP_OBJECT_MACHINE |
  4178. DSP_ATTRIBUTE_USERCERTIFICATE |
  4179. DSP_TYPE_EECERT;
  4180. dwObjectType = LPC_MACHINEOBJECT;
  4181. }
  4182. else
  4183. {
  4184. dspFlags =
  4185. DSP_OBJECT_USER |
  4186. DSP_ATTRIBUTE_USERCERTIFICATE |
  4187. DSP_TYPE_EECERT;
  4188. dwObjectType = LPC_USEROBJECT;
  4189. }
  4190. }
  4191. else
  4192. {
  4193. if (0 == LSTRCMPIS(pwszType, L"NTAuthCA"))
  4194. {
  4195. dspFlags = DSP_OBJECT_NTAUTHCERT |
  4196. DSP_ATTRIBUTE_CACERTIFICATE |
  4197. DSP_TYPE_ROOTCACERT |
  4198. DSP_TYPE_SUBCACERT;
  4199. pwszSanitizedCN = L"NTAuthCertificates";
  4200. }
  4201. else
  4202. if (0 == LSTRCMPIS(pwszType, L"RootCA"))
  4203. {
  4204. dspFlags = DSP_OBJECT_AIA |
  4205. DSP_OBJECT_ROOTTRUST |
  4206. DSP_ATTRIBUTE_CACERTIFICATE |
  4207. DSP_TYPE_ROOTCACERT;
  4208. }
  4209. else
  4210. if (0 == LSTRCMPIS(pwszType, L"SubCA"))
  4211. {
  4212. dspFlags = DSP_OBJECT_AIA |
  4213. DSP_ATTRIBUTE_CACERTIFICATE |
  4214. DSP_TYPE_SUBCACERT;
  4215. }
  4216. else
  4217. if (0 == LSTRCMPIS(pwszType, L"CrossCA"))
  4218. {
  4219. // Don't publish to "Certification Authorities" (root CAs)
  4220. // because Win2k crypt32 can't handle zero byte cACertificate
  4221. // attributes, and aborts processing valid roots.
  4222. dspFlags = DSP_OBJECT_AIA |
  4223. //DSP_OBJECT_ROOTTRUST |
  4224. DSP_ATTRIBUTE_CROSSCERTPAIR |
  4225. DSP_TYPE_SUBCACERT;
  4226. }
  4227. else
  4228. if (0 == LSTRCMPIS(pwszType, L"KRA"))
  4229. {
  4230. dspFlags = DSP_OBJECT_KRA |
  4231. DSP_ATTRIBUTE_USERCERTIFICATE |
  4232. DSP_TYPE_KRACERT |
  4233. DSP_TYPE_EECERT;
  4234. dwObjectType = LPC_KRAOBJECT;
  4235. }
  4236. else
  4237. if (0 == LSTRCMPIS(pwszType, L"User"))
  4238. {
  4239. dspFlags = DSP_OBJECT_USER |
  4240. DSP_ATTRIBUTE_USERCERTIFICATE |
  4241. DSP_TYPE_EECERT;
  4242. dwObjectType = LPC_USEROBJECT;
  4243. }
  4244. else
  4245. if (0 == LSTRCMPIS(pwszType, L"Machine"))
  4246. {
  4247. dspFlags = DSP_OBJECT_MACHINE |
  4248. DSP_ATTRIBUTE_USERCERTIFICATE |
  4249. DSP_TYPE_EECERT;
  4250. dwObjectType = LPC_MACHINEOBJECT;
  4251. }
  4252. else
  4253. {
  4254. hr = E_INVALIDARG;
  4255. _JumpErrorStr(hr, error, "pwszType", pwszType);
  4256. }
  4257. if (!fKRA && (DSP_TYPE_KRACERT & dspFlags))
  4258. {
  4259. _PrintError(S_OK, "forcing KRA");
  4260. }
  4261. if (fCA && (DSP_TYPE_EECERT & dspFlags))
  4262. {
  4263. _PrintError(S_OK, "forcing non-CA");
  4264. }
  4265. if (!fCA &&
  4266. ((DSP_TYPE_ROOTCACERT | DSP_TYPE_SUBCACERT) & dspFlags))
  4267. {
  4268. _PrintError(S_OK, "forcing CA");
  4269. }
  4270. if (!fRoot &&
  4271. DSP_TYPE_ROOTCACERT ==
  4272. ((DSP_TYPE_ROOTCACERT | DSP_TYPE_SUBCACERT) & dspFlags))
  4273. {
  4274. _PrintError(S_OK, "forcing Root");
  4275. }
  4276. }
  4277. if (NULL == pwszSanitizedCN)
  4278. {
  4279. hr = myGetCommonName(
  4280. fCA?
  4281. &pCertContext->pCertInfo->Subject :
  4282. &pCertContext->pCertInfo->Issuer,
  4283. TRUE,
  4284. &pwszCN);
  4285. _JumpIfError(hr, error, "myGetCommonName");
  4286. hr = mySanitizeName(pwszCN, &pwszSanitizedCNAlloc);
  4287. _JumpIfError(hr, error, "mySanitizeName");
  4288. pwszSanitizedCN = pwszSanitizedCNAlloc;
  4289. }
  4290. hr = dsPublishCert(
  4291. pCertContext,
  4292. pwszSanitizedCN,
  4293. dspFlags,
  4294. dwObjectType);
  4295. _JumpIfError(hr, error, "dsPublishCert");
  4296. error:
  4297. if (NULL != pwszCN)
  4298. {
  4299. LocalFree(pwszCN);
  4300. }
  4301. if (NULL != pwszSanitizedCNAlloc)
  4302. {
  4303. LocalFree(pwszSanitizedCNAlloc);
  4304. }
  4305. return(hr);
  4306. }
  4307. HRESULT
  4308. dsPublishCRLFromContext(
  4309. IN CRL_CONTEXT const *pCRLContext,
  4310. IN BOOL fDelta)
  4311. {
  4312. HRESULT hr;
  4313. HRESULT hr2;
  4314. CRL_DIST_POINTS_INFO *pcdp = NULL;
  4315. CERT_EXTENSION *pExt;
  4316. WCHAR *pwszURL = NULL;
  4317. DWORD cb;
  4318. DWORD i;
  4319. DWORD j;
  4320. pExt = CertFindExtension(
  4321. szOID_CRL_SELF_CDP,
  4322. pCRLContext->pCrlInfo->cExtension,
  4323. pCRLContext->pCrlInfo->rgExtension);
  4324. if (NULL == pExt && !fDelta)
  4325. {
  4326. pExt = CertFindExtension(
  4327. szOID_FRESHEST_CRL,
  4328. pCRLContext->pCrlInfo->cExtension,
  4329. pCRLContext->pCrlInfo->rgExtension);
  4330. }
  4331. if (NULL == pExt)
  4332. {
  4333. wprintf(myLoadResourceString(IDS_ERROR_EXTENSION_MISSING));
  4334. wprintf(wszNewLine);
  4335. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  4336. _JumpError(hr, error, "CertFindExtension");
  4337. }
  4338. if (!myDecodeObject(
  4339. X509_ASN_ENCODING,
  4340. X509_CRL_DIST_POINTS,
  4341. pExt->Value.pbData,
  4342. pExt->Value.cbData,
  4343. CERTLIB_USE_LOCALALLOC,
  4344. (VOID **) &pcdp,
  4345. &cb))
  4346. {
  4347. hr = myHLastError();
  4348. _JumpError(hr, error, "myDecodeObject");
  4349. }
  4350. hr = S_OK;
  4351. for (i = 0; i < pcdp->cDistPoint; i++)
  4352. {
  4353. CRL_DIST_POINT const *pDistPoint = &pcdp->rgDistPoint[i];
  4354. if (CRL_DIST_POINT_FULL_NAME !=
  4355. pDistPoint->DistPointName.dwDistPointNameChoice)
  4356. {
  4357. continue;
  4358. }
  4359. for (j = 0; j < pDistPoint->DistPointName.FullName.cAltEntry; j++)
  4360. {
  4361. CERT_ALT_NAME_ENTRY const *pAltNameEntry = &pDistPoint->DistPointName.FullName.rgAltEntry[j];
  4362. #define wszLDAPCOLON L"ldap:"
  4363. WCHAR awcLDAP[ARRAYSIZE(wszLDAPCOLON)];
  4364. if (CERT_ALT_NAME_URL != pAltNameEntry->dwAltNameChoice)
  4365. {
  4366. continue;
  4367. }
  4368. if (ARRAYSIZE(awcLDAP) > wcslen(pAltNameEntry->pwszURL))
  4369. {
  4370. continue;
  4371. }
  4372. CopyMemory(awcLDAP, pAltNameEntry->pwszURL, sizeof(awcLDAP));
  4373. awcLDAP[ARRAYSIZE(awcLDAP) - 1] = L'\0';
  4374. if (0 != LSTRCMPIS(awcLDAP, wszLDAPCOLON))
  4375. {
  4376. continue;
  4377. }
  4378. if (NULL != pwszURL)
  4379. {
  4380. LocalFree(pwszURL);
  4381. pwszURL = NULL;
  4382. }
  4383. hr2 = myInternetUncanonicalizeURL(pAltNameEntry->pwszURL, &pwszURL);
  4384. _PrintIfError(hr2, "myInternetUncanonicalizeURL");
  4385. if (S_OK == hr)
  4386. {
  4387. hr = hr2; // Save first error
  4388. }
  4389. hr2 = dsPublishCRL(
  4390. NULL,
  4391. pCRLContext,
  4392. fDelta,
  4393. NULL != pwszURL? pwszURL : pAltNameEntry->pwszURL);
  4394. _PrintIfError(hr2, "dsPublishCRL");
  4395. if (S_OK == hr)
  4396. {
  4397. hr = hr2; // Save first error
  4398. }
  4399. }
  4400. _JumpIfError(hr, error, "dsPublishCRL");
  4401. }
  4402. error:
  4403. if (NULL != pwszURL)
  4404. {
  4405. LocalFree(pwszURL);
  4406. }
  4407. if (NULL != pcdp)
  4408. {
  4409. LocalFree(pcdp);
  4410. }
  4411. return(hr);
  4412. }
  4413. HRESULT
  4414. dsPublishCRLFromParms(
  4415. IN CRL_CONTEXT const *pCRLContext,
  4416. IN BOOL fDelta,
  4417. IN WCHAR const *pwszServerName,
  4418. OPTIONAL IN WCHAR const *pwszSanitizedCN)
  4419. {
  4420. HRESULT hr;
  4421. WCHAR *pwszServerNameAlloc = NULL; // Shouldn't be necessary
  4422. LDAP *pld = NULL;
  4423. BSTR strDomainDN = NULL;
  4424. BSTR strConfigDN = NULL;
  4425. WCHAR *pwszCN = NULL;
  4426. WCHAR *pwszSanitizedCNAlloc = NULL;
  4427. WCHAR *pwszSanitizedCNAlloc2 = NULL;
  4428. WCHAR *pwszURL = NULL;
  4429. DWORD iCert = 0;
  4430. DWORD iCRL = 0;
  4431. WCHAR const *pwszTemplate;
  4432. if (NULL == pwszServerName)
  4433. {
  4434. hr = myGetMachineDnsName(&pwszServerNameAlloc);
  4435. _JumpIfError(hr, error, "myGetMachineDnsName");
  4436. pwszServerName = pwszServerNameAlloc;
  4437. }
  4438. hr = myLdapOpen(
  4439. g_pwszDC,
  4440. RLBF_REQUIRE_SECURE_LDAP,
  4441. &pld,
  4442. &strDomainDN,
  4443. &strConfigDN);
  4444. _JumpIfError(hr, error, "myLdapOpen");
  4445. if (NULL == pwszSanitizedCN)
  4446. {
  4447. hr = myGetCommonName(&pCRLContext->pCrlInfo->Issuer, FALSE, &pwszCN);
  4448. _JumpIfError(hr, error, "myGetCommonName");
  4449. hr = mySanitizeName(pwszCN, &pwszSanitizedCNAlloc);
  4450. _JumpIfError(hr, error, "mySanitizeName");
  4451. pwszSanitizedCN = pwszSanitizedCNAlloc;
  4452. }
  4453. if (MAXDWORD == dsGetNumericSuffix(pwszSanitizedCN))
  4454. {
  4455. CERT_EXTENSION *pExt;
  4456. pExt = CertFindExtension(
  4457. szOID_CERTSRV_CA_VERSION,
  4458. pCRLContext->pCrlInfo->cExtension,
  4459. pCRLContext->pCrlInfo->rgExtension);
  4460. if (NULL != pExt)
  4461. {
  4462. DWORD NameId;
  4463. DWORD cb;
  4464. WCHAR const *pwsz;
  4465. cb = sizeof(NameId);
  4466. NameId = 0;
  4467. if (!CryptDecodeObject(
  4468. X509_ASN_ENCODING,
  4469. X509_INTEGER,
  4470. pExt->Value.pbData,
  4471. pExt->Value.cbData,
  4472. 0,
  4473. &NameId,
  4474. &cb))
  4475. {
  4476. hr = myHLastError();
  4477. _JumpError(hr, error, "CryptDecodeObject");
  4478. }
  4479. iCert = CANAMEIDTOICERT(NameId);
  4480. iCRL = CANAMEIDTOIKEY(NameId);
  4481. }
  4482. }
  4483. pwszTemplate = g_wszzLDAPRevocationURLTemplate;
  4484. hr = myFormatCertsrvStringArray(
  4485. FALSE, // fURL
  4486. pwszServerName, // pwszServerName_p1_2
  4487. pwszSanitizedCN, // pwszSanitizedName_p3_7
  4488. iCert, // iCert_p4
  4489. MAXDWORD, // iCertTarget_p4
  4490. strDomainDN, // pwszDomainDN_p5
  4491. strConfigDN, // pwszConfigDN_p6
  4492. iCRL, // iCRL_p8
  4493. fDelta, // fDeltaCRL_p9
  4494. FALSE, // fDSAttrib_p10_11
  4495. 1, // cStrings
  4496. &pwszTemplate, // apwszStringsIn
  4497. &pwszURL); // apwszStringsOut
  4498. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  4499. hr = dsPublishCRL(pld, pCRLContext, fDelta, pwszURL);
  4500. _JumpIfError(hr, error, "dsPublishCRL");
  4501. error:
  4502. if (NULL != pwszCN)
  4503. {
  4504. LocalFree(pwszCN);
  4505. }
  4506. if (NULL != pwszSanitizedCNAlloc2)
  4507. {
  4508. LocalFree(pwszSanitizedCNAlloc2);
  4509. }
  4510. if (NULL != pwszSanitizedCNAlloc)
  4511. {
  4512. LocalFree(pwszSanitizedCNAlloc);
  4513. }
  4514. if (NULL != pwszURL)
  4515. {
  4516. LocalFree(pwszURL);
  4517. }
  4518. if (NULL != pwszServerNameAlloc)
  4519. {
  4520. LocalFree(pwszServerNameAlloc);
  4521. }
  4522. myLdapClose(pld, strDomainDN, strConfigDN);
  4523. return(hr);
  4524. }
  4525. // pwszType: NTAuthCA | RootCA | SubCA | CrossCA | KRA | User | Machine
  4526. // pwszDSCDPContainer: machine name
  4527. HRESULT
  4528. verbDSPublish(
  4529. IN WCHAR const *pwszOption,
  4530. IN WCHAR const *pwszfn,
  4531. OPTIONAL IN WCHAR const *pwszTypeOrDSCDPContainer,
  4532. OPTIONAL IN WCHAR const *pwszDSCN,
  4533. IN WCHAR const *pwszArg4)
  4534. {
  4535. HRESULT hr;
  4536. CERT_CONTEXT const *pCertContext = NULL;
  4537. CRL_CONTEXT const *pCRLContext = NULL;
  4538. CSASSERT(NULL != pwszfn);
  4539. hr = cuLoadCert(pwszfn, &pCertContext);
  4540. if (S_OK == hr)
  4541. {
  4542. if (NULL != pwszDSCN)
  4543. {
  4544. hr = E_INVALIDARG;
  4545. _JumpError(hr, error, "non-NULL CDP parms");
  4546. }
  4547. hr = dsPublishCertFromContext(pCertContext, pwszTypeOrDSCDPContainer);
  4548. _JumpIfError(hr, error, "dsPublishCertFromContext");
  4549. }
  4550. else
  4551. {
  4552. CERT_EXTENSION *pExt;
  4553. BOOL fDelta;
  4554. hr = cuLoadCRL(pwszfn, &pCRLContext);
  4555. if (S_OK != hr)
  4556. {
  4557. cuPrintError(IDS_FORMAT_LOADCERTORCRL, hr);
  4558. #if 1
  4559. WCHAR *pwszURL = NULL;
  4560. HRESULT hr2 = myInternetUncanonicalizeURL(pwszfn, &pwszURL);
  4561. _PrintIfError(hr2, "myInternetUncanonicalizeURL");
  4562. if (NULL != pwszURL)
  4563. {
  4564. LocalFree(pwszURL);
  4565. }
  4566. #endif
  4567. goto error;
  4568. }
  4569. pExt = CertFindExtension(
  4570. szOID_DELTA_CRL_INDICATOR,
  4571. pCRLContext->pCrlInfo->cExtension,
  4572. pCRLContext->pCrlInfo->rgExtension);
  4573. fDelta = NULL != pExt;
  4574. if (NULL != pwszTypeOrDSCDPContainer)
  4575. {
  4576. hr = dsPublishCRLFromParms(
  4577. pCRLContext,
  4578. fDelta,
  4579. pwszTypeOrDSCDPContainer,
  4580. pwszDSCN);
  4581. _JumpIfError(hr, error, "dsPublishCRLFromParms");
  4582. }
  4583. else
  4584. {
  4585. hr = dsPublishCRLFromContext(pCRLContext, fDelta);
  4586. _JumpIfError(hr, error, "dsPublishCRLFromContext");
  4587. }
  4588. }
  4589. error:
  4590. cuUnloadCRL(&pCRLContext);
  4591. cuUnloadCert(&pCertContext);
  4592. return(hr);
  4593. }
  4594. HRESULT
  4595. dsDumpOIDDisplayNames(
  4596. IN LDAP *pld,
  4597. IN WCHAR const *pwszOIDDN,
  4598. IN WCHAR const *pwszObjId,
  4599. IN DWORD dwLanguageId,
  4600. IN OUT DWORD *pdwType,
  4601. OUT BOOL *pfObjectExists,
  4602. OUT BOOL *pfLangIdExists,
  4603. OPTIONAL OUT WCHAR ***pppwszLdapVal)
  4604. {
  4605. HRESULT hr;
  4606. LDAP_TIMEVAL timeval;
  4607. LDAPMessage *pmsg = NULL;
  4608. LDAPMessage *pres;
  4609. DWORD cres;
  4610. WCHAR **ppwszLdapVal = NULL;
  4611. *pfObjectExists = FALSE;
  4612. *pfLangIdExists = FALSE;
  4613. if (NULL != pppwszLdapVal)
  4614. {
  4615. *pppwszLdapVal = NULL;
  4616. }
  4617. timeval.tv_sec = csecLDAPTIMEOUT;
  4618. timeval.tv_usec = 0;
  4619. hr = ldap_search_st(
  4620. pld, // ld
  4621. const_cast<WCHAR *>(pwszOIDDN), // base
  4622. LDAP_SCOPE_BASE,
  4623. NULL, // filter
  4624. NULL, // attrs
  4625. FALSE, // attrsonly
  4626. &timeval, // timeout
  4627. &pmsg); // res
  4628. if (S_OK != hr)
  4629. {
  4630. hr = myHLdapError2(pld, hr, LDAP_NO_SUCH_OBJECT, NULL);
  4631. _PrintErrorStr2(
  4632. hr,
  4633. "ldap_search_st",
  4634. pwszOIDDN,
  4635. HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND));
  4636. if (HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND) != hr)
  4637. {
  4638. goto error;
  4639. }
  4640. }
  4641. else
  4642. {
  4643. cres = ldap_count_entries(pld, pmsg);
  4644. if (0 != cres)
  4645. {
  4646. for (pres = ldap_first_entry(pld, pmsg);
  4647. NULL != pres && NULL == ppwszLdapVal;
  4648. pres = ldap_next_entry(pld, pres))
  4649. {
  4650. DWORD i;
  4651. ppwszLdapVal = ldap_get_values(pld, pres, OID_PROP_OID);
  4652. if (NULL != ppwszLdapVal)
  4653. {
  4654. if (NULL != ppwszLdapVal[0] &&
  4655. 0 == lstrcmp(pwszObjId, ppwszLdapVal[0]))
  4656. {
  4657. *pfObjectExists = TRUE;
  4658. }
  4659. ldap_value_free(ppwszLdapVal);
  4660. ppwszLdapVal = NULL;
  4661. }
  4662. if (*pfObjectExists)
  4663. {
  4664. ppwszLdapVal = ldap_get_values(pld, pres, OID_PROP_TYPE);
  4665. if (NULL != ppwszLdapVal)
  4666. {
  4667. if (NULL != ppwszLdapVal[0])
  4668. {
  4669. DWORD dw = _wtoi(ppwszLdapVal[0]);
  4670. if (*pdwType != dw)
  4671. {
  4672. if (MAXDWORD != *pdwType)
  4673. {
  4674. wprintf(myLoadResourceString(IDS_TYPE_MISMATCH)); // "Type mismatch"
  4675. wprintf(wszNewLine);
  4676. hr = HRESULT_FROM_WIN32(RPC_S_ENTRY_ALREADY_EXISTS);
  4677. _JumpError(hr, error, "*pdwType mismatch");
  4678. }
  4679. *pdwType = dw;
  4680. }
  4681. }
  4682. ldap_value_free(ppwszLdapVal);
  4683. ppwszLdapVal = NULL;
  4684. }
  4685. i = 0;
  4686. ppwszLdapVal = ldap_get_values(
  4687. pld,
  4688. pres,
  4689. OID_PROP_LOCALIZED_NAME);
  4690. if (NULL != ppwszLdapVal)
  4691. {
  4692. for ( ; NULL != ppwszLdapVal[i]; i++)
  4693. {
  4694. wprintf(L" %u: %ws\n", i, ppwszLdapVal[i]);
  4695. if (!*pfLangIdExists)
  4696. {
  4697. hr = myLdapOIDIsMatchingLangId(
  4698. ppwszLdapVal[i],
  4699. dwLanguageId,
  4700. pfLangIdExists);
  4701. _PrintIfError(hr, "myLdapOIDIsMatchingLangId");
  4702. }
  4703. }
  4704. }
  4705. if (0 == i)
  4706. {
  4707. wprintf(myLoadResourceString(IDS_NO_DISPLAY_NAMES)); // "No display names"
  4708. wprintf(wszNewLine);
  4709. }
  4710. break;
  4711. }
  4712. }
  4713. }
  4714. }
  4715. if (NULL != pppwszLdapVal)
  4716. {
  4717. *pppwszLdapVal = ppwszLdapVal;
  4718. ppwszLdapVal = NULL;
  4719. }
  4720. hr = S_OK;
  4721. error:
  4722. if (NULL != ppwszLdapVal)
  4723. {
  4724. ldap_value_free(ppwszLdapVal);
  4725. }
  4726. if (NULL != pmsg)
  4727. {
  4728. ldap_msgfree(pmsg);
  4729. }
  4730. return(hr);
  4731. }
  4732. // Set OID_PROP_LOCALIZED_NAME on the appropriate OID object under g_wszCNOID.
  4733. HRESULT
  4734. verbOIDName(
  4735. IN WCHAR const *pwszOption,
  4736. IN WCHAR const *pwszObjId,
  4737. OPTIONAL IN WCHAR const *pwszDisplayName,
  4738. OPTIONAL IN WCHAR const *pwszLanguageId,
  4739. OPTIONAL IN WCHAR const *pwszType)
  4740. {
  4741. HRESULT hr;
  4742. DWORD dwLanguageId;
  4743. DWORD dwType;
  4744. WCHAR const *pwszName;
  4745. LDAP *pld = NULL;
  4746. BSTR strDomainDN = NULL;
  4747. BSTR strConfigDN = NULL;
  4748. WCHAR *pwszOIDCN = NULL;
  4749. WCHAR *pwszOIDContainer = NULL;
  4750. WCHAR *pwszOIDDN = NULL;
  4751. WCHAR **ppwszLdapVal = NULL;
  4752. BOOL fObjectExists = FALSE;
  4753. BOOL fLangIdExists = FALSE;
  4754. WCHAR *pwszError = NULL;
  4755. if (NULL != pwszLanguageId)
  4756. {
  4757. hr = myGetLong(pwszLanguageId, (LONG *) &dwLanguageId);
  4758. _JumpIfError(hr, error, "dwLanguageId must be a number");
  4759. if (64 * 1024 <= dwLanguageId)
  4760. {
  4761. hr = E_INVALIDARG;
  4762. _JumpError(hr, error, "dwLanguageId too large");
  4763. }
  4764. }
  4765. else
  4766. {
  4767. dwLanguageId = GetUserDefaultUILanguage();
  4768. if (0 == dwLanguageId)
  4769. {
  4770. dwLanguageId = GetSystemDefaultUILanguage();
  4771. }
  4772. if (g_fVerbose)
  4773. {
  4774. wprintf(
  4775. L"%ws: %x (%u)\n",
  4776. myLoadResourceString(IDS_SYSLANGID_COLON), // "System default Language Id:"
  4777. dwLanguageId,
  4778. dwLanguageId);
  4779. }
  4780. }
  4781. if (NULL != pwszType)
  4782. {
  4783. hr = myGetLong(pwszType, (LONG *) &dwType);
  4784. _JumpIfError(hr, error, "dwType must be a number");
  4785. }
  4786. else
  4787. {
  4788. dwType = MAXDWORD;
  4789. }
  4790. hr = myVerifyObjId(pwszObjId);
  4791. if (S_OK != hr)
  4792. {
  4793. wprintf(myLoadResourceString(IDS_INVALID_OBJECTID)); // "Invalid ObjectId"
  4794. wprintf(wszNewLine);
  4795. _JumpError(hr, error, "myVerifyObjId");
  4796. }
  4797. pwszName = cuGetOIDName(pwszObjId);
  4798. if (S_OK == hr || L'\0' != *pwszName)
  4799. {
  4800. if (L'\0' == *pwszName)
  4801. {
  4802. pwszName = myLoadResourceString(IDS_UNKNOWN_OBJECTID); // "Unknown ObjectId"
  4803. }
  4804. wprintf(L"%ws -- %ws\n", pwszObjId, pwszName);
  4805. }
  4806. hr = myOIDHashOIDToString(pwszObjId, &pwszOIDCN);
  4807. _JumpIfError(hr, error, "myOIDHashOIDToString");
  4808. hr = myLdapOpen(
  4809. g_pwszDC,
  4810. NULL != pwszDisplayName? RLBF_REQUIRE_SECURE_LDAP : 0,
  4811. &pld,
  4812. &strDomainDN,
  4813. &strConfigDN);
  4814. if (S_OK != hr)
  4815. {
  4816. _PrintError2(hr, "myLdapOpen", HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN));
  4817. if (NULL == pwszDisplayName)
  4818. {
  4819. hr = S_OK;
  4820. }
  4821. goto error;
  4822. }
  4823. hr = BuildDN(g_wszCNOID, strConfigDN, FALSE, &pwszOIDContainer);
  4824. _JumpIfError(hr, error, "BuildDN");
  4825. hr = BuildDN(pwszOIDCN, pwszOIDContainer, TRUE, &pwszOIDDN);
  4826. _JumpIfError(hr, error, "BuildDN");
  4827. hr = dsDumpOIDDisplayNames(
  4828. pld,
  4829. pwszOIDDN,
  4830. pwszObjId,
  4831. dwLanguageId,
  4832. &dwType,
  4833. &fObjectExists,
  4834. &fLangIdExists,
  4835. &ppwszLdapVal);
  4836. _JumpIfError(hr, error, "dsDumpOIDDisplayNames");
  4837. if (NULL != pwszDisplayName)
  4838. {
  4839. DWORD dwDisposition;
  4840. if (0 == LSTRCMPIS(pwszDisplayName, L"delete"))
  4841. {
  4842. pwszDisplayName = NULL; // delete existing entry
  4843. }
  4844. if (fObjectExists)
  4845. {
  4846. if (fLangIdExists)
  4847. {
  4848. if (!g_fForce && NULL != pwszDisplayName)
  4849. {
  4850. hr = HRESULT_FROM_WIN32(RPC_S_ENTRY_ALREADY_EXISTS);
  4851. _JumpError(hr, error, "ldap_get_values");
  4852. }
  4853. }
  4854. else
  4855. {
  4856. if (NULL == pwszDisplayName)
  4857. {
  4858. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  4859. _JumpError(hr, error, "not found");
  4860. }
  4861. }
  4862. }
  4863. else
  4864. {
  4865. if (!g_fForce || NULL == pwszDisplayName)
  4866. {
  4867. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  4868. _JumpError(hr, error, "ldap_first/next_entry");
  4869. }
  4870. }
  4871. //wprintf(L"%u: %u,%ws\n", dwType, dwLanguageId, pwszDisplayName);
  4872. if (!fObjectExists)
  4873. {
  4874. CSASSERT(NULL != pwszDisplayName);
  4875. if (MAXDWORD == dwType)
  4876. {
  4877. dwType = CERT_OID_TYPE_TEMPLATE;
  4878. }
  4879. hr = myLdapCreateOIDObject(
  4880. pld,
  4881. pwszOIDDN,
  4882. dwType,
  4883. pwszObjId,
  4884. &dwDisposition,
  4885. &pwszError);
  4886. _JumpIfError(hr, error, "myLdapCreateOIDObject");
  4887. CSASSERT(NULL == pwszError);
  4888. }
  4889. hr = myLdapAddOrDeleteOIDDisplayNameToAttribute(
  4890. pld,
  4891. ppwszLdapVal,
  4892. dwLanguageId,
  4893. pwszDisplayName,
  4894. pwszOIDDN,
  4895. OID_PROP_LOCALIZED_NAME,
  4896. &dwDisposition,
  4897. &pwszError);
  4898. _JumpIfError(hr, error, "myLdapAddOrDeleteOIDDisplayNameToAttribute");
  4899. wprintf(wszNewLine);
  4900. if (LDAP_SUCCESS == dwDisposition)
  4901. {
  4902. wprintf(
  4903. myLoadResourceString(
  4904. NULL == pwszDisplayName?
  4905. IDS_FORMAT_DELETED_FROM_DS_STORE : // "%ws deleted from DS store."
  4906. IDS_FORMAT_ADDED_TO_DS_STORE), // "%ws added to DS store."
  4907. myLoadResourceString(IDS_LOCALIZEDNAME)); // "Localized name"
  4908. wprintf(wszNewLine);
  4909. hr = dsDumpOIDDisplayNames(
  4910. pld,
  4911. pwszOIDDN,
  4912. pwszObjId,
  4913. dwLanguageId,
  4914. &dwType,
  4915. &fObjectExists,
  4916. &fLangIdExists,
  4917. NULL); // pppwszLdapVal
  4918. _JumpIfError(hr, error, "dsDumpOIDDisplayNames");
  4919. }
  4920. else
  4921. {
  4922. CSASSERT(LDAP_ATTRIBUTE_OR_VALUE_EXISTS == dwDisposition);
  4923. CSASSERT(NULL != pwszDisplayName);
  4924. wprintf(
  4925. myLoadResourceString(IDS_FORMAT_ALREADY_IN_DS_STORE), // "%ws already in DS store."
  4926. myLoadResourceString(IDS_LOCALIZEDNAME)); // "Localized name"
  4927. wprintf(wszNewLine);
  4928. }
  4929. }
  4930. hr = S_OK;
  4931. error:
  4932. if (NULL != pwszError)
  4933. {
  4934. wprintf(L"%ws\n", pwszError);
  4935. LocalFree(pwszError);
  4936. }
  4937. if (NULL != ppwszLdapVal)
  4938. {
  4939. ldap_value_free(ppwszLdapVal);
  4940. }
  4941. if (NULL != pwszOIDCN)
  4942. {
  4943. LocalFree(pwszOIDCN);
  4944. }
  4945. if (NULL != pwszOIDDN)
  4946. {
  4947. LocalFree(pwszOIDDN);
  4948. }
  4949. if (NULL != pwszOIDContainer)
  4950. {
  4951. LocalFree(pwszOIDContainer);
  4952. }
  4953. myLdapClose(pld, strDomainDN, strConfigDN);
  4954. return(hr);
  4955. }
  4956. HRESULT
  4957. verbPulse(
  4958. IN WCHAR const *pwszOption,
  4959. IN WCHAR const *pwszArg1,
  4960. IN WCHAR const *pwszArg2,
  4961. IN WCHAR const *pwszArg3,
  4962. IN WCHAR const *pwszArg4)
  4963. {
  4964. HRESULT hr;
  4965. HANDLE hEventAE = NULL;
  4966. LPCWSTR pcwszGlobal = L"Global\\";
  4967. CAutoLPWSTR pwszEvent;
  4968. pwszEvent = (LPWSTR) LocalAlloc(LMEM_FIXED,
  4969. sizeof(WCHAR)*(1+wcslen(pcwszGlobal)+
  4970. wcslen(MACHINE_AUTOENROLLMENT_TRIGGER_EVENT)));
  4971. _JumpIfAllocFailed(pwszEvent, error);
  4972. wcscpy(pwszEvent, pcwszGlobal);
  4973. wcscat(pwszEvent, MACHINE_AUTOENROLLMENT_TRIGGER_EVENT);
  4974. hEventAE = OpenEvent(
  4975. EVENT_MODIFY_STATE,
  4976. FALSE,
  4977. pwszEvent);
  4978. if (NULL == hEventAE)
  4979. {
  4980. hr = myHLastError();
  4981. _JumpError(hr, error, "OpenEvent");
  4982. }
  4983. if (!PulseEvent(hEventAE))
  4984. {
  4985. hr = myHLastError();
  4986. _JumpError(hr, error, "PulseEvent");
  4987. }
  4988. hr = S_OK;
  4989. error:
  4990. if (NULL != hEventAE)
  4991. {
  4992. CloseHandle(hEventAE);
  4993. }
  4994. return(hr);
  4995. }
  4996. // This function gets the group membership for a given machine...
  4997. HRESULT
  4998. cuGetGroupMembership(
  4999. IN WCHAR const *pwszSamName)
  5000. {
  5001. HRESULT hr;
  5002. WCHAR *pwszDomain = NULL;
  5003. WCHAR *pwszMachine = NULL;
  5004. DOMAIN_CONTROLLER_INFO *pDCInfo = NULL;
  5005. GROUP_USERS_INFO_0 *pgui0 = NULL;
  5006. DWORD cGroup;
  5007. DWORD cGroupTotal;
  5008. DWORD i;
  5009. hr = mySplitConfigString(pwszSamName, &pwszDomain, &pwszMachine);
  5010. _JumpIfError(hr, error, "mySplitConfigString");
  5011. if (NULL == pwszMachine || NULL == wcschr(pwszMachine, L'$'))
  5012. {
  5013. wprintf(myLoadResourceString(IDS_ERROR_CHECK_MACHINE_NAME));
  5014. wprintf(wszNewLine);
  5015. hr = E_INVALIDARG;
  5016. _JumpError(hr, error, "bad machine name");
  5017. }
  5018. hr = DsGetDcName(
  5019. NULL,
  5020. pwszDomain,
  5021. NULL,
  5022. NULL,
  5023. DS_RETURN_FLAT_NAME,
  5024. &pDCInfo);
  5025. if (S_OK != hr)
  5026. {
  5027. hr = myHError(hr);
  5028. _JumpError(hr, error, "DsGetDcName");
  5029. }
  5030. hr = NetUserGetGroups(
  5031. pDCInfo->DomainControllerName,
  5032. pwszMachine,
  5033. 0, // level
  5034. (BYTE **) &pgui0,
  5035. MAX_PREFERRED_LENGTH, // prefmaxlen
  5036. &cGroup,
  5037. &cGroupTotal);
  5038. if (S_OK != hr)
  5039. {
  5040. hr = myHError(hr);
  5041. _JumpError(hr, error, "NetUserGetGroups");
  5042. }
  5043. wprintf(
  5044. L"\n%ws\n",
  5045. myLoadResourceString(IDS_GROUP_LIST_COLON)); // "Group Memberships:"
  5046. for (i = 0; i < cGroup; i++)
  5047. {
  5048. wprintf(L" %ws\n", pgui0[i].grui0_name);
  5049. }
  5050. hr = S_OK;
  5051. error:
  5052. if (NULL != pwszDomain)
  5053. {
  5054. LocalFree(pwszDomain);
  5055. }
  5056. if (NULL != pwszMachine)
  5057. {
  5058. LocalFree(pwszMachine);
  5059. }
  5060. if (NULL != pgui0)
  5061. {
  5062. NetApiBufferFree(pgui0);
  5063. }
  5064. return(hr);
  5065. }
  5066. #define wszDSSPN L"servicePrincipalName"
  5067. #define wszDSOBJECTCATEGORY L"ObjectCategory"
  5068. #define wszDSSAMACCOUNTNAME L"sAMAccountName"
  5069. #define wszDSUSERACCOUNTCONTROL L"userAccountControl"
  5070. HRESULT
  5071. verbMachineInfo(
  5072. IN WCHAR const *pwszOption,
  5073. IN WCHAR const *pwszMachine,
  5074. IN WCHAR const *pwszArg2,
  5075. IN WCHAR const *pwszArg3,
  5076. IN WCHAR const *pwszArg4)
  5077. {
  5078. HRESULT hr;
  5079. LPWSTR pwszDC;
  5080. DWORD dwGetDCFlags = DS_GC_SERVER_REQUIRED | DS_RETURN_DNS_NAME;
  5081. DOMAIN_CONTROLLER_INFO *pDCInfo = NULL;
  5082. DS_NAME_RESULT *pNameResults = NULL;
  5083. ULONG ldaperr;
  5084. WCHAR *pwszError = NULL;
  5085. char *pszFunc = NULL;
  5086. LDAP *pld = NULL;
  5087. LDAPMessage *SearchResult = NULL;
  5088. LDAPMessage *Entry = NULL;
  5089. WCHAR *pwszAttrName = NULL;
  5090. WCHAR **prgVal = NULL;
  5091. WCHAR **prgSPN = NULL;
  5092. WCHAR **prgDNS = NULL;
  5093. berval **Values = NULL;
  5094. BerElement *bElement = NULL;
  5095. BOOL fRediscover;
  5096. HANDLE hDS = NULL;
  5097. WCHAR *apwszAttrName[] = {
  5098. CA_PROP_DNSNAME,
  5099. wszDSSPN,
  5100. wszDSOBJECTCATEGORY,
  5101. wszDSSAMACCOUNTNAME,
  5102. wszDSUSERACCOUNTCONTROL,
  5103. NULL
  5104. };
  5105. WCHAR *ObjectClassFilter = L"objectClass=computer";
  5106. // Get (and check) machine object in DS
  5107. // Check:
  5108. // 1) SPN
  5109. // 2) Group Membership
  5110. // 3) DNSHostName
  5111. // 4) Object Class
  5112. // 5) Object Category
  5113. if (NULL == wcschr(pwszMachine, L'$'))
  5114. {
  5115. wprintf(myLoadResourceString(IDS_ERROR_NO_TRAILING), pwszMachine);
  5116. wprintf(wszNewLine);
  5117. hr = E_INVALIDARG;
  5118. _JumpError(hr, error, "machine name missing $");
  5119. }
  5120. fRediscover = FALSE;
  5121. while (TRUE)
  5122. {
  5123. if (fRediscover)
  5124. {
  5125. dwGetDCFlags |= DS_FORCE_REDISCOVERY;
  5126. }
  5127. // in case we rediscovered...
  5128. if (NULL != pDCInfo)
  5129. {
  5130. NetApiBufferFree(pDCInfo);
  5131. pDCInfo = NULL;
  5132. }
  5133. if (NULL != pNameResults)
  5134. {
  5135. DsFreeNameResult(pNameResults);
  5136. pNameResults = NULL;
  5137. }
  5138. if (NULL != pld)
  5139. {
  5140. ldap_unbind(pld);
  5141. pld = NULL;
  5142. }
  5143. if (NULL != pwszError)
  5144. {
  5145. LocalFree(pwszError);
  5146. pwszError = NULL;
  5147. }
  5148. pszFunc = "DsGetDCName";
  5149. hr = DsGetDcName(NULL, NULL, NULL, NULL, dwGetDCFlags, &pDCInfo);
  5150. if (S_OK != hr)
  5151. {
  5152. hr = myHError(hr);
  5153. _JumpError(hr, error, pszFunc);
  5154. }
  5155. if (NULL == pDCInfo ||
  5156. 0 == (pDCInfo->Flags & DS_GC_FLAG) ||
  5157. 0 == (pDCInfo->Flags & DS_DNS_CONTROLLER_FLAG) ||
  5158. NULL == pDCInfo->DomainControllerName)
  5159. {
  5160. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
  5161. _JumpErrorStr(hr, error, pszFunc, L"pDCInfo");
  5162. }
  5163. // Modify DC name
  5164. pwszDC = pDCInfo->DomainControllerName;
  5165. while (*pwszDC == L'\\')
  5166. {
  5167. pwszDC++;
  5168. }
  5169. pszFunc = "DsBind";
  5170. hr = DsBind(pwszDC, NULL, &hDS);
  5171. if (S_OK != hr)
  5172. {
  5173. hr = myHError(hr);
  5174. _PrintError(hr, pszFunc);
  5175. if (!fRediscover)
  5176. {
  5177. fRediscover = TRUE;
  5178. continue;
  5179. }
  5180. _JumpError(hr, error, pszFunc);
  5181. }
  5182. pszFunc = "DsCrackNames";
  5183. hr = DsCrackNames(
  5184. hDS,
  5185. DS_NAME_NO_FLAGS,
  5186. DS_NT4_ACCOUNT_NAME,
  5187. DS_FQDN_1779_NAME,
  5188. 1, // cNames
  5189. &pwszMachine, // rpNames (IN)
  5190. &pNameResults);
  5191. if (S_OK != hr)
  5192. {
  5193. hr = myHError(hr);
  5194. _PrintError(hr, pszFunc);
  5195. if (!fRediscover) // only do this once
  5196. {
  5197. fRediscover = TRUE;
  5198. continue;
  5199. }
  5200. _JumpError(hr, error, pszFunc);
  5201. }
  5202. if (1 > pNameResults->cItems ||
  5203. DS_NAME_NO_ERROR != pNameResults->rItems[0].status)
  5204. {
  5205. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
  5206. _JumpErrorStr(hr, error, pszFunc, L"pNameResults");
  5207. }
  5208. // ldap_bind to GC
  5209. pszFunc = "ldap_init";
  5210. pld = ldap_init(pwszDC, LDAP_GC_PORT);
  5211. if (NULL == pld)
  5212. {
  5213. hr = myHLdapLastError(NULL, &pwszError);
  5214. _PrintErrorStr(hr, pszFunc, pwszError);
  5215. if (!fRediscover) // only do this once
  5216. {
  5217. fRediscover = TRUE;
  5218. continue;
  5219. }
  5220. _JumpErrorStr(hr, error, pszFunc, pwszError);
  5221. }
  5222. // do this because we're explicitly setting DC name; see bug# 347563
  5223. pszFunc = "ldap_set_option";
  5224. ldaperr = ldap_set_option(pld, LDAP_OPT_AREC_EXCLUSIVE, LDAP_OPT_ON);
  5225. if (LDAP_SUCCESS != ldaperr)
  5226. {
  5227. hr = myHLdapError(pld, ldaperr, &pwszError);
  5228. _PrintErrorStr(hr, pszFunc, pwszError);
  5229. if (!fRediscover) // only do this once
  5230. {
  5231. fRediscover = TRUE;
  5232. continue;
  5233. }
  5234. _JumpErrorStr(hr, error, pszFunc, pwszError);
  5235. }
  5236. pszFunc = "ldap_bind_s";
  5237. ldaperr = ldap_bind_s(pld, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  5238. if (LDAP_SUCCESS != ldaperr)
  5239. {
  5240. hr = myHLdapError(pld, ldaperr, &pwszError);
  5241. _PrintErrorStr(hr, pszFunc, pwszError);
  5242. if (!fRediscover) // only do this once
  5243. {
  5244. fRediscover = TRUE;
  5245. continue;
  5246. }
  5247. _JumpErrorStr(hr, error, pszFunc, pwszError);
  5248. }
  5249. break;
  5250. }
  5251. pszFunc = "ldap_searh_s";
  5252. ldaperr = ldap_search_s(
  5253. pld,
  5254. pNameResults->rItems[0].pName,
  5255. LDAP_SCOPE_BASE,
  5256. ObjectClassFilter,
  5257. apwszAttrName,
  5258. FALSE,
  5259. &SearchResult);
  5260. if (LDAP_SUCCESS != ldaperr)
  5261. {
  5262. hr = myHLdapError(pld, ldaperr, &pwszError);
  5263. _JumpErrorStr(hr, error, pszFunc, pwszError);
  5264. }
  5265. // should only be 1 entry...
  5266. for (Entry = ldap_first_entry(pld, SearchResult);
  5267. NULL != Entry;
  5268. Entry = ldap_next_entry(pld, Entry))
  5269. {
  5270. for (pwszAttrName = ldap_first_attribute(pld, Entry, &bElement);
  5271. NULL != pwszAttrName;
  5272. pwszAttrName = ldap_next_attribute(pld, Entry, bElement))
  5273. {
  5274. DWORD i;
  5275. if (NULL != pwszError)
  5276. {
  5277. LocalFree(pwszError);
  5278. pwszError = NULL;
  5279. }
  5280. prgVal = ldap_get_values(pld, Entry, pwszAttrName);
  5281. if (NULL == prgVal)
  5282. {
  5283. pszFunc = "ldap_get_values";
  5284. hr = myHLdapLastError(pld, &pwszError);
  5285. _PrintErrorStr(hr, pszFunc, pwszError);
  5286. wprintf(L"%hs(%ws): %ws\n", pszFunc, pwszAttrName, pwszError);
  5287. continue;
  5288. }
  5289. // Display values & store away DNSHostName & SPN values for
  5290. // comparison.
  5291. //DisplayLdapValues(pwszAttrName, prgVal);
  5292. wprintf(L"\n%ws:\n", pwszAttrName);
  5293. for (i = 0; NULL != prgVal[i]; i++)
  5294. {
  5295. wprintf(L" %ws\n", prgVal[i]);
  5296. }
  5297. if (0 == LSTRCMPIS(pwszAttrName, CA_PROP_DNSNAME))
  5298. {
  5299. prgDNS = prgVal;
  5300. }
  5301. else if (0 == LSTRCMPIS(pwszAttrName, wszDSSPN))
  5302. {
  5303. prgSPN = prgVal;
  5304. }
  5305. else if (NULL != prgVal)
  5306. {
  5307. ldap_value_free(prgVal);
  5308. prgVal = NULL;
  5309. }
  5310. }
  5311. }
  5312. // There *will* be problems w/SPNs.
  5313. // This should help determine what problems there are.
  5314. if (NULL == prgDNS)
  5315. {
  5316. wprintf(
  5317. myLoadResourceString(IDS_FORMAT_MISSING_MACHINE_ATTRIBUTE), // "Machine object missing %ws attribute."
  5318. CA_PROP_DNSNAME);
  5319. wprintf(wszNewLine);
  5320. }
  5321. if (NULL == prgSPN)
  5322. {
  5323. wprintf(
  5324. myLoadResourceString(IDS_FORMAT_MISSING_MACHINE_ATTRIBUTE), // "Machine object missing %ws attribute."
  5325. wszDSSPN);
  5326. wprintf(wszNewLine);
  5327. }
  5328. // Now let's get the group membership for this machine
  5329. hr = cuGetGroupMembership(pwszMachine);
  5330. _PrintIfError(hr, "cuGetGroupMembership");
  5331. hr = S_OK;
  5332. error:
  5333. if (NULL != prgDNS)
  5334. {
  5335. ldap_value_free(prgDNS);
  5336. }
  5337. if (NULL != prgSPN)
  5338. {
  5339. ldap_value_free(prgSPN);
  5340. }
  5341. if (NULL != SearchResult)
  5342. {
  5343. ldap_msgfree(SearchResult);
  5344. }
  5345. if (NULL != pDCInfo)
  5346. {
  5347. NetApiBufferFree(pDCInfo);
  5348. }
  5349. if (NULL != hDS)
  5350. {
  5351. DsUnBind(&hDS);
  5352. }
  5353. if (NULL != pNameResults)
  5354. {
  5355. DsFreeNameResult(pNameResults);
  5356. }
  5357. if (NULL != pld)
  5358. {
  5359. ldap_unbind(pld);
  5360. }
  5361. if (NULL != pwszError)
  5362. {
  5363. if (NULL != pszFunc)
  5364. {
  5365. wprintf(L"%hs: ", pszFunc);
  5366. }
  5367. wprintf(L"%ws\n", pwszError);
  5368. LocalFree(pwszError);
  5369. }
  5370. return(hr);
  5371. }