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.

4410 lines
131 KiB

  1. //---------------------------------------------------------------------------;
  2. //
  3. //
  4. // Microsoft Windows
  5. // Copyright (C) Microsoft Corporation, 1992 - 1995
  6. //
  7. // File: cdssrch.cxx
  8. //
  9. // Contents: Microsoft ADs LDAP Provider Generic Object
  10. //
  11. //
  12. // History: 03-02-97 ShankSh Created.
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "ldapc.hxx"
  16. #pragma hdrstop
  17. const int MAX_BYTES = 1048576;
  18. const int NO_LDAP_RESULT_HANDLES = 32;
  19. static BOOL
  20. IsValidPrefValue(
  21. ADS_SEARCHPREF_INFO SearchPref
  22. );
  23. static
  24. HRESULT
  25. LdapValueToADsColumn(
  26. LPWSTR pszColumnName,
  27. DWORD dwSyntaxId,
  28. DWORD dwValues,
  29. VOID **lpValue,
  30. ADS_SEARCH_COLUMN * pColumn
  31. );
  32. HRESULT
  33. UnicodeToUTF8String(
  34. LPCWSTR pUnicode,
  35. LPSTR *ppUTF8
  36. );
  37. HRESULT
  38. UTF8ToUnicodeString(
  39. LPCSTR pUTF8,
  40. LPWSTR *ppUnicode
  41. );
  42. //
  43. // Sets the appropriate search preferences.
  44. //
  45. HRESULT
  46. ADsSetSearchPreference(
  47. IN PADS_SEARCHPREF_INFO pSearchPrefs,
  48. IN DWORD dwNumPrefs,
  49. OUT LDAP_SEARCH_PREF * pLdapPref,
  50. IN LPWSTR pszLDAPServer,
  51. IN LPWSTR pszLDAPDn,
  52. IN CCredentials& Credentials,
  53. IN DWORD dwPort
  54. )
  55. {
  56. HRESULT hr = S_OK;
  57. BOOL fWarning = FALSE;
  58. DWORD i, j;
  59. BOOL fPagedSearch = FALSE, fSorting = TRUE, fVLV = FALSE, fAttribScoped = FALSE;
  60. DWORD dwSecDescType = ADSI_LDAPC_SECDESC_NONE;
  61. PADS_SORTKEY pSortKeyArray = NULL;
  62. DWORD dwSortKeyArrayLen = 0, nKeys = 0;
  63. BOOL fSetCaching = FALSE; // TRUE if user explicitly set a caching preference
  64. BOOL fSetScope = FALSE; // TRUE if user explicitly set a scope preference
  65. PADS_VLV pVLV = NULL;
  66. DWORD dwVLVLen = 0;
  67. LPSTR pUTF8Target = NULL;
  68. DWORD dwUTF8TargetLen = 0;
  69. LPWSTR pAttribScoped = NULL;
  70. DWORD dwSecurityMask;
  71. if (!pSearchPrefs && dwNumPrefs > 0 || !pLdapPref) {
  72. RRETURN (E_ADS_BAD_PARAMETER);
  73. }
  74. for (i=0; i<dwNumPrefs; i++) {
  75. pSearchPrefs[i].dwStatus = ADS_STATUS_S_OK;
  76. if (!IsValidPrefValue(pSearchPrefs[i]) ) {
  77. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  78. fWarning = TRUE;
  79. continue;
  80. }
  81. switch(pSearchPrefs[i].dwSearchPref) {
  82. case ADS_SEARCHPREF_ASYNCHRONOUS:
  83. pLdapPref->_fAsynchronous = pSearchPrefs[i].vValue.Boolean;
  84. break;
  85. case ADS_SEARCHPREF_ATTRIBTYPES_ONLY:
  86. pLdapPref->_fAttrsOnly = pSearchPrefs[i].vValue.Boolean;
  87. break;
  88. case ADS_SEARCHPREF_SIZE_LIMIT:
  89. pLdapPref->_dwSizeLimit = pSearchPrefs[i].vValue.Integer;
  90. break;
  91. case ADS_SEARCHPREF_TIME_LIMIT:
  92. pLdapPref->_dwTimeLimit = pSearchPrefs[i].vValue.Integer;
  93. break;
  94. case ADS_SEARCHPREF_TIMEOUT:
  95. pLdapPref->_timeout.tv_sec = pSearchPrefs[i].vValue.Integer;
  96. break;
  97. case ADS_SEARCHPREF_PAGESIZE:
  98. if (pLdapPref->_fDirSync) {
  99. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  100. }
  101. ReadPagingSupportedAttr(
  102. pszLDAPServer,
  103. &fPagedSearch,
  104. Credentials,
  105. dwPort
  106. ) ;
  107. if (fPagedSearch) {
  108. pLdapPref->_dwPageSize = pSearchPrefs[i].vValue.Integer;
  109. }
  110. else {
  111. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
  112. fWarning = TRUE;
  113. }
  114. break;
  115. case ADS_SEARCHPREF_PAGED_TIME_LIMIT:
  116. ReadPagingSupportedAttr(
  117. pszLDAPServer,
  118. &fPagedSearch,
  119. Credentials,
  120. dwPort
  121. ) ;
  122. if (fPagedSearch) {
  123. pLdapPref->_dwPagedTimeLimit = pSearchPrefs[i].vValue.Integer;
  124. }
  125. else {
  126. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
  127. fWarning = TRUE;
  128. }
  129. break;
  130. case ADS_SEARCHPREF_DEREF_ALIASES:
  131. pLdapPref->_dwDerefAliases = pSearchPrefs[i].vValue.Integer;
  132. break;
  133. case ADS_SEARCHPREF_SEARCH_SCOPE:
  134. // if doing a attribute-scoped query and user tries to set scope
  135. // to anything other than ADS_SCOPE_BASE, reject
  136. if (pLdapPref->_pAttribScoped && (pSearchPrefs[i].vValue.Integer != ADS_SCOPE_BASE)) {
  137. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  138. }
  139. switch (pSearchPrefs[i].vValue.Integer) {
  140. case ADS_SCOPE_SUBTREE:
  141. pLdapPref->_dwSearchScope = LDAP_SCOPE_SUBTREE;
  142. break;
  143. case ADS_SCOPE_ONELEVEL:
  144. pLdapPref->_dwSearchScope = LDAP_SCOPE_ONELEVEL;
  145. break;
  146. case ADS_SCOPE_BASE:
  147. pLdapPref->_dwSearchScope = LDAP_SCOPE_BASE;
  148. break;
  149. }
  150. fSetScope = TRUE; // set so if user later tries to do
  151. // attrib-scoped query, and user set scope
  152. // to other than ADS_SCOPE_BASE, can detect & reject
  153. break;
  154. case ADS_SEARCHPREF_CHASE_REFERRALS:
  155. switch (pSearchPrefs[i].vValue.Integer) {
  156. case ADS_CHASE_REFERRALS_NEVER:
  157. pLdapPref->_dwChaseReferrals = (DWORD) (DWORD_PTR)LDAP_OPT_OFF;
  158. break;
  159. case ADS_CHASE_REFERRALS_SUBORDINATE:
  160. pLdapPref->_dwChaseReferrals = LDAP_CHASE_SUBORDINATE_REFERRALS;
  161. break;
  162. case ADS_CHASE_REFERRALS_EXTERNAL:
  163. pLdapPref->_dwChaseReferrals = LDAP_CHASE_EXTERNAL_REFERRALS;
  164. break;
  165. case ADS_CHASE_REFERRALS_ALWAYS:
  166. pLdapPref->_dwChaseReferrals = (DWORD) (DWORD_PTR) LDAP_OPT_ON;
  167. break;
  168. }
  169. break;
  170. case ADS_SEARCHPREF_SORT_ON:
  171. ReadSortingSupportedAttr(
  172. pszLDAPServer,
  173. &fSorting,
  174. Credentials,
  175. dwPort
  176. ) ;
  177. if (!fSorting) {
  178. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
  179. fWarning = TRUE;
  180. continue;
  181. }
  182. //
  183. // The value is actually a pointer to the LDAP Sort Key whose
  184. // structure is as defined in the sort control RFC extension.
  185. //
  186. pSortKeyArray = (PADS_SORTKEY) pSearchPrefs[i].vValue.ProviderSpecific.lpValue;
  187. dwSortKeyArrayLen = pSearchPrefs[i].vValue.ProviderSpecific.dwLength;
  188. if (!pSortKeyArray || !dwSortKeyArrayLen ) {
  189. continue;
  190. }
  191. if (dwSortKeyArrayLen % sizeof(ADS_SORTKEY) != 0 ) {
  192. //
  193. // The data given does not seem to contain a proper SortKey
  194. // structure
  195. //
  196. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  197. fWarning = TRUE;
  198. continue;
  199. }
  200. nKeys = dwSortKeyArrayLen / sizeof(ADS_SORTKEY);
  201. if (pLdapPref->_pSortKeys) {
  202. //
  203. // Free the previous one
  204. //
  205. FreeSortKeys(pLdapPref->_pSortKeys, pLdapPref->_nSortKeys);
  206. }
  207. pLdapPref->_pSortKeys = (PLDAPSortKey) AllocADsMem(
  208. sizeof(LDAPSortKey) * nKeys);
  209. if (!pLdapPref->_pSortKeys) {
  210. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  211. }
  212. for (j=0; j<nKeys; j++) {
  213. pLdapPref->_pSortKeys[j].sk_attrtype =
  214. AllocADsStr(pSortKeyArray[j].pszAttrType);
  215. pLdapPref->_pSortKeys[j].sk_matchruleoid =
  216. pSortKeyArray[j].pszReserved;
  217. pLdapPref->_pSortKeys[j].sk_reverseorder =
  218. pSortKeyArray[j].fReverseorder;
  219. }
  220. pLdapPref->_nSortKeys = nKeys;
  221. break;
  222. case ADS_SEARCHPREF_CACHE_RESULTS:
  223. // if doing a VLV search and user tries to turn on caching, reject
  224. if (pLdapPref->_pVLVInfo && pSearchPrefs[i].vValue.Boolean) {
  225. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  226. }
  227. pLdapPref->_fCacheResults = pSearchPrefs[i].vValue.Boolean;
  228. fSetCaching = TRUE; // set so if we later determine user wants to
  229. // do a VLV search, we can reject if user tried
  230. // to explicitly turn on caching
  231. break;
  232. //
  233. // Like paged, setting this preference will mean that we use it
  234. // by default, it is not used.
  235. //
  236. case ADS_SEARCHPREF_DIRSYNC:
  237. if (pLdapPref->_dwPageSize) {
  238. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  239. }
  240. pLdapPref->_fDirSync = TRUE;
  241. //
  242. // Check if previous value is set and free if necessary.
  243. //
  244. if (pLdapPref->_pProvSpecific) {
  245. if (pLdapPref->_pProvSpecific->lpValue) {
  246. FreeADsMem(pLdapPref->_pProvSpecific->lpValue);
  247. pLdapPref->_pProvSpecific->lpValue = NULL;
  248. }
  249. FreeADsMem(pLdapPref->_pProvSpecific);
  250. pLdapPref->_pProvSpecific = NULL;
  251. }
  252. //
  253. // Copy over the info here.
  254. //
  255. pLdapPref->_pProvSpecific =
  256. (PADS_PROV_SPECIFIC) AllocADsMem(sizeof(ADS_PROV_SPECIFIC));
  257. if (!pLdapPref->_pProvSpecific) {
  258. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  259. }
  260. pLdapPref->_pProvSpecific->dwLength =
  261. pSearchPrefs[i].vValue.ProviderSpecific.dwLength;
  262. //
  263. // If the octet string is anything other than NULL,
  264. // we need to copy it over. If it is NULL, then this is
  265. // the first time the control is being used.
  266. //
  267. if (pLdapPref->_pProvSpecific->dwLength > 0) {
  268. pLdapPref->_pProvSpecific->lpValue =
  269. (PBYTE)AllocADsMem(pLdapPref->_pProvSpecific->dwLength);
  270. if (!pLdapPref->_pProvSpecific->lpValue) {
  271. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  272. }
  273. memcpy(
  274. pLdapPref->_pProvSpecific->lpValue,
  275. pSearchPrefs[i].vValue.ProviderSpecific.lpValue,
  276. pLdapPref->_pProvSpecific->dwLength
  277. );
  278. }
  279. break;
  280. case ADS_SEARCHPREF_TOMBSTONE :
  281. pLdapPref->_fTombStone = pSearchPrefs[i].vValue.Boolean;
  282. break;
  283. case ADS_SEARCHPREF_VLV:
  284. // If user tried to explicitly turn on caching, reject
  285. // Later on, we'll turn off caching
  286. if ( fSetCaching && pLdapPref->_fCacheResults) {
  287. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  288. }
  289. // test for server support of VLV
  290. ReadVLVSupportedAttr(
  291. pszLDAPServer,
  292. &fVLV,
  293. Credentials,
  294. dwPort
  295. ) ;
  296. if (!fVLV) {
  297. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
  298. fWarning = TRUE;
  299. continue;
  300. }
  301. // basic sanity checks of user-supplied data
  302. pVLV = (PADS_VLV) pSearchPrefs[i].vValue.ProviderSpecific.lpValue;
  303. dwVLVLen = pSearchPrefs[i].vValue.ProviderSpecific.dwLength;
  304. if (!pVLV || !dwVLVLen ) {
  305. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  306. fWarning = TRUE;
  307. continue;
  308. }
  309. if (dwVLVLen != sizeof(ADS_VLV)) {
  310. //
  311. // The data given does not seem to contain a proper VLV
  312. // structure
  313. //
  314. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  315. fWarning = TRUE;
  316. continue;
  317. }
  318. // free the previous LDAPVLVInfo, if one exists (generally, it shouldn't)
  319. if (pLdapPref->_pVLVInfo)
  320. FreeLDAPVLVInfo(pLdapPref->_pVLVInfo);
  321. // Copy the user's VLV search preferences into a LDAPVLVInfo
  322. // Note that we copy the dwOffset and dwContentCount even if the user
  323. // wants to do a greaterThanOrEqual-type VLV search. This is because
  324. // we'll ignore those members if ldvlv_attrvalue != NULL.
  325. pLdapPref->_pVLVInfo = (PLDAPVLVInfo) AllocADsMem(sizeof(LDAPVLVInfo));
  326. if (!pLdapPref->_pVLVInfo)
  327. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  328. pLdapPref->_pVLVInfo->ldvlv_version = LDAP_VLVINFO_VERSION; // 1
  329. pLdapPref->_pVLVInfo->ldvlv_before_count = pVLV->dwBeforeCount;
  330. pLdapPref->_pVLVInfo->ldvlv_after_count = pVLV->dwAfterCount;
  331. pLdapPref->_pVLVInfo->ldvlv_offset = pVLV->dwOffset;
  332. pLdapPref->_pVLVInfo->ldvlv_count = pVLV->dwContentCount;
  333. pLdapPref->_pVLVInfo->ldvlv_attrvalue = NULL;
  334. pLdapPref->_pVLVInfo->ldvlv_context = NULL;
  335. pLdapPref->_pVLVInfo->ldvlv_extradata = NULL;
  336. // copy the greaterThanOrEqual attribute, if provided by the user
  337. if (pVLV->pszTarget) {
  338. pLdapPref->_pVLVInfo->ldvlv_attrvalue = (PBERVAL) AllocADsMem(sizeof(BERVAL));
  339. if (!pLdapPref->_pVLVInfo->ldvlv_attrvalue)
  340. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  341. // convert Unicode to UDF-8
  342. // important: do NOT include the NULL terminator in the LDAPVLVInfo.ldvlv_attrvalue
  343. hr = UnicodeToUTF8String(pVLV->pszTarget, &pUTF8Target);
  344. BAIL_ON_FAILURE(hr);
  345. // we want the number of bytes, not the number of MBCS characters
  346. dwUTF8TargetLen = strlen(pUTF8Target);
  347. pLdapPref->_pVLVInfo->ldvlv_attrvalue->bv_len = dwUTF8TargetLen;
  348. pLdapPref->_pVLVInfo->ldvlv_attrvalue->bv_val = (PCHAR) AllocADsMem(dwUTF8TargetLen);
  349. if (!pLdapPref->_pVLVInfo->ldvlv_attrvalue->bv_val)
  350. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  351. memcpy(pLdapPref->_pVLVInfo->ldvlv_attrvalue->bv_val,
  352. pUTF8Target,
  353. dwUTF8TargetLen);
  354. }
  355. // copy the context ID, if provided by the user
  356. if (pVLV->lpContextID && pVLV->dwContextIDLength) {
  357. pLdapPref->_pVLVInfo->ldvlv_context = (PBERVAL) AllocADsMem(sizeof(BERVAL));
  358. if (pLdapPref->_pVLVInfo->ldvlv_context == NULL)
  359. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  360. pLdapPref->_pVLVInfo->ldvlv_context->bv_val = (PCHAR) AllocADsMem(pVLV->dwContextIDLength);
  361. if (pLdapPref->_pVLVInfo->ldvlv_context->bv_val == NULL)
  362. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  363. pLdapPref->_pVLVInfo->ldvlv_context->bv_len = pVLV->dwContextIDLength;
  364. memcpy(pLdapPref->_pVLVInfo->ldvlv_context->bv_val,
  365. pVLV->lpContextID,
  366. pVLV->dwContextIDLength);
  367. }
  368. // disable caching, since it's not supported in conjunction with VLV
  369. pLdapPref->_fCacheResults = FALSE;
  370. break;
  371. case ADS_SEARCHPREF_ATTRIBUTE_QUERY:
  372. // If user tried to explicitly set scope to other than "base", reject
  373. // Later on, we'll set it to base.
  374. if ( fSetScope && pLdapPref->_dwSearchScope != LDAP_SCOPE_BASE) {
  375. BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
  376. }
  377. // test for server support of attribute-scoped query
  378. ReadAttribScopedSupportedAttr(
  379. pszLDAPServer,
  380. &fAttribScoped,
  381. Credentials,
  382. dwPort
  383. ) ;
  384. if (!fAttribScoped) {
  385. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
  386. fWarning = TRUE;
  387. continue;
  388. }
  389. // basic sanity checks of user-supplied data
  390. pAttribScoped = pSearchPrefs[i].vValue.CaseIgnoreString;
  391. if (!pAttribScoped) {
  392. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  393. fWarning = TRUE;
  394. continue;
  395. }
  396. // free the previous ADS_ATTRIBUTE_QUERY, if one exists (generally, it shouldn't)
  397. if (pLdapPref->_pAttribScoped) {
  398. FreeADsStr(pLdapPref->_pAttribScoped);
  399. pLdapPref->_pAttribScoped = NULL;
  400. }
  401. // copy the ADS_ATTRIBUTE_QUERY
  402. pLdapPref->_pAttribScoped = AllocADsStr(pAttribScoped);
  403. if (!(pLdapPref->_pAttribScoped)) {
  404. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  405. }
  406. // set search scope to base (only scope supported by attrib-scoped query)
  407. pLdapPref->_dwSearchScope = LDAP_SCOPE_BASE;
  408. break;
  409. case ADS_SEARCHPREF_SECURITY_MASK:
  410. //
  411. // test for server support of security descriptor control
  412. //
  413. ReadSecurityDescriptorControlType(
  414. pszLDAPServer,
  415. &dwSecDescType,
  416. Credentials,
  417. dwPort
  418. );
  419. if (dwSecDescType != ADSI_LDAPC_SECDESC_NT) {
  420. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
  421. fWarning = TRUE;
  422. continue;
  423. }
  424. //
  425. // sanity check of user supplied data
  426. //
  427. dwSecurityMask = pSearchPrefs[i].vValue.Integer;
  428. if (dwSecurityMask > (OWNER_SECURITY_INFORMATION |
  429. GROUP_SECURITY_INFORMATION |
  430. SACL_SECURITY_INFORMATION |
  431. DACL_SECURITY_INFORMATION)) {
  432. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
  433. fWarning = TRUE;
  434. continue;
  435. }
  436. //
  437. // enable the option
  438. //
  439. pLdapPref->_fSecurityDescriptorControl = TRUE;
  440. pLdapPref->_SecurityDescriptorMask = static_cast<SECURITY_INFORMATION>(dwSecurityMask);
  441. break;
  442. default:
  443. pSearchPrefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
  444. fWarning = TRUE;
  445. continue;
  446. }
  447. }
  448. error:
  449. if (pUTF8Target)
  450. FreeADsMem(pUTF8Target);
  451. //
  452. // Need to return the hr if it was something like out of mem.
  453. // Most often though it will be either S_OK or s-error ocurred.
  454. //
  455. if (FAILED(hr)) {
  456. //
  457. // Free sort keys and dirsync data if applicable
  458. //
  459. if (pLdapPref->_pSortKeys) {
  460. FreeSortKeys(pLdapPref->_pSortKeys, pLdapPref->_nSortKeys);
  461. pLdapPref->_pSortKeys = NULL;
  462. pLdapPref->_nSortKeys = 0;
  463. }
  464. if (pLdapPref->_pProvSpecific) {
  465. if (pLdapPref->_pProvSpecific->lpValue) {
  466. FreeADsMem(pLdapPref->_pProvSpecific->lpValue);
  467. }
  468. FreeADsMem(pLdapPref->_pProvSpecific);
  469. pLdapPref->_pProvSpecific = NULL;
  470. }
  471. //
  472. // Free VLV information if applicable
  473. //
  474. if (pLdapPref->_pVLVInfo) {
  475. FreeLDAPVLVInfo(pLdapPref->_pVLVInfo);
  476. pLdapPref->_pVLVInfo = NULL;
  477. }
  478. //
  479. // Free attrib-scoped query if applicable
  480. //
  481. if (pLdapPref->_pAttribScoped) {
  482. FreeADsStr(pLdapPref->_pAttribScoped);
  483. pLdapPref->_pAttribScoped = NULL;
  484. }
  485. RRETURN(hr);
  486. }
  487. RRETURN (fWarning ? S_ADS_ERRORSOCCURRED : S_OK);
  488. }
  489. HRESULT
  490. ADsExecuteSearch(
  491. IN LDAP_SEARCH_PREF LdapPref,
  492. IN LPWSTR pszADsPath,
  493. IN LPWSTR pszLdapServer,
  494. IN LPWSTR pszLdapDn,
  495. IN LPWSTR pszSearchFilter,
  496. IN LPWSTR * pAttributeNames,
  497. IN DWORD dwNumberAttributes,
  498. OUT PADS_SEARCH_HANDLE phSearchHandle
  499. )
  500. {
  501. PLDAP_SEARCHINFO phSearchInfo = NULL;
  502. LPWSTR szCurrAttr = NULL;
  503. DWORD dwAttrNamesLen = 0;
  504. HRESULT hr = S_OK;
  505. ULONG i, j;
  506. LPWSTR pszAttrNameBuffer = NULL, *ppszAttrs = NULL;
  507. OBJECTINFO ObjectInfo;
  508. POBJECTINFO pObjectInfo = &ObjectInfo;
  509. //
  510. // Initilize so that we wont end up freeing bad data.
  511. //
  512. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  513. if (!phSearchHandle ) {
  514. RRETURN (E_ADS_BAD_PARAMETER);
  515. }
  516. //
  517. // Allocate search handle
  518. //
  519. phSearchInfo = (PLDAP_SEARCHINFO) AllocADsMem(sizeof(LDAP_SEARCHINFO));
  520. if(!phSearchInfo)
  521. BAIL_ON_FAILURE (hr = E_OUTOFMEMORY);
  522. memset(phSearchInfo, 0, sizeof(LDAP_SEARCHINFO));
  523. phSearchInfo->_pszADsPathContext = AllocADsStr(pszADsPath);
  524. if(!(phSearchInfo->_pszADsPathContext))
  525. BAIL_ON_FAILURE (hr = E_OUTOFMEMORY);
  526. if (pszSearchFilter) {
  527. phSearchInfo->_pszSearchFilter = AllocADsStr(pszSearchFilter);
  528. }
  529. else {
  530. phSearchInfo->_pszSearchFilter = AllocADsStr(L"(objectClass=*)");
  531. }
  532. if(!(phSearchInfo->_pszSearchFilter))
  533. BAIL_ON_FAILURE (hr = E_OUTOFMEMORY);
  534. if (pszLdapServer) {
  535. phSearchInfo->_pszLdapServer = AllocADsStr(pszLdapServer);
  536. if (!phSearchInfo->_pszLdapServer) {
  537. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  538. }
  539. }
  540. if (pszLdapDn) {
  541. phSearchInfo->_pszBindContextDn = AllocADsStr(pszLdapDn);
  542. if(!(phSearchInfo->_pszBindContextDn)){
  543. BAIL_ON_FAILURE (hr = E_OUTOFMEMORY);
  544. }
  545. }
  546. phSearchInfo->_fADsPathPresent = FALSE;
  547. phSearchInfo->_fADsPathReturned = FALSE;
  548. phSearchInfo->_fADsPathOnly = FALSE;
  549. if (dwNumberAttributes == -1) {
  550. //
  551. // Specifies returning all attributes
  552. //
  553. phSearchInfo->_ppszAttrs = NULL;
  554. phSearchInfo->_pszAttrNameBuffer = NULL;
  555. phSearchInfo->_fADsPathPresent = TRUE;
  556. }
  557. else {
  558. ppszAttrs = (LPWSTR *) AllocADsMem(
  559. sizeof(LPWSTR) *
  560. (dwNumberAttributes + 1)
  561. );
  562. if (!ppszAttrs)
  563. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  564. for (i = 0; i < dwNumberAttributes; i++)
  565. dwAttrNamesLen+= (wcslen(pAttributeNames[i]) + 1) * sizeof(WCHAR);
  566. pszAttrNameBuffer = (LPWSTR) AllocADsMem(
  567. dwAttrNamesLen
  568. );
  569. if (!pszAttrNameBuffer)
  570. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  571. szCurrAttr = pszAttrNameBuffer;
  572. for (i = 0, j = 0; i < dwNumberAttributes; i++) {
  573. wcscpy(szCurrAttr, pAttributeNames[i]);
  574. ppszAttrs[j] = szCurrAttr;
  575. szCurrAttr += wcslen(ppszAttrs[j]) + 1;
  576. if(_wcsicmp(ppszAttrs[j], L"ADsPath") == 0) {
  577. //
  578. // This attribute need not be sent
  579. //
  580. phSearchInfo->_fADsPathPresent = TRUE;
  581. }
  582. else {
  583. j++;
  584. }
  585. }
  586. // If the query requests only ADsPath, then set ppszAttrs[0] to some
  587. // attribute. Setting it to NULL results in all attributes being
  588. // returned, which is a huge performance hit. Instead, request only
  589. // the objectclass (guaranteed to be present on all LDAP servers).
  590. if (0 == j)
  591. {
  592. FreeADsMem(pszAttrNameBuffer);
  593. pszAttrNameBuffer = (LPWSTR) AllocADsStr(L"objectClass");
  594. if(pszAttrNameBuffer == NULL) {
  595. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  596. }
  597. FreeADsMem(ppszAttrs);
  598. ppszAttrs = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * 2);
  599. if(ppszAttrs == NULL) {
  600. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  601. }
  602. ppszAttrs[0] = pszAttrNameBuffer;
  603. ppszAttrs[1] = NULL;
  604. phSearchInfo->_fADsPathOnly = TRUE;
  605. }
  606. else
  607. ppszAttrs[j] = NULL;
  608. phSearchInfo->_ppszAttrs = ppszAttrs;
  609. phSearchInfo->_pszAttrNameBuffer = pszAttrNameBuffer;
  610. }
  611. hr = ADsObject(pszADsPath, pObjectInfo);
  612. BAIL_ON_FAILURE(hr);
  613. phSearchInfo->_dwPort = pObjectInfo->PortNumber;
  614. phSearchInfo->_pConnection = NULL;
  615. phSearchInfo->_hPagedSearch = NULL;
  616. phSearchInfo->_pSearchResults = NULL;
  617. phSearchInfo->_cSearchResults = 0;
  618. phSearchInfo->_dwCurrResult = 0;
  619. phSearchInfo->_dwMaxResultGot = 0;
  620. phSearchInfo->_currMsgId = (DWORD) -1;
  621. phSearchInfo->_pCurrentRow = NULL;
  622. phSearchInfo->_pFirstAttr = NULL;
  623. phSearchInfo->_fLastResult = FALSE;
  624. phSearchInfo->_fLastPage = FALSE;
  625. phSearchInfo->_fBefFirstRow = TRUE;
  626. phSearchInfo->_hrLastSearch = S_OK;
  627. phSearchInfo->_fNonFatalErrors = FALSE;
  628. phSearchInfo->_fAbandon = FALSE;
  629. phSearchInfo->_dwVLVOffset = 0;
  630. phSearchInfo->_dwVLVCount = 0;
  631. phSearchInfo->_pVLVContextID = NULL;
  632. phSearchInfo->_pBerValAttribScoped = NULL;
  633. //
  634. // Copy the search preference structure and also make a copy of the memory
  635. // that the internal pointers point to. This can probably be done better by
  636. // an assignment operator.
  637. //
  638. phSearchInfo->_SearchPref = LdapPref;
  639. phSearchInfo->_SearchPref._pVLVInfo = NULL;
  640. phSearchInfo->_SearchPref._pAttribScoped = NULL;
  641. // sorting
  642. if (LdapPref._pSortKeys) {
  643. phSearchInfo->_SearchPref._pSortKeys = (PLDAPSortKey) AllocADsMem(
  644. sizeof(LDAPSortKey) * LdapPref._nSortKeys);
  645. if (!phSearchInfo->_SearchPref._pSortKeys) {
  646. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  647. }
  648. memcpy(
  649. phSearchInfo->_SearchPref._pSortKeys,
  650. LdapPref._pSortKeys,
  651. sizeof(LDAPSortKey) * LdapPref._nSortKeys
  652. );
  653. //
  654. // We need to copy over all the attibutes.
  655. //
  656. for (i=0; i < LdapPref._nSortKeys; i++) {
  657. phSearchInfo->_SearchPref._pSortKeys[i].sk_attrtype =
  658. AllocADsStr( LdapPref._pSortKeys[i].sk_attrtype);
  659. if (!phSearchInfo->_SearchPref._pSortKeys[i].sk_attrtype) {
  660. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  661. }
  662. }
  663. }
  664. // VLV
  665. if (LdapPref._pVLVInfo) {
  666. hr = CopyLDAPVLVInfo(LdapPref._pVLVInfo, &(phSearchInfo->_SearchPref._pVLVInfo));
  667. BAIL_ON_FAILURE(hr);
  668. }
  669. // Attribute-scoped query
  670. if (LdapPref._pAttribScoped) {
  671. phSearchInfo->_SearchPref._pAttribScoped = AllocADsStr(LdapPref._pAttribScoped);
  672. if (!(phSearchInfo->_SearchPref._pAttribScoped)) {
  673. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  674. }
  675. }
  676. *phSearchHandle = phSearchInfo;
  677. FreeObjectInfo(pObjectInfo);
  678. RRETURN(S_OK);
  679. error:
  680. FreeObjectInfo(pObjectInfo);
  681. if(phSearchInfo) {
  682. if (phSearchInfo->_pszLdapServer) {
  683. FreeADsStr(phSearchInfo->_pszLdapServer);
  684. }
  685. if(phSearchInfo->_pszBindContextDn)
  686. FreeADsStr(phSearchInfo->_pszBindContextDn);
  687. if(phSearchInfo->_pszADsPathContext)
  688. FreeADsStr(phSearchInfo->_pszADsPathContext);
  689. if(phSearchInfo->_pszSearchFilter)
  690. FreeADsStr(phSearchInfo->_pszSearchFilter);
  691. if(phSearchInfo->_ppszAttrs)
  692. FreeADsMem(phSearchInfo->_ppszAttrs);
  693. else if(ppszAttrs)
  694. FreeADsMem(ppszAttrs);
  695. if(phSearchInfo->_pszAttrNameBuffer)
  696. FreeADsMem(phSearchInfo->_pszAttrNameBuffer);
  697. else if(pszAttrNameBuffer)
  698. FreeADsMem(pszAttrNameBuffer);
  699. if (phSearchInfo->_SearchPref._pVLVInfo) {
  700. FreeLDAPVLVInfo(phSearchInfo->_SearchPref._pVLVInfo);
  701. }
  702. if (phSearchInfo->_SearchPref._pAttribScoped) {
  703. FreeADsStr(phSearchInfo->_SearchPref._pAttribScoped);
  704. }
  705. FreeADsMem(phSearchInfo);
  706. }
  707. RRETURN (hr);
  708. }
  709. HRESULT
  710. ADsAbandonSearch(
  711. IN ADS_SEARCH_HANDLE hSearchHandle
  712. )
  713. {
  714. PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle;
  715. DWORD dwStatus = 0;
  716. // If there is an outstanding message id, call LdapAbandon
  717. //
  718. if (phSearchInfo->_currMsgId != (DWORD) -1) {
  719. dwStatus = LdapAbandon(
  720. phSearchInfo->_pConnection,
  721. phSearchInfo->_currMsgId
  722. );
  723. }
  724. //
  725. // Make sure that we don't do extra searches anymore. We only give back
  726. // whatever rows we have already received from the server
  727. //
  728. phSearchInfo->_fAbandon = TRUE;
  729. RRETURN(S_OK);
  730. }
  731. HRESULT
  732. ADsCloseSearchHandle (
  733. IN ADS_SEARCH_HANDLE hSearchHandle
  734. )
  735. {
  736. HRESULT hr = S_OK;
  737. PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle;
  738. DWORD i=0;
  739. if (!phSearchInfo)
  740. RRETURN (E_ADS_BAD_PARAMETER);
  741. if (phSearchInfo->_pszLdapServer)
  742. FreeADsStr(phSearchInfo->_pszLdapServer);
  743. if(phSearchInfo->_pszBindContextDn)
  744. FreeADsStr(phSearchInfo->_pszBindContextDn);
  745. if(phSearchInfo->_pszADsPathContext)
  746. FreeADsStr(phSearchInfo->_pszADsPathContext);
  747. if(phSearchInfo->_pszSearchFilter)
  748. FreeADsStr(phSearchInfo->_pszSearchFilter);
  749. if(phSearchInfo->_ppszAttrs)
  750. FreeADsMem(phSearchInfo->_ppszAttrs);
  751. if(phSearchInfo->_pszAttrNameBuffer)
  752. FreeADsMem(phSearchInfo->_pszAttrNameBuffer);
  753. if (phSearchInfo->_pSearchResults) {
  754. for (DWORD i=0; i <= phSearchInfo->_dwMaxResultGot; i++) {
  755. LdapMsgFree(
  756. phSearchInfo->_pSearchResults[i]
  757. );
  758. }
  759. FreeADsMem(phSearchInfo->_pSearchResults);
  760. }
  761. if (phSearchInfo->_hPagedSearch) {
  762. LdapSearchAbandonPage( phSearchInfo->_pConnection,
  763. phSearchInfo->_hPagedSearch
  764. );
  765. }
  766. //
  767. // Free ServerControls
  768. //
  769. if (phSearchInfo->_ServerControls) {
  770. //
  771. // This code assumes there are only VLV, sort, dirsync,
  772. // security descriptor & attribute-scoped query controls.
  773. // If more controls are added, modify the code accordingly.
  774. // Nothing needs to be freed for the dirsync control for now.
  775. // Freeing the searchpref will take care of the controls data.
  776. //
  777. for (i=0; phSearchInfo->_ServerControls[i]; i++) {
  778. BOOL fSortControl = FALSE;
  779. BOOL fVLVControl = FALSE;
  780. BOOL fSecDescControl = FALSE;
  781. if (phSearchInfo->_ServerControls[i]->ldctl_oid) {
  782. // Compare with sort control
  783. if (wcscmp(
  784. phSearchInfo->_ServerControls[i]->ldctl_oid,
  785. LDAP_SERVER_SORT_OID_W
  786. ) == 0 ) {
  787. fSortControl = TRUE;
  788. } else {
  789. fSortControl = FALSE;
  790. }
  791. // Compare with VLV control
  792. if (wcscmp(
  793. phSearchInfo->_ServerControls[i]->ldctl_oid,
  794. LDAP_CONTROL_VLVREQUEST_W
  795. ) == 0 ) {
  796. fVLVControl = TRUE;
  797. } else {
  798. fVLVControl = FALSE;
  799. }
  800. // Compare with security descriptor control
  801. if (wcscmp(
  802. phSearchInfo->_ServerControls[i]->ldctl_oid,
  803. LDAP_SERVER_SD_FLAGS_OID_W
  804. ) == 0 ) {
  805. fSecDescControl = TRUE;
  806. } else {
  807. fSecDescControl = FALSE;
  808. }
  809. }
  810. //
  811. // Free the sort control if this is it.
  812. //
  813. if (fSortControl) {
  814. if (phSearchInfo->_ServerControls[i]->ldctl_oid != NULL) {
  815. ldap_memfree( phSearchInfo->_ServerControls[i]->ldctl_oid );
  816. }
  817. if (phSearchInfo->_ServerControls[i]->ldctl_value.bv_val != NULL) {
  818. ldap_memfreeA( phSearchInfo->_ServerControls[i]->ldctl_value.bv_val );
  819. }
  820. }
  821. //
  822. // Free the security descriptor control if this is it
  823. //
  824. if (fSecDescControl) {
  825. if (phSearchInfo->_ServerControls[i]->ldctl_value.bv_val != NULL) {
  826. FreeADsMem( phSearchInfo->_ServerControls[i]->ldctl_value.bv_val );
  827. }
  828. }
  829. //
  830. // Need to free the control if sort or not.
  831. // Exception: VLV control is freed with LdapControlFree,
  832. // not with FreeADsMem
  833. //
  834. if (fVLVControl) {
  835. LdapControlFree( phSearchInfo->_ServerControls[i] );
  836. }
  837. else {
  838. FreeADsMem( phSearchInfo->_ServerControls[i] );
  839. }
  840. }
  841. FreeADsMem( phSearchInfo->_ServerControls );
  842. }
  843. //
  844. // Free SearchPref data
  845. //
  846. FreeSortKeys(
  847. phSearchInfo->_SearchPref._pSortKeys,
  848. phSearchInfo->_SearchPref._nSortKeys
  849. );
  850. FreeLDAPVLVInfo(phSearchInfo->_SearchPref._pVLVInfo);
  851. if (phSearchInfo->_SearchPref._pAttribScoped)
  852. FreeADsStr(phSearchInfo->_SearchPref._pAttribScoped);
  853. //
  854. // Free Dirsync control infromation.
  855. //
  856. if (phSearchInfo->_SearchPref._fDirSync) {
  857. if (phSearchInfo->_SearchPref._pProvSpecific) {
  858. //
  859. // Free the data if applicable.
  860. //
  861. if (phSearchInfo->_SearchPref._pProvSpecific->lpValue) {
  862. FreeADsMem(phSearchInfo->_SearchPref._pProvSpecific->lpValue);
  863. }
  864. //
  865. // Free the struct itself
  866. //
  867. FreeADsMem(phSearchInfo->_SearchPref._pProvSpecific);
  868. phSearchInfo->_SearchPref._pProvSpecific = NULL;
  869. }
  870. }
  871. if (phSearchInfo->_pVLVContextID) {
  872. if (phSearchInfo->_pVLVContextID->bv_val) {
  873. FreeADsMem(phSearchInfo->_pVLVContextID->bv_val);
  874. }
  875. FreeADsMem(phSearchInfo->_pVLVContextID);
  876. }
  877. if (phSearchInfo->_pBerVal) {
  878. ber_bvfree(phSearchInfo->_pBerVal);
  879. }
  880. if (phSearchInfo->_pBerValAttribScoped) {
  881. ber_bvfree(phSearchInfo->_pBerValAttribScoped);
  882. }
  883. if(phSearchInfo->_pConnection)
  884. LdapCloseObject(
  885. phSearchInfo->_pConnection
  886. );
  887. FreeADsMem(phSearchInfo);
  888. RRETURN (hr);
  889. }
  890. HRESULT
  891. ADsGetFirstRow(
  892. IN ADS_SEARCH_HANDLE hSearchHandle,
  893. IN CCredentials& Credentials
  894. )
  895. {
  896. HRESULT hr = S_OK;
  897. DWORD dwStatus = NO_ERROR, dwStatus2 = NO_ERROR;
  898. PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle;
  899. LDAP *ld = NULL;
  900. BOOL fNewOptionSet = FALSE;
  901. DWORD oldOption = 0;
  902. DWORD newOption = 0;
  903. if (!phSearchInfo) {
  904. RRETURN(E_ADS_BAD_PARAMETER);
  905. }
  906. if(!phSearchInfo->_pConnection) {
  907. hr = LdapOpenObject(
  908. phSearchInfo->_pszLdapServer,
  909. phSearchInfo->_pszBindContextDn,
  910. &phSearchInfo->_pConnection,
  911. Credentials,
  912. phSearchInfo->_dwPort
  913. );
  914. BAIL_ON_FAILURE(hr);
  915. //
  916. // Set the preferences like deref aliases, time limit and size limit
  917. //
  918. if (ld = phSearchInfo->_pConnection->LdapHandle) {
  919. ld->ld_deref = phSearchInfo->_SearchPref._dwDerefAliases;
  920. ld->ld_sizelimit = phSearchInfo->_SearchPref._dwSizeLimit;
  921. ld->ld_timelimit = phSearchInfo->_SearchPref._dwTimeLimit;
  922. }
  923. hr = AddSearchControls(phSearchInfo, Credentials);
  924. BAIL_ON_FAILURE(hr);
  925. }
  926. ld = phSearchInfo->_pConnection->LdapHandle;
  927. dwStatus = ldap_get_option(
  928. ld,
  929. LDAP_OPT_REFERRALS,
  930. &(oldOption)
  931. );
  932. newOption = phSearchInfo->_SearchPref._dwChaseReferrals;
  933. dwStatus2 = ldap_set_option(
  934. ld,
  935. LDAP_OPT_REFERRALS,
  936. &(newOption)
  937. );
  938. if (dwStatus == NO_ERROR && dwStatus2 == NO_ERROR)
  939. fNewOptionSet = TRUE;
  940. if(!phSearchInfo->_pSearchResults) {
  941. //
  942. // Get the results. This function uses various members of pSearchInfo
  943. // and returns the result in phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]
  944. // which can be used to call LdapFirstEntry and LdapNextEntry
  945. //
  946. hr = ADsGetResults(
  947. phSearchInfo
  948. );
  949. //
  950. // Update the VLV server response if applicable
  951. //
  952. if (phSearchInfo->_SearchPref._pVLVInfo
  953. && phSearchInfo->_pSearchResults
  954. && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) {
  955. HRESULT hrVLV = S_OK;
  956. hrVLV = StoreVLVInfo(
  957. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  958. phSearchInfo
  959. );
  960. //
  961. // we only care if storing the cookie failed
  962. // if the search otherwise succeeded
  963. //
  964. if (FAILED(hrVLV) && SUCCEEDED(hr)) {
  965. hr = hrVLV;
  966. }
  967. }
  968. //
  969. // Update the Attribute-Scoped Query info if applicable
  970. //
  971. if (phSearchInfo->_SearchPref._pAttribScoped
  972. && phSearchInfo->_pSearchResults
  973. && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) {
  974. HRESULT hrASQ = S_OK;
  975. hrASQ = StoreAttribScopedInfo(
  976. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  977. phSearchInfo
  978. );
  979. //
  980. // we only care if storing the info failed
  981. // if the search otherwise succeeded
  982. //
  983. if (FAILED(hrASQ) && SUCCEEDED(hr)) {
  984. hr = hrASQ;
  985. }
  986. }
  987. //
  988. // Update the dirsync control cookie if applicable.
  989. //
  990. if (phSearchInfo->_SearchPref._fDirSync
  991. && phSearchInfo->_pSearchResults
  992. && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) {
  993. //
  994. // Store the cookie info in searchprefs.
  995. //
  996. StoreDirSyncCookie(
  997. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  998. phSearchInfo
  999. );
  1000. while (hr == S_ADS_NOMORE_ROWS) {
  1001. //
  1002. // Try and get more results - this will handle the
  1003. // case of the DirSync cookie indicating more rows
  1004. // correctly.
  1005. //
  1006. hr = ADsGetMoreResultsDirSync(
  1007. phSearchInfo,
  1008. Credentials
  1009. );
  1010. BAIL_ON_FAILURE(hr);
  1011. }
  1012. }
  1013. if (FAILED(hr) || hr == S_ADS_NOMORE_ROWS) {
  1014. goto error;
  1015. }
  1016. }
  1017. //
  1018. // Need to set the cur result to 0 as it maybe a case
  1019. // where we are now going back to the top of a multiple
  1020. // page search. This will make no difference if the cache
  1021. // is turned off.
  1022. //
  1023. phSearchInfo->_dwCurrResult = 0;
  1024. hr = LdapFirstEntry(
  1025. phSearchInfo->_pConnection,
  1026. phSearchInfo->_pSearchResults[0],
  1027. &phSearchInfo->_pCurrentRow
  1028. );
  1029. BAIL_ON_FAILURE(hr);
  1030. if(phSearchInfo->_pCurrentRow) {
  1031. phSearchInfo->_pFirstAttr = NULL;
  1032. phSearchInfo->_fBefFirstRow = FALSE;
  1033. hr = S_OK;
  1034. }
  1035. else {
  1036. hr = S_ADS_NOMORE_ROWS;
  1037. //
  1038. // Might be DirSync case where we need to try fetch
  1039. // more results.
  1040. //
  1041. if (phSearchInfo->_SearchPref._fDirSync
  1042. && phSearchInfo->_fMoreDirSync ) {
  1043. //
  1044. // Try and get more results - this will handle the
  1045. // case of the DirSync cookie indicating more rows
  1046. // correctly.
  1047. //
  1048. hr = ADsGetMoreResultsDirSync(
  1049. phSearchInfo,
  1050. Credentials
  1051. );
  1052. BAIL_ON_FAILURE(hr);
  1053. }
  1054. }
  1055. error:
  1056. if (ld && fNewOptionSet) {
  1057. ldap_set_option(
  1058. ld,
  1059. LDAP_OPT_REFERRALS,
  1060. &(oldOption)
  1061. );
  1062. }
  1063. //
  1064. // When there is no more rows to be returned, return whatever error
  1065. // that was returned from the last search
  1066. //
  1067. if (hr == S_ADS_NOMORE_ROWS) {
  1068. if (phSearchInfo->_hrLastSearch != S_OK) {
  1069. RRETURN(phSearchInfo->_hrLastSearch);
  1070. }
  1071. else if (phSearchInfo->_fNonFatalErrors) {
  1072. RRETURN(S_ADS_ERRORSOCCURRED);
  1073. }
  1074. else {
  1075. RRETURN(hr);
  1076. }
  1077. }
  1078. else {
  1079. RRETURN(hr);
  1080. }
  1081. }
  1082. HRESULT
  1083. ADsGetNextRow(
  1084. IN ADS_SEARCH_HANDLE hSearchHandle,
  1085. IN CCredentials& Credentials
  1086. )
  1087. {
  1088. HRESULT hr = S_OK;
  1089. DWORD dwStatus = NO_ERROR, dwStatus2 = NO_ERROR;
  1090. PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle;
  1091. LDAP *ld = NULL;
  1092. BOOL fNewOptionSet = FALSE;
  1093. DWORD oldOption = 0;
  1094. DWORD newOption = 0;
  1095. if (!phSearchInfo) {
  1096. RRETURN(E_ADS_BAD_PARAMETER);
  1097. }
  1098. if(!phSearchInfo->_pConnection) {
  1099. hr = LdapOpenObject(
  1100. phSearchInfo->_pszLdapServer,
  1101. phSearchInfo->_pszBindContextDn,
  1102. &phSearchInfo->_pConnection,
  1103. Credentials,
  1104. phSearchInfo->_dwPort
  1105. );
  1106. BAIL_ON_FAILURE(hr);
  1107. //
  1108. // Set the preferences like deref aliases, time limit and size limit
  1109. //
  1110. if (ld = phSearchInfo->_pConnection->LdapHandle) {
  1111. ld->ld_deref = phSearchInfo->_SearchPref._dwDerefAliases;
  1112. ld->ld_sizelimit = phSearchInfo->_SearchPref._dwSizeLimit;
  1113. ld->ld_timelimit = phSearchInfo->_SearchPref._dwTimeLimit;
  1114. }
  1115. hr = AddSearchControls(phSearchInfo, Credentials);
  1116. BAIL_ON_FAILURE(hr);
  1117. }
  1118. ld = phSearchInfo->_pConnection->LdapHandle;
  1119. dwStatus = ldap_get_option(
  1120. ld,
  1121. LDAP_OPT_REFERRALS,
  1122. &(oldOption)
  1123. );
  1124. newOption = phSearchInfo->_SearchPref._dwChaseReferrals;
  1125. dwStatus2 = ldap_set_option(
  1126. ld,
  1127. LDAP_OPT_REFERRALS,
  1128. &(newOption)
  1129. );
  1130. if (dwStatus == NO_ERROR && dwStatus2 == NO_ERROR)
  1131. fNewOptionSet = TRUE;
  1132. if(!phSearchInfo->_pSearchResults) {
  1133. //
  1134. // Get the results. This function uses various members of pSearchInfo
  1135. // and returns the result in phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]
  1136. // which can be used to call LdapFirstEntry and LdapNextEntry
  1137. //
  1138. hr = ADsGetResults(
  1139. phSearchInfo
  1140. );
  1141. //
  1142. // Update the dirsync control cookie if applicable.
  1143. //
  1144. if (phSearchInfo->_SearchPref._fDirSync
  1145. && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) {
  1146. //
  1147. // Store the cookie info in searchprefs.
  1148. //
  1149. StoreDirSyncCookie(
  1150. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1151. phSearchInfo
  1152. );
  1153. }
  1154. //
  1155. // Update the VLV server response if applicable
  1156. //
  1157. if (phSearchInfo->_SearchPref._pVLVInfo
  1158. && phSearchInfo->_pSearchResults
  1159. && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) {
  1160. HRESULT hrVLV = S_OK;
  1161. hrVLV = StoreVLVInfo(
  1162. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1163. phSearchInfo
  1164. );
  1165. //
  1166. // we only care if storing the cookie failed if the search
  1167. // otherwise succeeded
  1168. //
  1169. if (FAILED(hrVLV) && SUCCEEDED(hr)) {
  1170. hr = hrVLV;
  1171. }
  1172. }
  1173. //
  1174. // Update the Attribute-Scoped Query info if applicable
  1175. //
  1176. if (phSearchInfo->_SearchPref._pAttribScoped
  1177. && phSearchInfo->_pSearchResults
  1178. && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) {
  1179. HRESULT hrASQ = S_OK;
  1180. hrASQ = StoreAttribScopedInfo(
  1181. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1182. phSearchInfo
  1183. );
  1184. //
  1185. // we only care if storing the info failed
  1186. // if the search otherwise succeeded
  1187. //
  1188. if (FAILED(hrASQ) && SUCCEEDED(hr)) {
  1189. hr = hrASQ;
  1190. }
  1191. }
  1192. if (hr == S_ADS_NOMORE_ROWS) {
  1193. //
  1194. // Try and get more results - this will handle the
  1195. // case of the DirSync cookie indicating more rows
  1196. // correctly.
  1197. //
  1198. hr = ADsGetMoreResultsDirSync(
  1199. phSearchInfo,
  1200. Credentials
  1201. );
  1202. BAIL_ON_FAILURE(hr);
  1203. }
  1204. if (FAILED(hr) || hr == S_ADS_NOMORE_ROWS) {
  1205. goto error;
  1206. }
  1207. }
  1208. //
  1209. // If the current row has not been obtained, get it now. Need to
  1210. // distinguish between the case where we are after the end of the result
  1211. // from the case where we are before the beginning of the result. In
  1212. // both cases _pCurrentRow is NULL, but _fBefFirstRow is TRUE only in
  1213. // the latter case.
  1214. //
  1215. if(!phSearchInfo->_pCurrentRow) {
  1216. if(phSearchInfo->_fBefFirstRow)
  1217. {
  1218. //
  1219. // Call the ldap specific function to get the first row.
  1220. //
  1221. hr = LdapFirstEntry(
  1222. phSearchInfo->_pConnection,
  1223. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1224. &phSearchInfo->_pCurrentRow
  1225. );
  1226. }
  1227. }
  1228. else {
  1229. //
  1230. // Call the ldap specific function to get the next row
  1231. //
  1232. hr = LdapNextEntry(
  1233. phSearchInfo->_pConnection,
  1234. phSearchInfo->_pCurrentRow,
  1235. &phSearchInfo->_pCurrentRow
  1236. );
  1237. }
  1238. if (!phSearchInfo->_pCurrentRow
  1239. && (phSearchInfo->_dwCurrResult < phSearchInfo->_dwMaxResultGot)) {
  1240. //
  1241. // In this case we need to proceed to the next result in memory
  1242. //
  1243. hr = S_OK;
  1244. while (!phSearchInfo->_pCurrentRow
  1245. && phSearchInfo->_dwCurrResult < phSearchInfo->_dwMaxResultGot
  1246. && SUCCEEDED(hr)) {
  1247. //
  1248. // With Dirsync we may have results that do not have
  1249. // any entries in them, but the next one may.
  1250. //
  1251. phSearchInfo->_dwCurrResult++;
  1252. hr = LdapFirstEntry(
  1253. phSearchInfo->_pConnection,
  1254. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1255. &phSearchInfo->_pCurrentRow
  1256. );
  1257. }
  1258. }
  1259. else if (!phSearchInfo->_pCurrentRow
  1260. && (!phSearchInfo->_fLastResult
  1261. || !phSearchInfo->_fLastPage
  1262. || phSearchInfo->_fMoreDirSync )
  1263. ) {
  1264. //
  1265. // Now if both lastResult and page are true, we need to call
  1266. // ADsGetMoreResultsDirSync. This is the unusual case.
  1267. //
  1268. if (phSearchInfo->_fLastResult && phSearchInfo->_fLastPage) {
  1269. hr = ADsGetMoreResultsDirSync(
  1270. phSearchInfo,
  1271. Credentials
  1272. );
  1273. }
  1274. else {
  1275. //
  1276. // This means that there are more results to be obtained
  1277. // although the current result has reached its end.
  1278. // Call the function to get more results in
  1279. // phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]
  1280. // It will increment _dwCurrResult and reallocate if needed.
  1281. //
  1282. hr = ADsGetMoreResults(
  1283. phSearchInfo
  1284. );
  1285. }
  1286. //
  1287. // In async searches, we will know if we have to call
  1288. // ADsGetMoreResultsAsync only now. So recheck.
  1289. //
  1290. if (hr == S_ADS_NOMORE_ROWS
  1291. && phSearchInfo->_SearchPref._fAsynchronous
  1292. ) {
  1293. if (phSearchInfo->_fLastResult && phSearchInfo->_fLastPage) {
  1294. hr = ADsGetMoreResultsDirSync(
  1295. phSearchInfo,
  1296. Credentials
  1297. );
  1298. }
  1299. }
  1300. //
  1301. // Update the dirsync control cookie if applicable.
  1302. //
  1303. if (phSearchInfo->_SearchPref._fDirSync
  1304. && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) {
  1305. //
  1306. // Store the cookie info in searchprefs.
  1307. //
  1308. StoreDirSyncCookie(
  1309. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1310. phSearchInfo
  1311. );
  1312. }
  1313. //
  1314. // Update the Attribute-Scoped Query info if applicable
  1315. //
  1316. if (phSearchInfo->_SearchPref._pAttribScoped
  1317. && phSearchInfo->_pSearchResults
  1318. && phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) {
  1319. HRESULT hrASQ = S_OK;
  1320. hrASQ = StoreAttribScopedInfo(
  1321. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1322. phSearchInfo
  1323. );
  1324. //
  1325. // we only care if storing the info failed
  1326. // if the search otherwise succeeded
  1327. //
  1328. if (FAILED(hrASQ) && SUCCEEDED(hr)) {
  1329. hr = hrASQ;
  1330. }
  1331. }
  1332. if (FAILED(hr) || hr == S_ADS_NOMORE_ROWS) {
  1333. goto error;
  1334. }
  1335. hr = LdapFirstEntry(
  1336. phSearchInfo->_pConnection,
  1337. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1338. &phSearchInfo->_pCurrentRow
  1339. );
  1340. if (!phSearchInfo->_pCurrentRow) {
  1341. //
  1342. // This means that we can possibly have more results
  1343. // but this time we did not get any - not yet a NULL
  1344. // cookie on a paged search that is.
  1345. //
  1346. ADsSetLastError(
  1347. ERROR_MORE_DATA,
  1348. L"Calling GetNextRow can potentially return more results.",
  1349. L"LDAP Provider"
  1350. );
  1351. }
  1352. }
  1353. BAIL_ON_FAILURE(hr);
  1354. if(phSearchInfo->_pCurrentRow) {
  1355. phSearchInfo->_pFirstAttr = NULL;
  1356. phSearchInfo->_fBefFirstRow = FALSE;
  1357. hr = S_OK;
  1358. }
  1359. else {
  1360. hr = S_ADS_NOMORE_ROWS;
  1361. //
  1362. // Might be DirSync case where we need to try fetch
  1363. // more results.
  1364. //
  1365. if (phSearchInfo->_SearchPref._fDirSync
  1366. && phSearchInfo->_fMoreDirSync ) {
  1367. //
  1368. // Try and get more results - this will handle the
  1369. // case of the DirSync cookie indicating more rows
  1370. // correctly.
  1371. //
  1372. hr = ADsGetMoreResultsDirSync(
  1373. phSearchInfo,
  1374. Credentials
  1375. );
  1376. BAIL_ON_FAILURE(hr);
  1377. }
  1378. }
  1379. error:
  1380. if (ld && fNewOptionSet) {
  1381. ldap_set_option(
  1382. ld,
  1383. LDAP_OPT_REFERRALS,
  1384. &(oldOption)
  1385. );
  1386. }
  1387. //
  1388. // When there is no more rows to be returned, return whatever error
  1389. // that was returned from the last search
  1390. //
  1391. if (hr == S_ADS_NOMORE_ROWS) {
  1392. if (phSearchInfo->_hrLastSearch != S_OK) {
  1393. RRETURN(phSearchInfo->_hrLastSearch);
  1394. }
  1395. else if (phSearchInfo->_fNonFatalErrors) {
  1396. RRETURN(S_ADS_ERRORSOCCURRED);
  1397. }
  1398. else {
  1399. RRETURN(hr);
  1400. }
  1401. }
  1402. else {
  1403. RRETURN(hr);
  1404. }
  1405. }
  1406. //
  1407. // Function to get the results by performing the appropriate search depending
  1408. // on the preferences; Paged Results, Sorting, Synchronous, Asynchrnous or
  1409. // Timed Synchronous
  1410. //
  1411. HRESULT
  1412. ADsGetResults(
  1413. IN PLDAP_SEARCHINFO phSearchInfo
  1414. )
  1415. {
  1416. HRESULT hr = S_OK;
  1417. DWORD dwError;
  1418. WCHAR pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH];
  1419. ULONG totalCount;
  1420. int resType;
  1421. ADsAssert(phSearchInfo);
  1422. //
  1423. // If abandon has been called, we don't get more results.
  1424. //
  1425. if (phSearchInfo->_fAbandon) {
  1426. RRETURN(S_ADS_NOMORE_ROWS);
  1427. }
  1428. if(!phSearchInfo->_pSearchResults) {
  1429. //
  1430. // Allocate an array of handles to Search Results
  1431. //
  1432. phSearchInfo->_pSearchResults = (LDAPMessage **) AllocADsMem(
  1433. sizeof(LDAPMessage *) *
  1434. NO_LDAP_RESULT_HANDLES);
  1435. if(!phSearchInfo->_pSearchResults) {
  1436. hr = E_OUTOFMEMORY;
  1437. goto error;
  1438. }
  1439. phSearchInfo->_dwCurrResult = 0;
  1440. phSearchInfo->_cSearchResults = NO_LDAP_RESULT_HANDLES;
  1441. //
  1442. // Should also set the cur max to 0;
  1443. //
  1444. phSearchInfo->_dwMaxResultGot = 0;
  1445. }
  1446. // Initialize Result to NULL
  1447. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] = NULL;
  1448. //
  1449. // Call the ldap specific search function
  1450. //
  1451. if (phSearchInfo->_SearchPref._dwPageSize != 0) {
  1452. //
  1453. // Paged results
  1454. //
  1455. if(!phSearchInfo->_hPagedSearch ) {
  1456. hr = LdapSearchInitPage(
  1457. phSearchInfo->_pConnection,
  1458. phSearchInfo->_pszBindContextDn,
  1459. phSearchInfo->_SearchPref._dwSearchScope,
  1460. phSearchInfo->_pszSearchFilter,
  1461. phSearchInfo->_ppszAttrs,
  1462. phSearchInfo->_SearchPref._fAttrsOnly,
  1463. phSearchInfo->_ServerControls,
  1464. phSearchInfo->_ClientControls,
  1465. phSearchInfo->_SearchPref._dwPagedTimeLimit,
  1466. phSearchInfo->_SearchPref._dwSizeLimit,
  1467. NULL,
  1468. &phSearchInfo->_hPagedSearch
  1469. );
  1470. BAIL_ON_FAILURE(hr);
  1471. }
  1472. if ( phSearchInfo->_SearchPref._fAsynchronous ) {
  1473. hr = LdapGetNextPage(
  1474. phSearchInfo->_pConnection,
  1475. phSearchInfo->_hPagedSearch,
  1476. phSearchInfo->_SearchPref._dwPageSize,
  1477. (ULONG *)&phSearchInfo->_currMsgId
  1478. );
  1479. if (FAILED(hr)) {
  1480. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) {
  1481. phSearchInfo->_fLastPage = TRUE;
  1482. RRETURN(S_ADS_NOMORE_ROWS);
  1483. } else {
  1484. BAIL_ON_FAILURE(hr);
  1485. }
  1486. }
  1487. //
  1488. // Wait for one page worth of results to get back.
  1489. //
  1490. hr = LdapResult(
  1491. phSearchInfo->_pConnection,
  1492. phSearchInfo->_currMsgId,
  1493. LDAP_MSG_ALL,
  1494. phSearchInfo->_SearchPref._timeout.tv_sec ?
  1495. &phSearchInfo->_SearchPref._timeout : NULL,
  1496. &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1497. &resType
  1498. );
  1499. if (FAILED(hr)) {
  1500. if ((hr == HRESULT_FROM_WIN32(ERROR_DS_INVALID_DN_SYNTAX)) ||
  1501. (hr == HRESULT_FROM_WIN32(ERROR_DS_NAMING_VIOLATION)) ||
  1502. (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION)) ||
  1503. (hr == HRESULT_FROM_WIN32(ERROR_DS_FILTER_UNKNOWN)) ||
  1504. (hr == HRESULT_FROM_WIN32(ERROR_DS_PARAM_ERROR)) ||
  1505. (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) {
  1506. phSearchInfo->_fLastResult = TRUE;
  1507. RRETURN(S_ADS_NOMORE_ROWS);
  1508. }
  1509. else {
  1510. BAIL_ON_FAILURE(hr);
  1511. }
  1512. }
  1513. hr = LdapGetPagedCount(
  1514. phSearchInfo->_pConnection,
  1515. phSearchInfo->_hPagedSearch,
  1516. &totalCount,
  1517. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]
  1518. );
  1519. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) {
  1520. hr = S_OK;
  1521. }
  1522. //
  1523. // if hr failed, we will do the corresponding according to whether there is any result returned in our mechanism later
  1524. //
  1525. }
  1526. else {
  1527. hr = LdapGetNextPageS(
  1528. phSearchInfo->_pConnection,
  1529. phSearchInfo->_hPagedSearch,
  1530. phSearchInfo->_SearchPref._timeout.tv_sec ?
  1531. &phSearchInfo->_SearchPref._timeout : NULL,
  1532. phSearchInfo->_SearchPref._dwPageSize,
  1533. &totalCount,
  1534. &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]
  1535. );
  1536. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) {
  1537. phSearchInfo->_fLastPage = TRUE;
  1538. RRETURN(S_ADS_NOMORE_ROWS);
  1539. }
  1540. //
  1541. // if hr failed, we will do the corresponding according to whether there is any result returned in our mechanism later
  1542. //
  1543. phSearchInfo->_fLastResult = TRUE;
  1544. }
  1545. }
  1546. else if (phSearchInfo->_SearchPref._fAsynchronous) {
  1547. hr = LdapSearchExt(
  1548. phSearchInfo->_pConnection,
  1549. phSearchInfo->_pszBindContextDn,
  1550. phSearchInfo->_SearchPref._dwSearchScope,
  1551. phSearchInfo->_pszSearchFilter,
  1552. phSearchInfo->_ppszAttrs,
  1553. phSearchInfo->_SearchPref._fAttrsOnly,
  1554. phSearchInfo->_ServerControls,
  1555. phSearchInfo->_ClientControls,
  1556. phSearchInfo->_SearchPref._dwPagedTimeLimit,
  1557. phSearchInfo->_SearchPref._dwSizeLimit,
  1558. &phSearchInfo->_currMsgId
  1559. );
  1560. BAIL_ON_FAILURE(hr);
  1561. //
  1562. // Wait for atleast one result
  1563. //
  1564. hr = LdapResult(
  1565. phSearchInfo->_pConnection,
  1566. phSearchInfo->_currMsgId,
  1567. LDAP_MSG_RECEIVED,
  1568. phSearchInfo->_SearchPref._timeout.tv_sec ?
  1569. &phSearchInfo->_SearchPref._timeout : NULL,
  1570. &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1571. &resType
  1572. );
  1573. if ((hr == HRESULT_FROM_WIN32(ERROR_DS_INVALID_DN_SYNTAX)) ||
  1574. (hr == HRESULT_FROM_WIN32(ERROR_DS_NAMING_VIOLATION)) ||
  1575. (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION)) ||
  1576. (hr == HRESULT_FROM_WIN32(ERROR_DS_FILTER_UNKNOWN)) ||
  1577. (hr == HRESULT_FROM_WIN32(ERROR_DS_PARAM_ERROR)) ||
  1578. (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) {
  1579. phSearchInfo->_fLastResult = TRUE;
  1580. RRETURN(S_ADS_NOMORE_ROWS);
  1581. }
  1582. //
  1583. // if hr failed, we will do the corresponding according to whether there is any result returned in our mechanism later
  1584. //
  1585. phSearchInfo->_fLastPage = TRUE;
  1586. }
  1587. else if (phSearchInfo->_SearchPref._timeout.tv_sec != 0) {
  1588. hr = LdapSearchExtS(
  1589. phSearchInfo->_pConnection,
  1590. phSearchInfo->_pszBindContextDn,
  1591. phSearchInfo->_SearchPref._dwSearchScope,
  1592. phSearchInfo->_pszSearchFilter,
  1593. phSearchInfo->_ppszAttrs,
  1594. phSearchInfo->_SearchPref._fAttrsOnly,
  1595. phSearchInfo->_ServerControls,
  1596. phSearchInfo->_ClientControls,
  1597. &phSearchInfo->_SearchPref._timeout,
  1598. phSearchInfo->_SearchPref._dwSizeLimit,
  1599. &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]
  1600. );
  1601. phSearchInfo->_fLastResult = TRUE;
  1602. phSearchInfo->_fLastPage = TRUE;
  1603. }
  1604. else {
  1605. hr = LdapSearchExtS(
  1606. phSearchInfo->_pConnection,
  1607. phSearchInfo->_pszBindContextDn,
  1608. phSearchInfo->_SearchPref._dwSearchScope,
  1609. phSearchInfo->_pszSearchFilter,
  1610. phSearchInfo->_ppszAttrs,
  1611. phSearchInfo->_SearchPref._fAttrsOnly,
  1612. phSearchInfo->_ServerControls,
  1613. phSearchInfo->_ClientControls,
  1614. NULL,
  1615. phSearchInfo->_SearchPref._dwSizeLimit,
  1616. &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]
  1617. );
  1618. phSearchInfo->_fLastResult = TRUE;
  1619. phSearchInfo->_fLastPage = TRUE;
  1620. }
  1621. //
  1622. // Only if there are zero rows returned, return the error,
  1623. // otherwise, store the error and return when GetNextRow is
  1624. // called for the last time
  1625. //
  1626. if (FAILED(hr) &&
  1627. (LdapCountEntries( phSearchInfo->_pConnection,
  1628. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) == 0)) {
  1629. BAIL_ON_FAILURE(hr);
  1630. }
  1631. else {
  1632. phSearchInfo->_hrLastSearch = hr;
  1633. hr = S_OK;
  1634. }
  1635. phSearchInfo->_pCurrentRow = NULL;
  1636. error:
  1637. RRETURN(hr);
  1638. }
  1639. //
  1640. // For Asynchronous or paged searches, more results need to be obtained, once
  1641. // the current result set is exhausted. This function gets the next result set
  1642. // if one is available. In the case of paged results, this might translate to
  1643. // getting the next page.
  1644. //
  1645. HRESULT
  1646. ADsGetMoreResults(
  1647. IN PLDAP_SEARCHINFO phSearchInfo
  1648. )
  1649. {
  1650. HRESULT hr = S_OK;
  1651. DWORD dwError;
  1652. LPWSTR pszLDAPPath;
  1653. WCHAR pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH];
  1654. ULONG totalCount;
  1655. int resType;
  1656. ADsAssert(phSearchInfo);
  1657. //
  1658. // If abandon has been called, we don't get more results.
  1659. //
  1660. if (phSearchInfo->_fAbandon) {
  1661. RRETURN(S_ADS_NOMORE_ROWS);
  1662. }
  1663. if (phSearchInfo->_fLastResult && phSearchInfo->_fLastPage)
  1664. RRETURN (S_ADS_NOMORE_ROWS);
  1665. if (phSearchInfo->_fLastResult == FALSE) {
  1666. //
  1667. // if we need to cache the results, then we save the result in the
  1668. // phSearchInfo->_pSearchResults array. If we don't need to cache it,
  1669. // release the result and save it in the same place.
  1670. if ( phSearchInfo->_SearchPref._fCacheResults ) {
  1671. ADsAssert(phSearchInfo->_dwCurrResult
  1672. == phSearchInfo->_dwMaxResultGot);
  1673. phSearchInfo->_dwCurrResult++;
  1674. phSearchInfo->_dwMaxResultGot++;
  1675. if (phSearchInfo->_dwCurrResult >= phSearchInfo->_cSearchResults) {
  1676. //
  1677. // Need to allocate more memory for handles
  1678. //
  1679. phSearchInfo->_pSearchResults = (LDAPMessage **) ReallocADsMem(
  1680. (void *) phSearchInfo->_pSearchResults,
  1681. sizeof(LDAPMessage *) *
  1682. phSearchInfo->_cSearchResults,
  1683. sizeof(LDAPMessage *) *
  1684. (phSearchInfo->_cSearchResults +
  1685. NO_LDAP_RESULT_HANDLES));
  1686. if(!phSearchInfo->_pSearchResults) {
  1687. hr = E_OUTOFMEMORY;
  1688. phSearchInfo->_dwCurrResult--;
  1689. phSearchInfo->_dwMaxResultGot--;
  1690. goto error;
  1691. }
  1692. phSearchInfo->_cSearchResults += NO_LDAP_RESULT_HANDLES;
  1693. }
  1694. }
  1695. else {
  1696. //
  1697. // Release and use the same space to store the next result.
  1698. //
  1699. LdapMsgFree(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  1700. }
  1701. // Initialize Result to NULL
  1702. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] = NULL;
  1703. hr = LdapResult(
  1704. phSearchInfo->_pConnection,
  1705. phSearchInfo->_currMsgId,
  1706. LDAP_MSG_RECEIVED,
  1707. phSearchInfo->_SearchPref._timeout.tv_sec ?
  1708. &phSearchInfo->_SearchPref._timeout : NULL,
  1709. &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1710. &resType
  1711. );
  1712. if ((hr == HRESULT_FROM_WIN32(ERROR_DS_INVALID_DN_SYNTAX)) ||
  1713. (hr == HRESULT_FROM_WIN32(ERROR_DS_NAMING_VIOLATION)) ||
  1714. (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION)) ||
  1715. (hr == HRESULT_FROM_WIN32(ERROR_DS_FILTER_UNKNOWN)) ||
  1716. (hr == HRESULT_FROM_WIN32(ERROR_DS_PARAM_ERROR)) ||
  1717. (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) {
  1718. phSearchInfo->_fLastResult = TRUE;
  1719. }
  1720. else {
  1721. phSearchInfo->_hrLastSearch = hr;
  1722. hr = S_OK;
  1723. RRETURN(hr);
  1724. }
  1725. }
  1726. //
  1727. // The last result has been reached. Check if we need to look for further
  1728. // pages
  1729. //
  1730. if ( phSearchInfo->_fLastPage == FALSE) {
  1731. //
  1732. // if we need to cache the results, then we save the result in the
  1733. // phSearchInfo->_pSearchResults array. If we don't need to cache it,
  1734. // release the result and save it in the same place.
  1735. if ( phSearchInfo->_SearchPref._fCacheResults ) {
  1736. ADsAssert(phSearchInfo->_dwCurrResult
  1737. == phSearchInfo->_dwMaxResultGot);
  1738. phSearchInfo->_dwCurrResult++;
  1739. phSearchInfo->_dwMaxResultGot++;
  1740. if (phSearchInfo->_dwCurrResult >= phSearchInfo->_cSearchResults) {
  1741. //
  1742. // Need to allocate more memory for handles
  1743. //
  1744. phSearchInfo->_pSearchResults = (LDAPMessage **) ReallocADsMem(
  1745. (void *) phSearchInfo->_pSearchResults,
  1746. sizeof(LDAPMessage *) *
  1747. phSearchInfo->_cSearchResults,
  1748. sizeof(LDAPMessage *) *
  1749. (phSearchInfo->_cSearchResults +
  1750. NO_LDAP_RESULT_HANDLES));
  1751. if(!phSearchInfo->_pSearchResults) {
  1752. hr = E_OUTOFMEMORY;
  1753. goto error;
  1754. }
  1755. phSearchInfo->_cSearchResults += NO_LDAP_RESULT_HANDLES;
  1756. }
  1757. }
  1758. else {
  1759. //
  1760. // Release and use the same space to store the next result.
  1761. //
  1762. LdapMsgFree(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  1763. }
  1764. // Initialize Result to NULL
  1765. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult] = NULL;
  1766. if ( phSearchInfo->_SearchPref._fAsynchronous ) {
  1767. hr = LdapGetNextPage(
  1768. phSearchInfo->_pConnection,
  1769. phSearchInfo->_hPagedSearch,
  1770. phSearchInfo->_SearchPref._dwPageSize,
  1771. (ULONG *) &phSearchInfo->_currMsgId
  1772. );
  1773. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) {
  1774. phSearchInfo->_fLastPage = TRUE;
  1775. if (phSearchInfo->_SearchPref._fCacheResults) {
  1776. phSearchInfo->_dwCurrResult--;
  1777. phSearchInfo->_dwMaxResultGot--;
  1778. }
  1779. RRETURN(S_ADS_NOMORE_ROWS);
  1780. }
  1781. BAIL_ON_FAILURE(hr);
  1782. //
  1783. // Wait for one page worth of results to get back.
  1784. //
  1785. hr = LdapResult(
  1786. phSearchInfo->_pConnection,
  1787. phSearchInfo->_currMsgId,
  1788. LDAP_MSG_ALL,
  1789. phSearchInfo->_SearchPref._timeout.tv_sec ?
  1790. &phSearchInfo->_SearchPref._timeout : NULL,
  1791. &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1792. &resType
  1793. );
  1794. phSearchInfo->_fLastResult = FALSE;
  1795. if ((hr == HRESULT_FROM_WIN32(ERROR_DS_INVALID_DN_SYNTAX)) ||
  1796. (hr == HRESULT_FROM_WIN32(ERROR_DS_NAMING_VIOLATION)) ||
  1797. (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION)) ||
  1798. (hr == HRESULT_FROM_WIN32(ERROR_DS_FILTER_UNKNOWN)) ||
  1799. (hr == HRESULT_FROM_WIN32(ERROR_DS_PARAM_ERROR)) ||
  1800. (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) {
  1801. phSearchInfo->_fLastResult = TRUE;
  1802. RRETURN(S_ADS_NOMORE_ROWS);
  1803. }
  1804. BAIL_ON_FAILURE(hr);
  1805. hr = LdapGetPagedCount(
  1806. phSearchInfo->_pConnection,
  1807. phSearchInfo->_hPagedSearch,
  1808. &totalCount,
  1809. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]
  1810. );
  1811. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) {
  1812. hr = S_OK;
  1813. }
  1814. BAIL_ON_FAILURE(hr);
  1815. }
  1816. else {
  1817. hr = LdapGetNextPageS(
  1818. phSearchInfo->_pConnection,
  1819. phSearchInfo->_hPagedSearch,
  1820. phSearchInfo->_SearchPref._timeout.tv_sec ?
  1821. &phSearchInfo->_SearchPref._timeout : NULL,
  1822. phSearchInfo->_SearchPref._dwPageSize,
  1823. &totalCount,
  1824. &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]
  1825. );
  1826. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_RESULTS_RETURNED)) {
  1827. //
  1828. // Since we hit the last page we need to get the
  1829. // count of the max and currResults down by one.
  1830. //
  1831. if (phSearchInfo->_SearchPref._fCacheResults) {
  1832. phSearchInfo->_dwCurrResult--;
  1833. phSearchInfo->_dwMaxResultGot--;
  1834. }
  1835. phSearchInfo->_fLastPage = TRUE;
  1836. RRETURN(S_ADS_NOMORE_ROWS);
  1837. }
  1838. BAIL_ON_FAILURE(hr);
  1839. }
  1840. RRETURN(S_OK);
  1841. }
  1842. //
  1843. // If we came here, we have reached the end
  1844. //
  1845. hr = S_ADS_NOMORE_ROWS;
  1846. error:
  1847. RRETURN(hr);
  1848. }
  1849. HRESULT
  1850. ADsGetPreviousRow(
  1851. IN ADS_SEARCH_HANDLE hSearchHandle,
  1852. IN CCredentials& Credentials
  1853. )
  1854. {
  1855. PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle;
  1856. LDAPMessage *pTmpRow, *pTargetRow, *pPrevRow = NULL;
  1857. DWORD dwOrigCurrResult;
  1858. HRESULT hr;
  1859. if (!phSearchInfo) {
  1860. RRETURN(E_ADS_BAD_PARAMETER);
  1861. }
  1862. if(!phSearchInfo->_pConnection) {
  1863. // cannot ask for previous row if connection not established
  1864. RRETURN(E_ADS_BAD_PARAMETER);
  1865. }
  1866. if(!phSearchInfo->_pSearchResults) {
  1867. // cannot ask for previous row if no results have been obtained
  1868. RRETURN(E_ADS_BAD_PARAMETER);
  1869. }
  1870. // save value in case we need to restore later
  1871. dwOrigCurrResult = phSearchInfo->_dwCurrResult;
  1872. if(NULL == phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult])
  1873. // we are at the end of the entire search result list
  1874. {
  1875. ADsAssert(!phSearchInfo->_pCurrentRow);
  1876. if(phSearchInfo->_dwCurrResult > 0)
  1877. // we need to get the last entry of the previous result
  1878. phSearchInfo->_dwCurrResult--;
  1879. else
  1880. {
  1881. phSearchInfo->_fBefFirstRow = TRUE;
  1882. RRETURN(S_ADS_NOMORE_ROWS);
  1883. }
  1884. }
  1885. ADsAssert(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  1886. hr = LdapFirstEntry(phSearchInfo->_pConnection,
  1887. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1888. &pTmpRow);
  1889. BAIL_ON_FAILURE(hr);
  1890. // row whose predecessor we are looking for (this may be NULL)
  1891. pTargetRow = phSearchInfo->_pCurrentRow;
  1892. if(pTmpRow == pTargetRow)
  1893. // we are at the first row of the current result
  1894. {
  1895. if(phSearchInfo->_dwCurrResult > 0)
  1896. {
  1897. // we need to get the last entry of the previous result
  1898. phSearchInfo->_dwCurrResult--;
  1899. pTargetRow = NULL;
  1900. hr = LdapFirstEntry(phSearchInfo->_pConnection,
  1901. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  1902. &pTmpRow);
  1903. BAIL_ON_FAILURE(hr);
  1904. }
  1905. else
  1906. {
  1907. phSearchInfo->_pCurrentRow = NULL;
  1908. phSearchInfo->_fBefFirstRow = TRUE;
  1909. RRETURN(S_ADS_NOMORE_ROWS);
  1910. }
  1911. }
  1912. while(pTmpRow != pTargetRow)
  1913. {
  1914. pPrevRow = pTmpRow;
  1915. hr = LdapNextEntry(phSearchInfo->_pConnection,
  1916. pTmpRow,
  1917. &pTmpRow);
  1918. BAIL_ON_FAILURE(hr);
  1919. }
  1920. ADsAssert(pPrevRow);
  1921. phSearchInfo->_pCurrentRow = pPrevRow;
  1922. phSearchInfo->_pFirstAttr = NULL;
  1923. RRETURN(S_OK);
  1924. error:
  1925. phSearchInfo->_dwCurrResult = dwOrigCurrResult;
  1926. RRETURN(hr);
  1927. }
  1928. HRESULT
  1929. ADsGetColumn(
  1930. IN ADS_SEARCH_HANDLE hSearchHandle,
  1931. IN LPWSTR pszColumnName,
  1932. IN CCredentials& Credentials,
  1933. DWORD dwPort,
  1934. OUT PADS_SEARCH_COLUMN pColumn
  1935. )
  1936. {
  1937. PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle;
  1938. VOID **ppValue = NULL;
  1939. struct berval **ppBerValue = NULL;
  1940. WCHAR **ppStrValue = NULL;
  1941. int cValueCount;
  1942. HRESULT hr = S_OK;
  1943. DWORD dwStatus;
  1944. LPWSTR pszDn, pszADsPathName = NULL;
  1945. DWORD dwSyntaxId;
  1946. DWORD dwError;
  1947. WCHAR pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH];
  1948. PADS_VLV pVLV = NULL;
  1949. if( !pColumn ||
  1950. !phSearchInfo ||
  1951. !phSearchInfo->_pSearchResults )
  1952. RRETURN (E_ADS_BAD_PARAMETER);
  1953. pColumn->pszAttrName = NULL;
  1954. pColumn->dwADsType = ADSTYPE_INVALID;
  1955. pColumn->pADsValues = NULL;
  1956. pColumn->dwNumValues = 0;
  1957. pColumn->hReserved = NULL;
  1958. if(!phSearchInfo->_pConnection)
  1959. RRETURN (E_ADS_BAD_PARAMETER);
  1960. if (!phSearchInfo->_pCurrentRow
  1961. && _wcsicmp(pszColumnName, ADS_DIRSYNC_COOKIE)
  1962. && _wcsicmp(pszColumnName, ADS_VLV_RESPONSE)) {
  1963. //
  1964. // Current row is not valid and you are not asking for the
  1965. // dirsync cookie - so we will fail.
  1966. //
  1967. RRETURN(E_ADS_BAD_PARAMETER);
  1968. }
  1969. pColumn->pszAttrName = AllocADsStr(pszColumnName);
  1970. if (!pColumn->pszAttrName)
  1971. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1972. if(!_wcsicmp (pszColumnName, L"ADsPath")) {
  1973. //
  1974. // Get the DN of the entry.
  1975. //
  1976. hr = LdapGetDn(
  1977. phSearchInfo->_pConnection,
  1978. phSearchInfo->_pCurrentRow,
  1979. &pszDn
  1980. );
  1981. BAIL_ON_FAILURE(hr);
  1982. //
  1983. // Build the ADsPath
  1984. //
  1985. hr = BuildADsPathFromLDAPPath(
  1986. phSearchInfo->_pszADsPathContext,
  1987. pszDn,
  1988. &pszADsPathName
  1989. );
  1990. BAIL_ON_FAILURE(hr);
  1991. LdapMemFree(pszDn);
  1992. pColumn->pADsValues = (PADSVALUE) AllocADsMem(sizeof(ADSVALUE));
  1993. if (!pColumn->pADsValues)
  1994. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1995. pColumn->dwADsType = ADSTYPE_CASE_IGNORE_STRING;
  1996. pColumn->dwNumValues = 1;
  1997. pColumn->pADsValues[0].dwType = ADSTYPE_CASE_IGNORE_STRING;
  1998. pColumn->pADsValues[0].CaseIgnoreString = AllocADsStr(pszADsPathName);
  1999. if (!pColumn->pADsValues[0].CaseIgnoreString)
  2000. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2001. FreeADsMem(pszADsPathName);
  2002. RRETURN(S_OK);
  2003. }
  2004. else if (phSearchInfo->_SearchPref._fDirSync) {
  2005. //
  2006. // See if we need to return the dirsync control info.
  2007. //
  2008. if (!_wcsicmp (pszColumnName, ADS_DIRSYNC_COOKIE)) {
  2009. pColumn->pADsValues = (PADSVALUE) AllocADsMem(sizeof(ADSVALUE));
  2010. if (!pColumn->pADsValues)
  2011. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2012. pColumn->dwADsType = ADSTYPE_PROV_SPECIFIC;
  2013. pColumn->dwNumValues = 1;
  2014. pColumn->pADsValues[0].dwType = ADSTYPE_PROV_SPECIFIC;
  2015. //
  2016. // Copy the control over if appropriate if not we will
  2017. // return NULL or empty data for the result.
  2018. //
  2019. if (phSearchInfo->_SearchPref._pProvSpecific->lpValue) {
  2020. pColumn->pADsValues[0].ProviderSpecific.dwLength =
  2021. phSearchInfo->_SearchPref._pProvSpecific->dwLength;
  2022. pColumn->pADsValues[0].ProviderSpecific.lpValue = (LPBYTE)
  2023. AllocADsMem(
  2024. pColumn->pADsValues[0].ProviderSpecific.dwLength
  2025. );
  2026. if (!pColumn->pADsValues[0].ProviderSpecific.lpValue) {
  2027. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2028. }
  2029. memcpy(
  2030. pColumn->pADsValues[0].ProviderSpecific.lpValue,
  2031. phSearchInfo->_SearchPref._pProvSpecific->lpValue,
  2032. phSearchInfo->_SearchPref._pProvSpecific->dwLength
  2033. );
  2034. }
  2035. RRETURN(S_OK);
  2036. } // if DirSyncControlStruct is being asked for.
  2037. } // if dirsync set.
  2038. else if (phSearchInfo->_SearchPref._pVLVInfo) {
  2039. //
  2040. // See if we need to return the VLV control info.
  2041. //
  2042. if (!_wcsicmp (pszColumnName, ADS_VLV_RESPONSE)) {
  2043. pColumn->pADsValues = (PADSVALUE) AllocADsMem(sizeof(ADSVALUE));
  2044. if (!pColumn->pADsValues)
  2045. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2046. pColumn->dwADsType = ADSTYPE_PROV_SPECIFIC;
  2047. pColumn->dwNumValues = 1;
  2048. pColumn->pADsValues[0].dwType = ADSTYPE_PROV_SPECIFIC;
  2049. pColumn->pADsValues[0].ProviderSpecific.dwLength = sizeof(ADS_VLV);
  2050. pColumn->pADsValues[0].ProviderSpecific.lpValue = (LPBYTE) AllocADsMem(sizeof(ADS_VLV));
  2051. if (!pColumn->pADsValues[0].ProviderSpecific.lpValue)
  2052. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2053. // copy the VLV data into the ADS_VLV
  2054. pVLV = (PADS_VLV) pColumn->pADsValues[0].ProviderSpecific.lpValue;
  2055. pVLV->dwBeforeCount = 0;
  2056. pVLV->dwAfterCount = 0;
  2057. pVLV->dwOffset = phSearchInfo->_dwVLVOffset;
  2058. pVLV->dwContentCount = phSearchInfo->_dwVLVCount;
  2059. pVLV->pszTarget = NULL;
  2060. // copy the VLV context ID, if available
  2061. pVLV->lpContextID = NULL;
  2062. pVLV->dwContextIDLength = 0;
  2063. if (phSearchInfo->_pVLVContextID && phSearchInfo->_pVLVContextID->bv_len) {
  2064. pVLV->lpContextID = (LPBYTE) AllocADsMem(phSearchInfo->_pVLVContextID->bv_len);
  2065. if (!pVLV->lpContextID)
  2066. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2067. pVLV->dwContextIDLength = phSearchInfo->_pVLVContextID->bv_len;
  2068. memcpy(pVLV->lpContextID,
  2069. phSearchInfo->_pVLVContextID->bv_val,
  2070. phSearchInfo->_pVLVContextID->bv_len);
  2071. }
  2072. RRETURN(S_OK);
  2073. } // if VLV response is being asked for
  2074. } // if VLV set
  2075. if (phSearchInfo->_fADsPathOnly) {
  2076. //
  2077. // Only ADsPath attribute requested in the search,
  2078. // so don't return any other column values.
  2079. //
  2080. RRETURN (E_ADS_COLUMN_NOT_SET);
  2081. }
  2082. if (phSearchInfo->_SearchPref._fAttrsOnly) {
  2083. //
  2084. // Only Names got. So, don't return any values
  2085. //
  2086. RRETURN (S_OK);
  2087. }
  2088. //
  2089. // Call the helper function to get the LDAP specific type
  2090. //
  2091. hr = LdapGetSyntaxOfAttributeOnServer(
  2092. phSearchInfo->_pszLdapServer,
  2093. pszColumnName,
  2094. &dwSyntaxId,
  2095. Credentials,
  2096. dwPort
  2097. );
  2098. if (hr == E_ADS_CANT_CONVERT_DATATYPE) {
  2099. //
  2100. // This means that the server didn't give back the schema and we don't
  2101. // have it in the default schema. Return an octet blob.
  2102. //
  2103. dwSyntaxId = LDAPTYPE_OCTETSTRING;
  2104. hr = S_OK;
  2105. }
  2106. if (hr == E_ADS_PROPERTY_NOT_FOUND) {
  2107. //
  2108. // Not on the server, we will return as provider specific.
  2109. // LDAPTYPE_UNKNOWN will be mapped to ADSTYPE_PROVIDER_SPECIFIC
  2110. // when we build the ADsColumn.
  2111. //
  2112. dwSyntaxId = LDAPTYPE_UNKNOWN;
  2113. hr = S_OK;
  2114. }
  2115. BAIL_ON_FAILURE(hr);
  2116. //
  2117. // Now get the data
  2118. //
  2119. switch ( dwSyntaxId )
  2120. {
  2121. case LDAPTYPE_CERTIFICATE:
  2122. case LDAPTYPE_CERTIFICATELIST:
  2123. case LDAPTYPE_CERTIFICATEPAIR:
  2124. case LDAPTYPE_PASSWORD:
  2125. case LDAPTYPE_TELETEXTERMINALIDENTIFIER:
  2126. case LDAPTYPE_AUDIO:
  2127. case LDAPTYPE_JPEG:
  2128. case LDAPTYPE_FAX:
  2129. case LDAPTYPE_OCTETSTRING:
  2130. case LDAPTYPE_SECURITY_DESCRIPTOR:
  2131. case LDAPTYPE_UNKNOWN:
  2132. hr = LdapGetValuesLen(
  2133. phSearchInfo->_pConnection,
  2134. phSearchInfo->_pCurrentRow,
  2135. pszColumnName,
  2136. &ppBerValue,
  2137. &cValueCount
  2138. );
  2139. ppValue = (VOID **) ppBerValue;
  2140. break;
  2141. default:
  2142. hr = LdapGetValues(
  2143. phSearchInfo->_pConnection,
  2144. phSearchInfo->_pCurrentRow,
  2145. pszColumnName,
  2146. &ppStrValue,
  2147. &cValueCount
  2148. );
  2149. ppValue = (VOID **) ppStrValue;
  2150. break;
  2151. }
  2152. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE)) {
  2153. hr=E_ADS_COLUMN_NOT_SET;
  2154. }
  2155. BAIL_ON_FAILURE(hr);
  2156. hr = LdapValueToADsColumn(
  2157. pszColumnName,
  2158. dwSyntaxId,
  2159. cValueCount,
  2160. ppValue,
  2161. pColumn
  2162. );
  2163. BAIL_ON_FAILURE(hr);
  2164. RRETURN(S_OK);
  2165. error:
  2166. ADsFreeColumn(pColumn);
  2167. if (pszADsPathName)
  2168. FreeADsMem(pszADsPathName);
  2169. RRETURN (hr);
  2170. }
  2171. HRESULT
  2172. ADsGetNextColumnName(
  2173. IN ADS_SEARCH_HANDLE hSearchHandle,
  2174. OUT LPWSTR * ppszColumnName
  2175. )
  2176. {
  2177. HRESULT hr = S_OK;
  2178. PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle;
  2179. DWORD dwStatus, dwError;
  2180. WCHAR pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH];
  2181. if( !phSearchInfo ||
  2182. !phSearchInfo->_pSearchResults ||
  2183. !ppszColumnName)
  2184. RRETURN (E_ADS_BAD_PARAMETER);
  2185. *ppszColumnName = NULL;
  2186. if (!phSearchInfo->_fADsPathOnly) {
  2187. if (!phSearchInfo->_pFirstAttr)
  2188. hr = LdapFirstAttribute(
  2189. phSearchInfo->_pConnection,
  2190. phSearchInfo->_pCurrentRow,
  2191. &phSearchInfo->_pFirstAttr,
  2192. ppszColumnName
  2193. );
  2194. else
  2195. hr = LdapNextAttribute(
  2196. phSearchInfo->_pConnection,
  2197. phSearchInfo->_pCurrentRow,
  2198. phSearchInfo->_pFirstAttr,
  2199. ppszColumnName
  2200. );
  2201. BAIL_ON_FAILURE(hr);
  2202. }
  2203. if (*ppszColumnName) {
  2204. // Nothing to do in this case.
  2205. }
  2206. else if ( phSearchInfo->_fADsPathPresent) {
  2207. //
  2208. // If ADsPath was specified return it as the last column
  2209. //
  2210. if (!phSearchInfo->_fADsPathReturned) {
  2211. *ppszColumnName = AllocADsStr(L"ADsPath");
  2212. phSearchInfo->_fADsPathReturned = TRUE;
  2213. }
  2214. else {
  2215. //
  2216. // We need to reset it back so that we return it for the next
  2217. // row
  2218. //
  2219. phSearchInfo->_fADsPathReturned = FALSE;
  2220. hr = S_ADS_NOMORE_COLUMNS;
  2221. }
  2222. }
  2223. else {
  2224. hr = S_ADS_NOMORE_COLUMNS;
  2225. }
  2226. error:
  2227. RRETURN (hr);
  2228. }
  2229. HRESULT
  2230. ADsFreeColumn(
  2231. IN PADS_SEARCH_COLUMN pColumn
  2232. )
  2233. {
  2234. HRESULT hr = S_OK;
  2235. if(!pColumn)
  2236. RRETURN (E_ADS_BAD_PARAMETER);
  2237. switch(pColumn->dwADsType) {
  2238. case ADSTYPE_OCTET_STRING:
  2239. case ADSTYPE_NT_SECURITY_DESCRIPTOR:
  2240. case ADSTYPE_PROV_SPECIFIC:
  2241. //
  2242. // Call the LDAP free value routine if not DirSyncControl
  2243. // or VLV
  2244. //
  2245. if (pColumn->pszAttrName
  2246. && !_wcsicmp(ADS_VLV_RESPONSE, pColumn->pszAttrName)) {
  2247. //
  2248. // VLV, so free the ADS_VLV and its members
  2249. //
  2250. if (pColumn->pADsValues && pColumn->pADsValues[0].ProviderSpecific.lpValue) {
  2251. if (((PADS_VLV)(pColumn->pADsValues[0].ProviderSpecific.lpValue))->lpContextID) {
  2252. FreeADsMem(((PADS_VLV)(pColumn->pADsValues[0].ProviderSpecific.lpValue))->lpContextID);
  2253. }
  2254. FreeADsMem(pColumn->pADsValues[0].ProviderSpecific.lpValue);
  2255. }
  2256. }
  2257. else if (pColumn->pszAttrName
  2258. && _wcsicmp(ADS_DIRSYNC_COOKIE, pColumn->pszAttrName)
  2259. ) {
  2260. LdapValueFreeLen((struct berval **)pColumn->hReserved);
  2261. pColumn->hReserved = NULL;
  2262. } else {
  2263. //
  2264. // DirSyncControlStruct - so we free the ADsValue.
  2265. //
  2266. if (pColumn->pADsValues[0].ProviderSpecific.lpValue) {
  2267. FreeADsMem(pColumn->pADsValues[0].ProviderSpecific.lpValue);
  2268. }
  2269. }
  2270. break;
  2271. case ADSTYPE_CASE_IGNORE_STRING:
  2272. case ADSTYPE_NUMERIC_STRING:
  2273. case ADSTYPE_PRINTABLE_STRING:
  2274. case ADSTYPE_DN_STRING:
  2275. case ADSTYPE_CASE_EXACT_STRING:
  2276. if(!pColumn->hReserved) {
  2277. //
  2278. // The column just contains a DN.
  2279. //
  2280. FreeADsMem(pColumn->pADsValues[0].CaseIgnoreString);
  2281. }
  2282. else {
  2283. LdapValueFree( (WCHAR **)pColumn->hReserved);
  2284. pColumn->hReserved = NULL;
  2285. }
  2286. break;
  2287. case ADSTYPE_INTEGER:
  2288. case ADSTYPE_LARGE_INTEGER:
  2289. case ADSTYPE_BOOLEAN:
  2290. case ADSTYPE_UTC_TIME:
  2291. // Nothing to free
  2292. break;
  2293. case ADSTYPE_DN_WITH_BINARY:
  2294. case ADSTYPE_DN_WITH_STRING:
  2295. AdsTypeFreeAdsObjects(
  2296. pColumn->pADsValues,
  2297. pColumn->dwNumValues
  2298. );
  2299. //
  2300. // Do not want to free this twice
  2301. //
  2302. pColumn->pADsValues = NULL;
  2303. break;
  2304. case ADSTYPE_INVALID:
  2305. //
  2306. // This comes from the result of search by setting _SearchPref._fAttrsOnly
  2307. // nothing need to be done
  2308. //
  2309. break;
  2310. default:
  2311. // unknown type;
  2312. hr = E_ADS_BAD_PARAMETER;
  2313. }
  2314. if (pColumn->pszAttrName)
  2315. FreeADsStr(pColumn->pszAttrName);
  2316. if (pColumn->pADsValues) {
  2317. FreeADsMem(pColumn->pADsValues);
  2318. pColumn->pADsValues = NULL;
  2319. }
  2320. RRETURN(hr);
  2321. }
  2322. BOOL
  2323. IsValidPrefValue(
  2324. ADS_SEARCHPREF_INFO SearchPref
  2325. )
  2326. {
  2327. switch(SearchPref.dwSearchPref) {
  2328. case ADS_SEARCHPREF_ASYNCHRONOUS:
  2329. case ADS_SEARCHPREF_ATTRIBTYPES_ONLY:
  2330. case ADS_SEARCHPREF_CACHE_RESULTS:
  2331. case ADS_SEARCHPREF_TOMBSTONE:
  2332. if (SearchPref.vValue.dwType != ADSTYPE_BOOLEAN)
  2333. return FALSE;
  2334. break;
  2335. case ADS_SEARCHPREF_DEREF_ALIASES:
  2336. case ADS_SEARCHPREF_SIZE_LIMIT:
  2337. case ADS_SEARCHPREF_TIME_LIMIT:
  2338. case ADS_SEARCHPREF_SEARCH_SCOPE:
  2339. case ADS_SEARCHPREF_TIMEOUT:
  2340. case ADS_SEARCHPREF_PAGESIZE:
  2341. case ADS_SEARCHPREF_PAGED_TIME_LIMIT:
  2342. case ADS_SEARCHPREF_CHASE_REFERRALS:
  2343. if (SearchPref.vValue.dwType != ADSTYPE_INTEGER)
  2344. return FALSE;
  2345. break;
  2346. case ADS_SEARCHPREF_SORT_ON:
  2347. if (SearchPref.vValue.dwType != ADSTYPE_PROV_SPECIFIC)
  2348. return FALSE;
  2349. break;
  2350. case ADS_SEARCHPREF_DIRSYNC:
  2351. if (SearchPref.vValue.dwType != ADSTYPE_PROV_SPECIFIC)
  2352. return FALSE;
  2353. break;
  2354. case ADS_SEARCHPREF_VLV:
  2355. if (SearchPref.vValue.dwType != ADSTYPE_PROV_SPECIFIC)
  2356. return FALSE;
  2357. break;
  2358. case ADS_SEARCHPREF_ATTRIBUTE_QUERY:
  2359. if (SearchPref.vValue.dwType != ADSTYPE_CASE_IGNORE_STRING)
  2360. return FALSE;
  2361. break;
  2362. case ADS_SEARCHPREF_SECURITY_MASK:
  2363. if (SearchPref.vValue.dwType != ADSTYPE_INTEGER)
  2364. return FALSE;
  2365. break;
  2366. default:
  2367. return FALSE;
  2368. }
  2369. return TRUE;
  2370. }
  2371. HRESULT
  2372. LdapValueToADsColumn(
  2373. LPWSTR pszColumnName,
  2374. DWORD dwSyntaxId,
  2375. DWORD dwValues,
  2376. VOID **ppValue,
  2377. ADS_SEARCH_COLUMN * pColumn
  2378. )
  2379. {
  2380. HRESULT hr = S_OK;
  2381. DWORD i, j;
  2382. if(!pszColumnName || !pColumn)
  2383. RRETURN(E_ADS_BAD_PARAMETER);
  2384. pColumn->hReserved = (HANDLE) ppValue;
  2385. pColumn->dwNumValues = dwValues;
  2386. if (dwValues < 1) {
  2387. //
  2388. // Need to set the ADsValue struct to NULL as it does
  2389. // not make sense to return any ADsValues
  2390. //
  2391. pColumn->pADsValues = NULL;
  2392. } else {
  2393. pColumn->pADsValues = (PADSVALUE) AllocADsMem(
  2394. sizeof(ADSVALUE) * dwValues
  2395. );
  2396. if (!pColumn->pADsValues)
  2397. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2398. }
  2399. pColumn->dwADsType = MapLDAPTypeToADSType(dwSyntaxId);
  2400. switch (dwSyntaxId) {
  2401. case LDAPTYPE_BITSTRING:
  2402. case LDAPTYPE_PRINTABLESTRING:
  2403. case LDAPTYPE_DIRECTORYSTRING:
  2404. case LDAPTYPE_COUNTRYSTRING:
  2405. case LDAPTYPE_DN:
  2406. case LDAPTYPE_NUMERICSTRING:
  2407. case LDAPTYPE_IA5STRING:
  2408. case LDAPTYPE_CASEIGNORESTRING:
  2409. case LDAPTYPE_OID:
  2410. case LDAPTYPE_TELEPHONENUMBER:
  2411. case LDAPTYPE_ATTRIBUTETYPEDESCRIPTION:
  2412. case LDAPTYPE_OBJECTCLASSDESCRIPTION:
  2413. case LDAPTYPE_DELIVERYMETHOD:
  2414. case LDAPTYPE_ENHANCEDGUIDE:
  2415. case LDAPTYPE_FACSIMILETELEPHONENUMBER:
  2416. case LDAPTYPE_GUIDE:
  2417. case LDAPTYPE_NAMEANDOPTIONALUID:
  2418. case LDAPTYPE_POSTALADDRESS:
  2419. case LDAPTYPE_PRESENTATIONADDRESS:
  2420. case LDAPTYPE_TELEXNUMBER:
  2421. case LDAPTYPE_DSAQUALITYSYNTAX:
  2422. case LDAPTYPE_DATAQUALITYSYNTAX:
  2423. case LDAPTYPE_MAILPREFERENCE:
  2424. case LDAPTYPE_OTHERMAILBOX:
  2425. case LDAPTYPE_ACCESSPOINTDN:
  2426. case LDAPTYPE_ORNAME:
  2427. case LDAPTYPE_ORADDRESS:
  2428. for (i=0; i < dwValues; i++) {
  2429. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  2430. pColumn->pADsValues[i].CaseIgnoreString = (LPWSTR) ppValue[i];
  2431. }
  2432. break;
  2433. case LDAPTYPE_CASEEXACTSTRING:
  2434. for (i=0; i < dwValues; i++) {
  2435. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  2436. pColumn->pADsValues[i].CaseExactString = (LPWSTR) ppValue[i];
  2437. }
  2438. break;
  2439. case LDAPTYPE_UTCTIME:
  2440. for (i=0; i < dwValues; i++) {
  2441. SYSTEMTIME st;
  2442. hr = UTCTimeStringToUTCTime((LPWSTR)ppValue[i],
  2443. &st);
  2444. BAIL_ON_FAILURE(hr);
  2445. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  2446. pColumn->pADsValues[i].UTCTime = st;
  2447. }
  2448. LdapValueFree((WCHAR **)pColumn->hReserved);
  2449. pColumn->hReserved = NULL;
  2450. break;
  2451. case LDAPTYPE_GENERALIZEDTIME:
  2452. for (i=0; i < dwValues; i++) {
  2453. SYSTEMTIME st;
  2454. hr = GenTimeStringToUTCTime((LPWSTR)ppValue[i],
  2455. &st);
  2456. BAIL_ON_FAILURE(hr);
  2457. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  2458. pColumn->pADsValues[i].UTCTime = st;
  2459. }
  2460. LdapValueFree((WCHAR **)pColumn->hReserved);
  2461. pColumn->hReserved = NULL;
  2462. break;
  2463. case LDAPTYPE_CERTIFICATE:
  2464. case LDAPTYPE_CERTIFICATELIST:
  2465. case LDAPTYPE_CERTIFICATEPAIR:
  2466. case LDAPTYPE_PASSWORD:
  2467. case LDAPTYPE_TELETEXTERMINALIDENTIFIER:
  2468. case LDAPTYPE_AUDIO:
  2469. case LDAPTYPE_JPEG:
  2470. case LDAPTYPE_FAX:
  2471. case LDAPTYPE_OCTETSTRING:
  2472. case LDAPTYPE_SECURITY_DESCRIPTOR:
  2473. for (i=0; i < dwValues; i++) {
  2474. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  2475. pColumn->pADsValues[i].OctetString.dwLength = ((struct berval **)ppValue)[i]->bv_len;
  2476. pColumn->pADsValues[i].OctetString.lpValue = (LPBYTE)
  2477. ((struct berval **) ppValue)[i]->bv_val;
  2478. }
  2479. break;
  2480. case LDAPTYPE_BOOLEAN:
  2481. for (i=0; i < dwValues; i++) {
  2482. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  2483. if ( _wcsicmp( (WCHAR *) ppValue[i], L"TRUE") == 0 ) {
  2484. pColumn->pADsValues[i].Boolean = TRUE;
  2485. }
  2486. else if ( _wcsicmp( (WCHAR *) ppValue[i], L"FALSE") == 0 ) {
  2487. pColumn->pADsValues[i].Boolean = FALSE;
  2488. }
  2489. else {
  2490. BAIL_ON_FAILURE(hr = E_ADS_CANT_CONVERT_DATATYPE);
  2491. }
  2492. }
  2493. LdapValueFree((WCHAR **)pColumn->hReserved);
  2494. pColumn->hReserved = NULL;
  2495. break;
  2496. case LDAPTYPE_INTEGER:
  2497. for (i=0; i < dwValues; i++) {
  2498. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  2499. pColumn->pADsValues[i].Integer = _wtol((WCHAR *) ppValue[i]);
  2500. }
  2501. LdapValueFree((WCHAR **)pColumn->hReserved);
  2502. pColumn->hReserved = NULL;
  2503. break;
  2504. case LDAPTYPE_INTEGER8:
  2505. for (i=0; i < dwValues; i++) {
  2506. pColumn->pADsValues[i].dwType = pColumn->dwADsType;
  2507. swscanf ((WCHAR *) ppValue[i], L"%I64d", &pColumn->pADsValues[i].LargeInteger);
  2508. }
  2509. LdapValueFree((WCHAR **)pColumn->hReserved);
  2510. pColumn->hReserved = NULL;
  2511. break;
  2512. case LDAPTYPE_DNWITHBINARY:
  2513. for (i=0; i < dwValues; i++) {
  2514. hr = LdapDNWithBinToAdsTypeHelper(
  2515. (LPWSTR) ppValue[i],
  2516. &pColumn->pADsValues[i]
  2517. );
  2518. BAIL_ON_FAILURE(hr);
  2519. }
  2520. LdapValueFree((WCHAR **)pColumn->hReserved);
  2521. pColumn->hReserved = NULL;
  2522. break;
  2523. case LDAPTYPE_DNWITHSTRING:
  2524. for (i=0; i < dwValues; i++) {
  2525. hr = LdapDNWithStrToAdsTypeHelper(
  2526. (LPWSTR) ppValue[i],
  2527. &pColumn->pADsValues[i]
  2528. );
  2529. BAIL_ON_FAILURE(hr);
  2530. }
  2531. LdapValueFree((WCHAR **)pColumn->hReserved);
  2532. pColumn->hReserved = NULL;
  2533. break;
  2534. default:
  2535. pColumn->dwADsType = ADSTYPE_PROV_SPECIFIC;
  2536. for (i=0; i < dwValues; i++) {
  2537. pColumn->pADsValues[i].dwType = ADSTYPE_PROV_SPECIFIC;
  2538. pColumn->pADsValues[i].ProviderSpecific.dwLength =
  2539. ((struct berval **)ppValue)[i]->bv_len;
  2540. pColumn->pADsValues[i].ProviderSpecific.lpValue =
  2541. (LPBYTE) ((struct berval **) ppValue)[i]->bv_val;
  2542. }
  2543. break;
  2544. }
  2545. RRETURN(hr);
  2546. error:
  2547. if (pColumn->pADsValues) {
  2548. FreeADsMem(pColumn->pADsValues);
  2549. pColumn->pADsValues = NULL;
  2550. pColumn->dwNumValues = 0;
  2551. }
  2552. RRETURN(hr);
  2553. }
  2554. //
  2555. // To add the server controls. The controls will be set internally in the
  2556. // handle. Right now, we support sort, dirsync and domain scope controls.
  2557. //
  2558. HRESULT
  2559. AddSearchControls(
  2560. PLDAP_SEARCHINFO phSearchInfo,
  2561. CCredentials& Credentials
  2562. )
  2563. {
  2564. HRESULT hr = S_OK;
  2565. PLDAPSortKey *ppSortKeys = NULL;
  2566. PLDAPControl pSortControl = NULL, *ppServerControls = NULL;
  2567. PLDAPControl pDirSyncControl = NULL;
  2568. PLDAPControl pDomCtrl = NULL;
  2569. PLDAPControl pTombStoneCtrl = NULL;
  2570. PLDAPControl pVLVControl = NULL;
  2571. PLDAPControl pAttribScopedCtrl = NULL;
  2572. PLDAPControl pSecurityDescCtrl = NULL;
  2573. PBERVAL pBerVal = NULL;
  2574. DWORD nKeys=0, i=0;
  2575. DWORD dwControls = 0;
  2576. DWORD dwCurControl = 0;
  2577. BOOL fDomainScopeControl = FALSE;
  2578. BOOL fTombStone = FALSE;
  2579. BYTE * pbSecDescValue = NULL;
  2580. if (phSearchInfo->_SearchPref._pSortKeys) {
  2581. dwControls++;
  2582. }
  2583. if (phSearchInfo->_SearchPref._fDirSync) {
  2584. dwControls++;
  2585. }
  2586. if (phSearchInfo->_SearchPref._fTombStone) {
  2587. dwControls++;
  2588. fTombStone = TRUE;
  2589. }
  2590. if (phSearchInfo->_SearchPref._pVLVInfo) {
  2591. dwControls++;
  2592. }
  2593. if (phSearchInfo->_SearchPref._pAttribScoped) {
  2594. dwControls++;
  2595. }
  2596. if (phSearchInfo->_SearchPref._fSecurityDescriptorControl) {
  2597. dwControls++;
  2598. }
  2599. if (phSearchInfo->_SearchPref._dwChaseReferrals == LDAP_CHASE_EXTERNAL_REFERRALS
  2600. || phSearchInfo->_SearchPref._dwChaseReferrals == (DWORD)(DWORD_PTR)LDAP_OPT_OFF) {
  2601. //
  2602. // Try and see if we can add the additional ADControl.
  2603. //
  2604. hr = ReadDomScopeSupportedAttr(
  2605. phSearchInfo->_pszLdapServer,
  2606. &fDomainScopeControl,
  2607. Credentials,
  2608. phSearchInfo->_dwPort
  2609. );
  2610. if (FAILED(hr)) {
  2611. hr = S_OK;
  2612. fDomainScopeControl = FALSE;
  2613. }
  2614. else if (fDomainScopeControl == TRUE) {
  2615. dwControls++;
  2616. }
  2617. }
  2618. if (!dwControls) {
  2619. RRETURN(S_OK);
  2620. }
  2621. ADsAssert(phSearchInfo);
  2622. if (phSearchInfo->_ServerControls) {
  2623. while (phSearchInfo->_ServerControls[i]) {
  2624. //
  2625. // Free the pre-existing controls in preparation for adding in a new
  2626. // batch.
  2627. //
  2628. // The algorithm is:
  2629. // If this is the VLV control, free it with LdapControlFree
  2630. // All other controls are freed with FreeADsMem
  2631. // The sort & security descriptor controls also have additional
  2632. // memory associated with them that must be freed here.
  2633. // (some other controls, like ASQ or DirSync, also have additonal
  2634. // memory that must be freed, but this memory is tracked via
  2635. // _ldap_searchinfo and the freeing is done when we actually
  2636. // process adding the new control below)
  2637. //
  2638. //
  2639. // If this is the VLV control, need to free it
  2640. // using LdapControlFree
  2641. //
  2642. if ((phSearchInfo->_ServerControls[i]->ldctl_oid)
  2643. && (wcscmp(
  2644. phSearchInfo->_ServerControls[i]->ldctl_oid,
  2645. LDAP_CONTROL_VLVREQUEST_W
  2646. ) == 0)) {
  2647. LdapControlFree(phSearchInfo->_ServerControls[i]);
  2648. }
  2649. else {
  2650. //
  2651. // If this is the sort or security descriptor control, we
  2652. // need to free some additional stuff.
  2653. //
  2654. if ((phSearchInfo->_ServerControls[i]->ldctl_oid)
  2655. && (wcscmp(
  2656. phSearchInfo->_ServerControls[i]->ldctl_oid,
  2657. LDAP_SERVER_SORT_OID_W
  2658. ) == 0)
  2659. ) {
  2660. //
  2661. // This is a sort control
  2662. //
  2663. if (phSearchInfo->_ServerControls[i]->ldctl_oid) {
  2664. ldap_memfree(phSearchInfo->_ServerControls[i]->ldctl_oid);
  2665. }
  2666. if (phSearchInfo->_ServerControls[i]->ldctl_value.bv_val) {
  2667. ldap_memfreeA(
  2668. phSearchInfo->_ServerControls[i]->ldctl_value.bv_val
  2669. );
  2670. }
  2671. }
  2672. else if ((phSearchInfo->_ServerControls[i]->ldctl_oid)
  2673. && (wcscmp(phSearchInfo->_ServerControls[i]->ldctl_oid,
  2674. LDAP_SERVER_SD_FLAGS_OID_W) == 0)) {
  2675. //
  2676. // This is a security descriptor control
  2677. //
  2678. if (phSearchInfo->_ServerControls[i]->ldctl_value.bv_val) {
  2679. FreeADsMem(phSearchInfo->_ServerControls[i]->ldctl_value.bv_val);
  2680. }
  2681. }
  2682. // free the control (for any control except VLV, which
  2683. // we already freed above)
  2684. FreeADsMem(phSearchInfo->_ServerControls[i]);
  2685. }
  2686. i++;
  2687. }
  2688. FreeADsMem(phSearchInfo->_ServerControls);
  2689. phSearchInfo->_ServerControls = NULL;
  2690. }
  2691. nKeys = phSearchInfo->_SearchPref._nSortKeys;
  2692. //
  2693. // One more than our dwControls is the number we need.
  2694. //
  2695. ppServerControls = (PLDAPControl *)
  2696. AllocADsMem( sizeof(PLDAPControl) * (dwControls+1) );
  2697. if (!ppServerControls) {
  2698. RRETURN(E_OUTOFMEMORY);
  2699. }
  2700. //
  2701. // Process the VLV control
  2702. //
  2703. if (phSearchInfo->_SearchPref._pVLVInfo) {
  2704. hr = LdapCreateVLVControl(phSearchInfo->_pConnection,
  2705. phSearchInfo->_SearchPref._pVLVInfo,
  2706. TRUE,
  2707. &pVLVControl
  2708. );
  2709. BAIL_ON_FAILURE(hr);
  2710. ppServerControls[dwCurControl++] = pVLVControl;
  2711. }
  2712. //
  2713. // Process the sort control.
  2714. //
  2715. if (phSearchInfo->_SearchPref._pSortKeys) {
  2716. ppSortKeys = (PLDAPSortKey *) AllocADsMem( sizeof(PLDAPSortKey) *
  2717. (nKeys+1) );
  2718. if (!ppSortKeys) {
  2719. RRETURN(E_OUTOFMEMORY);
  2720. }
  2721. pSortControl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl));
  2722. if (!pSortControl) {
  2723. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2724. }
  2725. for (i=0; i<nKeys; i++) {
  2726. ppSortKeys[i] = &(phSearchInfo->_SearchPref._pSortKeys[i]);
  2727. }
  2728. ppSortKeys[nKeys] = NULL;
  2729. hr = LdapEncodeSortControl(
  2730. phSearchInfo->_pConnection,
  2731. ppSortKeys,
  2732. pSortControl,
  2733. TRUE
  2734. );
  2735. BAIL_ON_FAILURE(hr);
  2736. ppServerControls[dwCurControl++] = pSortControl;
  2737. if (ppSortKeys) {
  2738. FreeADsMem(ppSortKeys);
  2739. }
  2740. }
  2741. //
  2742. // Handle the dirsync control if applicable
  2743. //
  2744. if (phSearchInfo->_SearchPref._fDirSync) {
  2745. pDirSyncControl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl));
  2746. if (!pDirSyncControl) {
  2747. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2748. }
  2749. hr = BerEncodeReplicationCookie(
  2750. phSearchInfo->_SearchPref._pProvSpecific->lpValue,
  2751. phSearchInfo->_SearchPref._pProvSpecific->dwLength,
  2752. &pBerVal
  2753. );
  2754. BAIL_ON_FAILURE(hr);
  2755. pDirSyncControl->ldctl_oid = LDAP_SERVER_DIRSYNC_OID_W;
  2756. pDirSyncControl->ldctl_value.bv_len = pBerVal->bv_len;
  2757. pDirSyncControl->ldctl_value.bv_val = (PCHAR) pBerVal->bv_val;
  2758. pDirSyncControl->ldctl_iscritical = TRUE;
  2759. //
  2760. // Clear the info in the search handle if applicable
  2761. //
  2762. if (phSearchInfo->_pBerVal) {
  2763. ber_bvfree(phSearchInfo->_pBerVal);
  2764. }
  2765. phSearchInfo->_pBerVal = pBerVal;
  2766. ppServerControls[dwCurControl++] = pDirSyncControl;
  2767. }
  2768. //
  2769. // Process the DomainScope control if applicable
  2770. //
  2771. if (fDomainScopeControl) {
  2772. pDomCtrl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl));
  2773. if (!pDomCtrl) {
  2774. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2775. }
  2776. pDomCtrl->ldctl_oid = LDAP_SERVER_DOMAIN_SCOPE_OID_W;
  2777. pDomCtrl->ldctl_value.bv_len = 0;
  2778. pDomCtrl->ldctl_value.bv_val = NULL;
  2779. pDomCtrl->ldctl_iscritical = FALSE;
  2780. ppServerControls[dwCurControl++] = pDomCtrl;
  2781. }
  2782. //
  2783. // Process the tombstone control if applicable
  2784. //
  2785. if (fTombStone) {
  2786. pTombStoneCtrl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl));
  2787. if (!pTombStoneCtrl) {
  2788. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2789. }
  2790. pTombStoneCtrl->ldctl_oid = LDAP_SERVER_SHOW_DELETED_OID_W;
  2791. pTombStoneCtrl->ldctl_value.bv_len = 0;
  2792. pTombStoneCtrl->ldctl_value.bv_val = NULL;
  2793. pTombStoneCtrl->ldctl_iscritical = TRUE;
  2794. ppServerControls[dwCurControl++] = pTombStoneCtrl;
  2795. }
  2796. //
  2797. // Process the attribute scoped query control
  2798. //
  2799. if (phSearchInfo->_SearchPref._pAttribScoped) {
  2800. pAttribScopedCtrl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl));
  2801. if (!pAttribScopedCtrl) {
  2802. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2803. }
  2804. hr = BerEncodeAttribScopedControlValue(phSearchInfo->_SearchPref._pAttribScoped,
  2805. &pBerVal);
  2806. BAIL_ON_FAILURE(hr);
  2807. pAttribScopedCtrl->ldctl_oid = LDAP_SERVER_ASQ_OID_W;
  2808. pAttribScopedCtrl->ldctl_value.bv_len = pBerVal->bv_len;
  2809. pAttribScopedCtrl->ldctl_value.bv_val = pBerVal->bv_val;
  2810. pAttribScopedCtrl->ldctl_iscritical = TRUE;
  2811. //
  2812. // Clear the info in the search handle if applicable
  2813. //
  2814. if (phSearchInfo->_pBerValAttribScoped) {
  2815. ber_bvfree(phSearchInfo->_pBerValAttribScoped);
  2816. }
  2817. phSearchInfo->_pBerValAttribScoped = pBerVal;
  2818. ppServerControls[dwCurControl++] = pAttribScopedCtrl;
  2819. }
  2820. //
  2821. // Process the security descriptor control
  2822. //
  2823. if (phSearchInfo->_SearchPref._fSecurityDescriptorControl) {
  2824. pSecurityDescCtrl = (LDAPControl *) AllocADsMem(sizeof(LDAPControl));
  2825. if (!pSecurityDescCtrl) {
  2826. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2827. }
  2828. pbSecDescValue = (BYTE *) AllocADsMem(5);
  2829. if (!pbSecDescValue) {
  2830. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2831. }
  2832. ZeroMemory(pbSecDescValue, 5);
  2833. pbSecDescValue[0] = 0x30; // Start sequence tag
  2834. pbSecDescValue[1] = 0x03; // Length in bytes of following
  2835. pbSecDescValue[2] = 0x02; // Actual value this and next 2
  2836. pbSecDescValue[3] = 0x01;
  2837. pbSecDescValue[4] = (BYTE) ((ULONG)phSearchInfo->_SearchPref._SecurityDescriptorMask);
  2838. pSecurityDescCtrl->ldctl_oid = LDAP_SERVER_SD_FLAGS_OID_W;
  2839. pSecurityDescCtrl->ldctl_value.bv_len = 5;
  2840. pSecurityDescCtrl->ldctl_value.bv_val = (PCHAR) pbSecDescValue;
  2841. pSecurityDescCtrl->ldctl_iscritical = TRUE;
  2842. ppServerControls[dwCurControl++] = pSecurityDescCtrl;
  2843. }
  2844. ppServerControls[dwControls] = NULL;
  2845. phSearchInfo->_ServerControls = ppServerControls;
  2846. RRETURN(S_OK);
  2847. error:
  2848. if (ppServerControls) {
  2849. FreeADsMem(ppServerControls);
  2850. }
  2851. if (pSortControl) {
  2852. FreeADsMem(pSortControl);
  2853. }
  2854. if (pDirSyncControl) {
  2855. FreeADsMem(pSortControl);
  2856. }
  2857. if (pDomCtrl) {
  2858. FreeADsMem(pDomCtrl);
  2859. }
  2860. if (pTombStoneCtrl) {
  2861. FreeADsMem(pTombStoneCtrl);
  2862. }
  2863. if (pAttribScopedCtrl) {
  2864. FreeADsMem(pAttribScopedCtrl);
  2865. }
  2866. if (pVLVControl) {
  2867. LdapControlFree(pVLVControl);
  2868. }
  2869. if (pSecurityDescCtrl) {
  2870. FreeADsMem(pSecurityDescCtrl);
  2871. }
  2872. if (ppSortKeys) {
  2873. FreeADsMem(ppSortKeys);
  2874. }
  2875. if (pbSecDescValue) {
  2876. FreeADsMem(pbSecDescValue);
  2877. }
  2878. RRETURN(hr);
  2879. }
  2880. void
  2881. FreeSortKeys(
  2882. IN PLDAPSortKey pSortKeys,
  2883. IN DWORD dwSortKeys
  2884. )
  2885. {
  2886. for (DWORD i=0; i < dwSortKeys; i++) {
  2887. if (pSortKeys[i].sk_attrtype) {
  2888. FreeADsStr(pSortKeys[i].sk_attrtype);
  2889. }
  2890. }
  2891. if (pSortKeys) {
  2892. FreeADsMem(pSortKeys);
  2893. }
  2894. }
  2895. //
  2896. // Copy a LDAPVLVInfo (and the data it points to) from
  2897. // *pVLVInfoSource to **ppVLVInfoTarget.
  2898. //
  2899. // Note that pVLVInfoSource->ldvlv_extradata is not copied,
  2900. // and is set to NULL in **ppVLVInfoTarget. If the caller
  2901. // uses this for anything, copying it is the caller's
  2902. // responsibility.
  2903. //
  2904. HRESULT
  2905. CopyLDAPVLVInfo(
  2906. PLDAPVLVInfo pVLVInfoSource,
  2907. PLDAPVLVInfo *ppVLVInfoTarget
  2908. )
  2909. {
  2910. HRESULT hr = S_OK;
  2911. PLDAPVLVInfo pVLVInfo = NULL;
  2912. if (!pVLVInfoSource || !ppVLVInfoTarget)
  2913. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  2914. *ppVLVInfoTarget = NULL;
  2915. pVLVInfo = (PLDAPVLVInfo) AllocADsMem(sizeof(LDAPVLVInfo));
  2916. if (!pVLVInfo)
  2917. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2918. // copy the non-pointer members
  2919. *pVLVInfo = *pVLVInfoSource;
  2920. pVLVInfo->ldvlv_attrvalue = NULL;
  2921. pVLVInfo->ldvlv_context = NULL;
  2922. pVLVInfo->ldvlv_extradata = NULL;
  2923. // copy the pointer members
  2924. if (pVLVInfoSource->ldvlv_attrvalue) {
  2925. pVLVInfo->ldvlv_attrvalue = (PBERVAL) AllocADsMem(sizeof(BERVAL));
  2926. if (!pVLVInfo->ldvlv_attrvalue)
  2927. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2928. pVLVInfo->ldvlv_attrvalue->bv_len = pVLVInfoSource->ldvlv_attrvalue->bv_len;
  2929. pVLVInfo->ldvlv_attrvalue->bv_val = (PCHAR) AllocADsMem(pVLVInfo->ldvlv_attrvalue->bv_len);
  2930. if (!pVLVInfo->ldvlv_attrvalue->bv_val)
  2931. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2932. memcpy(pVLVInfo->ldvlv_attrvalue->bv_val,
  2933. pVLVInfoSource->ldvlv_attrvalue->bv_val,
  2934. pVLVInfo->ldvlv_attrvalue->bv_len);
  2935. }
  2936. if (pVLVInfoSource->ldvlv_context) {
  2937. pVLVInfo->ldvlv_context = (PBERVAL) AllocADsMem(sizeof(BERVAL));
  2938. if (!pVLVInfo->ldvlv_context)
  2939. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2940. pVLVInfo->ldvlv_context->bv_len = pVLVInfoSource->ldvlv_context->bv_len;
  2941. pVLVInfo->ldvlv_context->bv_val = (PCHAR) AllocADsMem(pVLVInfo->ldvlv_context->bv_len);
  2942. if (!pVLVInfo->ldvlv_context->bv_val)
  2943. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  2944. memcpy(pVLVInfo->ldvlv_context->bv_val,
  2945. pVLVInfoSource->ldvlv_context->bv_val,
  2946. pVLVInfo->ldvlv_context->bv_len);
  2947. }
  2948. *ppVLVInfoTarget = pVLVInfo;
  2949. RRETURN(hr);
  2950. error:
  2951. FreeLDAPVLVInfo(pVLVInfo);
  2952. RRETURN(hr);
  2953. }
  2954. //
  2955. // Free a LDAPVLVInfo (and the data it points to)
  2956. //
  2957. // Note that pVLVInfoSource->ldvlv_extradata is not freed.
  2958. // If the caller uses this for anything, freeing it before
  2959. // calling this function is the caller's responsibility.
  2960. //
  2961. void
  2962. FreeLDAPVLVInfo(
  2963. IN PLDAPVLVInfo pVLVInfo
  2964. )
  2965. {
  2966. if (pVLVInfo) {
  2967. if (pVLVInfo->ldvlv_attrvalue) {
  2968. if (pVLVInfo->ldvlv_attrvalue->bv_val) {
  2969. FreeADsMem(pVLVInfo->ldvlv_attrvalue->bv_val);
  2970. }
  2971. FreeADsMem(pVLVInfo->ldvlv_attrvalue);
  2972. }
  2973. if (pVLVInfo->ldvlv_context) {
  2974. if (pVLVInfo->ldvlv_context->bv_val) {
  2975. FreeADsMem(pVLVInfo->ldvlv_context->bv_val);
  2976. }
  2977. FreeADsMem(pVLVInfo->ldvlv_context);
  2978. }
  2979. FreeADsMem(pVLVInfo);
  2980. }
  2981. }
  2982. HRESULT
  2983. StoreVLVInfo(
  2984. LDAPMessage *pLDAPMsg,
  2985. PLDAP_SEARCHINFO phSearchInfo
  2986. )
  2987. {
  2988. HRESULT hr = S_OK;
  2989. PLDAPControl *ppServerControls = NULL;
  2990. ULONG ulTarget = 0;
  2991. ULONG ulCount = 0;
  2992. PBERVAL pContextID = NULL;
  2993. PBERVAL pContextIDCopy = NULL;
  2994. if (!pLDAPMsg) {
  2995. RRETURN(S_OK);
  2996. }
  2997. //
  2998. // Retrieve the server controls
  2999. //
  3000. hr = LdapParseResult(
  3001. phSearchInfo->_pConnection,
  3002. pLDAPMsg,
  3003. NULL, // ret code
  3004. NULL, // matched dn's
  3005. NULL, // err msg's
  3006. NULL, // referrals
  3007. &ppServerControls,
  3008. FALSE // freeIt
  3009. );
  3010. BAIL_ON_FAILURE(hr);
  3011. if (!ppServerControls) {
  3012. //
  3013. // Could not get the control
  3014. //
  3015. BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND);
  3016. }
  3017. //
  3018. // Parse the VLV response control
  3019. //
  3020. hr = LdapParseVLVControl(
  3021. phSearchInfo->_pConnection,
  3022. ppServerControls,
  3023. &ulTarget,
  3024. &ulCount,
  3025. &pContextID
  3026. );
  3027. BAIL_ON_FAILURE(hr);
  3028. //
  3029. // Copy the new context ID, if one was returned by the server
  3030. //
  3031. if (pContextID && pContextID->bv_val && pContextID->bv_len) {
  3032. pContextIDCopy = (PBERVAL) AllocADsMem(sizeof(BERVAL));
  3033. if (!pContextIDCopy)
  3034. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3035. pContextIDCopy->bv_len = pContextID->bv_len;
  3036. pContextIDCopy->bv_val = (PCHAR) AllocADsMem(pContextID->bv_len);
  3037. if (!pContextIDCopy->bv_val)
  3038. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3039. memcpy(pContextIDCopy->bv_val,
  3040. pContextID->bv_val,
  3041. pContextID->bv_len);
  3042. }
  3043. //
  3044. // Copy VLV response control info into the _ldap_searchinfo
  3045. // If the server did not return context ID, pContextIDCopy == NULL.
  3046. //
  3047. phSearchInfo->_dwVLVOffset = ulTarget;
  3048. phSearchInfo->_dwVLVCount = ulCount;
  3049. // free the previous context ID
  3050. if (phSearchInfo->_pVLVContextID) {
  3051. if (phSearchInfo->_pVLVContextID->bv_val) {
  3052. FreeADsMem(phSearchInfo->_pVLVContextID->bv_val);
  3053. }
  3054. FreeADsMem(phSearchInfo->_pVLVContextID);
  3055. }
  3056. phSearchInfo->_pVLVContextID = pContextIDCopy;
  3057. error :
  3058. if (pContextID)
  3059. BerBvFree(pContextID);
  3060. if (ppServerControls) {
  3061. ldap_controls_free(ppServerControls);
  3062. }
  3063. if (FAILED(hr)) {
  3064. if (pContextIDCopy) {
  3065. if (pContextIDCopy->bv_val) {
  3066. FreeADsMem(pContextIDCopy->bv_val);
  3067. }
  3068. FreeADsMem(pContextIDCopy);
  3069. }
  3070. }
  3071. RRETURN(hr);
  3072. }
  3073. HRESULT
  3074. StoreAttribScopedInfo(
  3075. LDAPMessage *pLDAPMsg,
  3076. PLDAP_SEARCHINFO phSearchInfo
  3077. )
  3078. {
  3079. HRESULT hr = S_OK;
  3080. PLDAPControl *ppServerControls = NULL;
  3081. DWORD dwCtr = 0;
  3082. BERVAL berVal;
  3083. BerElement *pBer = NULL;
  3084. int retval = LDAP_SUCCESS;
  3085. if (!pLDAPMsg) {
  3086. RRETURN(S_OK);
  3087. }
  3088. hr = LdapParseResult(
  3089. phSearchInfo->_pConnection,
  3090. pLDAPMsg,
  3091. NULL, // ret code
  3092. NULL, // matched dn's
  3093. NULL, // err msg's
  3094. NULL, // referrals
  3095. &ppServerControls,
  3096. FALSE // freeIt
  3097. );
  3098. BAIL_ON_FAILURE(hr);
  3099. //
  3100. // See if the ASQ control is in there.
  3101. //
  3102. while (ppServerControls
  3103. && ppServerControls[dwCtr]
  3104. && wcscmp(
  3105. ppServerControls[dwCtr]->ldctl_oid,
  3106. LDAP_SERVER_ASQ_OID_W
  3107. ) != 0) {
  3108. dwCtr++;
  3109. }
  3110. if (!ppServerControls || !ppServerControls[dwCtr]) {
  3111. //
  3112. // Could not get the control
  3113. //
  3114. BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND);
  3115. }
  3116. //
  3117. // Get the info we need.
  3118. //
  3119. berVal.bv_len = ppServerControls[dwCtr]->ldctl_value.bv_len;
  3120. berVal.bv_val = ppServerControls[dwCtr]->ldctl_value.bv_val;
  3121. pBer = ber_init(&berVal);
  3122. if (ber_scanf(pBer, "{e}", &retval) != NO_ERROR) {
  3123. BAIL_ON_FAILURE(hr = E_FAIL);
  3124. }
  3125. //
  3126. // Test for non-fatal error codes
  3127. //
  3128. if (retval == LDAP_AFFECTS_MULTIPLE_DSAS)
  3129. phSearchInfo->_fNonFatalErrors = TRUE;
  3130. error :
  3131. if (ppServerControls) {
  3132. ldap_controls_free(ppServerControls);
  3133. }
  3134. if (pBer) {
  3135. ber_free(pBer, 1);
  3136. }
  3137. RRETURN(hr);
  3138. }
  3139. HRESULT
  3140. StoreDirSyncCookie(
  3141. LDAPMessage *pLDAPMsg,
  3142. PLDAP_SEARCHINFO phSearchInfo
  3143. )
  3144. {
  3145. HRESULT hr = S_OK;
  3146. PADS_PROV_SPECIFIC pProvSpecific = NULL;
  3147. PLDAPControl *ppServerControls = NULL;
  3148. DWORD dwCtr = 0;
  3149. BERVAL berVal;
  3150. BerElement *pBer = NULL;
  3151. PBERVAL pBerVal = NULL;
  3152. DWORD dwSize;
  3153. BOOL fMoreData = FALSE;
  3154. if (!pLDAPMsg) {
  3155. RRETURN(S_OK);
  3156. }
  3157. phSearchInfo->_fMoreDirSync = FALSE;
  3158. //
  3159. // Build the new value and then assign it to the searchpref
  3160. // information. That way, if there are errors we wont loose
  3161. // the last cookie.
  3162. //
  3163. hr = LdapParseResult(
  3164. phSearchInfo->_pConnection,
  3165. pLDAPMsg,
  3166. NULL, // ret code
  3167. NULL, // matched dn's
  3168. NULL, // err msg's
  3169. NULL, // referrals
  3170. &ppServerControls,
  3171. FALSE // freeIt
  3172. );
  3173. BAIL_ON_FAILURE(hr);
  3174. //
  3175. // See if the dirsync control is in there.
  3176. //
  3177. while (ppServerControls
  3178. && ppServerControls[dwCtr]
  3179. && wcscmp(
  3180. ppServerControls[dwCtr]->ldctl_oid,
  3181. LDAP_SERVER_DIRSYNC_OID_W
  3182. ) != 0) {
  3183. dwCtr++;
  3184. }
  3185. if (!ppServerControls || !ppServerControls[dwCtr]) {
  3186. //
  3187. // Could not get the control
  3188. //
  3189. BAIL_ON_FAILURE(hr = E_ADS_PROPERTY_NOT_FOUND);
  3190. }
  3191. //
  3192. // Get the info we need.
  3193. //
  3194. berVal.bv_len = ppServerControls[dwCtr]->ldctl_value.bv_len;
  3195. berVal.bv_val = ppServerControls[dwCtr]->ldctl_value.bv_val;
  3196. pBer = ber_init(&berVal);
  3197. ber_scanf(pBer, "{iiO}", &fMoreData, &dwSize, &pBerVal);
  3198. phSearchInfo->_fMoreDirSync = fMoreData;
  3199. pProvSpecific = (PADS_PROV_SPECIFIC)
  3200. AllocADsMem(sizeof(ADS_PROV_SPECIFIC));
  3201. if (!pProvSpecific) {
  3202. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3203. }
  3204. pProvSpecific->lpValue = (LPBYTE) AllocADsMem(pBerVal->bv_len);
  3205. if (!pProvSpecific->lpValue) {
  3206. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3207. }
  3208. pProvSpecific->dwLength = pBerVal->bv_len;
  3209. memcpy(pProvSpecific->lpValue, (LPBYTE) pBerVal->bv_val, pBerVal->bv_len);
  3210. //
  3211. // At this point it is safe to clear the Info on the dirsync control
  3212. //
  3213. if (phSearchInfo->_SearchPref._pProvSpecific) {
  3214. if (phSearchInfo->_SearchPref._pProvSpecific->lpValue) {
  3215. FreeADsMem(phSearchInfo->_SearchPref._pProvSpecific->lpValue);
  3216. }
  3217. FreeADsMem(phSearchInfo->_SearchPref._pProvSpecific);
  3218. }
  3219. phSearchInfo->_SearchPref._pProvSpecific = pProvSpecific;
  3220. error :
  3221. if (ppServerControls) {
  3222. ldap_controls_free(ppServerControls);
  3223. }
  3224. if (FAILED(hr)) {
  3225. //
  3226. // Handle the Provider Specific struct if applicable.
  3227. //
  3228. if (pProvSpecific) {
  3229. if (pProvSpecific->lpValue) {
  3230. FreeADsMem(pProvSpecific->lpValue);
  3231. }
  3232. FreeADsMem(pProvSpecific);
  3233. }
  3234. }
  3235. if (pBerVal) {
  3236. ber_bvfree(pBerVal);
  3237. }
  3238. if (pBer) {
  3239. ber_free(pBer, 1);
  3240. }
  3241. RRETURN(hr);
  3242. }
  3243. HRESULT
  3244. BerEncodeReplicationCookie(
  3245. PBYTE pCookie,
  3246. DWORD dwLen,
  3247. PBERVAL *ppBerVal
  3248. )
  3249. {
  3250. HRESULT hr = E_FAIL;
  3251. BerElement *pBer = NULL;
  3252. pBer = ber_alloc_t(LBER_USE_DER);
  3253. if (!pBer) {
  3254. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3255. }
  3256. //
  3257. // flag - set to zero, so order of parent & child objects is not important
  3258. //
  3259. if (ber_printf(pBer, "{iio}", 0, MAX_BYTES, pCookie, dwLen) == -1) {
  3260. BAIL_ON_FAILURE(hr = E_FAIL);
  3261. }
  3262. //
  3263. // Pull data from the BerElement into a BERVAL struct.
  3264. // Caller needs to free ppBerVal.
  3265. //
  3266. if (ber_flatten(pBer, ppBerVal) != 0) {
  3267. BAIL_ON_FAILURE(hr = E_FAIL);
  3268. }
  3269. hr = S_OK;
  3270. error:
  3271. if (pBer) {
  3272. ber_free(pBer,1);
  3273. }
  3274. return hr;
  3275. }
  3276. HRESULT
  3277. BerEncodeAttribScopedControlValue(
  3278. LPCWSTR pAttribScoped,
  3279. PBERVAL *ppBerVal
  3280. )
  3281. {
  3282. HRESULT hr = S_OK;
  3283. BerElement *pBer = NULL;
  3284. LPSTR pszAttribute = NULL;
  3285. pBer = ber_alloc_t(LBER_USE_DER);
  3286. if (!pBer) {
  3287. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  3288. }
  3289. //
  3290. // Translate the Unicode strings to UTF-8
  3291. //
  3292. hr = UnicodeToUTF8String(pAttribScoped, &pszAttribute);
  3293. BAIL_ON_FAILURE(hr);
  3294. //
  3295. // BER-encode the attributeScopedQueryRequestControlValue
  3296. //
  3297. if (ber_printf(pBer, "{s}", pszAttribute) == -1) {
  3298. BAIL_ON_FAILURE(hr = E_FAIL);
  3299. }
  3300. //
  3301. // Pull data from the BerElement into a BERVAL struct.
  3302. // Caller needs to free ppBerVal.
  3303. //
  3304. if (ber_flatten(pBer, ppBerVal) != 0) {
  3305. BAIL_ON_FAILURE(hr = E_FAIL);
  3306. }
  3307. error:
  3308. if (pBer) {
  3309. ber_free(pBer,1);
  3310. }
  3311. if (pszAttribute)
  3312. FreeADsMem(pszAttribute);
  3313. return hr;
  3314. }
  3315. //
  3316. // This is called only by ADsGetMoreResultsDirSync.
  3317. //
  3318. HRESULT
  3319. ADsGetMoreResultsDirSyncHelper(
  3320. IN PLDAP_SEARCHINFO phSearchInfo,
  3321. CCredentials& Credentials
  3322. )
  3323. {
  3324. HRESULT hr = S_OK;
  3325. DWORD dwError;
  3326. LPWSTR pszLDAPPath;
  3327. WCHAR pszErrorBuf[MAX_PATH], pszNameBuf[MAX_PATH];
  3328. ULONG totalCount;
  3329. int resType;
  3330. ADsAssert(phSearchInfo);
  3331. //
  3332. // If the searchpref is not dirsync, abandon has been called
  3333. // or if the cookie indicated that there is no more data then
  3334. // we should return right away.
  3335. //
  3336. if (!phSearchInfo->_SearchPref._fDirSync
  3337. || phSearchInfo->_fAbandon
  3338. || !phSearchInfo->_fMoreDirSync) {
  3339. RRETURN(S_ADS_NOMORE_ROWS);
  3340. }
  3341. //
  3342. // We need to update the controls
  3343. //
  3344. hr = AddSearchControls(
  3345. phSearchInfo,
  3346. Credentials
  3347. );
  3348. BAIL_ON_FAILURE(hr);
  3349. //
  3350. // Need to allocate more messages in the buffer
  3351. //
  3352. if ( phSearchInfo->_SearchPref._fCacheResults ) {
  3353. ADsAssert(phSearchInfo->_dwCurrResult
  3354. == phSearchInfo->_dwMaxResultGot);
  3355. phSearchInfo->_dwCurrResult++;
  3356. phSearchInfo->_dwMaxResultGot++;
  3357. if (phSearchInfo->_dwCurrResult >= phSearchInfo->_cSearchResults) {
  3358. //
  3359. // Need to allocate more memory for handles
  3360. //
  3361. phSearchInfo->_pSearchResults = (LDAPMessage **) ReallocADsMem(
  3362. (void *) phSearchInfo->_pSearchResults,
  3363. sizeof(LDAPMessage *) *
  3364. phSearchInfo->_cSearchResults,
  3365. sizeof(LDAPMessage *) *
  3366. (phSearchInfo->_cSearchResults +
  3367. NO_LDAP_RESULT_HANDLES));
  3368. if(!phSearchInfo->_pSearchResults) {
  3369. hr = E_OUTOFMEMORY;
  3370. phSearchInfo->_dwCurrResult--;
  3371. phSearchInfo->_dwMaxResultGot--;
  3372. goto error;
  3373. }
  3374. phSearchInfo->_cSearchResults += NO_LDAP_RESULT_HANDLES;
  3375. }
  3376. }
  3377. else {
  3378. //
  3379. // Release and use the same space to store the next result.
  3380. //
  3381. LdapMsgFree(phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]);
  3382. }
  3383. //
  3384. // Async and sync searches need to be handled differently.
  3385. //
  3386. if (phSearchInfo->_SearchPref._fAsynchronous) {
  3387. //
  3388. // Asynchronous search.
  3389. //
  3390. hr = LdapSearchExt(
  3391. phSearchInfo->_pConnection,
  3392. phSearchInfo->_pszBindContextDn,
  3393. phSearchInfo->_SearchPref._dwSearchScope,
  3394. phSearchInfo->_pszSearchFilter,
  3395. phSearchInfo->_ppszAttrs,
  3396. phSearchInfo->_SearchPref._fAttrsOnly,
  3397. phSearchInfo->_ServerControls,
  3398. phSearchInfo->_ClientControls,
  3399. phSearchInfo->_SearchPref._dwPagedTimeLimit,
  3400. phSearchInfo->_SearchPref._dwSizeLimit,
  3401. &phSearchInfo->_currMsgId
  3402. );
  3403. BAIL_ON_FAILURE(hr);
  3404. phSearchInfo->_fLastResult = FALSE;
  3405. //
  3406. // Wait for atleast one result
  3407. //
  3408. hr = LdapResult(
  3409. phSearchInfo->_pConnection,
  3410. phSearchInfo->_currMsgId,
  3411. LDAP_MSG_RECEIVED,
  3412. phSearchInfo->_SearchPref._timeout.tv_sec ?
  3413. &phSearchInfo->_SearchPref._timeout : NULL,
  3414. &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  3415. &resType
  3416. );
  3417. if ((hr == HRESULT_FROM_WIN32(ERROR_DS_INVALID_DN_SYNTAX)) ||
  3418. (hr == HRESULT_FROM_WIN32(ERROR_DS_NAMING_VIOLATION)) ||
  3419. (hr == HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION)) ||
  3420. (hr == HRESULT_FROM_WIN32(ERROR_DS_FILTER_UNKNOWN)) ||
  3421. (hr == HRESULT_FROM_WIN32(ERROR_DS_PARAM_ERROR)) ||
  3422. (hr == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER))) {
  3423. phSearchInfo->_fLastResult = TRUE;
  3424. RRETURN(S_ADS_NOMORE_ROWS);
  3425. }
  3426. else {
  3427. //
  3428. // Only if there are zero rows returned, return the error,
  3429. // otherwise, store the error and return when GetNextRow is
  3430. // called for the last time
  3431. //
  3432. if (FAILED(hr) &&
  3433. (LdapCountEntries( phSearchInfo->_pConnection,
  3434. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult])
  3435. == 0)) {
  3436. BAIL_ON_FAILURE(hr);
  3437. }
  3438. else {
  3439. phSearchInfo->_hrLastSearch = hr;
  3440. hr = S_OK;
  3441. }
  3442. }
  3443. phSearchInfo->_fLastPage = TRUE;
  3444. }
  3445. else {
  3446. //
  3447. // Synchronous search
  3448. //
  3449. hr = LdapSearchExtS(
  3450. phSearchInfo->_pConnection,
  3451. phSearchInfo->_pszBindContextDn,
  3452. phSearchInfo->_SearchPref._dwSearchScope,
  3453. phSearchInfo->_pszSearchFilter,
  3454. phSearchInfo->_ppszAttrs,
  3455. phSearchInfo->_SearchPref._fAttrsOnly,
  3456. phSearchInfo->_ServerControls,
  3457. phSearchInfo->_ClientControls,
  3458. (phSearchInfo->_SearchPref._timeout.tv_sec == 0) ?
  3459. NULL :
  3460. &phSearchInfo->_SearchPref._timeout,
  3461. phSearchInfo->_SearchPref._dwSizeLimit,
  3462. &phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]
  3463. );
  3464. phSearchInfo->_fLastResult = TRUE;
  3465. phSearchInfo->_fLastPage = TRUE;
  3466. }
  3467. //
  3468. // Only if there are zero rows returned, return the error,
  3469. // otherwise, store the error and return when GetNextRow is
  3470. // called for the last time
  3471. //
  3472. if (FAILED(hr) &&
  3473. (LdapCountEntries( phSearchInfo->_pConnection,
  3474. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult]) == 0)) {
  3475. BAIL_ON_FAILURE(hr);
  3476. }
  3477. else {
  3478. phSearchInfo->_hrLastSearch = hr;
  3479. hr = S_OK;
  3480. }
  3481. error:
  3482. RRETURN(hr);
  3483. }
  3484. //
  3485. // This function is very similar to GetMoreResults except that
  3486. // it will issue a new search if applicable for the dirsync control.
  3487. //
  3488. HRESULT
  3489. ADsGetMoreResultsDirSync(
  3490. IN PLDAP_SEARCHINFO phSearchInfo,
  3491. CCredentials& Credentials
  3492. )
  3493. {
  3494. HRESULT hr = S_OK;
  3495. BOOL fTryAndGetResults = TRUE;
  3496. //
  3497. // If the searchpref is not dirsync, abandon has been called
  3498. // or if the cookie indicated that there is no more data then
  3499. // we should return right away.
  3500. //
  3501. if (!phSearchInfo->_SearchPref._fDirSync
  3502. || phSearchInfo->_fAbandon
  3503. || !phSearchInfo->_fMoreDirSync) {
  3504. RRETURN(S_ADS_NOMORE_ROWS);
  3505. }
  3506. while (fTryAndGetResults) {
  3507. fTryAndGetResults = FALSE;
  3508. hr = ADsGetMoreResultsDirSyncHelper(
  3509. phSearchInfo,
  3510. Credentials
  3511. );
  3512. BAIL_ON_FAILURE(hr);
  3513. StoreDirSyncCookie(
  3514. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  3515. phSearchInfo
  3516. );
  3517. if (hr == S_ADS_NOMORE_ROWS && phSearchInfo->_fMoreDirSync) {
  3518. fTryAndGetResults = TRUE;
  3519. }
  3520. //
  3521. // Now we want to see if the first row was valid. We could
  3522. // get back an entry but then not have any rows, just a cookie
  3523. //
  3524. if (!fTryAndGetResults) {
  3525. hr = LdapFirstEntry(
  3526. phSearchInfo->_pConnection,
  3527. phSearchInfo->_pSearchResults[phSearchInfo->_dwCurrResult],
  3528. &phSearchInfo->_pCurrentRow
  3529. );
  3530. BAIL_ON_FAILURE(hr);
  3531. if(phSearchInfo->_pCurrentRow) {
  3532. phSearchInfo->_pFirstAttr = NULL;
  3533. phSearchInfo->_fBefFirstRow = FALSE;
  3534. hr = S_OK;
  3535. }
  3536. else {
  3537. hr = S_ADS_NOMORE_ROWS;
  3538. if (phSearchInfo->_fMoreDirSync) {
  3539. fTryAndGetResults = TRUE;
  3540. }
  3541. }
  3542. } // if !Try and get more results.
  3543. } // while try and get more results.
  3544. error :
  3545. RRETURN(hr);
  3546. }
  3547. //+---------------------------------------------------------------------------
  3548. // Function: LdapInitializeSearchPreferences - Exported helper routine.
  3549. //
  3550. // Synopsis: Initializes the search preferences struc to the default values.
  3551. // With this function we can isolate the code in one place.
  3552. //
  3553. // Arguments: pSearchPrefs - Ptr to search prefs being initialized.
  3554. // fCacheResults - The cache results pref is set to this.
  3555. //
  3556. // Returns: N/A.
  3557. //
  3558. // Modifies: pSearchPrefs.
  3559. //
  3560. //----------------------------------------------------------------------------
  3561. void
  3562. LdapInitializeSearchPreferences(
  3563. LDAP_SEARCH_PREF *pSearchPrefs,
  3564. BOOL fCacheResults
  3565. )
  3566. {
  3567. ADsAssert(pSearchPrefs);
  3568. pSearchPrefs->_fAsynchronous = FALSE;
  3569. pSearchPrefs->_dwDerefAliases = FALSE;
  3570. pSearchPrefs->_dwSizeLimit = 0;
  3571. pSearchPrefs->_dwTimeLimit = 0;
  3572. pSearchPrefs->_fAttrsOnly = FALSE;
  3573. pSearchPrefs->_dwSearchScope = LDAP_SCOPE_SUBTREE;
  3574. pSearchPrefs->_timeout.tv_sec = 0;
  3575. pSearchPrefs->_timeout.tv_usec = 0;
  3576. pSearchPrefs->_dwPageSize = 0;
  3577. pSearchPrefs->_dwPagedTimeLimit = 0;
  3578. pSearchPrefs->_dwChaseReferrals = ADS_CHASE_REFERRALS_EXTERNAL;
  3579. pSearchPrefs->_pSortKeys = NULL;
  3580. pSearchPrefs->_nSortKeys = 0;
  3581. pSearchPrefs->_fDirSync = FALSE;
  3582. pSearchPrefs->_pProvSpecific = NULL;
  3583. pSearchPrefs->_fTombStone = FALSE;
  3584. pSearchPrefs->_fCacheResults = fCacheResults;
  3585. pSearchPrefs->_pVLVInfo = NULL;
  3586. pSearchPrefs->_pAttribScoped = NULL;
  3587. pSearchPrefs->_fSecurityDescriptorControl = FALSE;
  3588. }
  3589. //+---------------------------------------------------------------------------
  3590. // Function: ADsHelperGetCurrentRowMessage - used for Umi Search support.
  3591. //
  3592. // Synopsis: This returns the current row and the handle of the search.
  3593. // Neither are refCounted but this should not matter cause these
  3594. // will no longer be in use by the caller beyond the scope of
  3595. // the search (before the search is "closed", the handle and
  3596. // message that are got from this search will no longer be in
  3597. // use).
  3598. //
  3599. // Arguments: hSearchHandle - Handle to the search.
  3600. // ppAdsLdp - Pointer to hold returned lda handle.
  3601. // ppLdapMsg - Pointer to hold the current "rows" msg.
  3602. //
  3603. // Returns: S_OK or any appropriate error code.
  3604. //
  3605. // Modifies: ppAdsLdp and ppLdapMsg if successful.
  3606. //
  3607. //----------------------------------------------------------------------------
  3608. HRESULT
  3609. ADsHelperGetCurrentRowMessage(
  3610. IN ADS_SEARCH_HANDLE hSearchHandle,
  3611. OUT PADSLDP *ppAdsLdp,
  3612. OUT LDAPMessage **ppLdapMsg
  3613. )
  3614. {
  3615. HRESULT hr = S_OK;
  3616. PLDAP_SEARCHINFO phSearchInfo = (PLDAP_SEARCHINFO) hSearchHandle;
  3617. if( !phSearchInfo
  3618. || !phSearchInfo->_pSearchResults) {
  3619. RRETURN (E_ADS_BAD_PARAMETER);
  3620. }
  3621. if (!phSearchInfo->_pConnection || !phSearchInfo->_pCurrentRow) {
  3622. //
  3623. // Dont have the info we need
  3624. //
  3625. RRETURN(E_FAIL);
  3626. }
  3627. else {
  3628. //
  3629. // We have the handle and the row we need.
  3630. //
  3631. *ppAdsLdp = phSearchInfo->_pConnection;
  3632. *ppLdapMsg = phSearchInfo->_pCurrentRow;
  3633. }
  3634. RRETURN(hr);
  3635. }