Source code of Windows XP (NT5)
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.

1739 lines
45 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: oidmgr.cpp
  7. //
  8. // Contents: DS OID management functions.
  9. //
  10. //---------------------------------------------------------------------------
  11. #include "pch.cpp"
  12. #pragma hdrstop
  13. #include <winldap.h>
  14. #include <ntldap.h>
  15. #include <cainfop.h>
  16. #include <oidmgr.h>
  17. #include <certca.h>
  18. #include "csldap.h"
  19. #define __dwFILE__ __dwFILE_CERTCLIB_OIDMGR_CPP__
  20. //the global critical section
  21. CRITICAL_SECTION g_csOidURL;
  22. extern BOOL g_fOidURL;
  23. ULARGE_INTEGER g_ftOidTime;
  24. BOOL g_fFailedTime=FALSE;
  25. //the # of seconds in which we will not re-find a DC
  26. #define CA_OID_MGR_FAIL_PERIOD 5
  27. #define FILETIME_TICKS_PER_SECOND 10000000
  28. //the cache of the enterprise root oid
  29. LPWSTR g_pwszEnterpriseRootOID=NULL;
  30. static WCHAR * s_wszOIDContainerSearch = L"(&(CN=OID)(objectCategory=" wszDSOIDCLASSNAME L"))";
  31. static WCHAR * s_wszOIDContainerDN = L"CN=OID,CN=Public Key Services,CN=Services,";
  32. WCHAR *g_awszOIDContainerAttrs[] = {OID_CONTAINER_PROP_OID,
  33. OID_CONTAINER_PROP_GUID,
  34. NULL};
  35. //---------------------------------------------------------------------------
  36. //
  37. // CAOIDAllocAndCopy
  38. //
  39. //---------------------------------------------------------------------------
  40. HRESULT CAOIDAllocAndCopy(LPWSTR pwszSrc,
  41. LPWSTR *ppwszDest)
  42. {
  43. if((NULL==ppwszDest) || (NULL==pwszSrc))
  44. return E_INVALIDARG;
  45. *ppwszDest=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (wcslen(pwszSrc) + 1));
  46. if(NULL==(*ppwszDest))
  47. return E_OUTOFMEMORY;
  48. wcscpy(*ppwszDest, pwszSrc);
  49. return S_OK;
  50. }
  51. //---------------------------------------------------------------------------
  52. //
  53. // CAOIDGetRandom
  54. //
  55. // We build a random x1.x2 string. X is a 32 bit unsigned integer. x1 > 1
  56. // and x2 > 500.
  57. //---------------------------------------------------------------------------
  58. HRESULT CAOIDGetRandom(LPWSTR *ppwszRandom)
  59. {
  60. HRESULT hr=E_FAIL;
  61. DWORD dwRandom1=0;
  62. DWORD dwRandom2=0;
  63. DWORD cbData=sizeof(DWORD);
  64. WCHAR wszRandom1[DWORD_STRING_LENGTH];
  65. WCHAR wszRandom2[DWORD_STRING_LENGTH];
  66. HCRYPTPROV hProv=NULL;
  67. //there is a bug in cryptAcquireContextW that if container is NULL, provider
  68. //can not be ansi.
  69. if(!CryptAcquireContextA(
  70. &hProv,
  71. NULL,
  72. MS_DEF_PROV_A,
  73. PROV_RSA_FULL,
  74. CRYPT_VERIFYCONTEXT))
  75. {
  76. hr= myHLastError();
  77. _JumpError(hr, error, "CryptAcquireContextA");
  78. }
  79. if(!CryptGenRandom(hProv, cbData, (BYTE *)&dwRandom1))
  80. {
  81. hr= myHLastError();
  82. _JumpError(hr, error, "CryptGenRandom");
  83. }
  84. if(!CryptGenRandom(hProv, cbData, (BYTE *)&dwRandom2))
  85. {
  86. hr= myHLastError();
  87. _JumpError(hr, error, "CryptGenRandom");
  88. }
  89. if(dwRandom1 <= OID_RESERVE_DEFAULT_ONE)
  90. dwRandom1 +=OID_RESERVE_DEFAULT_ONE;
  91. if(dwRandom2 <= OID_RESERVR_DEFAULT_TWO)
  92. dwRandom2 += OID_RESERVR_DEFAULT_TWO;
  93. wszRandom1[0]=L'\0';
  94. wsprintf(wszRandom1, L"%lu", dwRandom1);
  95. wszRandom2[0]=L'\0';
  96. wsprintf(wszRandom2, L"%lu", dwRandom2);
  97. *ppwszRandom=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) *
  98. (wcslen(wszRandom1) + wcslen(wszOID_DOT) + wcslen(wszRandom2) + 1));
  99. if(NULL==(*ppwszRandom))
  100. {
  101. hr= E_OUTOFMEMORY;
  102. _JumpError(hr, error, "CryptGenRandom");
  103. }
  104. wcscpy(*ppwszRandom, wszRandom1);
  105. wcscat(*ppwszRandom, wszOID_DOT);
  106. wcscat(*ppwszRandom, wszRandom2);
  107. hr=S_OK;
  108. error:
  109. if(hProv)
  110. CryptReleaseContext(hProv, 0);
  111. return hr;
  112. }
  113. //---------------------------------------------------------------------------
  114. //
  115. // CAOIDMapGUIDToOID
  116. //
  117. // GUID string is in the form of DWORD.DWORD.DWORD.DWORD
  118. // 12 characters are sufficient to present a 2^32 value.
  119. //---------------------------------------------------------------------------
  120. HRESULT CAOIDMapGUIDToOID(LDAP_BERVAL *pGuidVal, LPWSTR *ppwszGUID)
  121. {
  122. HRESULT hr=E_INVALIDARG;
  123. DWORD iIndex=0;
  124. WCHAR wszString[DWORD_STRING_LENGTH];
  125. *ppwszGUID=NULL;
  126. if((4 * sizeof(DWORD)) != (pGuidVal->bv_len))
  127. _JumpError(hr, error, "ArgumentCheck");
  128. *ppwszGUID=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * GUID_STRING_LENGTH);
  129. if(NULL==(*ppwszGUID))
  130. {
  131. hr = E_OUTOFMEMORY;
  132. _JumpError(hr, error, "LocalAlloc");
  133. }
  134. for(iIndex=0; iIndex < 4; iIndex++)
  135. {
  136. wszString[0]=L'\0';
  137. wsprintf(wszString, L"%lu", ((DWORD *)(pGuidVal->bv_val))[iIndex]);
  138. if(0==iIndex)
  139. {
  140. wcscpy(*ppwszGUID, wszString);
  141. }
  142. else
  143. {
  144. wcscat(*ppwszGUID, wszOID_DOT);
  145. wcscat(*ppwszGUID, wszString);
  146. }
  147. }
  148. hr = S_OK;
  149. error:
  150. return hr;
  151. }
  152. //--------------------------------------------------------------------------
  153. //
  154. // FormatMessageUnicode
  155. //
  156. //--------------------------------------------------------------------------
  157. HRESULT FormatMessageUnicode(LPWSTR *ppwszFormat,LPWSTR pwszString,...)
  158. {
  159. va_list argList;
  160. DWORD cbMsg=0;
  161. // format message into requested buffer
  162. va_start(argList, pwszString);
  163. cbMsg = FormatMessageW(
  164. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  165. pwszString,
  166. 0, // dwMessageId
  167. 0, // dwLanguageId
  168. (LPWSTR) (ppwszFormat),
  169. 0, // minimum size to allocate
  170. &argList);
  171. va_end(argList);
  172. if(0 != cbMsg)
  173. return S_OK;
  174. return E_INVALIDARG;
  175. }
  176. //---------------------------------------------------------------------------
  177. //
  178. // DoesOIDExist
  179. //
  180. //
  181. //---------------------------------------------------------------------------
  182. BOOL DoesOIDExist(LDAP *pld,
  183. LPWSTR bstrConfig,
  184. LPCWSTR pwszOID)
  185. {
  186. BOOL fExit=FALSE;
  187. struct l_timeval timeout;
  188. ULONG ldaperr=0;
  189. DWORD dwCount=0;
  190. LPWSTR awszAttr[2];
  191. CERTSTR bstrDN = NULL;
  192. LDAPMessage *SearchResult = NULL;
  193. LPWSTR pwszFilter = NULL;
  194. if(NULL==pwszOID)
  195. goto error;
  196. bstrDN = CertAllocStringLen(NULL, wcslen(bstrConfig) + wcslen(s_wszOIDContainerDN));
  197. if(NULL == bstrDN)
  198. goto error;
  199. wcscpy(bstrDN, s_wszOIDContainerDN);
  200. wcscat(bstrDN, bstrConfig);
  201. timeout.tv_sec = csecLDAPTIMEOUT;
  202. timeout.tv_usec = 0;
  203. awszAttr[0]=OID_PROP_OID;
  204. awszAttr[1]=NULL;
  205. if(S_OK != FormatMessageUnicode(&pwszFilter, L"(%1!s!=%2!s!)",
  206. OID_PROP_OID, pwszOID))
  207. goto error;
  208. __try
  209. {
  210. ldaperr = ldap_search_stW(
  211. pld,
  212. (LPWSTR)bstrDN,
  213. LDAP_SCOPE_ONELEVEL,
  214. pwszFilter,
  215. awszAttr,
  216. 0,
  217. &timeout,
  218. &SearchResult);
  219. if(LDAP_SUCCESS != ldaperr)
  220. goto error;
  221. dwCount = ldap_count_entries(pld, SearchResult);
  222. if(0 != dwCount)
  223. fExit=TRUE;
  224. }
  225. __except(EXCEPTION_EXECUTE_HANDLER)
  226. {
  227. }
  228. error:
  229. if(pwszFilter)
  230. LocalFree((HLOCAL)pwszFilter);
  231. if(SearchResult)
  232. ldap_msgfree(SearchResult);
  233. if(bstrDN)
  234. CertFreeString(bstrDN);
  235. return fExit;
  236. }
  237. //---------------------------------------------------------------------------
  238. //
  239. // CAOIDUpdateDS
  240. //
  241. //
  242. //---------------------------------------------------------------------------
  243. HRESULT CAOIDUpdateDS(LDAP *pld,
  244. LPWSTR pwszConfig,
  245. ENT_OID_INFO *pOidInfo)
  246. {
  247. HRESULT hr=E_INVALIDARG;
  248. BOOL fNew=FALSE;
  249. ULONG ldaperr=0;
  250. LDAPMod modObjectClass,
  251. modCN,
  252. modType,
  253. modOID,
  254. modDisplayName,
  255. modCPS;
  256. LDAPMod *mods[OID_ATTR_COUNT + 1];
  257. DWORD cMod=0;
  258. WCHAR wszType[DWORD_STRING_LENGTH];
  259. LPWSTR awszObjectClass[3],
  260. awszCN[2],
  261. awszType[2],
  262. awszOID[2],
  263. awszDisplayName[2],
  264. awszCPS[2];
  265. CHAR sdBerValue[] = {0x30, 0x03, 0x02, 0x01, DACL_SECURITY_INFORMATION |
  266. OWNER_SECURITY_INFORMATION |
  267. GROUP_SECURITY_INFORMATION};
  268. LDAPControl se_info_control =
  269. {
  270. LDAP_SERVER_SD_FLAGS_OID_W,
  271. {
  272. 5, sdBerValue
  273. },
  274. TRUE
  275. };
  276. LDAPControl permissive_modify_control =
  277. {
  278. LDAP_SERVER_PERMISSIVE_MODIFY_OID_W,
  279. {
  280. 0, NULL
  281. },
  282. FALSE
  283. };
  284. PLDAPControl server_controls[3] =
  285. {
  286. &se_info_control,
  287. &permissive_modify_control,
  288. NULL
  289. };
  290. CHAR sdBerValueDaclOnly[] = {0x30, 0x03, 0x02, 0x01, DACL_SECURITY_INFORMATION};
  291. LDAPControl se_info_control_dacl_only =
  292. {
  293. LDAP_SERVER_SD_FLAGS_OID_W,
  294. {
  295. 5, sdBerValueDaclOnly
  296. },
  297. TRUE
  298. };
  299. PLDAPControl server_controls_dacl_only[3] =
  300. {
  301. &se_info_control_dacl_only,
  302. &permissive_modify_control,
  303. NULL
  304. };
  305. CERTSTR bstrDN = NULL;
  306. LPWSTR pwszCN = NULL;
  307. if(NULL== (pOidInfo->pwszOID))
  308. _JumpError(hr , error, "ArgumentCheck");
  309. //if we are changing the OID value, we are creating a new oid
  310. fNew = OID_ATTR_OID & (pOidInfo->dwAttr);
  311. //set up the base DN
  312. if(S_OK != (hr = myOIDHashOIDToString(pOidInfo->pwszOID, &pwszCN)))
  313. _JumpError(hr , error, "myOIDHashOIDToString");
  314. bstrDN = CertAllocStringLen(NULL, wcslen(pwszConfig) + wcslen(s_wszOIDContainerDN)+wcslen(pwszCN)+4);
  315. if(bstrDN == NULL)
  316. {
  317. hr = E_OUTOFMEMORY;
  318. _JumpError(hr, error, "CertAllocStringLen");
  319. }
  320. wcscpy(bstrDN, L"CN=");
  321. wcscat(bstrDN, pwszCN);
  322. wcscat(bstrDN, L",");
  323. wcscat(bstrDN, s_wszOIDContainerDN);
  324. wcscat(bstrDN, pwszConfig);
  325. //set up all the mods
  326. modObjectClass.mod_op = LDAP_MOD_REPLACE;
  327. modObjectClass.mod_type = L"objectclass";
  328. modObjectClass.mod_values = awszObjectClass;
  329. awszObjectClass[0] = wszDSTOPCLASSNAME;
  330. awszObjectClass[1] = wszDSOIDCLASSNAME;
  331. awszObjectClass[2] = NULL;
  332. mods[cMod++] = &modObjectClass;
  333. modCN.mod_op = LDAP_MOD_REPLACE;
  334. modCN.mod_type = L"cn";
  335. modCN.mod_values = awszCN;
  336. awszCN[0] = pwszCN;
  337. awszCN[1] = NULL;
  338. mods[cMod++] = &modCN;
  339. modOID.mod_op = LDAP_MOD_REPLACE;
  340. modOID.mod_type = OID_PROP_OID;
  341. modOID.mod_values = awszOID;
  342. awszOID[0] = pOidInfo->pwszOID;
  343. awszOID[1] = NULL;
  344. mods[cMod++] = &modOID;
  345. if(OID_ATTR_DISPLAY_NAME & (pOidInfo->dwAttr))
  346. {
  347. modDisplayName.mod_op = LDAP_MOD_REPLACE;
  348. modDisplayName.mod_type = OID_PROP_DISPLAY_NAME;
  349. if(pOidInfo->pwszDisplayName)
  350. {
  351. modDisplayName.mod_values = awszDisplayName;
  352. awszDisplayName[0] = pOidInfo->pwszDisplayName;
  353. awszDisplayName[1] = NULL;
  354. }
  355. else
  356. modDisplayName.mod_values = NULL;
  357. if(!fNew)
  358. mods[cMod++] = &modDisplayName;
  359. }
  360. if(OID_ATTR_CPS & (pOidInfo->dwAttr))
  361. {
  362. modCPS.mod_op = LDAP_MOD_REPLACE;
  363. modCPS.mod_type = OID_PROP_CPS;
  364. if(pOidInfo->pwszCPS)
  365. {
  366. modCPS.mod_values = awszCPS;
  367. awszCPS[0] = pOidInfo->pwszCPS;
  368. awszCPS[1] = NULL;
  369. }
  370. else
  371. modCPS.mod_values = NULL;
  372. if(!fNew)
  373. mods[cMod++] = &modCPS;
  374. }
  375. if(OID_ATTR_TYPE & (pOidInfo->dwAttr))
  376. {
  377. modType.mod_op = LDAP_MOD_REPLACE;
  378. modType.mod_type = OID_PROP_TYPE;
  379. modType.mod_values = awszType;
  380. awszType[0] = wszType;
  381. awszType[1] = NULL;
  382. wsprintf(wszType, L"%d", pOidInfo->dwType);
  383. mods[cMod++] = &modType;
  384. }
  385. mods[cMod++]=NULL;
  386. //update the DS
  387. __try
  388. {
  389. if(fNew)
  390. {
  391. ldaperr = ldap_add_ext_sW(pld, bstrDN, mods, server_controls, NULL);
  392. _PrintIfError(ldaperr, "ldap_add_s");
  393. }
  394. else
  395. {
  396. ldaperr = ldap_modify_ext_sW(
  397. pld,
  398. bstrDN,
  399. &mods[2],
  400. server_controls_dacl_only,
  401. NULL); // skip past objectClass and cn
  402. if(LDAP_ATTRIBUTE_OR_VALUE_EXISTS == ldaperr)
  403. ldaperr = LDAP_SUCCESS;
  404. _PrintIfError(ldaperr, "ldap_modify_ext_sW");
  405. }
  406. if ((LDAP_SUCCESS != ldaperr) && (LDAP_ALREADY_EXISTS != ldaperr))
  407. {
  408. hr = myHLdapError(pld, ldaperr, NULL);
  409. _JumpError(ldaperr, error, fNew? "ldap_add_s" : "ldap_modify_sW");
  410. }
  411. hr=S_OK;
  412. }
  413. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  414. {
  415. }
  416. error:
  417. if(pwszCN)
  418. LocalFree(pwszCN);
  419. if(bstrDN)
  420. CertFreeString(bstrDN);
  421. return hr;
  422. }
  423. //---------------------------------------------------------------------------
  424. //
  425. // CAOIDRetrieveEnterpriseRootWithConfig
  426. //
  427. // Get the enterpriseRoot from the displayName attribute of the container.
  428. // If the attribute is missing, add the one with GUID of the container.
  429. //
  430. // Free memory via LocalFree().
  431. //---------------------------------------------------------------------------
  432. HRESULT CAOIDRetrieveEnterpriseRootWithConfig(LDAP *pld,
  433. LPWSTR pwszConfig,
  434. DWORD dwFlag,
  435. LPWSTR *ppwszOID)
  436. {
  437. HRESULT hr=E_INVALIDARG;
  438. struct l_timeval timeout;
  439. ULONG ldaperr=0;
  440. DWORD dwCount=0;
  441. LDAPMessage *Entry=NULL;
  442. LDAPMod *mods[2];
  443. LDAPMod modOIDName;
  444. LPWSTR valOIDName[2];
  445. CHAR sdBerValueDaclOnly[] = {0x30, 0x03, 0x02, 0x01, DACL_SECURITY_INFORMATION};
  446. LDAPControl se_info_control_dacl_only =
  447. {
  448. LDAP_SERVER_SD_FLAGS_OID_W,
  449. {
  450. 5, sdBerValueDaclOnly
  451. },
  452. TRUE
  453. };
  454. LDAPControl permissive_modify_control =
  455. {
  456. LDAP_SERVER_PERMISSIVE_MODIFY_OID_W,
  457. {
  458. 0, NULL
  459. },
  460. FALSE
  461. };
  462. PLDAPControl server_controls_dacl_only[3] =
  463. {
  464. &se_info_control_dacl_only,
  465. &permissive_modify_control,
  466. NULL
  467. };
  468. CERTSTR bstrOIDContainer = NULL;
  469. LDAPMessage *SearchResult = NULL;
  470. WCHAR **wszLdapVal = NULL;
  471. LDAP_BERVAL **pGuidVal = NULL;
  472. LPWSTR pwszGUID = NULL;
  473. __try
  474. {
  475. if(NULL==ppwszOID)
  476. _JumpError(hr , error, "ArgumentCheck");
  477. *ppwszOID=NULL;
  478. //retrive the displayName attribute of the container if available
  479. bstrOIDContainer = CertAllocStringLen(NULL, wcslen(pwszConfig) + wcslen(s_wszOIDContainerDN));
  480. if(NULL == bstrOIDContainer)
  481. {
  482. hr = E_OUTOFMEMORY;
  483. _JumpError(hr, error, "CertAllocStringLen");
  484. }
  485. wcscpy(bstrOIDContainer, s_wszOIDContainerDN);
  486. wcscat(bstrOIDContainer, pwszConfig);
  487. timeout.tv_sec = csecLDAPTIMEOUT;
  488. timeout.tv_usec = 0;
  489. ldaperr = ldap_search_stW(
  490. pld,
  491. (LPWSTR)bstrOIDContainer,
  492. LDAP_SCOPE_BASE,
  493. s_wszOIDContainerSearch,
  494. g_awszOIDContainerAttrs,
  495. 0,
  496. &timeout,
  497. &SearchResult);
  498. if(LDAP_SUCCESS != ldaperr)
  499. {
  500. hr = myHLdapError(pld, ldaperr, NULL);
  501. _JumpError(hr, error, "ldap_search_stW");
  502. }
  503. dwCount = ldap_count_entries(pld, SearchResult);
  504. //we should only find one container
  505. if((1 != dwCount) || (NULL == (Entry = ldap_first_entry(pld, SearchResult))))
  506. {
  507. // No entries were found.
  508. hr = myHLdapError(pld, LDAP_NO_SUCH_OBJECT, NULL);
  509. _JumpError(hr, error, "ldap_search_stW");
  510. }
  511. wszLdapVal = ldap_get_values(pld, Entry, OID_CONTAINER_PROP_OID);
  512. //make sure the displayName is a valud enterprise OID
  513. if(wszLdapVal && wszLdapVal[0])
  514. {
  515. hr=CAOIDAllocAndCopy(wszLdapVal[0], ppwszOID);
  516. if(S_OK == hr)
  517. {
  518. //cache the enterprise root
  519. CAOIDAllocAndCopy(*ppwszOID, &g_pwszEnterpriseRootOID);
  520. goto error;
  521. }
  522. }
  523. //no displayName is present or valid, we have to derive the displayName
  524. //from the GUID of the container
  525. pGuidVal = ldap_get_values_len(pld, Entry, OID_CONTAINER_PROP_GUID);
  526. if((NULL==pGuidVal) || (NULL==pGuidVal[0]))
  527. {
  528. hr = myHLdapError(pld, LDAP_NO_SUCH_ATTRIBUTE, NULL);
  529. _JumpError(hr, error, "getGUIDFromDS");
  530. }
  531. if(S_OK != (hr=CAOIDMapGUIDToOID(pGuidVal[0], &pwszGUID)))
  532. _JumpError(hr, error, "CAOIDMapGUIDToOID");
  533. //contantenate the strings
  534. *ppwszOID=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) *
  535. (wcslen(wszOID_ENTERPRISE_ROOT) + wcslen(wszOID_DOT) + wcslen(pwszGUID) + 1));
  536. if(NULL==(*ppwszOID))
  537. {
  538. hr=E_OUTOFMEMORY;
  539. _JumpError(hr, error, "LocalAlloc");
  540. }
  541. wcscpy(*ppwszOID, wszOID_ENTERPRISE_ROOT);
  542. wcscat(*ppwszOID, wszOID_DOT);
  543. wcscat(*ppwszOID, pwszGUID);
  544. //cache the newly created displayName to the DS
  545. //no need to check for error since this is just a performance enhancement
  546. valOIDName[0]=*ppwszOID;
  547. valOIDName[1]=NULL;
  548. modOIDName.mod_op = LDAP_MOD_REPLACE;
  549. modOIDName.mod_type = OID_CONTAINER_PROP_OID;
  550. modOIDName.mod_values = valOIDName;
  551. mods[0]=&modOIDName;
  552. mods[1]=NULL;
  553. ldap_modify_ext_sW(
  554. pld,
  555. bstrOIDContainer,
  556. mods,
  557. server_controls_dacl_only,
  558. NULL);
  559. //cache the oid root in memory
  560. CAOIDAllocAndCopy(*ppwszOID, &g_pwszEnterpriseRootOID);
  561. hr = S_OK;
  562. }
  563. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  564. {
  565. }
  566. error:
  567. if(pwszGUID)
  568. LocalFree(pwszGUID);
  569. if(pGuidVal)
  570. ldap_value_free_len(pGuidVal);
  571. if(wszLdapVal)
  572. ldap_value_free(wszLdapVal);
  573. if(SearchResult)
  574. ldap_msgfree(SearchResult);
  575. if (bstrOIDContainer)
  576. CertFreeString(bstrOIDContainer);
  577. return hr;
  578. }
  579. //---------------------------------------------------------------------------
  580. //
  581. // CAOIDRetrieveEnterpriseRoot
  582. //
  583. // Get the enterpriseRoot from the displayName attribute of the container.
  584. // If the attribute is missing, add the one with GUID of the container.
  585. //
  586. // Free memory via LocalFree().
  587. //---------------------------------------------------------------------------
  588. HRESULT CAOIDRetrieveEnterpriseRoot(DWORD dwFlag, LPWSTR *ppwszOID)
  589. {
  590. HRESULT hr=E_INVALIDARG;
  591. LDAP *pld = NULL;
  592. CERTSTR bstrConfig = NULL;
  593. if(NULL==ppwszOID)
  594. _JumpError(hr , error, "ArgumentCheck");
  595. *ppwszOID=NULL;
  596. //retrieve the memory cache if available
  597. if(g_pwszEnterpriseRootOID)
  598. {
  599. hr=CAOIDAllocAndCopy(g_pwszEnterpriseRootOID, ppwszOID);
  600. goto error;
  601. }
  602. //retrieve the ldap handle and the config string
  603. if(S_OK != (hr = myDoesDSExist(TRUE)))
  604. _JumpError(hr , error, "myDoesDSExist");
  605. if(S_OK != (hr = myRobustLdapBind(&pld, FALSE)))
  606. _JumpError(hr , error, "myRobustLdapBind");
  607. hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
  608. if(S_OK != hr)
  609. {
  610. _JumpError(hr , error, "CAGetAuthoritativeDomainDn");
  611. }
  612. hr = CAOIDRetrieveEnterpriseRootWithConfig(pld, bstrConfig,
  613. dwFlag, ppwszOID);
  614. error:
  615. if(bstrConfig)
  616. CertFreeString(bstrConfig);
  617. if (pld)
  618. ldap_unbind(pld);
  619. return hr;
  620. }
  621. //---------------------------------------------------------------------------
  622. //
  623. // CAOIDBuildOIDWithRoot
  624. //
  625. //
  626. // Free memory via LocalFree().
  627. //---------------------------------------------------------------------------
  628. HRESULT CAOIDBuildOIDWithRoot(DWORD dwFlag, LPCWSTR pwszRoot, LPCWSTR pwszEndOID, LPWSTR *ppwszOID)
  629. {
  630. HRESULT hr=E_INVALIDARG;
  631. if(NULL==pwszRoot)
  632. _JumpError(hr , error, "ArgumentCheck");
  633. *ppwszOID=NULL;
  634. *ppwszOID=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) *
  635. (wcslen(pwszRoot) + wcslen(wszOID_DOT) + wcslen(pwszEndOID) + 1));
  636. if(NULL==(*ppwszOID))
  637. {
  638. hr = E_OUTOFMEMORY;
  639. _JumpError(hr , error, "LocalAlloc");
  640. }
  641. wcscpy(*ppwszOID, pwszRoot);
  642. wcscat(*ppwszOID, wszOID_DOT);
  643. wcscat(*ppwszOID, pwszEndOID);
  644. hr= S_OK;
  645. error:
  646. return hr;
  647. }
  648. //---------------------------------------------------------------------------
  649. //
  650. // CAOIDBuildOID
  651. //
  652. //
  653. // Free memory via LocalFree().
  654. //---------------------------------------------------------------------------
  655. HRESULT CAOIDBuildOID(DWORD dwFlag, LPCWSTR pwszEndOID, LPWSTR *ppwszOID)
  656. {
  657. HRESULT hr=E_INVALIDARG;
  658. LPWSTR pwszRoot=NULL;
  659. if((NULL==ppwszOID) || (NULL==pwszEndOID))
  660. _JumpError(hr , error, "ArgumentCheck");
  661. *ppwszOID=NULL;
  662. if(S_OK != (hr=CAOIDRetrieveEnterpriseRoot(0, &pwszRoot)))
  663. _JumpError(hr , error, "RetrieveEnterpriseRoot");
  664. hr= CAOIDBuildOIDWithRoot(dwFlag, pwszRoot, pwszEndOID, ppwszOID);
  665. error:
  666. if(pwszRoot)
  667. LocalFree(pwszRoot);
  668. return hr;
  669. }
  670. //------------------------------------------------------------------------
  671. // Convert the byte to its Hex presentation.
  672. //
  673. //
  674. //------------------------------------------------------------------------
  675. ULONG ByteToHex(BYTE byte, LPWSTR wszZero, LPWSTR wszA)
  676. {
  677. ULONG uValue=0;
  678. if(((ULONG)byte)<=9)
  679. {
  680. uValue=((ULONG)byte)+ULONG(*wszZero);
  681. }
  682. else
  683. {
  684. uValue=(ULONG)byte-10+ULONG(*wszA);
  685. }
  686. return uValue;
  687. }
  688. //--------------------------------------------------------------------------
  689. //
  690. // ConvertByteToWstr
  691. //
  692. // If fSpace is TRUE, we add a space every 2 bytes.
  693. //--------------------------------------------------------------------------
  694. HRESULT ConvertByteToWstr(BYTE *pbData,
  695. DWORD cbData,
  696. LPWSTR *ppwsz)
  697. {
  698. HRESULT hr=E_INVALIDARG;
  699. DWORD dwBufferSize=0;
  700. DWORD dwBufferIndex=0;
  701. DWORD dwEncodedIndex=0;
  702. LPWSTR pwszZero=L"0";
  703. LPWSTR pwszA=L"A";
  704. if(!pbData || !ppwsz)
  705. _JumpError(hr , error, "ArgumentCheck");
  706. //calculate the memory needed, in bytes
  707. //we need 2 wchars per byte, along with the NULL terminator
  708. dwBufferSize=sizeof(WCHAR)*(cbData*2+1);
  709. *ppwsz=(LPWSTR)LocalAlloc(LPTR, dwBufferSize);
  710. if(NULL==(*ppwsz))
  711. {
  712. hr=E_OUTOFMEMORY;
  713. _JumpError(hr , error, "LocalAlloc");
  714. }
  715. dwBufferIndex=0;
  716. //format the wchar buffer one byte at a time
  717. for(dwEncodedIndex=0; dwEncodedIndex<cbData; dwEncodedIndex++)
  718. {
  719. //format the higher 4 bits
  720. (*ppwsz)[dwBufferIndex]=(WCHAR)ByteToHex(
  721. (pbData[dwEncodedIndex]&UPPER_BITS)>>4,
  722. pwszZero, pwszA);
  723. dwBufferIndex++;
  724. //format the lower 4 bits
  725. (*ppwsz)[dwBufferIndex]=(WCHAR)ByteToHex(
  726. pbData[dwEncodedIndex]&LOWER_BITS,
  727. pwszZero, pwszA);
  728. dwBufferIndex++;
  729. }
  730. //add the NULL terminator to the string
  731. (*ppwsz)[dwBufferIndex]=L'\0';
  732. hr=S_OK;
  733. error:
  734. return hr;
  735. }
  736. //---------------------------------------------------------------------------
  737. // myOIDHashOIDToString
  738. //
  739. // Map the OID to a hash string in the format of oid.hash.
  740. //---------------------------------------------------------------------------
  741. HRESULT
  742. myOIDHashOIDToString(
  743. IN WCHAR const *pwszOID,
  744. OUT WCHAR **ppwsz)
  745. {
  746. HRESULT hr=E_INVALIDARG;
  747. BYTE pbHash[CERT_OID_MD5_HASH_SIZE];
  748. DWORD cbData=CERT_OID_MD5_HASH_SIZE;
  749. LPCWSTR pwszChar=NULL;
  750. DWORD dwIDLength=CERT_OID_IDENTITY_LENGTH;
  751. LPWSTR pwszHash=NULL;
  752. if((NULL==pwszOID) || (NULL==ppwsz))
  753. _JumpError(hr , error, "ArgumentCheck");
  754. *ppwsz=NULL;
  755. hr = myVerifyObjId(pwszOID);
  756. _JumpIfErrorStr2(hr, error, "myVerifyObjId", pwszOID, E_INVALIDARG);
  757. if(!CryptHashCertificate(
  758. NULL,
  759. CALG_MD5,
  760. 0,
  761. (BYTE * )pwszOID,
  762. sizeof(WCHAR) * wcslen(pwszOID),
  763. pbHash,
  764. &cbData))
  765. {
  766. hr= myHLastError();
  767. _JumpError(hr , error, "CryptHashCertificate");
  768. }
  769. //convert the hash to a string
  770. if(S_OK != (hr=ConvertByteToWstr(pbHash, CERT_OID_MD5_HASH_SIZE, &pwszHash)))
  771. _JumpError(hr , error, "ConvertByteToWstr");
  772. //find the last component of the oid. Take the first 16 characters
  773. pwszChar=wcsrchr(pwszOID, L'.');
  774. if(NULL==pwszChar)
  775. pwszChar=pwszOID;
  776. else
  777. pwszChar++;
  778. if(dwIDLength > wcslen(pwszChar))
  779. dwIDLength=wcslen(pwszChar);
  780. //the result string is oid.hash
  781. *ppwsz=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) *
  782. (dwIDLength + wcslen(pwszHash) + wcslen(wszOID_DOT) +1));
  783. if(NULL==*ppwsz)
  784. {
  785. hr= E_OUTOFMEMORY;
  786. _JumpError(hr , error, "LocalAlloc");
  787. }
  788. wcsncpy(*ppwsz, pwszChar, dwIDLength);
  789. (*ppwsz)[dwIDLength]=L'\0';
  790. wcscat(*ppwsz, wszOID_DOT);
  791. wcscat(*ppwsz, pwszHash);
  792. hr=S_OK;
  793. error:
  794. if(pwszHash)
  795. LocalFree(pwszHash);
  796. return hr;
  797. }
  798. //---------------------------------------------------------------------------
  799. // I_CAOIDCreateNew
  800. // Create a new OID based on the enterprise base
  801. //
  802. // Returns S_OK if successful.
  803. //---------------------------------------------------------------------------
  804. HRESULT I_CAOIDCreateNew(DWORD dwType, DWORD dwFlag, LPWSTR *ppwszOID)
  805. {
  806. HRESULT hr=E_INVALIDARG;
  807. ENT_OID_INFO oidInfo;
  808. DWORD iIndex=0;
  809. LDAP *pld = NULL;
  810. CERTSTR bstrConfig = NULL;
  811. LPWSTR pwszRoot = NULL;
  812. LPWSTR pwszNewOID = NULL;
  813. LPWSTR pwszRandom = NULL;
  814. if(NULL==ppwszOID)
  815. _JumpError(hr , error, "ArgumentCheck");
  816. *ppwszOID=NULL;
  817. //retrieve the root oid if available
  818. if(g_pwszEnterpriseRootOID)
  819. {
  820. if(S_OK != (hr=CAOIDAllocAndCopy(g_pwszEnterpriseRootOID, &pwszRoot)))
  821. goto error;
  822. }
  823. //retrieve the ldap handle and the config string
  824. if(S_OK != (hr = myDoesDSExist(TRUE)))
  825. _JumpError(hr , error, "myDoesDSExist");
  826. if(S_OK != (hr = myRobustLdapBind(&pld, FALSE)))
  827. _JumpError(hr , error, "myRobustLdapBind");
  828. hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
  829. if(S_OK != hr)
  830. {
  831. _JumpError(hr , error, "CAGetAuthoritativeDomainDn");
  832. }
  833. if(NULL==pwszRoot)
  834. {
  835. if(S_OK != (hr = CAOIDRetrieveEnterpriseRootWithConfig(pld, bstrConfig, 0, &pwszRoot)))
  836. _JumpError(hr , error, "CAOIDRetrieveEnterpriseRootWithConfig");
  837. }
  838. //we try to generate a random x1.x2 oid. x > 1 and x2 > 500
  839. for(iIndex=0; iIndex < OID_RANDOM_CREATION_TRIAL; iIndex++)
  840. {
  841. if(S_OK != (hr = CAOIDGetRandom(&pwszRandom)))
  842. _JumpError(hr , error, "CAOIDGetRandom");
  843. if(S_OK != (hr = CAOIDBuildOIDWithRoot(0, pwszRoot, pwszRandom, &pwszNewOID)))
  844. _JumpError(hr , error, "CAOIDBuildOIDWithRoot");
  845. if(!DoesOIDExist(pld, bstrConfig, pwszNewOID))
  846. break;
  847. LocalFree(pwszRandom);
  848. pwszRandom=NULL;
  849. LocalFree(pwszNewOID);
  850. pwszNewOID=NULL;
  851. }
  852. if(iIndex == OID_RANDOM_CREATION_TRIAL)
  853. {
  854. hr=E_FAIL;
  855. _JumpError(hr , error, "CAOIDGetRandom");
  856. }
  857. //update the oid information on the DS
  858. memset(&oidInfo, 0, sizeof(ENT_OID_INFO));
  859. oidInfo.dwAttr=OID_ATTR_ALL;
  860. oidInfo.dwType=dwType;
  861. oidInfo.pwszOID=pwszNewOID;
  862. if(S_OK != (hr=CAOIDUpdateDS(pld, bstrConfig, &oidInfo)))
  863. _JumpError(hr , error, "CAOIDUpdateDS");
  864. *ppwszOID=pwszNewOID;
  865. pwszNewOID=NULL;
  866. hr=S_OK;
  867. error:
  868. if(pwszRandom)
  869. LocalFree(pwszRandom);
  870. if(pwszNewOID)
  871. LocalFree(pwszNewOID);
  872. if(pwszRoot)
  873. LocalFree(pwszRoot);
  874. if(bstrConfig)
  875. CertFreeString(bstrConfig);
  876. if (pld)
  877. ldap_unbind(pld);
  878. return hr;
  879. }
  880. //---------------------------------------------------------------------------
  881. //
  882. // CAOIDCreateNew
  883. //
  884. //---------------------------------------------------------------------------
  885. HRESULT
  886. CAOIDCreateNew(
  887. IN DWORD dwType,
  888. IN DWORD dwFlag,
  889. OUT LPWSTR *ppwszOID)
  890. {
  891. return I_CAOIDCreateNew(dwType, dwFlag, ppwszOID);
  892. }
  893. //---------------------------------------------------------------------------
  894. // I_CAOIDSetProperty
  895. // Set a property on an oid.
  896. //
  897. //
  898. // Returns S_OK if successful.
  899. //---------------------------------------------------------------------------
  900. HRESULT
  901. I_CAOIDSetProperty(
  902. IN LPCWSTR pwszOID,
  903. IN DWORD dwProperty,
  904. IN LPVOID pPropValue)
  905. {
  906. HRESULT hr=E_INVALIDARG;
  907. ENT_OID_INFO oidInfo;
  908. LDAP *pld = NULL;
  909. CERTSTR bstrConfig = NULL;
  910. if(NULL==pwszOID)
  911. _JumpError(hr , error, "ArgumentCheck");
  912. //retrieve the ldap handle and the config string
  913. if(S_OK != (hr = myDoesDSExist(TRUE)))
  914. _JumpError(hr , error, "myDoesDSExist");
  915. if(S_OK != (hr = myRobustLdapBind(&pld, FALSE)))
  916. _JumpError(hr , error, "myRobustLdapBind");
  917. hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
  918. if(S_OK != hr)
  919. {
  920. _JumpError(hr , error, "CAGetAuthoritativeDomainDn");
  921. }
  922. //make sure the OID exist on the DS
  923. if(!DoesOIDExist(pld, bstrConfig, pwszOID))
  924. {
  925. hr=NTE_NOT_FOUND;
  926. _JumpError(hr , error, "OIDExits");
  927. }
  928. //update the oid information on the DS
  929. memset(&oidInfo, 0, sizeof(ENT_OID_INFO));
  930. oidInfo.pwszOID=(LPWSTR)pwszOID;
  931. switch(dwProperty)
  932. {
  933. case CERT_OID_PROPERTY_DISPLAY_NAME:
  934. oidInfo.dwAttr = OID_ATTR_DISPLAY_NAME;
  935. oidInfo.pwszDisplayName=(LPWSTR)pPropValue;
  936. break;
  937. case CERT_OID_PROPERTY_CPS:
  938. oidInfo.dwAttr = OID_ATTR_CPS;
  939. oidInfo.pwszCPS=(LPWSTR)pPropValue;
  940. break;
  941. default:
  942. hr=E_INVALIDARG;
  943. _JumpError(hr , error, "ArgumentCheck");
  944. }
  945. hr=CAOIDUpdateDS(pld, bstrConfig, &oidInfo);
  946. error:
  947. if(bstrConfig)
  948. CertFreeString(bstrConfig);
  949. if (pld)
  950. ldap_unbind(pld);
  951. return hr;
  952. }
  953. //---------------------------------------------------------------------------
  954. //
  955. // CAOIDSetProperty
  956. //
  957. //---------------------------------------------------------------------------
  958. HRESULT
  959. CAOIDSetProperty(
  960. IN LPCWSTR pwszOID,
  961. IN DWORD dwProperty,
  962. IN LPVOID pPropValue)
  963. {
  964. return I_CAOIDSetProperty(pwszOID, dwProperty, pPropValue);
  965. }
  966. //---------------------------------------------------------------------------
  967. // I_CAOIDAdd
  968. //
  969. // Returns S_OK if successful.
  970. // Returns CRYPT_E_EXISTS if the OID alreay exits in the DS repository
  971. //---------------------------------------------------------------------------
  972. HRESULT
  973. I_CAOIDAdd(
  974. IN DWORD dwType,
  975. IN DWORD dwFlag,
  976. IN LPCWSTR pwszOID)
  977. {
  978. HRESULT hr=E_INVALIDARG;
  979. ENT_OID_INFO oidInfo;
  980. LDAP *pld = NULL;
  981. CERTSTR bstrConfig = NULL;
  982. if(NULL==pwszOID)
  983. _JumpError(hr , error, "ArgumentCheck");
  984. //retrieve the ldap handle and the config string
  985. if(S_OK != (hr = myDoesDSExist(TRUE)))
  986. _JumpError(hr , error, "myDoesDSExist");
  987. if(S_OK != (hr = myRobustLdapBind(&pld, FALSE)))
  988. _JumpError(hr , error, "myRobustLdapBind");
  989. hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
  990. if(S_OK != hr)
  991. {
  992. _JumpError(hr , error, "CAGetAuthoritativeDomainDn");
  993. }
  994. //make sure the OID does not exist on the DS
  995. if(DoesOIDExist(pld, bstrConfig, pwszOID))
  996. {
  997. hr=CRYPT_E_EXISTS;
  998. _JumpError(hr , error, "OIDExits");
  999. }
  1000. //update the oid information on the DS
  1001. memset(&oidInfo, 0, sizeof(ENT_OID_INFO));
  1002. oidInfo.dwAttr=OID_ATTR_ALL;
  1003. oidInfo.dwType=dwType;
  1004. oidInfo.pwszOID=(LPWSTR)pwszOID;
  1005. hr=CAOIDUpdateDS(pld, bstrConfig, &oidInfo);
  1006. error:
  1007. if(bstrConfig)
  1008. CertFreeString(bstrConfig);
  1009. if (pld)
  1010. ldap_unbind(pld);
  1011. return hr;
  1012. }
  1013. //---------------------------------------------------------------------------
  1014. // CAOIDAdd
  1015. //
  1016. // Returns S_OK if successful.
  1017. // Returns CRYPT_E_EXISTS if the OID alreay exits in the DS repository
  1018. //---------------------------------------------------------------------------
  1019. HRESULT
  1020. CAOIDAdd(
  1021. IN DWORD dwType,
  1022. IN DWORD dwFlag,
  1023. IN LPCWSTR pwszOID)
  1024. {
  1025. return I_CAOIDAdd(dwType, dwFlag, pwszOID);
  1026. }
  1027. //---------------------------------------------------------------------------
  1028. //
  1029. // I_CAOIDDelete
  1030. //
  1031. //---------------------------------------------------------------------------
  1032. HRESULT
  1033. I_CAOIDDelete(
  1034. IN LPCWSTR pwszOID)
  1035. {
  1036. HRESULT hr=E_INVALIDARG;
  1037. ULONG ldaperr=0;
  1038. LDAP *pld = NULL;
  1039. CERTSTR bstrConfig = NULL;
  1040. CERTSTR bstrDN = NULL;
  1041. LPWSTR pwszCN = NULL;
  1042. if(NULL==pwszOID)
  1043. _JumpError(hr , error, "ArgumentCheck");
  1044. //retrieve the ldap handle and the config string
  1045. if(S_OK != (hr = myDoesDSExist(TRUE)))
  1046. _JumpError(hr , error, "myDoesDSExist");
  1047. if(S_OK != (hr = myRobustLdapBind(&pld, FALSE)))
  1048. _JumpError(hr , error, "myRobustLdapBind");
  1049. hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
  1050. if(S_OK != hr)
  1051. {
  1052. _JumpError(hr , error, "CAGetAuthoritativeDomainDn");
  1053. }
  1054. //set up the base DN
  1055. if(S_OK != (hr = myOIDHashOIDToString((LPWSTR)pwszOID, &pwszCN)))
  1056. _JumpError(hr , error, "myOIDHashOIDToString");
  1057. bstrDN = CertAllocStringLen(NULL, wcslen(bstrConfig) + wcslen(s_wszOIDContainerDN)+wcslen(pwszCN)+4);
  1058. if(bstrDN == NULL)
  1059. {
  1060. hr = E_OUTOFMEMORY;
  1061. _JumpError(hr, error, "CertAllocStringLen");
  1062. }
  1063. wcscpy(bstrDN, L"CN=");
  1064. wcscat(bstrDN, pwszCN);
  1065. wcscat(bstrDN, L",");
  1066. wcscat(bstrDN, s_wszOIDContainerDN);
  1067. wcscat(bstrDN, bstrConfig);
  1068. ldaperr = ldap_delete_s(pld, bstrDN);
  1069. if(LDAP_NO_SUCH_OBJECT == ldaperr)
  1070. ldaperr = LDAP_SUCCESS;
  1071. hr = myHLdapError(pld, ldaperr, NULL);
  1072. error:
  1073. if(pwszCN)
  1074. LocalFree(pwszCN);
  1075. if(bstrDN)
  1076. CertFreeString(bstrDN);
  1077. if(bstrConfig)
  1078. CertFreeString(bstrConfig);
  1079. if (pld)
  1080. ldap_unbind(pld);
  1081. return hr;
  1082. }
  1083. //---------------------------------------------------------------------------
  1084. //
  1085. // CAOIDDelete
  1086. //
  1087. //---------------------------------------------------------------------------
  1088. HRESULT
  1089. CAOIDDelete(
  1090. IN LPCWSTR pwszOID)
  1091. {
  1092. return I_CAOIDDelete(pwszOID);
  1093. }
  1094. //---------------------------------------------------------------------------
  1095. //
  1096. // I_CAOIDGetProperty
  1097. //
  1098. //---------------------------------------------------------------------------
  1099. HRESULT
  1100. I_CAOIDGetProperty(
  1101. IN LPCWSTR pwszOID,
  1102. IN DWORD dwProperty,
  1103. OUT LPVOID pPropValue)
  1104. {
  1105. HRESULT hr=E_INVALIDARG;
  1106. ULONG ldaperr=0;
  1107. DWORD dwCount=0;
  1108. struct l_timeval timeout;
  1109. LPWSTR awszAttr[4];
  1110. LDAPMessage *Entry=NULL;
  1111. WCHAR **wszLdapVal = NULL;
  1112. LPWSTR pwszFilter = NULL;
  1113. LDAPMessage *SearchResult = NULL;
  1114. LDAP *pld = NULL;
  1115. CERTSTR bstrConfig = NULL;
  1116. CERTSTR bstrDN = NULL;
  1117. LPWSTR pwszCN = NULL;
  1118. if((NULL==pwszOID) || (NULL==pPropValue))
  1119. _JumpError(hr , error, "ArgumentCheck");
  1120. //retrieve the ldap handle and the config string
  1121. if(S_OK != (hr = myDoesDSExist(TRUE)))
  1122. _JumpError(hr , error, "myDoesDSExist");
  1123. if(S_OK != (hr = myRobustLdapBind(&pld, FALSE)))
  1124. _JumpError(hr , error, "myRobustLdapBind");
  1125. hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
  1126. if(S_OK != hr)
  1127. {
  1128. _JumpError(hr , error, "CAGetAuthoritativeDomainDn");
  1129. }
  1130. //set up the base DN
  1131. if(S_OK != (hr = myOIDHashOIDToString((LPWSTR)pwszOID, &pwszCN)))
  1132. _JumpError(hr , error, "myOIDHashOIDToString");
  1133. bstrDN = CertAllocStringLen(NULL, wcslen(bstrConfig) + wcslen(s_wszOIDContainerDN)+wcslen(pwszCN)+4);
  1134. if(bstrDN == NULL)
  1135. {
  1136. hr = E_OUTOFMEMORY;
  1137. _JumpError(hr, error, "CertAllocStringLen");
  1138. }
  1139. wcscpy(bstrDN, L"CN=");
  1140. wcscat(bstrDN, pwszCN);
  1141. wcscat(bstrDN, L",");
  1142. wcscat(bstrDN, s_wszOIDContainerDN);
  1143. wcscat(bstrDN, bstrConfig);
  1144. //search for the OID, asking for all its attributes
  1145. timeout.tv_sec = csecLDAPTIMEOUT;
  1146. timeout.tv_usec = 0;
  1147. awszAttr[0]=OID_PROP_TYPE;
  1148. awszAttr[1]=OID_PROP_DISPLAY_NAME;
  1149. awszAttr[2]=OID_PROP_CPS;
  1150. awszAttr[3]=NULL;
  1151. if(S_OK != (hr=FormatMessageUnicode(&pwszFilter, L"(%1!s!=%2!s!)",
  1152. OID_PROP_OID, pwszOID)))
  1153. _JumpError(hr , error, "FormatMessageUnicode");
  1154. ldaperr = ldap_search_stW(
  1155. pld,
  1156. (LPWSTR)bstrDN,
  1157. LDAP_SCOPE_BASE,
  1158. pwszFilter,
  1159. awszAttr,
  1160. 0,
  1161. &timeout,
  1162. &SearchResult);
  1163. if(LDAP_SUCCESS != ldaperr)
  1164. {
  1165. hr = myHLdapError2(pld, ldaperr, LDAP_NO_SUCH_OBJECT, NULL);
  1166. _JumpErrorStr2(
  1167. hr,
  1168. error,
  1169. "ldap_search_stW",
  1170. pwszFilter,
  1171. HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND));
  1172. }
  1173. dwCount = ldap_count_entries(pld, SearchResult);
  1174. //we should only find one container
  1175. if((1 != dwCount) || (NULL == (Entry = ldap_first_entry(pld, SearchResult))))
  1176. {
  1177. // No entries were found.
  1178. //BUGBUG: why not use last ldap error?
  1179. //hr = myHLdapLastError(pld, NULL);
  1180. hr = myHLdapError(pld, LDAP_NO_SUCH_OBJECT, NULL);
  1181. _JumpError(hr, error, "ldap_search_stW");
  1182. }
  1183. switch(dwProperty)
  1184. {
  1185. case CERT_OID_PROPERTY_DISPLAY_NAME:
  1186. wszLdapVal = ldap_get_values(pld, Entry, OID_PROP_DISPLAY_NAME);
  1187. if(wszLdapVal && wszLdapVal[0])
  1188. {
  1189. hr=CAOIDAllocAndCopy(wszLdapVal[0], (LPWSTR *)pPropValue);
  1190. }
  1191. else
  1192. hr = myHLdapError(pld, LDAP_NO_SUCH_ATTRIBUTE, NULL);
  1193. break;
  1194. case CERT_OID_PROPERTY_CPS:
  1195. wszLdapVal = ldap_get_values(pld, Entry, OID_PROP_CPS);
  1196. if(wszLdapVal && wszLdapVal[0])
  1197. {
  1198. hr=CAOIDAllocAndCopy(wszLdapVal[0], (LPWSTR *)pPropValue);
  1199. }
  1200. else
  1201. hr = myHLdapError(pld, LDAP_NO_SUCH_ATTRIBUTE, NULL);
  1202. break;
  1203. case CERT_OID_PROPERTY_TYPE:
  1204. wszLdapVal = ldap_get_values(pld, Entry, OID_PROP_TYPE);
  1205. if(wszLdapVal && wszLdapVal[0])
  1206. {
  1207. *((DWORD *)pPropValue)=_wtol(wszLdapVal[0]);
  1208. hr=S_OK;
  1209. }
  1210. else
  1211. hr = myHLdapError(pld, LDAP_NO_SUCH_ATTRIBUTE, NULL);
  1212. break;
  1213. default:
  1214. hr=E_INVALIDARG;
  1215. }
  1216. if(hr != S_OK)
  1217. _JumpError(hr , error, "GetAttibuteValue");
  1218. error:
  1219. if(wszLdapVal)
  1220. ldap_value_free(wszLdapVal);
  1221. if(pwszFilter)
  1222. LocalFree((HLOCAL)pwszFilter);
  1223. if(SearchResult)
  1224. ldap_msgfree(SearchResult);
  1225. if(pwszCN)
  1226. LocalFree(pwszCN);
  1227. if(bstrDN)
  1228. CertFreeString(bstrDN);
  1229. if(bstrConfig)
  1230. CertFreeString(bstrConfig);
  1231. if (pld)
  1232. ldap_unbind(pld);
  1233. return hr;
  1234. }
  1235. //---------------------------------------------------------------------------
  1236. //
  1237. // CAOIDGetProperty
  1238. //
  1239. //---------------------------------------------------------------------------
  1240. HRESULT
  1241. CAOIDGetProperty(
  1242. IN LPCWSTR pwszOID,
  1243. IN DWORD dwProperty,
  1244. OUT LPVOID pPropValue)
  1245. {
  1246. return I_CAOIDGetProperty(pwszOID, dwProperty, pPropValue);
  1247. }
  1248. //---------------------------------------------------------------------------
  1249. //
  1250. // I_CAOIDFreeProperty
  1251. //
  1252. //---------------------------------------------------------------------------
  1253. HRESULT
  1254. I_CAOIDFreeProperty(
  1255. IN LPVOID pPropValue)
  1256. {
  1257. if(pPropValue)
  1258. LocalFree(pPropValue);
  1259. return S_OK;
  1260. }
  1261. //---------------------------------------------------------------------------
  1262. //
  1263. // CAOIDFreeProperty
  1264. //
  1265. //---------------------------------------------------------------------------
  1266. HRESULT
  1267. CAOIDFreeProperty(
  1268. IN LPVOID pPropValue)
  1269. {
  1270. return I_CAOIDFreeProperty(pPropValue);
  1271. }
  1272. //---------------------------------------------------------------------------
  1273. //
  1274. // CAOIDGetLdapURL
  1275. //
  1276. // Get the LDAP URL for the DS OID repository in the format of
  1277. // LDAP:///DN of the Repository/all attributes?one?filter.
  1278. //---------------------------------------------------------------------------
  1279. HRESULT
  1280. CAOIDGetLdapURL(
  1281. IN DWORD dwType,
  1282. IN DWORD dwFlag,
  1283. OUT LPWSTR *ppwszURL)
  1284. {
  1285. HRESULT hr=E_INVALIDARG;
  1286. ULONG ldaperr=0;
  1287. LPWSTR wszFilterFormat=L"ldap:///%1!s!%2!s!?%3!s!,%4!s!,%5!s!,%6!s!,%7!s!?one?%8!s!=%9!d!";
  1288. LPWSTR pwsz=NULL;
  1289. BOOL fDomainFail=FALSE;
  1290. FILETIME ftTime;
  1291. LPWSTR pwszURL=NULL;
  1292. LDAP *pld = NULL;
  1293. CERTSTR bstrConfig = NULL;
  1294. //the critical section has to be initalized
  1295. if (!g_fOidURL)
  1296. return(HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED));
  1297. EnterCriticalSection(&g_csOidURL);
  1298. //check if the previous failure has happened with 10 seconds
  1299. if(TRUE == g_fFailedTime)
  1300. {
  1301. //get the current time
  1302. GetSystemTimeAsFileTime(&ftTime);
  1303. g_ftOidTime.QuadPart += FILETIME_TICKS_PER_SECOND * CA_OID_MGR_FAIL_PERIOD;
  1304. if(0 > CompareFileTime(&ftTime, (LPFILETIME)&g_ftOidTime))
  1305. {
  1306. g_ftOidTime.QuadPart -= FILETIME_TICKS_PER_SECOND * CA_OID_MGR_FAIL_PERIOD;
  1307. hr=HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN);
  1308. _JumpError2(hr , error, "myDoesDSExist", HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN));
  1309. }
  1310. else
  1311. {
  1312. //clear up the error recording
  1313. g_fFailedTime=FALSE;
  1314. }
  1315. }
  1316. if(NULL==ppwszURL)
  1317. _JumpError(hr , error, "ArgumentCheck");
  1318. fDomainFail=TRUE;
  1319. //retrieve the ldap handle and the config string
  1320. if(S_OK != (hr = myDoesDSExist(TRUE)))
  1321. _JumpError2(hr , error, "myDoesDSExist", HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN));
  1322. if(S_OK != (hr = myRobustLdapBind(&pld, FALSE)))
  1323. _JumpError(hr , error, "myRobustLdapBind");
  1324. fDomainFail=FALSE;
  1325. hr = CAGetAuthoritativeDomainDn(pld, NULL, &bstrConfig);
  1326. if(S_OK != hr)
  1327. {
  1328. _JumpError(hr , error, "CAGetAuthoritativeDomainDn");
  1329. }
  1330. if(S_OK != (hr=FormatMessageUnicode(
  1331. &pwszURL,
  1332. wszFilterFormat,
  1333. s_wszOIDContainerDN,
  1334. bstrConfig,
  1335. OID_PROP_TYPE,
  1336. OID_PROP_OID,
  1337. OID_PROP_DISPLAY_NAME,
  1338. OID_PROP_CPS,
  1339. OID_PROP_LOCALIZED_NAME,
  1340. OID_PROP_TYPE,
  1341. dwType
  1342. )))
  1343. _JumpError(hr , error, "FormatMessageUnicode");
  1344. //we eliminate the filter if dwType is CERT_OID_TYPE_ALL
  1345. if(CERT_OID_TYPE_ALL == dwType)
  1346. {
  1347. pwsz=wcsrchr(pwszURL, L'?');
  1348. if(NULL==pwsz)
  1349. {
  1350. //something serious is wrong
  1351. hr=E_UNEXPECTED;
  1352. _JumpError(hr , error, "FormatMessageUnicode");
  1353. }
  1354. *pwsz=L'\0';
  1355. }
  1356. *ppwszURL=pwszURL;
  1357. pwszURL=NULL;
  1358. hr=S_OK;
  1359. error:
  1360. //remember the time if we failed due to lack of domain
  1361. if((S_OK != hr) && (TRUE == fDomainFail) && (FALSE==g_fFailedTime))
  1362. {
  1363. GetSystemTimeAsFileTime((LPFILETIME)&(g_ftOidTime));
  1364. g_fFailedTime=TRUE;
  1365. }
  1366. if(pwszURL)
  1367. LocalFree((HLOCAL)pwszURL);
  1368. if(bstrConfig)
  1369. CertFreeString(bstrConfig);
  1370. if (pld)
  1371. ldap_unbind(pld);
  1372. LeaveCriticalSection(&g_csOidURL);
  1373. return hr;
  1374. }
  1375. //---------------------------------------------------------------------------
  1376. //
  1377. // CAOIDFreeLdapURL
  1378. //
  1379. //---------------------------------------------------------------------------
  1380. HRESULT
  1381. CAOIDFreeLdapURL(
  1382. IN LPCWSTR pwszURL)
  1383. {
  1384. if(pwszURL)
  1385. LocalFree((HLOCAL)pwszURL);
  1386. return S_OK;
  1387. }