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.

816 lines
24 KiB

  1. #include "exldap.h"
  2. #include "folders.h"
  3. #include "treg.hpp"
  4. #include "errdct.hpp"
  5. #include "resstr.h"
  6. #include "LSAUtils.h"
  7. using namespace nsFolders;
  8. #ifdef _DEBUG
  9. #define new DEBUG_NEW
  10. #undef THIS_FILE
  11. static char THIS_FILE[] = __FILE__;
  12. #endif
  13. extern TErrorDct err;
  14. CLdapConnection::CLdapConnection()
  15. {
  16. m_exchServer[0] = 0;
  17. m_LD = NULL;
  18. m_port = LDAP_PORT;
  19. m_bUseSSL = FALSE;
  20. // try to dynamically load the LDAP DLL
  21. m_hDll = LoadLibrary(L"wldap32.dll");
  22. ldap_open = NULL;
  23. ldap_parse_result = NULL;
  24. ldap_parse_page_control = NULL;
  25. ldap_controls_free = NULL;
  26. ber_bvfree = NULL;
  27. ldap_first_entry = NULL;
  28. ldap_next_entry = NULL;
  29. ldap_value_free = NULL;
  30. ldap_get_values = NULL;
  31. ldap_create_page_control = NULL;
  32. ldap_search_ext_s = NULL;
  33. ldap_count_entries = NULL;
  34. ldap_msgfree = NULL;
  35. ldap_modify_s = NULL;
  36. LdapGetLastError = NULL;
  37. ldap_bind_sW = NULL;
  38. ldap_simple_bind_sW = NULL;
  39. ldap_unbind = NULL;
  40. ldap_connect = NULL;
  41. ldap_get_option = NULL;
  42. ldap_set_option = NULL;
  43. LdapMapErrorToWin32 = NULL;
  44. ldap_init = NULL;
  45. ldap_sslinit = NULL;
  46. if ( m_hDll )
  47. {
  48. ldap_open = (LDAP_OPEN *)GetProcAddress(m_hDll,"ldap_openW");
  49. ldap_parse_result = (LDAP_PARSE_RESULT *)GetProcAddress(m_hDll,"ldap_parse_resultW");
  50. ldap_parse_page_control = (LDAP_PARSE_PAGE_CONTROL*)GetProcAddress(m_hDll,"ldap_parse_page_controlW");
  51. ldap_controls_free = (LDAP_CONTROLS_FREE*)GetProcAddress(m_hDll,"ldap_controls_freeW");
  52. ber_bvfree = (BER_BVFREE*)GetProcAddress(m_hDll,"ber_bvfree");
  53. ldap_first_entry = (LDAP_FIRST_ENTRY*)GetProcAddress(m_hDll,"ldap_first_entry");
  54. ldap_next_entry = (LDAP_NEXT_ENTRY*)GetProcAddress(m_hDll,"ldap_next_entry");
  55. ldap_value_free = (LDAP_VALUE_FREE*)GetProcAddress(m_hDll,"ldap_value_freeW");
  56. ldap_get_values = (LDAP_GET_VALUES*)GetProcAddress(m_hDll,"ldap_get_valuesW");
  57. ldap_create_page_control = (LDAP_CREATE_PAGE_CONTROL*)GetProcAddress(m_hDll,"ldap_create_page_controlW");
  58. ldap_search_ext_s = (LDAP_SEARCH_EXT_S*)GetProcAddress(m_hDll,"ldap_search_ext_sW");
  59. ldap_count_entries = (LDAP_COUNT_ENTRIES*)GetProcAddress(m_hDll,"ldap_count_entries");
  60. ldap_msgfree = (LDAP_MSGFREE*)GetProcAddress(m_hDll,"ldap_msgfree");
  61. ldap_modify_s = (LDAP_MODIFY_S*)GetProcAddress(m_hDll,"ldap_modify_sW");
  62. LdapGetLastError = (LDAPGETLASTERROR*)GetProcAddress(m_hDll,"LdapGetLastError");
  63. ldap_bind_sW = (LDAP_BIND*)GetProcAddress(m_hDll,"ldap_bind_sW");
  64. ldap_simple_bind_sW = (LDAP_SIMPLE_BIND*)GetProcAddress(m_hDll,"ldap_simple_bind_sW");
  65. ldap_unbind = (LDAP_UNBIND*)GetProcAddress(m_hDll,"ldap_unbind");
  66. ldap_connect = (LDAP_CONNECT *)GetProcAddress(m_hDll,"ldap_connect");
  67. ldap_get_option = (LDAP_GET_OPTION*)GetProcAddress(m_hDll,"ldap_get_option");
  68. ldap_set_option = (LDAP_SET_OPTION*)GetProcAddress(m_hDll,"ldap_set_option");
  69. LdapMapErrorToWin32 = (LDAPMAPERRORTOWIN32*)GetProcAddress(m_hDll,"LdapMapErrorToWin32");
  70. ldap_init = (LDAP_INIT *)GetProcAddress(m_hDll,"ldap_initW");
  71. ldap_sslinit = (LDAP_SSLINIT *)GetProcAddress(m_hDll,"ldap_sslinitW");
  72. }
  73. }
  74. CLdapConnection::~CLdapConnection()
  75. {
  76. Close();
  77. if ( m_hDll )
  78. {
  79. FreeLibrary(m_hDll);
  80. ldap_open = NULL;
  81. ldap_parse_result = NULL;
  82. ldap_parse_page_control = NULL;
  83. ldap_controls_free = NULL;
  84. ber_bvfree = NULL;
  85. ldap_first_entry = NULL;
  86. ldap_next_entry = NULL;
  87. ldap_value_free = NULL;
  88. ldap_get_values = NULL;
  89. ldap_create_page_control = NULL;
  90. ldap_search_ext_s = NULL;
  91. ldap_count_entries = NULL;
  92. ldap_msgfree = NULL;
  93. ldap_modify_s = NULL;
  94. LdapGetLastError = NULL;
  95. ldap_bind_sW = NULL;
  96. ldap_unbind = NULL;
  97. ldap_simple_bind_sW = NULL;
  98. ldap_connect = NULL;
  99. LdapMapErrorToWin32 = NULL;
  100. ldap_init = NULL;
  101. ldap_sslinit = NULL;
  102. }
  103. }
  104. void CLdapConnection::SetCredentials(WCHAR const * domain, WCHAR const * user, WCHAR const * pwd)
  105. {
  106. WCHAR creds[LEN_Account + LEN_Domain + 6];
  107. // set the following for the simple bind
  108. swprintf(creds,L"cn=%ls,cn=%ls",(WCHAR*)user,(WCHAR*)domain);
  109. safecopy(m_credentials,creds);
  110. safecopy(m_password,pwd);
  111. // set the following for using SSPI
  112. m_creds.User = const_cast<WCHAR*>(user);
  113. m_creds.UserLength = (user == NULL) ? 0 : wcslen(user);
  114. m_creds.Password = NULL;
  115. m_creds.PasswordLength = 0;
  116. m_creds.Domain = const_cast<WCHAR*>(domain);
  117. m_creds.DomainLength = (domain == NULL) ? 0 : wcslen(domain);
  118. m_creds.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  119. }
  120. DWORD CLdapConnection::Connect(WCHAR const * server, ULONG port = LDAP_PORT)
  121. {
  122. DWORD rc = 0;
  123. safecopy(m_exchServer,server);
  124. // m_LD = CLdapConnection::ldap_open(m_exchServer,LDAP_SSL_PORT);
  125. // replace ldap_open(servername,..) with ldap_init and set LDAP_OPT_AREC_EXCLUSIVE
  126. // flag so that the following ldap calls (i.e. ldap_bind) will not need to
  127. // unnecessarily query for the domain controller
  128. if (m_LD)
  129. CLdapConnection::ldap_unbind(m_LD);
  130. m_LD = CLdapConnection::ldap_init(m_exchServer,port);
  131. if (!m_LD)
  132. {
  133. rc = CLdapConnection::LdapGetLastError();
  134. rc = CLdapConnection::LdapMapErrorToWin32(rc);
  135. }
  136. else
  137. {
  138. ULONG flags = 0;
  139. //set LDAP_OPT_AREC_EXCLUSIVE flag so that the following calls tp
  140. //ldap_open will not need to unnecessarily query for the domain controller
  141. flags = PtrToUlong(LDAP_OPT_ON);
  142. rc = ldap_set_option(m_LD, LDAP_OPT_AREC_EXCLUSIVE, &flags);
  143. if (!rc)
  144. {
  145. flags = LDAP_VERSION3;
  146. rc = ldap_set_option(m_LD,LDAP_OPT_VERSION, &flags);
  147. }
  148. if (!rc)
  149. rc = ldap_connect(m_LD,NULL);
  150. if (!rc)
  151. {
  152. if (m_creds.User != NULL)
  153. {
  154. //
  155. // Retrieve specified password from LSA secret. As credentials have been specified the
  156. // password is required therefore if unable to retrieve password an error is returned.
  157. //
  158. WCHAR szPassword[LEN_Password];
  159. rc = RetrievePassword(m_password, szPassword, sizeof(szPassword) / sizeof(szPassword[0]));
  160. if (rc == ERROR_SUCCESS)
  161. {
  162. m_creds.Password = szPassword;
  163. m_creds.PasswordLength = wcslen(szPassword);
  164. // use full credential and try only SSPI here and it will fall back on NTLM
  165. rc = CLdapConnection::ldap_bind_sW(m_LD,NULL,(PWCHAR)&m_creds,LDAP_AUTH_SSPI);
  166. if (rc)
  167. {
  168. rc = CLdapConnection::LdapMapErrorToWin32(rc);
  169. }
  170. m_creds.PasswordLength = 0;
  171. m_creds.Password = NULL;
  172. SecureZeroMemory(szPassword, sizeof(szPassword));
  173. }
  174. }
  175. else
  176. {
  177. // use NULL credential and try only SSPI here and it will fall back on NTLM
  178. rc = CLdapConnection::ldap_bind_sW(m_LD,NULL,NULL,LDAP_AUTH_SSPI);
  179. if (rc)
  180. {
  181. rc = CLdapConnection::LdapMapErrorToWin32(rc);
  182. }
  183. }
  184. }
  185. else
  186. {
  187. rc = CLdapConnection::LdapMapErrorToWin32(rc);
  188. }
  189. }
  190. return rc;
  191. }
  192. DWORD CLdapConnection::SSLConnect(WCHAR const * server, BOOL *sslEnabled, ULONG port)
  193. {
  194. DWORD rc = 0;
  195. safecopy(m_exchServer,server);
  196. *sslEnabled = FALSE;
  197. // m_LD = CLdapConnection::ldap_open(m_exchServer,LDAP_SSL_PORT);
  198. // replace ldap_open(servername,..) with ldap_init and set LDAP_OPT_AREC_EXCLUSIVE
  199. // flag so that the following ldap calls (i.e. ldap_bind) will not need to
  200. // unnecessarily query for the domain controller
  201. if (m_LD)
  202. CLdapConnection::ldap_unbind(m_LD);
  203. m_LD = CLdapConnection::ldap_sslinit(m_exchServer,port,1);
  204. if (!m_LD)
  205. {
  206. rc = CLdapConnection::LdapGetLastError();
  207. rc = CLdapConnection::LdapMapErrorToWin32(rc);
  208. }
  209. else
  210. {
  211. ULONG flags = 0;
  212. //set LDAP_OPT_AREC_EXCLUSIVE flag so that the following calls tp
  213. //ldap_open will not need to unnecessarily query for the domain controller
  214. flags = PtrToUlong(LDAP_OPT_ON);
  215. rc = ldap_set_option(m_LD, LDAP_OPT_AREC_EXCLUSIVE, (void*)&flags);
  216. if (!rc)
  217. {
  218. flags = LDAP_VERSION3;
  219. rc = ldap_set_option(m_LD,LDAP_OPT_VERSION,&flags);
  220. if (!rc)
  221. {
  222. // we need to check whether SSL is truly enabled
  223. rc = ldap_get_option(m_LD,LDAP_OPT_SSL,&flags);
  224. if (!rc && flags == 0)
  225. return rc;
  226. }
  227. }
  228. if (!rc)
  229. rc = ldap_connect(m_LD,NULL);
  230. if (!rc)
  231. {
  232. if (m_creds.User != NULL)
  233. {
  234. //
  235. // Retrieve specified password from LSA secret. As credentials have been specified the
  236. // password is required therefore if unable to retrieve password an error is returned.
  237. //
  238. WCHAR szPassword[LEN_Password];
  239. rc = RetrievePassword(m_password, szPassword, sizeof(szPassword) / sizeof(szPassword[0]));
  240. if (rc == ERROR_SUCCESS)
  241. {
  242. m_creds.Password = szPassword;
  243. m_creds.PasswordLength = wcslen(szPassword);
  244. // use full credential and try SSPI here and it will fall back on NTLM
  245. rc = CLdapConnection::ldap_bind_sW(m_LD,NULL,(PWCHAR)&m_creds,LDAP_AUTH_SSPI);
  246. if (rc)
  247. // it is Ok to use simple bind here since we're protected by SSL
  248. rc = CLdapConnection::ldap_simple_bind_sW(m_LD,m_credentials,szPassword);
  249. if (rc)
  250. {
  251. rc = CLdapConnection::LdapMapErrorToWin32(rc);
  252. }
  253. m_creds.PasswordLength = 0;
  254. m_creds.Password = NULL;
  255. SecureZeroMemory(szPassword, sizeof(szPassword));
  256. }
  257. }
  258. else
  259. {
  260. // use NULL credential and try only SSPI here and it will fall back on NTLM
  261. rc = CLdapConnection::ldap_bind_sW(m_LD,NULL,NULL,LDAP_AUTH_SSPI);
  262. if (rc)
  263. {
  264. rc = CLdapConnection::LdapMapErrorToWin32(rc);
  265. }
  266. }
  267. }
  268. else
  269. {
  270. rc = CLdapConnection::LdapMapErrorToWin32(rc);
  271. }
  272. }
  273. if (!rc)
  274. *sslEnabled = TRUE;
  275. return rc;
  276. }
  277. void CLdapConnection::Close()
  278. {
  279. if ( m_LD )
  280. {
  281. CLdapConnection::ldap_unbind(m_LD);
  282. m_LD = NULL;
  283. }
  284. }
  285. DWORD CLdapConnection::UpdateSimpleStringValue(WCHAR const * dn, WCHAR const * property, WCHAR const * value)
  286. {
  287. DWORD rc = ERROR_NOT_FOUND;
  288. if ( m_LD )
  289. {
  290. LDAPMod * mods[2];
  291. LDAPMod mod1;
  292. WCHAR * strVals[] = { const_cast<WCHAR*>(value),NULL };
  293. mods[0] = &mod1;
  294. mods[0]->mod_op = LDAP_MOD_REPLACE;
  295. mods[0]->mod_type = const_cast<WCHAR*>(property);
  296. mods[0]->mod_vals.modv_strvals = strVals;
  297. mods[1] = NULL;
  298. rc = CLdapConnection::ldap_modify_s(m_LD,const_cast<WCHAR*>(dn),mods);
  299. if ( rc )
  300. {
  301. rc = CLdapConnection::LdapMapErrorToWin32(rc);
  302. }
  303. }
  304. return rc;
  305. }
  306. // Helper function for SidToString - converts one BYTE of the SID into a string representation
  307. void
  308. CLdapConnection::AddByteToString(
  309. WCHAR ** string, // i/o- pointer to current location in string
  310. BYTE value // in - value (from SID) to add to the string
  311. )
  312. {
  313. WCHAR hi,
  314. lo;
  315. BYTE hiVal,
  316. loVal;
  317. loVal = value & 0x0F;
  318. hiVal = value & 0xF0;
  319. hiVal = hiVal >> 4;
  320. if ( hiVal < 10 )
  321. {
  322. hi=L'0' + hiVal;
  323. }
  324. else
  325. {
  326. hi=L'A' + ( hiVal - 10 );
  327. }
  328. if ( loVal < 10 )
  329. {
  330. lo=L'0' + loVal;
  331. }
  332. else
  333. {
  334. lo=L'A' + (loVal - 10 );
  335. }
  336. swprintf(*string,L"%c%c",hi,lo);
  337. *string+=2;
  338. }
  339. BYTE // ret- value for the digit, or 0 if value is not a valid hex digit
  340. CLdapConnection::HexValue(
  341. WCHAR value // in - character representing a hex digit
  342. )
  343. {
  344. BYTE val = 0;
  345. switch ( toupper((char)value) )
  346. {
  347. case L'1': val = 1; break;
  348. case L'2': val = 2; break;
  349. case L'3': val = 3; break;
  350. case L'4': val = 4; break;
  351. case L'5': val = 5; break;
  352. case L'6': val = 6; break;
  353. case L'7': val = 7; break;
  354. case L'8': val = 8; break;
  355. case L'9': val = 9; break;
  356. case L'A': val = 0xA; break;
  357. case L'B': val = 0xB; break;
  358. case L'C': val = 0xC; break;
  359. case L'D': val = 0xD; break;
  360. case L'E': val = 0xE; break;
  361. case L'F': val = 0xF; break;
  362. }
  363. return val;
  364. }
  365. BOOL // ret- 0=success, or ERROR_INSUFFICIENT_BUFFER
  366. CLdapConnection::BytesToString(
  367. BYTE * pBytes, // in - SID to represent as a string
  368. WCHAR * sidString, // out- buffer that will contain the
  369. DWORD numBytes // in - number of bytes in the buffer to copy
  370. )
  371. {
  372. BOOL bSuccess = TRUE;
  373. WCHAR * curr = sidString;
  374. // add each byte of the SID to the output string
  375. for ( int i = 0 ; i < (int)numBytes ; i++)
  376. {
  377. AddByteToString(&curr,pBytes[i]);
  378. }
  379. return bSuccess;
  380. }
  381. BOOL
  382. CLdapConnection::StringToBytes(
  383. WCHAR const * pString, // in - string representing the data
  384. BYTE * pBytes // out- binary representation of the data
  385. )
  386. {
  387. BOOL bSuccess = TRUE;
  388. int len = UStrLen(pString) / 2;
  389. for ( int i = 0 ; i < len ; i++, pString += 2 )
  390. {
  391. // each byte is represented by 2 characters
  392. WCHAR str[3];
  393. BYTE hi,lo;
  394. safecopy(str,pString);
  395. hi = HexValue(str[0]);
  396. lo = HexValue(str[1]);
  397. pBytes[i] = ((hi << 4)+lo);
  398. }
  399. return bSuccess;
  400. }
  401. CLdapEnum::~CLdapEnum()
  402. {
  403. if ( m_message )
  404. {
  405. m_connection.ldap_msgfree(m_message);
  406. m_message = NULL;
  407. }
  408. }
  409. DWORD
  410. CLdapEnum::Open(
  411. WCHAR const * query, // in - query to execute
  412. WCHAR const * basePoint, // in - basepoint for query
  413. short scope, // in - scope: 0=base only, 1=one level, 2=recursive
  414. long pageSize, // in - page size to use for large searches
  415. int numAttributes, // in - number of attributes to retrieve for each matching item
  416. WCHAR ** attrs // in - array of attribute names to retrieve for each matching item
  417. )
  418. {
  419. // open and bind before calling this function
  420. ULONG result;
  421. // PLDAPSearch searchBlock = NULL;
  422. PLDAPControl serverControls[2];
  423. // l_timeval timeout = { 1000,1000 };
  424. // ULONG totalCount = 0;
  425. berval cookie1 = { 0, NULL };
  426. // DWORD numRead = 0;
  427. if ( m_message )
  428. {
  429. m_connection.ldap_msgfree(m_message);
  430. m_message = NULL;
  431. }
  432. LDAP * ld = m_connection.GetHandle();
  433. safecopy(m_query,query);
  434. safecopy(m_basepoint,basePoint);
  435. m_scope = scope;
  436. m_pageSize = pageSize;
  437. m_nAttributes = numAttributes;
  438. m_AttrNames = attrs;
  439. result = m_connection.ldap_create_page_control(ld,
  440. pageSize,
  441. &cookie1,
  442. FALSE, // is critical
  443. &serverControls[0]
  444. );
  445. serverControls[1] = NULL;
  446. result = m_connection.ldap_search_ext_s(ld,
  447. m_basepoint,
  448. m_scope,
  449. m_query,
  450. m_AttrNames,
  451. FALSE,
  452. serverControls,
  453. NULL,
  454. NULL,
  455. 0,
  456. &m_message);
  457. if ( ! result )
  458. {
  459. m_nReturned = m_connection.ldap_count_entries(ld,m_message);
  460. m_nCurrent = 0;
  461. m_bOpen = TRUE;
  462. }
  463. return m_connection.LdapMapErrorToWin32(result);
  464. }
  465. DWORD
  466. CLdapEnum::Next(
  467. PWCHAR ** ppAttrs // out- array of values for the next matching item
  468. )
  469. {
  470. DWORD rc = 0;
  471. if ( ! m_bOpen )
  472. {
  473. rc = ERROR_NOT_FOUND;
  474. }
  475. else
  476. {
  477. if ( m_nReturned > m_nCurrent )
  478. {
  479. // return the next entry from the current page
  480. return GetNextEntry(ppAttrs);
  481. }
  482. else
  483. {
  484. // see if there are more pages of results to get
  485. rc = GetNextPage();
  486. if (! rc )
  487. {
  488. return GetNextEntry(ppAttrs);
  489. }
  490. }
  491. }
  492. return rc;
  493. }
  494. void CLdapEnum::FreeData(WCHAR ** values)
  495. {
  496. for ( int i = 0 ; m_AttrNames[i] ; i++ )
  497. {
  498. if ( values[i] )
  499. {
  500. delete [] values[i];
  501. values[i] = NULL;
  502. }
  503. }
  504. delete [] values;
  505. }
  506. DWORD
  507. CLdapEnum::GetNextEntry(
  508. PWCHAR ** ppAttrs
  509. )
  510. {
  511. DWORD rc = 0;
  512. WCHAR ** pValues = new PWCHAR[m_nAttributes+1];
  513. if (!pValues)
  514. return ERROR_NOT_ENOUGH_MEMORY;
  515. if ( m_nCurrent == 0 )
  516. {
  517. m_currMsg = m_connection.ldap_first_entry(m_connection.GetHandle(),m_message);
  518. }
  519. else
  520. {
  521. m_currMsg = m_connection.ldap_next_entry(m_connection.GetHandle(),m_currMsg);
  522. }
  523. if ( m_currMsg )
  524. {
  525. int curr;
  526. for ( curr = 0 ; m_AttrNames[curr] ; curr++ )
  527. {
  528. pValues[curr] = NULL;
  529. WCHAR ** allvals = m_connection.ldap_get_values(m_connection.GetHandle(),m_currMsg,m_AttrNames[curr] );
  530. if ( allvals )
  531. {
  532. try
  533. {
  534. pValues[curr] = new WCHAR[UStrLen(allvals[0])+1];
  535. }
  536. catch (...)
  537. {
  538. for (int j=0; j<curr; j++)
  539. {
  540. delete pValues[j];
  541. }
  542. delete pValues;
  543. throw;
  544. }
  545. if (!(pValues[curr]))
  546. {
  547. for (int j=0; j<curr; j++)
  548. {
  549. delete pValues[j];
  550. }
  551. delete pValues;
  552. return ERROR_NOT_ENOUGH_MEMORY;
  553. }
  554. UStrCpy(pValues[curr],allvals[0]);
  555. m_connection.ldap_value_free(allvals);
  556. allvals =NULL;
  557. }
  558. }
  559. }
  560. (*ppAttrs) = pValues;
  561. m_nCurrent++;
  562. return rc;
  563. }
  564. DWORD
  565. CLdapEnum::GetNextPage()
  566. {
  567. ULONG result = 0;
  568. LDAP * ld = m_connection.GetHandle();
  569. berval * currCookie = NULL;
  570. // berval * cookie2 = NULL;
  571. // WCHAR * matched = NULL;
  572. PLDAPControl * currControls = NULL;
  573. ULONG retcode = 0;
  574. // PLDAPControl * clientControls = NULL;
  575. // WCHAR * errMsg = NULL;
  576. PLDAPControl serverControls[2];
  577. // Get the server control from the message, and make a new control with the cookie from the server
  578. result = m_connection.ldap_parse_result(ld,m_message,&retcode,NULL,NULL,NULL,&currControls,FALSE);
  579. m_connection.ldap_msgfree(m_message);
  580. m_message = NULL;
  581. if ( ! result )
  582. {
  583. result = m_connection.ldap_parse_page_control(ld,currControls,&m_totalCount,&currCookie);
  584. // under Exchange 5.5, before SP 2, this will fail with LDAP_CONTROL_NOT_FOUND when there are
  585. // no more search results. With Exchange 5.5 SP 2, this succeeds, and gives us a cookie that will
  586. // cause us to start over at the beginning of the search results.
  587. }
  588. if ( ! result )
  589. {
  590. if ( currCookie->bv_len == 0 && currCookie->bv_val == 0 )
  591. {
  592. // under Exchange 5.5, SP 2, this means we're at the end of the results.
  593. // if we pass in this cookie again, we will start over at the beginning of the search results.
  594. result = LDAP_CONTROL_NOT_FOUND;
  595. }
  596. serverControls[0] = NULL;
  597. serverControls[1] = NULL;
  598. if ( ! result )
  599. {
  600. result = m_connection.ldap_create_page_control(ld,
  601. m_pageSize,
  602. currCookie,
  603. FALSE,
  604. serverControls);
  605. }
  606. m_connection.ldap_controls_free(currControls);
  607. currControls = NULL;
  608. m_connection.ber_bvfree(currCookie);
  609. currCookie = NULL;
  610. }
  611. // continue the search with the new cookie
  612. if ( ! result )
  613. {
  614. result = m_connection.ldap_search_ext_s(ld,
  615. m_basepoint,
  616. m_scope,
  617. m_query,
  618. m_AttrNames,
  619. FALSE,
  620. serverControls,
  621. NULL,
  622. NULL,
  623. 0,
  624. &m_message);
  625. if ( result && result != LDAP_CONTROL_NOT_FOUND )
  626. {
  627. // LDAP_CONTROL_NOT_FOUND means that we have reached the end of the search results
  628. // in Exchange 5.5, before SP 2 (the server doesn't return a page control when there
  629. // are no more pages, so we get LDAP_CONTROL_NOT_FOUND when we try to extract the page
  630. // control from the search results).
  631. }
  632. }
  633. if ( ! result )
  634. {
  635. m_nReturned = m_connection.ldap_count_entries(ld,m_message);
  636. m_nCurrent = 0;
  637. }
  638. return m_connection.LdapMapErrorToWin32(result);
  639. }
  640. void
  641. GetLDAPPort(
  642. DWORD * LDAPPort,
  643. DWORD * SSLPort
  644. )
  645. {
  646. TRegKey admtRegKey;
  647. DWORD rc;
  648. // assign the default values
  649. *LDAPPort = LDAP_PORT;
  650. *SSLPort = LDAP_SSL_PORT;
  651. // get ADMT key
  652. rc = admtRegKey.Open(GET_STRING(IDS_HKLM_DomainAdmin_Key),HKEY_LOCAL_MACHINE);
  653. if (rc == ERROR_SUCCESS)
  654. {
  655. DWORD portNumber;
  656. rc = admtRegKey.ValueGetDWORD(REGVAL_EXCHANGE_LDAP_PORT, &portNumber);
  657. if (rc == ERROR_SUCCESS)
  658. {
  659. *LDAPPort = portNumber;
  660. }
  661. else
  662. {
  663. err.MsgWrite(ErrW,
  664. DCT_MSG_UNABLE_TO_READ_EXCHANGE_LDAP_PORT_SSD,
  665. REGVAL_EXCHANGE_LDAP_PORT,
  666. GET_STRING(IDS_HKLM_DomainAdmin_Key),
  667. LDAP_PORT);
  668. }
  669. rc = admtRegKey.ValueGetDWORD(REGVAL_EXCHANGE_SSL_PORT, &portNumber);
  670. if (rc == ERROR_SUCCESS)
  671. {
  672. *SSLPort = portNumber;
  673. }
  674. else
  675. {
  676. err.MsgWrite(ErrW,
  677. DCT_MSG_UNABLE_TO_READ_EXCHANGE_SSL_PORT_SSD,
  678. REGVAL_EXCHANGE_SSL_PORT,
  679. GET_STRING(IDS_HKLM_DomainAdmin_Key),
  680. LDAP_SSL_PORT);
  681. }
  682. }
  683. else
  684. {
  685. err.MsgWrite(ErrW,
  686. DCT_MSG_UNABLE_TO_READ_EXCHANGE_LDAP_PORT_SSD,
  687. REGVAL_EXCHANGE_LDAP_PORT,
  688. GET_STRING(IDS_HKLM_DomainAdmin_Key),
  689. LDAP_PORT);
  690. err.MsgWrite(ErrW,
  691. DCT_MSG_UNABLE_TO_READ_EXCHANGE_SSL_PORT_SSD,
  692. REGVAL_EXCHANGE_SSL_PORT,
  693. GET_STRING(IDS_HKLM_DomainAdmin_Key),
  694. LDAP_SSL_PORT);
  695. }
  696. }