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.

959 lines
26 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
  3. File: ADHelpers.cpp
  4. Content: Implementation of helper routines for accessing Active Directory.
  5. Functions in this module require DSClient installed for down level
  6. clients.
  7. History: 11-15-99 dsie created
  8. ------------------------------------------------------------------------------*/
  9. #include "StdAfx.h"
  10. #include "CAPICOM.h"
  11. #include "AdHelpers.h"
  12. #include "Settings.h"
  13. ////////////////////
  14. //
  15. // Local typedefs
  16. //
  17. typedef HRESULT (WINAPI * PADSOPENOBJECT)(LPWSTR lpszPathName,
  18. LPWSTR lpszUserName,
  19. LPWSTR lpszPassword,
  20. DWORD dwReserved,
  21. REFIID riid,
  22. VOID FAR * FAR *ppObject);
  23. typedef HRESULT (WINAPI * PADSBUILDENUMERATOR)(IADsContainer * pADsContainer,
  24. IEnumVARIANT ** ppEnumVariant);
  25. typedef HRESULT (WINAPI * PADSENUMERATENEXT)(IEnumVARIANT * pEnumVariant,
  26. ULONG cElements,
  27. VARIANT FAR * pvar,
  28. ULONG FAR * pcElementsFetched);
  29. typedef HRESULT (WINAPI * PADSFREEENUMERATOR)(IEnumVARIANT * pEnumVariant);
  30. ////////////////////////////////////////////////////////////////////////////////
  31. //
  32. // Local functions.
  33. //
  34. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  35. Function : IsUserCertificateInGC
  36. Synopsis : Determine if the userCertificate attribute is replicated in the GC.
  37. Parameter: HMODULE hDLL - ActiveDS.DLL handle.
  38. BOOL * pbResult - Pointer to BOOL to receive result.
  39. Remark :
  40. ------------------------------------------------------------------------------*/
  41. static HRESULT IsUserCertificateInGC (HMODULE hDLL,
  42. BOOL * pbResult)
  43. {
  44. HRESULT hr = S_OK;
  45. IADs * pIADs = NULL;
  46. IDirectorySearch * pISchema = NULL;
  47. LPOLESTR pszList[] = {L"lDAPDisplayName", L"isMemberOfPartialAttributeSet"};
  48. LPOLESTR pszFilter = L"(&(objectCategory=attributeSchema)(lDAPDisplayName=userCertificate))";
  49. ADS_SEARCH_HANDLE hSearch = NULL;
  50. DWORD dwNumPrefs = 1;
  51. CComBSTR bstrPath;
  52. CComBSTR bstrSchema;
  53. ADS_SEARCHPREF_INFO SearchPrefs;
  54. CComVariant var;
  55. PADSOPENOBJECT pADsOpenObject;
  56. static BOOL bResult = FALSE;
  57. static BOOL bChecked = FALSE;
  58. DebugTrace("Entering IsUserCertificateInGC().\n");
  59. //
  60. // Sanity check.
  61. //
  62. ATLASSERT(hDLL);
  63. ATLASSERT(pbResult);
  64. //
  65. // If we had already checked once, use the cached result.
  66. //
  67. if (bChecked)
  68. {
  69. *pbResult = bResult;
  70. goto CommonExit;
  71. }
  72. //
  73. // Initialize.
  74. //
  75. if (!(bstrPath = L"LDAP://") || !(bstrSchema = L"schemaNamingContext"))
  76. {
  77. hr = E_OUTOFMEMORY;
  78. DebugTrace("Error [%#x]: bstrPath = L\"LDAP://\") || (bstrSchema = L\"schemaNamingContext\" failed.", hr);
  79. goto ErrorExit;
  80. }
  81. //
  82. // Get ADsOpenObject address pointer.
  83. //
  84. if (!(pADsOpenObject = (PADSOPENOBJECT) ::GetProcAddress(hDLL, "ADsOpenObject")))
  85. {
  86. hr = HRESULT_FROM_WIN32(::GetLastError());
  87. DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsOpenObject().\n", hr);
  88. goto ErrorExit;
  89. }
  90. //
  91. // Bind to rootDSE to get the schemaNamingContext property.
  92. //
  93. if (FAILED(hr = pADsOpenObject(L"LDAP://rootDSE",
  94. NULL,
  95. NULL,
  96. ADS_SECURE_AUTHENTICATION,
  97. IID_IADs,
  98. (void **) &pIADs)))
  99. {
  100. DebugTrace("Error [%#x]: ADsOpenObject() failed for IID_IADs.\n", hr);
  101. goto ErrorExit;
  102. }
  103. //
  104. // Get schema container path.
  105. //
  106. if (FAILED(hr = pIADs->Get(bstrSchema, &var)))
  107. {
  108. DebugTrace("Error [%#x]: pIADs->Get() failed.\n", hr);
  109. goto ErrorExit;
  110. }
  111. //
  112. // Build path to the schema container.
  113. //
  114. if (FAILED(hr = bstrPath.AppendBSTR(var.bstrVal)))
  115. {
  116. DebugTrace("Error [%#x]: bstrPath.AppendBSTR() failed.\n", hr);
  117. goto ErrorExit;
  118. }
  119. //
  120. // Bind to the actual schema container.
  121. //
  122. if (FAILED(hr = pADsOpenObject(bstrPath,
  123. NULL,
  124. NULL,
  125. ADS_SECURE_AUTHENTICATION,
  126. IID_IDirectorySearch,
  127. (void **) &pISchema)))
  128. {
  129. DebugTrace("Error [%#x]: ADsOpenObject() failed for IID_IDirectorySearch.\n", hr);
  130. goto ErrorExit;
  131. }
  132. //
  133. // Attributes are one-level deep in the Schema container so only
  134. // need to search one level.
  135. //
  136. SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  137. SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
  138. SearchPrefs.vValue.Integer = ADS_SCOPE_ONELEVEL;
  139. //
  140. // Set the search preference.
  141. //
  142. if (FAILED(hr = pISchema->SetSearchPreference(&SearchPrefs, dwNumPrefs)))
  143. {
  144. DebugTrace("Error [%#x]: pISchema->SetSearchPreference() failed.\n", hr);
  145. goto ErrorExit;
  146. }
  147. //
  148. // Execute search.
  149. //
  150. if (FAILED(hr = pISchema->ExecuteSearch(pszFilter,
  151. pszList,
  152. sizeof(pszList) / sizeof(LPOLESTR),
  153. &hSearch)))
  154. {
  155. DebugTrace("Error [%#x]: pISchema->ExecuteSearch() failed.\n", hr);
  156. goto ErrorExit;
  157. }
  158. //
  159. // Retrieve first row of data.
  160. //
  161. if (FAILED(hr = pISchema->GetFirstRow(hSearch)))
  162. {
  163. DebugTrace("Error [%#x]: pISchema->GetFirstRow() failed.\n", hr);
  164. goto ErrorExit;
  165. }
  166. //
  167. // Loop until no more row.
  168. //
  169. while (S_ADS_NOMORE_ROWS != hr)
  170. {
  171. ADS_SEARCH_COLUMN Column;
  172. //
  173. // Get the lDAPDisplayName column.
  174. //
  175. if (FAILED(hr = pISchema->GetColumn(hSearch,
  176. L"lDAPDisplayName",
  177. &Column)))
  178. {
  179. DebugTrace("Error [%#x]: pISchema->GetColumn() failed.\n", hr);
  180. goto ErrorExit;
  181. }
  182. DebugTrace("Info: %ls = %ls\n", Column.pszAttrName, Column.pADsValues->CaseIgnoreString);
  183. //
  184. // Is this attributeSchema for userCertificate?
  185. //
  186. if (0 == ::wcscmp(L"userCertificate", Column.pADsValues->CaseIgnoreString))
  187. {
  188. pISchema->FreeColumn(&Column);
  189. //
  190. // Get the isMemberOfPartialAttributeSet column.
  191. //
  192. if (FAILED(hr = pISchema->GetColumn(hSearch,
  193. L"isMemberOfPartialAttributeSet",
  194. &Column)))
  195. {
  196. DebugTrace("Error [%#x]: pISchema->GetColumn() failed.\n", hr);
  197. goto ErrorExit;
  198. }
  199. bResult = Column.pADsValues->Boolean;
  200. //
  201. // Should only have one row, so we don't really have to
  202. // break here, but is a little more effiecit to break,
  203. // since we don't need to ask for the next row to terminate
  204. // the loop.
  205. //
  206. pISchema->FreeColumn(&Column);
  207. break;
  208. }
  209. pISchema->FreeColumn(&Column);
  210. //
  211. // Get next row.
  212. //
  213. hr = pISchema->GetNextRow(hSearch);
  214. }
  215. //
  216. // Reset hr.
  217. //
  218. hr = S_OK;
  219. //
  220. // Return result to caller.
  221. //
  222. *pbResult = bResult;
  223. CommonExit:
  224. //
  225. // Free resource.
  226. //
  227. if (hSearch)
  228. {
  229. pISchema->CloseSearchHandle(hSearch);
  230. }
  231. if (pISchema)
  232. {
  233. pISchema->Release();
  234. }
  235. if (pIADs)
  236. {
  237. pIADs->Release();
  238. }
  239. DebugTrace("Leaving IsUserCertificateInGC().\n");
  240. return hr;
  241. ErrorExit:
  242. //
  243. // Sanity check.
  244. //
  245. ATLASSERT(FAILED(hr));
  246. goto CommonExit;
  247. }
  248. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  249. Function : BuildRootDSESearch
  250. Synopsis : Build a search container of the rootDSE.
  251. Parameter: HMODULE hDLL - ActiveDS.DLL handle.
  252. IDirectorySearch ** ppISearch - To receive container to search.
  253. Remark :
  254. ------------------------------------------------------------------------------*/
  255. static HRESULT BuildRootDSESearch (HMODULE hDLL,
  256. IDirectorySearch ** ppISearch)
  257. {
  258. HRESULT hr = S_OK;
  259. IADs * pIADs = NULL;
  260. CComBSTR bstrPath;
  261. CComBSTR bstrDefault;
  262. PADSOPENOBJECT pADsOpenObject;
  263. CComVariant var;
  264. DebugTrace("Entering BuildRootDSESearch().\n");
  265. //
  266. // Sanity check.
  267. //
  268. ATLASSERT(hDLL);
  269. ATLASSERT(ppISearch);
  270. //
  271. // Initialize.
  272. //
  273. if (!(bstrPath = L"LDAP://") || !(bstrDefault = L"defaultNamingContext"))
  274. {
  275. hr = E_OUTOFMEMORY;
  276. DebugTrace("Error [%#x]: bstrPath = L\"LDAP://\" || bstrDefault = L\"defaultNamingContext\" failed.", hr);
  277. goto ErrorExit;
  278. }
  279. //
  280. // Get ADsOpenObject address pointer.
  281. //
  282. if (!(pADsOpenObject = (PADSOPENOBJECT) ::GetProcAddress(hDLL, "ADsOpenObject")))
  283. {
  284. hr = HRESULT_FROM_WIN32(::GetLastError());
  285. DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsOpenObject().\n", hr);
  286. goto ErrorExit;
  287. }
  288. //
  289. // Get rootDSE.
  290. //
  291. if (FAILED(hr = pADsOpenObject(L"LDAP://rootDSE",
  292. NULL,
  293. NULL,
  294. ADS_SECURE_AUTHENTICATION,
  295. IID_IADs,
  296. (void **) &pIADs)))
  297. {
  298. DebugTrace("Error [%#x]: ADsOpenObject() failed for IID_IADs.\n", hr);
  299. goto ErrorExit;
  300. }
  301. //
  302. // Get current user's domain container DN.
  303. //
  304. if (FAILED(hr = pIADs->Get(bstrDefault, &var)))
  305. {
  306. DebugTrace("Error [%#x]: pIADs->Get() failed.\n", hr);
  307. goto ErrorExit;
  308. }
  309. //
  310. // Build path to the domain container.
  311. //
  312. if (FAILED(hr = bstrPath.AppendBSTR(var.bstrVal)))
  313. {
  314. DebugTrace("Error [%#x]: bstrPath.AppendBSTR(var.bstrVal) failed.", hr);
  315. goto ErrorExit;
  316. }
  317. //
  318. // Get IDerictorySearch interface pointer.
  319. //
  320. if (FAILED(hr = pADsOpenObject(bstrPath,
  321. NULL,
  322. NULL,
  323. ADS_SECURE_AUTHENTICATION,
  324. IID_IDirectorySearch,
  325. (void **) ppISearch)))
  326. {
  327. DebugTrace("Error [%#x]: ADsOpenObject() failed for IID_IDirectorySearch.\n", hr);
  328. goto ErrorExit;
  329. }
  330. CommonExit:
  331. //
  332. // Free resource.
  333. //
  334. if (pIADs)
  335. {
  336. pIADs->Release();
  337. }
  338. DebugTrace("Leaving BuildRootDSESearch().\n");
  339. return hr;
  340. ErrorExit:
  341. //
  342. // Sanity check.
  343. //
  344. ATLASSERT(FAILED(hr));
  345. goto CommonExit;
  346. }
  347. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  348. Function : BuildGlobalCatalogSearch
  349. Synopsis : Build a search container of the GC.
  350. Parameter: HMODULE hDLL - ActiveDS.DLL handle.
  351. IDirectorySearch ** ppISearch - To receive container to search.
  352. Remark :
  353. ------------------------------------------------------------------------------*/
  354. static HRESULT BuildGlobalCatalogSearch (HMODULE hDLL,
  355. IDirectorySearch ** ppISearch)
  356. {
  357. HRESULT hr = S_OK;
  358. IEnumVARIANT * pIEnum = NULL;
  359. IADsContainer * pIContainer = NULL;
  360. IDispatch * pIDispatch = NULL;
  361. ULONG lFetched = 0;
  362. PADSOPENOBJECT pADsOpenObject = NULL;
  363. PADSBUILDENUMERATOR pADsBuildEnumerator = NULL;
  364. PADSENUMERATENEXT pADsEnumerateNext = NULL;
  365. PADSFREEENUMERATOR pADsFreeEnumerator = NULL;
  366. CComVariant var;
  367. DebugTrace("Entering BuildGlobalCatalogSearch().\n");
  368. //
  369. // Sanity check.
  370. //
  371. ATLASSERT(hDLL);
  372. ATLASSERT(ppISearch);
  373. //
  374. // Initialize.
  375. //
  376. *ppISearch = NULL;
  377. //
  378. // Get ADs function address pointers.
  379. //
  380. if (!(pADsOpenObject = (PADSOPENOBJECT) ::GetProcAddress(hDLL, "ADsOpenObject")))
  381. {
  382. hr = HRESULT_FROM_WIN32(::GetLastError());
  383. DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsOpenObject().\n", hr);
  384. goto ErrorExit;
  385. }
  386. if (!(pADsBuildEnumerator = (PADSBUILDENUMERATOR) ::GetProcAddress(hDLL, "ADsBuildEnumerator")))
  387. {
  388. hr = HRESULT_FROM_WIN32(::GetLastError());
  389. DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsBuildEnumerator().\n", hr);
  390. goto ErrorExit;
  391. }
  392. if (!(pADsEnumerateNext = (PADSENUMERATENEXT) ::GetProcAddress(hDLL, "ADsEnumerateNext")))
  393. {
  394. hr = HRESULT_FROM_WIN32(::GetLastError());
  395. DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsEnumerateNext().\n", hr);
  396. goto ErrorExit;
  397. }
  398. if (!(pADsFreeEnumerator = (PADSFREEENUMERATOR) ::GetProcAddress(hDLL, "ADsFreeEnumerator")))
  399. {
  400. hr = HRESULT_FROM_WIN32(::GetLastError());
  401. DebugTrace("Error [%#x]: GetProcAddress() failed to load ADsFreeEnumerator().\n", hr);
  402. goto ErrorExit;
  403. }
  404. //
  405. // First, bind to the GC: namespace container object. The "real" GC DN
  406. // is a single immediate child of the GC: namespace, which must be
  407. // obtained using enumeration.
  408. //
  409. if (FAILED(hr = pADsOpenObject(L"GC:",
  410. NULL,
  411. NULL,
  412. ADS_SECURE_AUTHENTICATION,
  413. IID_IADsContainer,
  414. (void **) &pIContainer)))
  415. {
  416. DebugTrace("Error [%#x]: ADsOpenObject() failed for IID_IADsContainer.\n", hr);
  417. goto ErrorExit;
  418. }
  419. //
  420. // Fetch an enumeration interface for the GC container.
  421. //
  422. if (FAILED(hr = pADsBuildEnumerator(pIContainer, &pIEnum)))
  423. {
  424. DebugTrace("Error [%#x]: ADsBuildEnumerator() failed.\n", hr);
  425. goto ErrorExit;
  426. }
  427. //
  428. // Now enumerate.
  429. //
  430. if (FAILED(hr = pADsEnumerateNext(pIEnum, 1, &var, &lFetched)))
  431. {
  432. DebugTrace("Error [%#x]: ADsEnumerateNext() failed.\n", hr);
  433. goto ErrorExit;
  434. }
  435. //
  436. // There should only be one child in the GC object.
  437. //
  438. if (1 != lFetched)
  439. {
  440. hr = E_UNEXPECTED;
  441. DebugTrace("Error [%#x]: ADsEnumerateNext() returns lFetched = %d, which is not 1.\n", hr, lFetched);
  442. goto ErrorExit;
  443. }
  444. //
  445. // Obtain the IDispatch pointer.
  446. //
  447. pIDispatch = V_DISPATCH(&var);
  448. //
  449. // Return IDirectorySearch interface pointer to caller.
  450. //
  451. if (FAILED(hr = pIDispatch->QueryInterface(IID_IDirectorySearch,
  452. (void **) ppISearch)))
  453. {
  454. DebugTrace("Error [%#x]: pIDispatch->QueryInterface() failed for IID_IDirectorySearch.\n", hr);
  455. goto ErrorExit;
  456. }
  457. CommonExit:
  458. //
  459. // Free resource.
  460. //
  461. if (pIEnum)
  462. {
  463. pADsFreeEnumerator(pIEnum);
  464. }
  465. if (pIContainer)
  466. {
  467. pIContainer->Release();
  468. }
  469. DebugTrace("Leaving BuildGlobalCatalogSearch().\n");
  470. return hr;
  471. ErrorExit:
  472. //
  473. // Sanity check.
  474. //
  475. ATLASSERT(FAILED(hr));
  476. goto CommonExit;
  477. }
  478. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  479. Function : BuildADSearch
  480. Synopsis : Build a search container. We will first check to see if the
  481. userCertificate attribute is replicated in the global catalog.
  482. If so, we will bind the search to the GC, otherwise, will bind
  483. to default domain.
  484. Parameter: IDirectorySearch ** ppISearch - To receive container to search.
  485. Remark :
  486. ------------------------------------------------------------------------------*/
  487. static HRESULT BuildADSearch (IDirectorySearch ** ppISearch)
  488. {
  489. HRESULT hr = S_OK;
  490. BOOL bResult = FALSE;
  491. HMODULE hDLL = NULL;
  492. CAPICOM_ACTIVE_DIRECTORY_SEARCH_LOCATION SearchLocation = ActiveDirectorySearchLocation();
  493. DebugTrace("Entering BuildADSearch().\n");
  494. //
  495. // Sanity check.
  496. //
  497. ATLASSERT(ppISearch);
  498. //
  499. // Initialize.
  500. //
  501. *ppISearch = NULL;
  502. //
  503. // Load ActiveDS.DLL.
  504. //
  505. if (!(hDLL = ::LoadLibrary("ActiveDS.DLL")))
  506. {
  507. hr = CAPICOM_E_NOT_SUPPORTED;
  508. DebugTrace("Error: DSClient not installed.\n");
  509. goto ErrorExit;
  510. }
  511. //
  512. // Did user specify a search location?
  513. //
  514. if (CAPICOM_SEARCH_ANY == SearchLocation)
  515. {
  516. //
  517. // No, so determine if userCerticate is replicated in the GC.
  518. //
  519. if (FAILED(hr = ::IsUserCertificateInGC(hDLL, &bResult)))
  520. {
  521. DebugTrace("Error [%#x]: IsUserCertificateInGC() failed.\n", hr);
  522. goto ErrorExit;
  523. }
  524. //
  525. // Search GC or default domain.
  526. //
  527. SearchLocation = bResult ? CAPICOM_SEARCH_GLOBAL_CATALOG : CAPICOM_SEARCH_DEFAULT_DOMAIN;
  528. }
  529. //
  530. // Check to see where to search.
  531. //
  532. if (CAPICOM_SEARCH_GLOBAL_CATALOG == SearchLocation)
  533. {
  534. //
  535. // GC.
  536. //
  537. hr = ::BuildGlobalCatalogSearch(hDLL, ppISearch);
  538. }
  539. else
  540. {
  541. //
  542. // rootDSE (default domain).
  543. //
  544. hr = ::BuildRootDSESearch(hDLL, ppISearch);
  545. }
  546. CommonExit:
  547. //
  548. // Free resource.
  549. //
  550. if (hDLL)
  551. {
  552. ::FreeLibrary(hDLL);
  553. }
  554. DebugTrace("Leaving BuildADSearch().\n");
  555. return hr;
  556. ErrorExit:
  557. //
  558. // Sanity check.
  559. //
  560. ATLASSERT(FAILED(hr));
  561. goto CommonExit;
  562. }
  563. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  564. Function : LoadUserCertificates
  565. Synopsis : Load all certificates from the userCertificate attribute of the
  566. specified search container for users specified through the filter.
  567. Parameter: HCERTSTORE hCertStore - Certificate store handle of store to
  568. receive all the certificates.
  569. IDirectorySearch * pIContainer - Container to search.
  570. BSTR bstrFilter - Filter (See Store::Open() for more info).
  571. Remark :
  572. ------------------------------------------------------------------------------*/
  573. static HRESULT LoadUserCertificates (HCERTSTORE hCertStore,
  574. IDirectorySearch * pIContainer,
  575. LPOLESTR pszFilter)
  576. {
  577. HRESULT hr = S_OK;
  578. ADS_SEARCH_HANDLE hSearch = NULL;
  579. LPOLESTR pszSearchList[] = {L"userCertificate"};
  580. CComBSTR bstrSearchFilter;
  581. ADS_SEARCHPREF_INFO SearchPrefs;
  582. DebugTrace("Entering LoadUserCertificates().\n");
  583. //
  584. // Sanity check.
  585. //
  586. ATLASSERT(hCertStore);
  587. ATLASSERT(pIContainer);
  588. ATLASSERT(pszFilter);
  589. try
  590. {
  591. //
  592. // Initialize.
  593. //
  594. if (!(bstrSearchFilter = L"(&(objectClass=user)(objectCategory=person)"))
  595. {
  596. hr = E_OUTOFMEMORY;
  597. DebugTrace("Error [%#x]: bstrSearchFilter = L\"(&(objectClass=user)(objectCategory=person)\" failed.\n", hr);
  598. goto ErrorExit;
  599. }
  600. if (!(bstrSearchFilter += pszFilter))
  601. {
  602. hr = E_OUTOFMEMORY;
  603. DebugTrace("Error [%#x]: bstrSearchFilter += pszFilter failed.\n", hr);
  604. goto ErrorExit;
  605. }
  606. if (!(bstrSearchFilter += L")"))
  607. {
  608. hr = E_OUTOFMEMORY;
  609. DebugTrace("Error [%#x]: bstrSearchFilter += L\")\" failed.\n", hr);
  610. goto ErrorExit;
  611. }
  612. //
  613. // Specify subtree search.
  614. //
  615. SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  616. SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
  617. SearchPrefs.vValue.Integer = ADS_SCOPE_SUBTREE;
  618. //
  619. // Set the search preference.
  620. //
  621. if (FAILED(hr = pIContainer->SetSearchPreference(&SearchPrefs, 1)))
  622. {
  623. DebugTrace("Error [%#x]: pIContainer->SetSearchPreference() failed.\n", hr);
  624. goto ErrorExit;
  625. }
  626. //
  627. // Execute the search.
  628. //
  629. if (FAILED(hr = pIContainer->ExecuteSearch(bstrSearchFilter,
  630. pszSearchList,
  631. sizeof(pszSearchList)/sizeof(LPOLESTR),
  632. &hSearch)))
  633. {
  634. DebugTrace("Error [%#x]: pIContainer->ExecuteSearch() failed.\n", hr);
  635. goto ErrorExit;
  636. }
  637. //
  638. // Retrieve first row of data.
  639. //
  640. if (FAILED(hr = pIContainer->GetFirstRow(hSearch)))
  641. {
  642. DebugTrace("Error [%#x]: pIContainer->GetFirstRow() failed.\n", hr);
  643. goto ErrorExit;
  644. }
  645. //
  646. // Loop until no more row.
  647. //
  648. while (S_ADS_NOMORE_ROWS != hr)
  649. {
  650. DWORD dwValue;
  651. ADS_SEARCH_COLUMN Column;
  652. //
  653. // Try to get the userCertificate attribute.
  654. //
  655. if (FAILED(hr = pIContainer->GetColumn(hSearch, L"userCertificate", &Column)))
  656. {
  657. if (E_ADS_COLUMN_NOT_SET == hr)
  658. {
  659. //
  660. // Get next row.
  661. //
  662. hr = pIContainer->GetNextRow(hSearch);
  663. continue;
  664. }
  665. DebugTrace("Error [%#x]: pIContainer->GetColumn() failed.\n", hr);
  666. goto ErrorExit;
  667. }
  668. //
  669. // Import all the certificate values.
  670. //
  671. for (dwValue = 0; dwValue < Column.dwNumValues; dwValue++)
  672. {
  673. if (!::CertAddEncodedCertificateToStore(hCertStore,
  674. CAPICOM_ASN_ENCODING,
  675. (const PBYTE) Column.pADsValues[dwValue].OctetString.lpValue,
  676. Column.pADsValues[dwValue].OctetString.dwLength,
  677. CERT_STORE_ADD_USE_EXISTING,
  678. NULL))
  679. {
  680. hr = HRESULT_FROM_WIN32(::GetLastError());
  681. pIContainer->FreeColumn(&Column);
  682. DebugTrace("Error [%#x]: CertAddEncodedCertificateToStore() failed.\n", hr);
  683. goto ErrorExit;
  684. }
  685. }
  686. pIContainer->FreeColumn(&Column);
  687. //
  688. // Get next row.
  689. //
  690. hr = pIContainer->GetNextRow(hSearch);
  691. }
  692. //
  693. // Reset return code.
  694. //
  695. hr = S_OK;
  696. }
  697. catch(...)
  698. {
  699. hr = E_INVALIDARG;
  700. DebugTrace("Exception: invalid parameter.\n");
  701. goto ErrorExit;
  702. }
  703. CommonExit:
  704. //
  705. // Free resource.
  706. //
  707. if (hSearch)
  708. {
  709. pIContainer->CloseSearchHandle(hSearch);
  710. }
  711. DebugTrace("Leaving LoadUserCertificates().\n");
  712. return hr;
  713. ErrorExit:
  714. //
  715. // Sanity check.
  716. //
  717. ATLASSERT(FAILED(hr));
  718. goto CommonExit;
  719. }
  720. ////////////////////////////////////////////////////////////////////////////////
  721. //
  722. // Exported functions.
  723. //
  724. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  725. Function : LoadFromDirectory
  726. Synopsis : Load all certificates from the userCertificate attribute of users
  727. specified through the filter.
  728. Parameter: HCERTSTORE hCertStore - Certificate store handle of store to
  729. receive all the certificates.
  730. BSTR bstrFilter - Filter (See Store::Open() for more info).
  731. Remark :
  732. ------------------------------------------------------------------------------*/
  733. HRESULT LoadFromDirectory (HCERTSTORE hCertStore,
  734. BSTR bstrFilter)
  735. {
  736. HRESULT hr = S_OK;
  737. IDirectorySearch * pIContainerToSearch = NULL;
  738. DebugTrace("Entering LoadFromDirectory().\n");
  739. //
  740. // Sanity check.
  741. //
  742. ATLASSERT(bstrFilter);
  743. ATLASSERT(hCertStore);
  744. //
  745. // Build the AD search container.
  746. //
  747. if (FAILED(hr = ::BuildADSearch(&pIContainerToSearch)))
  748. {
  749. DebugTrace("Error [%#x]: BuildADSearch() failed.\n", hr);
  750. goto ErrorExit;
  751. }
  752. //
  753. // Load all userCertificate of the specified filter.
  754. //
  755. if (FAILED(hr = ::LoadUserCertificates(hCertStore,
  756. pIContainerToSearch,
  757. bstrFilter)))
  758. {
  759. DebugTrace("Error [%#x]: LoadUserCertificates() failed.\n", hr);
  760. goto ErrorExit;
  761. }
  762. CommonExit:
  763. //
  764. // Free resource.
  765. //
  766. if (pIContainerToSearch)
  767. {
  768. pIContainerToSearch->Release();
  769. }
  770. DebugTrace("Leaving LoadFromDirectory().\n");
  771. return hr;
  772. ErrorExit:
  773. //
  774. // Sanity check.
  775. //
  776. ATLASSERT(FAILED(hr));
  777. goto CommonExit;
  778. }