Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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