Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4623 lines
138 KiB

  1. /*++
  2. Copyright (c) 1998 - 2000 Microsoft Corporation
  3. Module Name:
  4. ldappx.cpp
  5. Abstract:
  6. Defines methods utilized by abstract data types used in LDAP portion of the H.323/LDAP proxy.
  7. LDAP Proxy is designed as an addition to H.323 proxy. The main purpose of the
  8. LDAP proxy is to maintain LDAP Address Translation Table, which is used to map
  9. aliases of H.323 endpoints to their IP addresses. The proxy adds an entry when it
  10. intercepts an LDAP PDU from a client to directory server, and the PDU matches all
  11. predefined criteria.
  12. Author(s): ArlieD, IlyaK 14-Jul-1999
  13. Revision History:
  14. 07/14/1999 File creation Arlie Davis (ArlieD)
  15. 08/20/1999 Improvement of processing of LDAP Ilya Kleyman (IlyaK)
  16. LDAP SearchRequests
  17. 12/20/1999 Added prediction of receive sizes in Ilya Kleyman (IlyaK)
  18. non-interpretative data transfer mode
  19. 02/20/2000 Added expiration policy of the entries Ilya Kleyman (IlyaK)
  20. in LDAP Address Translation Table
  21. 03/12/2000 Added support for multiple private and Ilya Kleyman (IlyaK)
  22. multiple public interface for RRAS
  23. --*/
  24. ///////////////////////////////////////////////////////////////////////////////
  25. // //
  26. // Include files //
  27. // //
  28. ///////////////////////////////////////////////////////////////////////////////
  29. #include "stdafx.h"
  30. #include "ber.h"
  31. ///////////////////////////////////////////////////////////////////////////////
  32. // //
  33. // Constants //
  34. // //
  35. ///////////////////////////////////////////////////////////////////////////////
  36. static const ANSI_STRING LdapText_C = ANSI_STRING_INIT("c");
  37. static const ANSI_STRING LdapText_CN = ANSI_STRING_INIT("cn");
  38. static const ANSI_STRING LdapText_ObjectClass = ANSI_STRING_INIT("objectClass");
  39. static const ANSI_STRING LdapText_O = ANSI_STRING_INIT("o");
  40. static const ANSI_STRING LdapText_OU = ANSI_STRING_INIT("ou");
  41. static const ANSI_STRING LdapText_RTPerson = ANSI_STRING_INIT("RTPerson");
  42. static const ANSI_STRING LdapText_Attribute_sipaddress = ANSI_STRING_INIT("sipaddress");
  43. static const ANSI_STRING LdapText_Attribute_ipAddress = ANSI_STRING_INIT("ipAddress");
  44. static const ANSI_STRING LdapText_Attribute_sttl = ANSI_STRING_INIT("sttl");
  45. static const ANSI_STRING LdapText_Attribute_comment = ANSI_STRING_INIT("comment");
  46. static const ANSI_STRING LdapText_Modify_EntryTTL = ANSI_STRING_INIT("EntryTTL");
  47. static const ANSI_STRING LdapText_GeneratedByTAPI = ANSI_STRING_INIT("Generated by TAPI3");
  48. static const ANSI_STRING LdapText_ModifiedByICS = ANSI_STRING_INIT("Made possible by ICS");
  49. static const ANSI_STRING LdapText_TableSizeExceededMessage = ANSI_STRING_INIT("Resources on proxy used up.");
  50. ///////////////////////////////////////////////////////////////////////////////
  51. // //
  52. // Global Variables //
  53. // //
  54. ///////////////////////////////////////////////////////////////////////////////
  55. SYNC_COUNTER LdapSyncCounter;
  56. LDAP_CONNECTION_ARRAY LdapConnectionArray;
  57. LDAP_TRANSLATION_TABLE LdapTranslationTable;
  58. LDAP_CODER LdapCoder;
  59. LDAP_ACCEPT LdapAccept;
  60. SOCKADDR_IN LdapListenSocketAddress;
  61. DWORD EnableLocalH323Routing;
  62. // utility functions ------------------------------------------------------------------
  63. #if DBG
  64. static BOOL BerDumpStopFn (VOID)
  65. {
  66. return FALSE;
  67. }
  68. static void BerDumpOutputFn (char * Format, ...)
  69. {
  70. if (DebugLevel > 0) {
  71. va_list Va;
  72. CHAR Text [0x200];
  73. va_start (Va, Format);
  74. _vsnprintf (Text, 0x200, Format, Va);
  75. va_end (Va);
  76. OutputDebugStringA (Text);
  77. }
  78. }
  79. static void BerDump (IN LPBYTE Data, IN DWORD Length)
  80. {
  81. ber_decode (BerDumpOutputFn, BerDumpStopFn, Data,
  82. 0, // DECODE_NEST_OCTET_STRINGS,
  83. 0, 0, Length, 0);
  84. }
  85. #endif // DBG
  86. // LdapQueryTable queries the LDAP translation table for a given alias.
  87. // The alias was one that was previously registered by a LDAP endpoint.
  88. // We do not care about the type of the alias (h323_ID vs emailID, etc.) --
  89. // the semantics of the alias type are left to the Q.931 code.
  90. //
  91. // returns S_OK on success
  92. // returns S_FALSE if no entry was found
  93. // returns an error code if an actual error occurred.
  94. HRESULT LdapQueryTableByAlias (
  95. IN ANSI_STRING * Alias,
  96. OUT DWORD * ReturnClientAddress) // host order
  97. {
  98. HRESULT Result;
  99. IN_ADDR Address;
  100. assert (Alias);
  101. assert (ReturnClientAddress);
  102. Result = LdapTranslationTable.QueryTableByAlias (Alias, &Address);
  103. if (Result == S_OK) {
  104. *ReturnClientAddress = ntohl (Address.s_addr);
  105. return Result;
  106. }
  107. Result = LdapTranslationTable.QueryTableByCN (Alias, &Address);
  108. if (Result == S_OK) {
  109. *ReturnClientAddress = ntohl (Address.s_addr);
  110. return Result;
  111. }
  112. return Result;
  113. }
  114. HRESULT LdapQueryTableByAliasServer (
  115. IN ANSI_STRING * Alias,
  116. IN SOCKADDR_IN * ServerAddress,
  117. OUT DWORD * ReturnClientAddress) // host order
  118. {
  119. HRESULT Result;
  120. IN_ADDR Address;
  121. assert (Alias);
  122. assert (ReturnClientAddress);
  123. Result = LdapTranslationTable.QueryTableByAliasServer (Alias, ServerAddress, &Address);
  124. if (Result == S_OK) {
  125. *ReturnClientAddress = ntohl (Address.s_addr);
  126. return Result;
  127. }
  128. Result = LdapTranslationTable.QueryTableByCNServer (Alias, ServerAddress, &Address);
  129. if (Result == S_OK) {
  130. *ReturnClientAddress = ntohl (Address.s_addr);
  131. return Result;
  132. }
  133. return Result;
  134. }
  135. #if DBG
  136. void LdapPrintTable (void) {
  137. LdapTranslationTable.PrintTable ();
  138. }
  139. #endif // DBG
  140. static DWORD LdapDeterminePacketBoundary (
  141. IN LDAP_BUFFER * Buffer,
  142. IN DWORD PacketOffset,
  143. OUT DWORD * NextPacketOffset, // Points to the beginning of next packet only if function returns ERROR_SUCCESS
  144. OUT DWORD * NextReceiveSize) // Is only meaningful when function returns any value other than ERROR_SUCCESS
  145. {
  146. DWORD PayloadLength;
  147. DWORD ASNHeaderLength = ASN_MIN_HEADER_LEN;
  148. DWORD PacketSize;
  149. DWORD ByteIndex;
  150. DWORD Length;
  151. LPBYTE Data;
  152. assert (Buffer);
  153. assert (Buffer -> Data.Data);
  154. Length = Buffer -> Data.Length - PacketOffset;
  155. Data = Buffer -> Data.Data;
  156. // Pick reasonable default for the size of
  157. // next receive request. Will be changed if necessary
  158. *NextReceiveSize = LDAP_BUFFER_RECEIVE_SIZE;
  159. if (Length != 0) {
  160. if (Data [PacketOffset] == ASN_SEQUENCE_TAG) {
  161. if (Length >= ASN_MIN_HEADER_LEN) {
  162. if (Data [PacketOffset + 1] & ASN_LONG_HEADER_BIT) {
  163. // Long (more than ASN_MIN_HEADER_LEN bytes) ASN header
  164. // Size of the payload length field is indicated in the
  165. // second nybble of second byte
  166. ASNHeaderLength += Data [PacketOffset + 1] & ~ASN_LONG_HEADER_BIT;
  167. // This is where the limit on payload length is established.
  168. // The test below assures it won't be greater than 2 ^ sizeof (DWORD) (4 GBytes)
  169. if (ASNHeaderLength <= ASN_MIN_HEADER_LEN + sizeof (DWORD)) {
  170. if (Length >= ASNHeaderLength) {
  171. PayloadLength = 0;
  172. for (ByteIndex = ASN_MIN_HEADER_LEN;
  173. ByteIndex < ASNHeaderLength;
  174. ByteIndex++) {
  175. PayloadLength *= 1 << CHAR_BIT;
  176. PayloadLength += (DWORD) Data [PacketOffset + ByteIndex];
  177. }
  178. } else {
  179. // Not enough data to even read the ASN header
  180. return ERROR_MORE_DATA;
  181. }
  182. } else {
  183. DebugF (_T("LDAP: Payload size field (%d bytes) is too big.\n"), ASNHeaderLength - ASN_MIN_HEADER_LEN);
  184. return ERROR_INVALID_DATA;
  185. }
  186. } else {
  187. // Short (Exactly ASN_MIN_HEADER_LEN bytes) ASN header
  188. // Payload length is indicated in the second byte
  189. PayloadLength = (DWORD) Data [PacketOffset + 1];
  190. }
  191. PacketSize = ASNHeaderLength + PayloadLength;
  192. if (Length >= PacketSize) {
  193. *NextPacketOffset = PacketOffset + PacketSize;
  194. return ERROR_SUCCESS;
  195. } else {
  196. *NextReceiveSize = PacketSize - Length;
  197. }
  198. }
  199. } else {
  200. Debug (_T("LDAP: Failed to find ASN sequence tag.\n"));
  201. return ERROR_INVALID_DATA;
  202. }
  203. }
  204. return ERROR_MORE_DATA;
  205. }
  206. static BOOL FindChar (
  207. IN ANSI_STRING * String,
  208. IN CHAR Char,
  209. OUT USHORT * ReturnIndex)
  210. {
  211. LPSTR Pos;
  212. LPSTR End;
  213. assert (String);
  214. assert (ReturnIndex);
  215. Pos = String -> Buffer;
  216. End = String -> Buffer + String -> Length / sizeof (CHAR);
  217. for (; Pos < End; Pos++) {
  218. if (*Pos == Char) {
  219. *ReturnIndex = (USHORT) (Pos - String -> Buffer);
  220. return TRUE;
  221. }
  222. }
  223. return FALSE;
  224. }
  225. static void ParseDirectoryPathElement (
  226. IN ANSI_STRING * Element,
  227. IN OUT LDAP_PATH_ELEMENTS * PathElements)
  228. {
  229. ANSI_STRING Tag;
  230. ANSI_STRING Value;
  231. USHORT Index;
  232. if (FindChar (Element, LDAP_PATH_EQUAL_CHAR, &Index)) {
  233. assert (Index * sizeof (CHAR) < Element -> Length);
  234. Tag.Buffer = Element -> Buffer;
  235. Tag.Length = Index * sizeof (CHAR);
  236. Index++; // step over separator
  237. Value.Buffer = Element -> Buffer + Index;
  238. Value.Length = Element -> Length - Index * sizeof (CHAR);
  239. if (RtlEqualStringConst (&Tag, &LdapText_C, TRUE))
  240. PathElements -> C = Value;
  241. else if (RtlEqualStringConst (&Tag, &LdapText_CN, TRUE))
  242. PathElements -> CN = Value;
  243. else if (RtlEqualStringConst (&Tag, &LdapText_ObjectClass, TRUE))
  244. PathElements -> ObjectClass = Value;
  245. else if (RtlEqualStringConst (&Tag, &LdapText_O, TRUE))
  246. PathElements -> O = Value;
  247. }
  248. }
  249. static void ParseDirectoryPath (
  250. IN ANSI_STRING * DirectoryPath,
  251. OUT LDAP_PATH_ELEMENTS * ReturnData)
  252. {
  253. ANSI_STRING SubString;
  254. USHORT Index;
  255. ANSI_STRING Element;
  256. assert (DirectoryPath);
  257. assert (ReturnData);
  258. assert (DirectoryPath -> Buffer);
  259. ZeroMemory (ReturnData, sizeof (LDAP_PATH_ELEMENTS));
  260. SubString = *DirectoryPath;
  261. while (FindChar (&SubString, LDAP_PATH_SEP_CHAR, &Index)) {
  262. assert (Index * sizeof (CHAR) < SubString.Length);
  263. Element.Buffer = SubString.Buffer;
  264. Element.Length = Index * sizeof (CHAR);
  265. Index++; // step over separator
  266. SubString.Buffer += Index;
  267. SubString.Length -= Index * sizeof (CHAR);
  268. ParseDirectoryPathElement (&Element, ReturnData);
  269. }
  270. ParseDirectoryPathElement (&SubString, ReturnData);
  271. }
  272. static void ParseObjectNameElement (
  273. IN ANSI_STRING * Element,
  274. IN OUT LDAP_OBJECT_NAME_ELEMENTS * ObjectNameElements)
  275. {
  276. ANSI_STRING Tag;
  277. ANSI_STRING Value;
  278. USHORT Index;
  279. if (FindChar (Element, LDAP_PATH_EQUAL_CHAR, &Index)) {
  280. assert (Index * sizeof (CHAR) < Element -> Length);
  281. Tag.Buffer = Element -> Buffer;
  282. Tag.Length = Index * sizeof (CHAR);
  283. Index++; // step over separator
  284. Value.Buffer = Element -> Buffer + Index;
  285. Value.Length = Element -> Length - Index * sizeof (CHAR);
  286. if (RtlEqualStringConst (&Tag, &LdapText_CN, TRUE))
  287. ObjectNameElements -> CN = Value;
  288. else if (RtlEqualStringConst (&Tag, &LdapText_O, TRUE))
  289. ObjectNameElements -> O = Value;
  290. else if (RtlEqualStringConst (&Tag, &LdapText_OU, TRUE))
  291. ObjectNameElements -> OU = Value;
  292. }
  293. }
  294. static void ParseObjectName (
  295. IN ANSI_STRING * ObjectName,
  296. OUT LDAP_OBJECT_NAME_ELEMENTS * ReturnData)
  297. {
  298. ANSI_STRING SubString;
  299. USHORT Index;
  300. ANSI_STRING Element;
  301. assert (ObjectName);
  302. assert (ReturnData);
  303. assert (ObjectName -> Buffer);
  304. ZeroMemory (ReturnData, sizeof (LDAP_OBJECT_NAME_ELEMENTS));
  305. SubString = *ObjectName;
  306. while (FindChar (&SubString, LDAP_PATH_SEP_CHAR, &Index)) {
  307. assert (Index * sizeof (CHAR) < SubString.Length);
  308. Element.Buffer = SubString.Buffer;
  309. Element.Length = Index * sizeof (CHAR);
  310. Index++; // step over separator
  311. SubString.Buffer += Index;
  312. SubString.Length -= Index * sizeof (CHAR);
  313. ParseObjectNameElement (&Element, ReturnData);
  314. }
  315. ParseObjectNameElement (&SubString, ReturnData);
  316. }
  317. // LDAP_TRANSLATION_ENTRY ------------------------------------------------
  318. HRESULT
  319. LDAP_TRANSLATION_ENTRY::IsRegisteredViaInterface (
  320. IN DWORD InterfaceAddress, // host order
  321. OUT BOOL *Result
  322. )
  323. /*++
  324. Routine Description:
  325. Determines whether the entry is registered via the
  326. interface specified
  327. Arguments:
  328. InterfaceAddress - address of the interface for which
  329. the determination is to be made.
  330. Result (out) - TRUE if entry was registered via the interface
  331. FALSE if entry was not registered via the interface
  332. Return Values:
  333. TRUE - if determination succeeded
  334. FALSE - if determination failed
  335. Notes:
  336. --*/
  337. {
  338. DWORD BestInterfaceAddress;
  339. ULONG Error;
  340. Error = GetBestInterfaceAddress (ntohl (ClientAddress.s_addr), &BestInterfaceAddress);
  341. *Result = FALSE;
  342. if (ERROR_SUCCESS == Error) {
  343. *Result = (BestInterfaceAddress == InterfaceAddress);
  344. }
  345. return HRESULT_FROM_WIN32 (Error);
  346. }
  347. // LDAP_TRANSLATION_TABLE ------------------------------------------------
  348. LDAP_TRANSLATION_TABLE::LDAP_TRANSLATION_TABLE (void)
  349. {
  350. IsEnabled = FALSE;
  351. GarbageCollectorTimerHandle = NULL;
  352. }
  353. LDAP_TRANSLATION_TABLE::~LDAP_TRANSLATION_TABLE (void)
  354. {
  355. assert (!IsEnabled);
  356. assert (Array.Length == 0);
  357. }
  358. void LDAP_TRANSLATION_TABLE::Stop (void)
  359. {
  360. HRESULT Result;
  361. Lock();
  362. IsEnabled = FALSE;
  363. if (GarbageCollectorTimerHandle) {
  364. if (DeleteTimerQueueTimer(NATH323_TIMER_QUEUE,
  365. GarbageCollectorTimerHandle,
  366. INVALID_HANDLE_VALUE))
  367. {
  368. DebugF (_T("LDAP: Garbage collection is deactivated.\n"));
  369. }
  370. else {
  371. Result = GetLastError ();
  372. DebugError (Result, _T("LDAP: Could not deactivate garbage collection.\n"));
  373. }
  374. GarbageCollectorTimerHandle = NULL;
  375. }
  376. Array.Free();
  377. Unlock ();
  378. }
  379. HRESULT LDAP_TRANSLATION_TABLE::Start (void)
  380. {
  381. HRESULT Result;
  382. Lock ();
  383. assert (!GarbageCollectorTimerHandle);
  384. if (CreateTimerQueueTimer(&GarbageCollectorTimerHandle,
  385. NATH323_TIMER_QUEUE,
  386. GarbageCollectorCallback,
  387. this,
  388. LDAP_TRANSLATION_TABLE_GARBAGE_COLLECTION_PERIOD,
  389. LDAP_TRANSLATION_TABLE_GARBAGE_COLLECTION_PERIOD, // periodic timer
  390. WT_EXECUTEINIOTHREAD)) {
  391. DebugF (_T("LDAP: Successfully activated garbage collection.\n"));
  392. IsEnabled = TRUE;
  393. Result = S_OK;
  394. }
  395. else {
  396. Result = GetLastError ();
  397. DebugLastError (_T("LDAP: Failed to activate garbage collection.\n"));
  398. }
  399. Unlock ();
  400. return Result;
  401. }
  402. // static
  403. void LDAP_TRANSLATION_TABLE::GarbageCollectorCallback (
  404. PVOID Context,
  405. BOOLEAN TimerOrWaitFired)
  406. {
  407. LDAP_TRANSLATION_TABLE * Table;
  408. Table = (LDAP_TRANSLATION_TABLE *) Context;
  409. Table -> RemoveOldEntries ();
  410. }
  411. HRESULT LDAP_TRANSLATION_TABLE::RefreshEntry (
  412. IN ANSI_STRING * Alias,
  413. IN ANSI_STRING * DirectoryPath,
  414. IN IN_ADDR ClientAddress,
  415. IN SOCKADDR_IN * ServerAddress,
  416. IN DWORD TimeToLive) // in seconds
  417. {
  418. DebugF (_T("LDAP: Refreshing local entry for (%.*S) @ %08X:%04X.\n"),
  419. ANSI_STRING_PRINTF (Alias),
  420. SOCKADDR_IN_PRINTF (ServerAddress));
  421. return InsertEntry (Alias, DirectoryPath, ClientAddress, ServerAddress, TimeToLive);
  422. }
  423. void LDAP_TRANSLATION_TABLE::RemoveOldEntries (void)
  424. {
  425. DWORD CurrentTime;
  426. DWORD Index;
  427. Lock ();
  428. if (IsEnabled) {
  429. CurrentTime = GetTickCount () / 1000;
  430. DebugF (_T("LDAP: Garbage collection commenced at %d.\n"), CurrentTime);
  431. Index = 0;
  432. while (Index < Array.Length) {
  433. if (CurrentTime > Array [Index].TimeStamp) {
  434. DebugF (_T("LDAP: Expiring entry @%d, alias -- (%.*S) from translation table.\n"),
  435. Index, ANSI_STRING_PRINTF (&Array [Index].Alias));
  436. Array[Index].FreeContents ();
  437. Array.DeleteAtPos (Index);
  438. InterfaceArray.StopQ931ReceiveRedirects ();
  439. } else {
  440. Index++;
  441. }
  442. }
  443. DebugF (_T("LDAP: Garbage collection completed.\n"));
  444. }
  445. Unlock ();
  446. }
  447. HRESULT LDAP_TRANSLATION_TABLE::QueryTableByAlias (
  448. IN ANSI_STRING * Alias,
  449. OUT IN_ADDR * ReturnClientAddress)
  450. {
  451. LDAP_TRANSLATION_ENTRY * Pos;
  452. LDAP_TRANSLATION_ENTRY * End;
  453. DWORD Index;
  454. HRESULT Result;
  455. assert (Alias);
  456. assert (ReturnClientAddress);
  457. Lock();
  458. if (IsEnabled) {
  459. Result = S_FALSE;
  460. Array.GetExtents (&Pos, &End);
  461. for (; Pos < End; Pos++) {
  462. if (RtlEqualStringConst (&Pos -> Alias, Alias, TRUE)) {
  463. *ReturnClientAddress = Pos -> ClientAddress;
  464. Result = S_OK;
  465. break;
  466. }
  467. }
  468. }
  469. else {
  470. Result = S_FALSE;
  471. }
  472. Unlock();
  473. return Result;
  474. }
  475. HRESULT LDAP_TRANSLATION_TABLE::QueryTableByCN (
  476. IN ANSI_STRING * CN,
  477. OUT IN_ADDR * ReturnClientAddress)
  478. {
  479. LDAP_TRANSLATION_ENTRY * Pos;
  480. LDAP_TRANSLATION_ENTRY * End;
  481. HRESULT Result;
  482. assert (CN);
  483. assert (ReturnClientAddress);
  484. Lock();
  485. if (IsEnabled) {
  486. Result = S_FALSE;
  487. Array.GetExtents (&Pos, &End);
  488. for (; Pos < End; Pos++) {
  489. if (RtlEqualStringConst (&Pos -> CN, CN, TRUE)) {
  490. *ReturnClientAddress = Pos -> ClientAddress;
  491. Result = S_OK;
  492. break;
  493. }
  494. }
  495. }
  496. else {
  497. Result = S_FALSE;
  498. }
  499. Unlock();
  500. return Result;
  501. }
  502. HRESULT LDAP_TRANSLATION_TABLE::QueryTableByAliasServer (
  503. IN ANSI_STRING * Alias,
  504. IN SOCKADDR_IN * ServerAddress,
  505. OUT IN_ADDR * ReturnClientAddress)
  506. {
  507. LDAP_TRANSLATION_ENTRY * Pos;
  508. LDAP_TRANSLATION_ENTRY * End;
  509. DWORD Index;
  510. HRESULT Result;
  511. BOOL ServerIsSame;
  512. BOOL AliasIsSame;
  513. assert (Alias);
  514. assert (ServerAddress);
  515. assert (ReturnClientAddress);
  516. Lock();
  517. if (IsEnabled) {
  518. Result = S_FALSE;
  519. Array.GetExtents (&Pos, &End);
  520. for (; Pos < End; Pos++) {
  521. AliasIsSame = RtlEqualStringConst (&Pos -> Alias, Alias, TRUE);
  522. ServerIsSame = (ServerAddress -> sin_addr.s_addr == Pos -> ServerAddress.sin_addr.s_addr) // addresses are literally equal
  523. ||
  524. ( ::NhIsLocalAddress (ServerAddress -> sin_addr.s_addr)
  525. && ::NhIsLocalAddress (Pos -> ServerAddress.sin_addr.s_addr)); // two addresses of the local machine
  526. if (AliasIsSame && ServerIsSame) {
  527. *ReturnClientAddress = Pos -> ClientAddress;
  528. Result = S_OK;
  529. break;
  530. }
  531. }
  532. }
  533. else {
  534. Result = S_FALSE;
  535. }
  536. Unlock();
  537. return Result;
  538. }
  539. HRESULT LDAP_TRANSLATION_TABLE::QueryTableByCNServer (
  540. IN ANSI_STRING * CN,
  541. IN SOCKADDR_IN * ServerAddress,
  542. OUT IN_ADDR * ReturnClientAddress)
  543. {
  544. LDAP_TRANSLATION_ENTRY * Pos;
  545. LDAP_TRANSLATION_ENTRY * End;
  546. HRESULT Result;
  547. BOOL ServerIsSame;
  548. BOOL CN_IsSame;
  549. assert (CN);
  550. assert (ServerAddress);
  551. assert (ReturnClientAddress);
  552. Lock();
  553. if (IsEnabled) {
  554. Result = S_FALSE;
  555. Array.GetExtents (&Pos, &End);
  556. for (; Pos < End; Pos++) {
  557. CN_IsSame = RtlEqualStringConst (&Pos -> CN, CN, TRUE);
  558. ServerIsSame = (ServerAddress -> sin_addr.s_addr == Pos -> ServerAddress.sin_addr.s_addr) // addresses are literally equal
  559. ||
  560. ( ::NhIsLocalAddress (ServerAddress -> sin_addr.s_addr)
  561. && ::NhIsLocalAddress (Pos -> ServerAddress.sin_addr.s_addr)); // two addresses of the local machine
  562. if (CN_IsSame && ServerIsSame) {
  563. *ReturnClientAddress = Pos -> ClientAddress;
  564. Result = S_OK;
  565. break;
  566. }
  567. }
  568. }
  569. else {
  570. Result = S_FALSE;
  571. }
  572. Unlock();
  573. return Result;
  574. }
  575. #if DBG
  576. void LDAP_TRANSLATION_TABLE::PrintTable (void)
  577. {
  578. LDAP_TRANSLATION_ENTRY * Pos;
  579. LDAP_TRANSLATION_ENTRY * End;
  580. DebugF (_T("LDAP: Printing out Address Translation Table.\n"));
  581. Lock();
  582. if (IsEnabled) {
  583. Array.GetExtents (&Pos, &End);
  584. DebugF (_T("\n"));
  585. for (; Pos < End; Pos++) {
  586. DebugF (_T("\tEntry at %x:\n"), Pos);
  587. DebugF (_T ("\t\tAlias - %.*S\n"),
  588. ANSI_STRING_PRINTF (&Pos -> Alias));
  589. DebugF (_T ("\t\tDirectoryPath - %.*S\n"),
  590. ANSI_STRING_PRINTF (&Pos -> DirectoryPath));
  591. DebugF (_T ("\t\tCN - %.*S\n"),
  592. ANSI_STRING_PRINTF (&Pos -> CN));
  593. DebugF (_T("\t\tClientAddress - %x\n"), ntohl(Pos->ClientAddress.s_addr));
  594. DebugF (_T("\t\tServerAddress - %x:%x\n"),
  595. SOCKADDR_IN_PRINTF (&Pos -> ServerAddress));
  596. DebugF (_T("\t\tTimeStamp - %u\n"), Pos -> TimeStamp);
  597. }
  598. DebugF (_T("\n"));
  599. }
  600. Unlock();
  601. }
  602. #endif
  603. HRESULT LDAP_TRANSLATION_TABLE::InsertEntry (
  604. IN ANSI_STRING * Alias,
  605. IN ANSI_STRING * DirectoryPath,
  606. IN IN_ADDR ClientAddress,
  607. IN SOCKADDR_IN * ServerAddress,
  608. IN DWORD TimeToLive) // in seconds
  609. {
  610. HRESULT Result;
  611. assert (Alias);
  612. assert (Alias -> Buffer);
  613. assert (DirectoryPath);
  614. assert (DirectoryPath -> Buffer);
  615. assert (ServerAddress);
  616. Lock();
  617. Result = InsertEntryLocked (Alias, DirectoryPath, ClientAddress, ServerAddress, TimeToLive);
  618. Unlock();
  619. #if DBG
  620. if (DebugLevel > 1)
  621. {
  622. LdapPrintTable ();
  623. }
  624. #endif // DBG
  625. return Result;
  626. }
  627. HRESULT LDAP_TRANSLATION_TABLE::FindEntryByPathServer (
  628. IN ANSI_STRING * DirectoryPath,
  629. IN SOCKADDR_IN * ServerAddress,
  630. OUT LDAP_TRANSLATION_ENTRY ** ReturnTranslationEntry)
  631. {
  632. LDAP_TRANSLATION_ENTRY * Pos;
  633. LDAP_TRANSLATION_ENTRY * End;
  634. HRESULT Result;
  635. Result = S_FALSE;
  636. Array.GetExtents (&Pos, &End);
  637. for (; Pos < End; Pos++) {
  638. if (RtlEqualStringConst (&Pos -> DirectoryPath, DirectoryPath, TRUE)
  639. && IsEqualSocketAddress (&Pos -> ServerAddress, ServerAddress)) {
  640. *ReturnTranslationEntry = Pos;
  641. Result = S_OK;
  642. break;
  643. }
  644. }
  645. return Result;
  646. }
  647. HRESULT LDAP_TRANSLATION_TABLE::FindEntryByAliasServer (
  648. IN ANSI_STRING * Alias,
  649. IN SOCKADDR_IN * ServerAddress,
  650. OUT LDAP_TRANSLATION_ENTRY ** ReturnTranslationEntry)
  651. {
  652. LDAP_TRANSLATION_ENTRY * Pos;
  653. LDAP_TRANSLATION_ENTRY * End;
  654. HRESULT Result;
  655. Result = S_FALSE;
  656. Array.GetExtents (&Pos, &End);
  657. for (; Pos < End; Pos++) {
  658. if (RtlEqualStringConst (&Pos -> Alias, Alias, TRUE)
  659. // && IsEqualSocketAddress (&Pos -> ServerAddress, ServerAddress)) {
  660. && Pos -> ServerAddress.sin_addr.s_addr == ServerAddress -> sin_addr.s_addr) {
  661. *ReturnTranslationEntry = Pos;
  662. Result = S_OK;
  663. break;
  664. }
  665. }
  666. return Result;
  667. }
  668. HRESULT LDAP_TRANSLATION_TABLE::InsertEntryLocked (
  669. IN ANSI_STRING * Alias,
  670. IN ANSI_STRING * DirectoryPath,
  671. IN IN_ADDR ClientAddress,
  672. IN SOCKADDR_IN * ServerAddress,
  673. IN DWORD TimeToLive) // in seconds
  674. {
  675. LDAP_TRANSLATION_ENTRY * TranslationEntry;
  676. LDAP_PATH_ELEMENTS PathElements;
  677. HRESULT Result;
  678. LDAP_TRANSLATION_ENTRY * Pos;
  679. LDAP_TRANSLATION_ENTRY * End;
  680. assert (Alias);
  681. assert (DirectoryPath);
  682. assert (ServerAddress);
  683. if (!IsEnabled)
  684. return S_FALSE;
  685. // locate any existing entry
  686. // the identity of the entry is determined by the tuple:
  687. // < ServerAddress ClientAlias >
  688. if (FindEntryByAliasServer (Alias, ServerAddress, &TranslationEntry) == S_OK) {
  689. Debug (_T("LDAP: Replacing existing translation entry.\n"));
  690. TranslationEntry -> FreeContents();
  691. }
  692. else {
  693. Debug (_T("LDAP: Allocating new translation entry.\n"));
  694. TranslationEntry = Array.AllocAtEnd();
  695. if (!TranslationEntry) {
  696. Debug (_T("LDAP: Failed to allocate translation entry.\n"));
  697. return E_OUTOFMEMORY;
  698. }
  699. }
  700. TranslationEntry -> ClientAddress = ClientAddress;
  701. TranslationEntry -> ServerAddress = *ServerAddress;
  702. TranslationEntry -> TimeStamp = GetTickCount () / 1000 + TimeToLive;
  703. // copy the strings
  704. CopyAnsiString (Alias, &TranslationEntry -> Alias);
  705. CopyAnsiString (DirectoryPath, &TranslationEntry -> DirectoryPath);
  706. if (TranslationEntry -> DirectoryPath.Buffer) {
  707. ParseDirectoryPath (&TranslationEntry -> DirectoryPath, &PathElements);
  708. if (PathElements.CN.Buffer) {
  709. TranslationEntry -> CN = PathElements.CN;
  710. }
  711. else {
  712. Debug (_T("LDAP: Cannot insert translation entry -- CN is not specified.\n"));
  713. TranslationEntry -> CN.Buffer = NULL;
  714. }
  715. }
  716. else {
  717. TranslationEntry -> CN.Buffer = NULL;
  718. }
  719. // test and make sure all allocation code paths succeeded
  720. if (TranslationEntry -> Alias.Buffer
  721. && TranslationEntry -> DirectoryPath.Buffer
  722. && TranslationEntry -> CN.Buffer) {
  723. Result = S_OK;
  724. } else {
  725. Debug (_T("LDAP: Failed to allocate memory (or failed to find CN).\n"));
  726. FreeAnsiString (&TranslationEntry -> Alias);
  727. FreeAnsiString (&TranslationEntry -> DirectoryPath);
  728. Array.DeleteEntry (TranslationEntry);
  729. Result = E_OUTOFMEMORY;
  730. }
  731. return Result;
  732. }
  733. HRESULT LDAP_TRANSLATION_TABLE::RemoveEntry (
  734. IN SOCKADDR_IN * ServerAddress,
  735. IN ANSI_STRING * DirectoryPath)
  736. {
  737. LDAP_TRANSLATION_ENTRY * Pos;
  738. LDAP_TRANSLATION_ENTRY * End;
  739. HRESULT Result;
  740. Lock();
  741. assert (ServerAddress);
  742. assert (DirectoryPath);
  743. Result = S_FALSE;
  744. Array.GetExtents (&Pos, &End);
  745. for (; Pos < End; Pos++) {
  746. if (RtlEqualString (DirectoryPath, &Pos -> DirectoryPath, TRUE)
  747. && Compare_SOCKADDR_IN (ServerAddress, &Pos -> ServerAddress) == 0) {
  748. Pos -> FreeContents();
  749. Array.DeleteEntry (Pos);
  750. InterfaceArray.StopQ931ReceiveRedirects ();
  751. Result = S_OK;
  752. break;
  753. }
  754. }
  755. Unlock();
  756. return Result;
  757. }
  758. HRESULT LDAP_TRANSLATION_TABLE::RemoveEntryByAliasServer (
  759. IN ANSI_STRING * Alias,
  760. IN SOCKADDR_IN * ServerAddress)
  761. {
  762. LDAP_TRANSLATION_ENTRY * Pos;
  763. LDAP_TRANSLATION_ENTRY * End;
  764. HRESULT Result;
  765. BOOL AliasIsSame;
  766. BOOL ServerIsSame;
  767. Lock ();
  768. assert (Alias);
  769. Result = S_FALSE;
  770. Array.GetExtents (&Pos, &End);
  771. for (; Pos < End; Pos++) {
  772. AliasIsSame = RtlEqualStringConst (&Pos -> Alias, Alias, TRUE);
  773. ServerIsSame = (ServerAddress -> sin_addr.s_addr == Pos -> ServerAddress.sin_addr.s_addr) // addresses are literally equal
  774. ||
  775. ( ::NhIsLocalAddress (ServerAddress -> sin_addr.s_addr)
  776. && ::NhIsLocalAddress (Pos -> ServerAddress.sin_addr.s_addr)); // two addresses of the local machine
  777. if (AliasIsSame && ServerIsSame) {
  778. Pos -> FreeContents();
  779. Array.DeleteEntry (Pos);
  780. InterfaceArray.StopQ931ReceiveRedirects ();
  781. Result = S_OK;
  782. break;
  783. }
  784. }
  785. Unlock ();
  786. return Result;
  787. }
  788. void
  789. LDAP_TRANSLATION_TABLE::OnInterfaceShutdown (
  790. IN DWORD InterfaceAddress
  791. )
  792. /*++
  793. Routine Description:
  794. Removes all entries registered by the clients reachable
  795. thorough the interface specified, except for entries registered by
  796. a local client.
  797. Arguments:
  798. InterfaceAddress - address of the interface for which
  799. the determination is to be made.
  800. Return Values:
  801. None
  802. Notes:
  803. --*/
  804. {
  805. DWORD ArrayIndex = 0;
  806. LDAP_TRANSLATION_ENTRY * Entry;
  807. BOOL IsEntryToBeDeleted;
  808. HRESULT Result;
  809. Lock ();
  810. if (IsEnabled) {
  811. DebugF (_T("LDAP: Forcibly removing non-local translation entries registered via %08X.\n"), InterfaceAddress);
  812. while (ArrayIndex < Array.GetLength ()) {
  813. Entry = &Array [ArrayIndex];
  814. Result = Entry -> IsRegisteredViaInterface (InterfaceAddress, &IsEntryToBeDeleted);
  815. // Don't delete the entry if it was registered by a local client. This is because
  816. // the client will still be available for H.323 calls.
  817. IsEntryToBeDeleted = IsEntryToBeDeleted && !::NhIsLocalAddress (Entry -> ClientAddress.s_addr);
  818. if (S_OK == Result) {
  819. if (IsEntryToBeDeleted) {
  820. DebugF (_T("LDAP: Forcibly removing entry (%.*S:%08X) @ %08X:%04X.\n"),
  821. ANSI_STRING_PRINTF (&Entry -> Alias),
  822. ntohl (Entry -> ClientAddress.s_addr),
  823. SOCKADDR_IN_PRINTF (&Entry -> ServerAddress));
  824. Entry -> FreeContents();
  825. Array.DeleteEntry (Entry);
  826. InterfaceArray.StopQ931ReceiveRedirects ();
  827. } else {
  828. ArrayIndex++;
  829. }
  830. } else {
  831. // There probably was something wrong with just this entry. Skip it and continue
  832. // searching for entries registered via the interface
  833. ArrayIndex++;
  834. DebugF (_T("LDAP: Failed to determine whether entry (%.*S:%08X) @ %08X:%04X was registered via interface %08X. Error=0x%x\n"),
  835. ANSI_STRING_PRINTF (&Entry -> Alias),
  836. ntohl (Entry -> ClientAddress.s_addr),
  837. SOCKADDR_IN_PRINTF (&Entry -> ServerAddress),
  838. InterfaceAddress,
  839. Result);
  840. }
  841. }
  842. }
  843. Unlock ();
  844. } // LDAP_TRANSLATION_TABLE::RemoveEntriesForClientsOnInterface
  845. BOOL LDAP_TRANSLATION_TABLE::ReachedMaximumSize (void) {
  846. DWORD NumberOfEntries;
  847. Lock ();
  848. NumberOfEntries = Array.Length;
  849. Unlock ();
  850. return NumberOfEntries >= LDAP_MAX_TRANSLATION_TABLE_SIZE;
  851. }
  852. // LDAP_SOCKET ----------------------------------------------
  853. LDAP_SOCKET::LDAP_SOCKET (
  854. IN LDAP_CONNECTION * ArgLdapConnection,
  855. IN LDAP_PUMP * ArgRecvPump,
  856. IN LDAP_PUMP * ArgSendPump)
  857. {
  858. assert (ArgLdapConnection);
  859. assert (ArgRecvPump);
  860. assert (ArgSendPump);
  861. LdapConnection = ArgLdapConnection;
  862. RecvPump = ArgRecvPump;
  863. SendPump = ArgSendPump;
  864. State = STATE_NONE;
  865. BytesToReceive = LDAP_BUFFER_RECEIVE_SIZE;
  866. Socket = INVALID_SOCKET;
  867. ZeroMemory (&RecvOverlapped, sizeof RecvOverlapped);
  868. RecvOverlapped.Socket = this;
  869. RecvBuffer = NULL;
  870. InitializeListHead (&RecvBufferQueue);
  871. ZeroMemory (&SendOverlapped, sizeof SendOverlapped);
  872. SendOverlapped.Socket = this;
  873. SendBuffer = NULL;
  874. InitializeListHead (&SendBufferQueue);
  875. ConnectEvent = NULL;
  876. ConnectWaitHandle = NULL;
  877. AttemptAnotherConnect = TRUE;
  878. IsNatRedirectActive = FALSE;
  879. }
  880. LDAP_SOCKET::~LDAP_SOCKET (void)
  881. {
  882. DeleteBufferList (&RecvBufferQueue);
  883. DeleteBufferList (&SendBufferQueue);
  884. if (RecvBuffer) {
  885. delete RecvBuffer;
  886. RecvBuffer = NULL;
  887. }
  888. assert (IsListEmpty (&RecvBufferQueue));
  889. assert (IsListEmpty (&SendBufferQueue));
  890. assert (!SendBuffer);
  891. assert (!ConnectEvent);
  892. assert (!ConnectWaitHandle);
  893. }
  894. void LDAP_SOCKET::DeleteBufferList (LIST_ENTRY * ListHead)
  895. {
  896. LIST_ENTRY * ListEntry;
  897. LDAP_BUFFER * Buffer;
  898. while (!IsListEmpty (ListHead)) {
  899. ListEntry = RemoveHeadList (ListHead);
  900. Buffer = CONTAINING_RECORD (ListEntry, LDAP_BUFFER, ListEntry);
  901. delete Buffer;
  902. }
  903. }
  904. BOOL LDAP_SOCKET::RecvRemoveBuffer (
  905. OUT LDAP_BUFFER ** ReturnBuffer)
  906. {
  907. LIST_ENTRY * ListEntry;
  908. assert (ReturnBuffer);
  909. if (IsListEmpty (&RecvBufferQueue))
  910. return FALSE;
  911. else {
  912. ListEntry = RemoveHeadList (&RecvBufferQueue);
  913. *ReturnBuffer = CONTAINING_RECORD (ListEntry, LDAP_BUFFER, ListEntry);
  914. return TRUE;
  915. }
  916. }
  917. void LDAP_SOCKET::RecvBuildBuffer (
  918. IN LPBYTE Data,
  919. IN DWORD Length)
  920. {
  921. LDAP_BUFFER * Buffer;
  922. assert (Data);
  923. AssertLocked();
  924. Buffer = new LDAP_BUFFER;
  925. if (!Buffer) {
  926. Debug (_T("LDAP: RecvBuildBuffer, allocation failure #1.\n"));
  927. return;
  928. }
  929. if (Buffer -> Data.Grow (Length)) {
  930. memcpy (Buffer -> Data.Data, Data, Length);
  931. Buffer -> Data.Length = Length;
  932. InsertTailList (&RecvBufferQueue, &Buffer -> ListEntry);
  933. }
  934. else {
  935. Debug (_T("LDAP: RecvBuildBuffer, allocation failure #2.\n"));
  936. delete Buffer;
  937. }
  938. }
  939. HRESULT LDAP_SOCKET::AcceptSocket (
  940. SOCKET LocalClientSocket)
  941. {
  942. if (State != STATE_NONE) {
  943. Debug (_T("LDAP: Not in a valid state for AcceptSocket (State != STATE_NONE).\n"));
  944. return E_UNEXPECTED;
  945. }
  946. State = STATE_CONNECTED;
  947. Socket = LocalClientSocket;
  948. // notify parent about state change
  949. LdapConnection -> OnStateChange (this, State);
  950. if (!BindIoCompletionCallback ((HANDLE) Socket, LDAP_SOCKET::IoCompletionCallback, 0)) {
  951. DebugLastError (_T("LDAP: Failed to bind I/O completion callback.\n"));
  952. return GetLastErrorAsResult ();
  953. }
  954. return S_OK;
  955. }
  956. HRESULT LDAP_SOCKET::IssueConnect (
  957. SOCKADDR_IN * DestinationAddress)
  958. {
  959. HRESULT Status;
  960. HRESULT Result;
  961. ULONG Error;
  962. INT RealSourceAddrSize = sizeof (SOCKADDR_IN);
  963. DWORD BestInterfaceAddress; // host order
  964. int ConnectError;
  965. BOOL KeepaliveOption;
  966. assert (DestinationAddress);
  967. if (State != STATE_NONE) {
  968. Debug (_T("LDAP: Not in a valid state for IssueConnect (State != STATE_NONE).\n"));
  969. return E_UNEXPECTED;
  970. }
  971. assert (Socket == INVALID_SOCKET);
  972. assert (!ConnectEvent);
  973. assert (!ConnectWaitHandle);
  974. ActualDestinationAddress = *DestinationAddress;
  975. // If ILS runs on a remote (public) machine, we need to determine on which public
  976. // interface we will connect to the server. This is so to override global interface-restricted
  977. // NAT redirect by creating a trivial NAT redirect to the server's address from
  978. // the address of the public interface determined.
  979. //
  980. // If server happens to run on the local machine, then we use loopback address
  981. // as this is the address from where we will be "connecting" to the server.
  982. if (!::NhIsLocalAddress (DestinationAddress -> sin_addr.s_addr)) {
  983. Error = GetBestInterfaceAddress (
  984. ntohl (DestinationAddress -> sin_addr.s_addr),
  985. &BestInterfaceAddress);
  986. if (ERROR_SUCCESS != Error) {
  987. Result = HRESULT_FROM_WIN32 (Error);
  988. DebugErrorF (Error, _T("LDAP: Failed to get best interface address for %08X.\n"),
  989. ntohl (DestinationAddress -> sin_addr.s_addr));
  990. return Result;
  991. }
  992. } else {
  993. BestInterfaceAddress = INADDR_LOOPBACK;
  994. }
  995. RealSourceAddress.sin_family = AF_INET;
  996. RealSourceAddress.sin_addr.s_addr = htonl (BestInterfaceAddress);
  997. RealSourceAddress.sin_port = htons (0);
  998. Socket = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
  999. if (Socket == INVALID_SOCKET) {
  1000. Result = GetLastErrorAsResult ();
  1001. DebugLastError (_T("LDAP: Failed to create destination socket.\n"));
  1002. } else {
  1003. // At this point we actually start the connect procedures. Everything before that
  1004. // was just a preparation, so the socket stayed in the STATE_NONE.
  1005. State = STATE_ISSUING_CONNECT;
  1006. if (SOCKET_ERROR == bind(Socket, (PSOCKADDR)&RealSourceAddress, RealSourceAddrSize)) {
  1007. Result = GetLastErrorAsResult();
  1008. DebugLastError (_T("LDAP: Failed to bind destination socket.\n"));
  1009. } else {
  1010. // Set keepalive on the socket
  1011. KeepaliveOption = TRUE;
  1012. if (SOCKET_ERROR == setsockopt (Socket, SOL_SOCKET, SO_KEEPALIVE,
  1013. (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
  1014. {
  1015. Result = GetLastErrorAsResult ();
  1016. DebugLastError (_T("LDAP: Failed to set keepalive on destination socket.\n"));
  1017. } else {
  1018. if (getsockname (Socket, (struct sockaddr *)&RealSourceAddress, &RealSourceAddrSize)) {
  1019. Result = GetLastErrorAsResult ();
  1020. DebugLastError (_T("LDAP: Failed to get name of TCP socket.\n"));
  1021. } else {
  1022. DebugF (_T("LDAP: 0x%x setting up trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
  1023. LdapConnection,
  1024. SOCKADDR_IN_PRINTF(&RealSourceAddress), SOCKADDR_IN_PRINTF(DestinationAddress),
  1025. SOCKADDR_IN_PRINTF(&RealSourceAddress), SOCKADDR_IN_PRINTF(DestinationAddress));
  1026. if( NO_ERROR != NatCreateRedirectEx (
  1027. NatHandle,
  1028. NatRedirectFlagLoopback,
  1029. IPPROTO_TCP,
  1030. DestinationAddress -> sin_addr.s_addr,
  1031. DestinationAddress -> sin_port,
  1032. RealSourceAddress.sin_addr.s_addr,
  1033. RealSourceAddress.sin_port,
  1034. DestinationAddress -> sin_addr.s_addr,
  1035. DestinationAddress -> sin_port,
  1036. RealSourceAddress.sin_addr.s_addr,
  1037. RealSourceAddress.sin_port,
  1038. NULL,
  1039. NULL,
  1040. NULL,
  1041. NULL)) {
  1042. Result = GetLastErrorAsResult();
  1043. DebugLastErrorF (_T("LDAP: 0x%x failed to create trivial redirect.\n"),
  1044. LdapConnection);
  1045. } else {
  1046. // we have successfully created a redirect
  1047. IsNatRedirectActive = TRUE;
  1048. do
  1049. {
  1050. ConnectEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
  1051. if (!ConnectEvent) {
  1052. Result = GetLastErrorAsResult();
  1053. DebugLastErrorF (_T("LDAP: 0x%x failed to create connect-event.\n"),
  1054. LdapConnection);
  1055. break;
  1056. }
  1057. Status = WSAEventSelect (Socket, ConnectEvent, FD_CONNECT);
  1058. if (Status) {
  1059. Result = GetLastErrorAsResult();
  1060. DebugLastErrorF (_T("LDAP: 0x%x failed to select events on the socket.\n"),
  1061. LdapConnection);
  1062. break;
  1063. }
  1064. LdapConnection -> AddRef ();
  1065. if (!RegisterWaitForSingleObject (
  1066. &ConnectWaitHandle,
  1067. ConnectEvent,
  1068. LDAP_SOCKET::OnConnectCompletion,
  1069. this,
  1070. INFINITE,
  1071. WT_EXECUTEDEFAULT)) {
  1072. Result = GetLastErrorAsResult();
  1073. DebugLastErrorF (_T("LDAP: 0x%x failed to RegisterWaitForSingleObject.\n"),
  1074. LdapConnection);
  1075. LdapConnection -> Release ();
  1076. break;
  1077. }
  1078. if (connect (Socket, (SOCKADDR *)DestinationAddress, sizeof (SOCKADDR_IN))) {
  1079. ConnectError = WSAGetLastError ();
  1080. if(ConnectError == WSAEWOULDBLOCK) {
  1081. State = STATE_CONNECT_PENDING;
  1082. LdapConnection->OnStateChange (this, State);
  1083. Result = S_OK;
  1084. } else {
  1085. // a real error
  1086. Result = GetLastErrorAsResult();
  1087. DebugLastErrorF (_T("LDAP: 0x%x failed to issue async connect.\n"),
  1088. LdapConnection);
  1089. FreeConnectResources ();
  1090. // If remote server refused to connect, make an attempt to
  1091. // connect on a different port. Don't try to do so
  1092. // for any other error.
  1093. if ((WSAECONNREFUSED == ConnectError || WSAECONNRESET == ConnectError)
  1094. && AttemptAnotherConnect) {
  1095. AttemptAnotherConnect = FALSE;
  1096. DebugF (_T ("LDAP: 0x%x cancels trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
  1097. LdapConnection,
  1098. SOCKADDR_IN_PRINTF (&RealSourceAddress),
  1099. SOCKADDR_IN_PRINTF (&ActualDestinationAddress),
  1100. SOCKADDR_IN_PRINTF (&RealSourceAddress),
  1101. SOCKADDR_IN_PRINTF (&ActualDestinationAddress));
  1102. NatCancelRedirect (
  1103. NatHandle,
  1104. IPPROTO_TCP,
  1105. ActualDestinationAddress.sin_addr.s_addr,
  1106. ActualDestinationAddress.sin_port,
  1107. RealSourceAddress.sin_addr.s_addr,
  1108. RealSourceAddress.sin_port,
  1109. ActualDestinationAddress.sin_addr.s_addr,
  1110. ActualDestinationAddress.sin_port,
  1111. RealSourceAddress.sin_addr.s_addr,
  1112. RealSourceAddress.sin_port);
  1113. IsNatRedirectActive = FALSE;
  1114. closesocket (Socket);
  1115. Socket = INVALID_SOCKET;
  1116. State = STATE_NONE;
  1117. Result = AttemptAlternateConnect (); // calls IssueConnect internally
  1118. }
  1119. LdapConnection -> Release ();
  1120. }
  1121. break;
  1122. } else {
  1123. // connect completed synchronously
  1124. // this should never occur
  1125. DebugF (_T("LDAP: 0x%x completed synchronously -- this should never occur.\n"),
  1126. LdapConnection);
  1127. FreeConnectResources ();
  1128. LdapConnection -> Release ();
  1129. Result = E_UNEXPECTED;
  1130. }
  1131. } while(FALSE);
  1132. }
  1133. }
  1134. }
  1135. }
  1136. }
  1137. return Result;
  1138. }
  1139. // static
  1140. void LDAP_SOCKET::IoCompletionCallback (
  1141. DWORD Status,
  1142. DWORD BytesTransferred,
  1143. LPOVERLAPPED Overlapped)
  1144. {
  1145. LDAP_OVERLAPPED * LdapOverlapped;
  1146. LDAP_CONNECTION * Connection;
  1147. LdapOverlapped = CONTAINING_RECORD (Overlapped, LDAP_OVERLAPPED, Overlapped);
  1148. assert (LdapOverlapped -> Socket);
  1149. Connection = LdapOverlapped -> Socket -> LdapConnection;
  1150. LdapOverlapped -> Socket -> OnIoComplete (Status, BytesTransferred, LdapOverlapped);
  1151. Connection -> Release();
  1152. }
  1153. void LDAP_SOCKET::OnIoComplete (
  1154. DWORD Status,
  1155. DWORD BytesTransferred,
  1156. LDAP_OVERLAPPED * Overlapped)
  1157. {
  1158. Lock();
  1159. assert (Overlapped -> IsPending);
  1160. Overlapped -> IsPending = FALSE;
  1161. Overlapped -> BytesTransferred = BytesTransferred;
  1162. if (Overlapped == &RecvOverlapped)
  1163. OnRecvComplete (Status);
  1164. else if (Overlapped == &SendOverlapped)
  1165. OnSendComplete (Status);
  1166. else {
  1167. AssertNeverReached();
  1168. }
  1169. Unlock();
  1170. }
  1171. // static
  1172. void LDAP_SOCKET::OnConnectCompletion (
  1173. PVOID Context,
  1174. BOOLEAN TimerOrWaitFired)
  1175. {
  1176. LDAP_SOCKET * LdapSocket;
  1177. assert (Context);
  1178. LdapSocket = (LDAP_SOCKET *) Context;
  1179. LdapSocket -> Lock ();
  1180. LdapSocket -> OnConnectCompletionLocked ();
  1181. LdapSocket -> Unlock ();
  1182. LdapSocket -> LdapConnection -> Release ();
  1183. }
  1184. void LDAP_SOCKET::OnRecvComplete (DWORD Status)
  1185. {
  1186. DWORD StartOffset;
  1187. DWORD NextPacketOffset;
  1188. DWORD NextReceiveSize = 0;
  1189. DWORD Result;
  1190. LIST_ENTRY * ListEntry;
  1191. LDAP_BUFFER * Buffer;
  1192. if (Status != ERROR_SUCCESS) {
  1193. if (State != STATE_TERMINATED) {
  1194. Terminate();
  1195. }
  1196. return;
  1197. }
  1198. if (RecvOverlapped.BytesTransferred == 0) {
  1199. #if DBG
  1200. if (this == &LdapConnection -> ClientSocket)
  1201. {
  1202. DebugF (_T("LDAP: 0x%x client has closed transport socket.\n"), LdapConnection);
  1203. }
  1204. else if (this == &LdapConnection -> ServerSocket)
  1205. {
  1206. DebugF (_T("LDAP: 0x%x server has closed transport socket.\n"), LdapConnection);
  1207. }
  1208. else
  1209. AssertNeverReached();
  1210. #endif
  1211. Terminate();
  1212. return;
  1213. }
  1214. assert (RecvBuffer);
  1215. assert (RecvBuffer -> Data.Length + RecvOverlapped.BytesTransferred
  1216. <= RecvBuffer -> Data.MaxLength);
  1217. RecvBuffer -> Data.Length += RecvOverlapped.BytesTransferred;
  1218. if (State == STATE_TERMINATED) {
  1219. DebugF (_T("LDAP: 0x%x is terminating, no further processing will occur.\n"), LdapConnection);
  1220. return;
  1221. }
  1222. if (RecvPump -> IsActivelyPassingData ()) {
  1223. StartOffset = 0;
  1224. for (;;) {
  1225. assert (StartOffset <= RecvBuffer -> Data.Length);
  1226. Result = LdapDeterminePacketBoundary (
  1227. RecvBuffer,
  1228. StartOffset,
  1229. &NextPacketOffset,
  1230. &NextReceiveSize);
  1231. if (Result == ERROR_SUCCESS) {
  1232. RecvBuildBuffer (&RecvBuffer -> Data.Data [StartOffset], NextPacketOffset - StartOffset);
  1233. StartOffset = NextPacketOffset;
  1234. } else {
  1235. RecvBuffer -> Data.DeleteRangeAtPos (0, StartOffset);
  1236. if (Result == ERROR_INVALID_DATA) {
  1237. RecvPump -> StartPassiveDataTransfer ();
  1238. DebugF (_T("LDAP: 0x%x starts non-interpreting data transfer.\n"), LdapConnection);
  1239. InsertTailList (&RecvBufferQueue, &RecvBuffer -> ListEntry);
  1240. RecvBuffer = NULL;
  1241. }
  1242. BytesToReceive = NextReceiveSize;
  1243. break;
  1244. }
  1245. }
  1246. } else {
  1247. LONG PreviousRecvSize;
  1248. LONG PredictedRecvSize;
  1249. HRESULT QueryResult;
  1250. DWORD BytesPreviouslyRequested = BytesToReceive;
  1251. QueryResult = RecvSizePredictor.RetrieveOldSample (0, &PreviousRecvSize);
  1252. if (ERROR_SUCCESS != RecvSizePredictor.AddSample ((LONG) RecvOverlapped.BytesTransferred)) {
  1253. delete RecvBuffer;
  1254. RecvBuffer = NULL;
  1255. DebugErrorF (Status, _T("LDAP: 0x%x could not add sample to SamplePredictor.\n"), LdapConnection);
  1256. Terminate();
  1257. return;
  1258. }
  1259. if (BytesPreviouslyRequested == RecvOverlapped.BytesTransferred) {
  1260. // Exact receive
  1261. if (ERROR_SUCCESS != QueryResult) {
  1262. BytesToReceive = (DWORD) (RecvOverlapped.BytesTransferred * 1.5);
  1263. } else {
  1264. PredictedRecvSize = RecvSizePredictor.PredictNextSample ();
  1265. if (PredictedRecvSize < (LONG) RecvOverlapped.BytesTransferred) {
  1266. if ((DWORD) PreviousRecvSize < RecvOverlapped.BytesTransferred) {
  1267. BytesToReceive = RecvOverlapped.BytesTransferred * 1000 / (DWORD) PreviousRecvSize *
  1268. RecvOverlapped.BytesTransferred / 1000;
  1269. } else {
  1270. BytesToReceive = (DWORD) PreviousRecvSize;
  1271. }
  1272. } else {
  1273. BytesToReceive = (DWORD) PredictedRecvSize;
  1274. }
  1275. }
  1276. } else {
  1277. // Inexact receive
  1278. PredictedRecvSize = RecvSizePredictor.PredictNextSample ();
  1279. BytesToReceive = (PredictedRecvSize < LDAP_BUFFER_RECEIVE_SIZE) ?
  1280. LDAP_BUFFER_RECEIVE_SIZE :
  1281. (DWORD) PredictedRecvSize;
  1282. }
  1283. if (BytesToReceive > LDAP_BUFFER_MAX_RECV_SIZE) {
  1284. DebugF (_T("LDAP: 0x%x intended to receive %d bytes. Lowering the number to %d bytes.\n"),
  1285. LdapConnection, BytesToReceive, LDAP_BUFFER_MAX_RECV_SIZE);
  1286. BytesToReceive = LDAP_BUFFER_MAX_RECV_SIZE;
  1287. }
  1288. InsertTailList (&RecvBufferQueue, &RecvBuffer -> ListEntry);
  1289. RecvBuffer = NULL;
  1290. }
  1291. while (!IsListEmpty (&RecvBufferQueue)) {
  1292. ListEntry = RemoveHeadList (&RecvBufferQueue);
  1293. Buffer = CONTAINING_RECORD (ListEntry, LDAP_BUFFER, ListEntry);
  1294. RecvPump -> OnRecvBuffer (Buffer);
  1295. }
  1296. RecvIssue ();
  1297. }
  1298. void LDAP_SOCKET::OnSendComplete (DWORD Status)
  1299. {
  1300. assert (SendBuffer);
  1301. delete SendBuffer;
  1302. SendBuffer = NULL;
  1303. // before notifying the owning context, transmit any buffers
  1304. // that are queued for send.
  1305. if (SendNextBuffer())
  1306. return;
  1307. SendPump -> OnSendDrain();
  1308. }
  1309. void LDAP_SOCKET::OnConnectCompletionLocked (void) {
  1310. WSANETWORKEVENTS NetworkEvents;
  1311. HRESULT Result;
  1312. int ConnectError;
  1313. AssertLocked();
  1314. if (State != STATE_CONNECT_PENDING) {
  1315. DebugF (_T("LDAP: 0x%x connect request completed, but socket is no longer interested.\n"), LdapConnection);
  1316. return;
  1317. }
  1318. if (WSAEnumNetworkEvents (Socket, ConnectEvent, &NetworkEvents)) {
  1319. DebugLastErrorF (_T("LDAP: 0x%x failed to retrieve network events.\n"), LdapConnection);
  1320. Terminate();
  1321. return;
  1322. }
  1323. if (!(NetworkEvents.lNetworkEvents & FD_CONNECT)) {
  1324. DebugF (_T("LDAP: 0x%x connect event fired, but event mask does not indicate that connect completed -- internal error.\n"),
  1325. LdapConnection);
  1326. Terminate();
  1327. return;
  1328. }
  1329. ConnectError = S_OK;
  1330. if (NetworkEvents.iErrorCode [FD_CONNECT_BIT]) {
  1331. ConnectError = NetworkEvents.iErrorCode [FD_CONNECT_BIT];
  1332. DebugErrorF (ConnectError, _T("LDAP: 0x%x failed async connect request. "), LdapConnection);
  1333. // If remote host refused to connect, we may attempt
  1334. // a connection to an alternate port later, so we don't terminate
  1335. // the socket. All other error codes result in termination.
  1336. if (WSAECONNRESET != ConnectError && WSAECONNREFUSED != ConnectError) {
  1337. Terminate ();
  1338. return;
  1339. }
  1340. }
  1341. FreeConnectResources ();
  1342. // If first attempt to connect fail, try to connect using an alternate port
  1343. if ((WSAECONNREFUSED == ConnectError || WSAECONNRESET == ConnectError)
  1344. && AttemptAnotherConnect) {
  1345. AttemptAnotherConnect = FALSE;
  1346. DebugF (_T ("LDAP: 0x%x cancels trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
  1347. LdapConnection,
  1348. SOCKADDR_IN_PRINTF (&RealSourceAddress),
  1349. SOCKADDR_IN_PRINTF (&ActualDestinationAddress),
  1350. SOCKADDR_IN_PRINTF (&RealSourceAddress),
  1351. SOCKADDR_IN_PRINTF (&ActualDestinationAddress));
  1352. NatCancelRedirect (
  1353. NatHandle,
  1354. IPPROTO_TCP,
  1355. ActualDestinationAddress.sin_addr.s_addr,
  1356. ActualDestinationAddress.sin_port,
  1357. RealSourceAddress.sin_addr.s_addr,
  1358. RealSourceAddress.sin_port,
  1359. ActualDestinationAddress.sin_addr.s_addr,
  1360. ActualDestinationAddress.sin_port,
  1361. RealSourceAddress.sin_addr.s_addr,
  1362. RealSourceAddress.sin_port);
  1363. IsNatRedirectActive = FALSE;
  1364. closesocket (Socket);
  1365. Socket = INVALID_SOCKET;
  1366. State = STATE_NONE;
  1367. Result = AttemptAlternateConnect ();
  1368. if (S_OK != Result) {
  1369. Terminate ();
  1370. }
  1371. return;
  1372. }
  1373. DebugF (_T("LDAP: 0x%x established connection to server %08X:%04X.\n"), LdapConnection, SOCKADDR_IN_PRINTF (&ActualDestinationAddress));
  1374. if (!BindIoCompletionCallback ((HANDLE)Socket, LDAP_SOCKET::IoCompletionCallback, 0)) {
  1375. DebugLastErrorF (_T("LDAP: 0x%x failed to bind I/O completion callback.\n"), LdapConnection);
  1376. Terminate();
  1377. return;
  1378. }
  1379. // Asynchronous connect succeeded
  1380. State = STATE_CONNECTED;
  1381. LdapConnection -> OnStateChange (this, State);
  1382. }
  1383. void LDAP_SOCKET::FreeConnectResources (void) {
  1384. // refrain from receiving notifications of further transport events
  1385. WSAEventSelect (Socket, ConnectEvent, 0);
  1386. assert (ConnectWaitHandle);
  1387. UnregisterWaitEx (ConnectWaitHandle, NULL);
  1388. ConnectWaitHandle = NULL;
  1389. assert (ConnectEvent);
  1390. CloseHandle(ConnectEvent);
  1391. ConnectEvent = NULL;
  1392. }
  1393. // assumes that connect resources for previous
  1394. // connect attempt were freed
  1395. HRESULT LDAP_SOCKET::AttemptAlternateConnect (void) {
  1396. HRESULT Result;
  1397. // switch connection port to the other alternative
  1398. ActualDestinationAddress.sin_port =
  1399. (ActualDestinationAddress.sin_port == htons (LDAP_STANDARD_PORT)) ?
  1400. htons (LDAP_ALTERNATE_PORT) :
  1401. htons (LDAP_STANDARD_PORT);
  1402. DebugF (_T("LDAP: 0x%x will try to connect on an alternate address %08X:%04X.\n"),
  1403. LdapConnection,
  1404. SOCKADDR_IN_PRINTF (&ActualDestinationAddress));
  1405. // attempting to connect on an alternate port
  1406. Result = IssueConnect (&ActualDestinationAddress);
  1407. if (S_OK != Result) {
  1408. DebugF (_T("LDAP: 0x%x failed to issue connect on an alternate address %08X:%04X.\n"),
  1409. LdapConnection,
  1410. SOCKADDR_IN_PRINTF (&ActualDestinationAddress));
  1411. }
  1412. return Result;
  1413. }
  1414. void LDAP_SOCKET::Terminate (void)
  1415. {
  1416. switch (State) {
  1417. case STATE_TERMINATED:
  1418. // nothing to do
  1419. return;
  1420. case STATE_NONE:
  1421. // a different kind of nothing to do
  1422. break;
  1423. default:
  1424. // in all other states, the socket handle must be set
  1425. assert (Socket != INVALID_SOCKET);
  1426. State = STATE_TERMINATED;
  1427. if (INVALID_SOCKET != Socket) {
  1428. closesocket (Socket);
  1429. Socket = INVALID_SOCKET;
  1430. }
  1431. if (IsNatRedirectActive) {
  1432. DebugF (_T ("LDAP: 0x%x cancels trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
  1433. LdapConnection,
  1434. SOCKADDR_IN_PRINTF (&RealSourceAddress),
  1435. SOCKADDR_IN_PRINTF (&ActualDestinationAddress),
  1436. SOCKADDR_IN_PRINTF (&RealSourceAddress),
  1437. SOCKADDR_IN_PRINTF (&ActualDestinationAddress));
  1438. NatCancelRedirect (
  1439. NatHandle,
  1440. IPPROTO_TCP,
  1441. ActualDestinationAddress.sin_addr.s_addr,
  1442. ActualDestinationAddress.sin_port,
  1443. RealSourceAddress.sin_addr.s_addr,
  1444. RealSourceAddress.sin_port,
  1445. ActualDestinationAddress.sin_addr.s_addr,
  1446. ActualDestinationAddress.sin_port,
  1447. RealSourceAddress.sin_addr.s_addr,
  1448. RealSourceAddress.sin_port);
  1449. IsNatRedirectActive = FALSE;
  1450. }
  1451. if (ConnectWaitHandle) {
  1452. if (UnregisterWaitEx (ConnectWaitHandle, NULL)) {
  1453. // Take care of the case when the connection was terminated AFTER
  1454. // async connect has been issued, but BEFORE the connect was completed.
  1455. //
  1456. // This should not normally happen.
  1457. LdapConnection -> Release ();
  1458. }
  1459. ConnectWaitHandle = NULL;
  1460. }
  1461. if (ConnectEvent) {
  1462. CloseHandle (ConnectEvent);
  1463. ConnectEvent = NULL;
  1464. }
  1465. SendPump -> Terminate ();
  1466. RecvPump -> Terminate ();
  1467. break;
  1468. }
  1469. LdapConnection -> OnStateChange (this, State);
  1470. }
  1471. HRESULT LDAP_SOCKET::RecvIssue (void)
  1472. {
  1473. WSABUF BufferArray [1];
  1474. DWORD Status;
  1475. DWORD BytesRequested;
  1476. if (RecvOverlapped.IsPending) {
  1477. DebugF (_T("LDAP: 0x%x receive is already pending.\n"), LdapConnection);
  1478. return S_OK;
  1479. }
  1480. if (!RecvPump -> CanIssueRecv()) {
  1481. // we gate the rate at which we receive data from the network on the
  1482. // rate at which the other network connection consumes it.
  1483. // this is how we preserve flow control.
  1484. return S_OK;
  1485. }
  1486. if (!RecvBuffer) {
  1487. RecvBuffer = new LDAP_BUFFER;
  1488. if (!RecvBuffer) {
  1489. DebugF (_T("LDAP: 0x%x RecvIssue allocation failure.\n"), LdapConnection);
  1490. Terminate();
  1491. return E_OUTOFMEMORY;
  1492. }
  1493. }
  1494. BytesRequested = RecvBuffer -> Data.Length + BytesToReceive;
  1495. if (!RecvBuffer -> Data.Grow (BytesRequested)) {
  1496. DebugF (_T("LDAP: 0x%x failed to expand receive buffer to %d bytes.\n"),
  1497. LdapConnection, BytesRequested);
  1498. Terminate();
  1499. return E_OUTOFMEMORY;
  1500. }
  1501. BufferArray [0].len = BytesToReceive;
  1502. BufferArray [0].buf = reinterpret_cast <char *>(RecvBuffer -> Data.Data) + RecvBuffer -> Data.Length;
  1503. ZeroMemory (&RecvOverlapped.Overlapped, sizeof (OVERLAPPED));
  1504. RecvFlags = 0;
  1505. LdapConnection -> AddRef ();
  1506. if (WSARecv (Socket, BufferArray, 1,
  1507. &RecvOverlapped.BytesTransferred, &RecvFlags,
  1508. &RecvOverlapped.Overlapped, NULL)) {
  1509. Status = WSAGetLastError();
  1510. if (Status != WSA_IO_PENDING) {
  1511. // a true error, probably a transport failure
  1512. LdapConnection -> Release ();
  1513. DebugErrorF (Status, _T("LDAP: 0x%x failed to issue receive.\n"), LdapConnection);
  1514. return HRESULT_FROM_WIN32 (Status);
  1515. }
  1516. }
  1517. RecvOverlapped.IsPending = TRUE;
  1518. return S_OK;
  1519. }
  1520. void LDAP_SOCKET::SendQueueBuffer (
  1521. IN LDAP_BUFFER * Buffer)
  1522. {
  1523. AssertLocked();
  1524. assert (!IsInList (&SendBufferQueue, &Buffer -> ListEntry));
  1525. InsertTailList (&SendBufferQueue, &Buffer -> ListEntry);
  1526. SendNextBuffer();
  1527. }
  1528. BOOL LDAP_SOCKET::SendNextBuffer (void)
  1529. {
  1530. WSABUF BufferArray [1];
  1531. LIST_ENTRY * ListEntry;
  1532. DWORD Status;
  1533. if (SendOverlapped.IsPending) {
  1534. assert (SendBuffer);
  1535. // Debug (_T("LDAP_SOCKET::SendNextMessage: already sending a message, must wait.\n"));
  1536. return FALSE;
  1537. }
  1538. assert (!SendBuffer);
  1539. // remove the next buffer to be sent from the queue
  1540. if (IsListEmpty (&SendBufferQueue))
  1541. return FALSE;
  1542. ListEntry = RemoveHeadList (&SendBufferQueue);
  1543. SendBuffer = CONTAINING_RECORD (ListEntry, LDAP_BUFFER, ListEntry);
  1544. BufferArray [0].buf = reinterpret_cast<char *> (SendBuffer -> Data.Data);
  1545. BufferArray [0].len = SendBuffer -> Data.Length;
  1546. ZeroMemory (&SendOverlapped.Overlapped, sizeof (OVERLAPPED));
  1547. LdapConnection -> AddRef ();
  1548. if (WSASend (Socket, BufferArray, 1,
  1549. &SendOverlapped.BytesTransferred, 0,
  1550. &SendOverlapped.Overlapped, NULL)) {
  1551. Status = WSAGetLastError();
  1552. if (Status != WSA_IO_PENDING) {
  1553. LdapConnection -> Release ();
  1554. DebugError (Status, _T("LDAP: Failed to issue send.\n"));
  1555. delete SendBuffer;
  1556. SendBuffer = NULL;
  1557. Terminate();
  1558. // we return TRUE, because we did dequeue a buffer,
  1559. // even if that buffer could not be transmitted.
  1560. return TRUE;
  1561. }
  1562. }
  1563. SendOverlapped.IsPending = TRUE;
  1564. return TRUE;
  1565. }
  1566. BOOL LDAP_SOCKET::GetLocalAddress (
  1567. OUT SOCKADDR_IN * ReturnAddress)
  1568. {
  1569. INT AddressLength;
  1570. AssertLocked();
  1571. if (State == STATE_CONNECTED) {
  1572. AddressLength = sizeof (SOCKADDR_IN);
  1573. if (getsockname (Socket, (SOCKADDR *) ReturnAddress, &AddressLength)) {
  1574. DebugLastErrorF (_T("LDAP: 0x%x failed to retrieve socket address.\n"), LdapConnection);
  1575. ZeroMemory (&ReturnAddress, sizeof (SOCKADDR_IN));
  1576. return FALSE;
  1577. }
  1578. return TRUE;
  1579. }
  1580. else {
  1581. return FALSE;
  1582. }
  1583. }
  1584. BOOL LDAP_SOCKET::GetRemoteAddress (
  1585. OUT SOCKADDR_IN * ReturnAddress)
  1586. {
  1587. INT AddressLength;
  1588. AssertLocked();
  1589. if (State == STATE_CONNECTED) {
  1590. AddressLength = sizeof (SOCKADDR_IN);
  1591. if (getpeername (Socket, (SOCKADDR *) ReturnAddress, &AddressLength)) {
  1592. DebugLastErrorF (_T("LDAP: 0x%x failed to retrieve peer address.\n"), LdapConnection);
  1593. ZeroMemory (&ReturnAddress, sizeof (SOCKADDR_IN));
  1594. return FALSE;
  1595. }
  1596. return TRUE;
  1597. }
  1598. else {
  1599. return FALSE;
  1600. }
  1601. }
  1602. // LDAP_CONNECTION ---------------------------------------------------
  1603. LDAP_CONNECTION::LDAP_CONNECTION (NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation)
  1604. : LIFETIME_CONTROLLER (&LdapSyncCounter) ,
  1605. ClientSocket (this, &PumpClientToServer, &PumpServerToClient),
  1606. ServerSocket (this, &PumpServerToClient, &PumpClientToServer),
  1607. PumpClientToServer (this, &ClientSocket, &ServerSocket),
  1608. PumpServerToClient (this, &ServerSocket, &ClientSocket)
  1609. {
  1610. SourceInterfaceAddress = 0;
  1611. DestinationInterfaceAddress = 0;
  1612. State = STATE_NONE;
  1613. DestinationAddress.sin_family = AF_INET;
  1614. DestinationAddress.sin_addr.s_addr = RedirectInformation -> DestinationAddress;
  1615. DestinationAddress.sin_port = RedirectInformation -> DestinationPort;
  1616. SourceAddress.sin_family = AF_INET;
  1617. SourceAddress.sin_addr.s_addr = RedirectInformation -> SourceAddress;
  1618. SourceAddress.sin_port = RedirectInformation -> SourcePort;
  1619. DebugF (_T("LDAP: 0x%x created.\n"), this);
  1620. }
  1621. HRESULT LDAP_CONNECTION::Initialize (
  1622. IN NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
  1623. )
  1624. {
  1625. HRESULT Result;
  1626. Lock ();
  1627. Result = InitializeLocked (RedirectInformation);
  1628. Unlock ();
  1629. return Result;
  1630. }
  1631. HRESULT LDAP_CONNECTION::InitializeLocked (
  1632. IN NAT_KEY_SESSION_MAPPING_EX_INFORMATION * RedirectInformation
  1633. )
  1634. {
  1635. ULONG Error;
  1636. DebugF (_T ("LDAP: 0x%x connection accepted on adapter %d.\n"), this, RedirectInformation -> AdapterIndex);
  1637. SourceInterfaceAddress = H323MapAdapterToAddress (RedirectInformation -> AdapterIndex);
  1638. if (INADDR_NONE == SourceInterfaceAddress) {
  1639. DebugF (_T ("LDAP: 0x%x failed to get source interface address (via H323MapAdapterToAddress).\n"), this);
  1640. return E_FAIL;
  1641. }
  1642. Error = GetBestInterfaceAddress (ntohl (DestinationAddress.sin_addr.s_addr), &DestinationInterfaceAddress);
  1643. if (ERROR_SUCCESS != Error) {
  1644. DebugErrorF (Error, _T ("LDAP: 0x%x failed to get destination interface address.\n"), this);
  1645. return HRESULT_FROM_WIN32 (Error);
  1646. }
  1647. DebugF (_T("LDAP: 0x%x arrived on interface %08X.\n"), this, SourceInterfaceAddress);
  1648. return S_OK;
  1649. }
  1650. LDAP_CONNECTION::~LDAP_CONNECTION (void)
  1651. {
  1652. DebugF (_T("LDAP: 0x%x destroyed.\n"), this);
  1653. }
  1654. void LDAP_CONNECTION::StartIo (void)
  1655. {
  1656. PumpClientToServer.Start ();
  1657. PumpServerToClient.Start ();
  1658. }
  1659. HRESULT LDAP_CONNECTION::AcceptSocket (
  1660. IN SOCKET Socket,
  1661. IN SOCKADDR_IN * LocalAddress,
  1662. IN SOCKADDR_IN * RemoteAddress,
  1663. IN SOCKADDR_IN * ArgActualDestinationAddress)
  1664. {
  1665. HRESULT Result;
  1666. Lock();
  1667. if (State == STATE_NONE) {
  1668. Result = ClientSocket.AcceptSocket (Socket);
  1669. if (Result == S_OK) {
  1670. Result = ServerSocket.IssueConnect (ArgActualDestinationAddress);
  1671. if (Result != S_OK) {
  1672. DebugErrorF (Result, _T("LDAP: 0x%x failed to issue async connect to %08X:%04X.\n"),
  1673. this,
  1674. SOCKADDR_IN_PRINTF (ArgActualDestinationAddress));
  1675. Terminate ();
  1676. }
  1677. }
  1678. else {
  1679. DebugErrorF (Result, _T("LDAP: 0x%x could not successfully complete accept.\n"), this);
  1680. Terminate ();
  1681. }
  1682. }
  1683. else {
  1684. DebugF (_T("LDAP: 0x%x is not in a valid state for accept (state != STATE_NONE).\n"), this);
  1685. Result = E_UNEXPECTED;
  1686. }
  1687. Unlock();
  1688. return Result;
  1689. }
  1690. HRESULT LDAP_CONNECTION::CreateOperation (
  1691. IN LDAP_OPERATION_TYPE Type,
  1692. IN LDAP_MESSAGE_ID MessageID,
  1693. IN ANSI_STRING * DirectoryPath,
  1694. IN ANSI_STRING * Alias,
  1695. IN IN_ADDR ClientAddress,
  1696. IN SOCKADDR_IN * ServerAddress,
  1697. IN DWORD EntryTimeToLive // in seconds
  1698. )
  1699. {
  1700. LDAP_OPERATION * Operation;
  1701. DWORD Index;
  1702. HRESULT Result;
  1703. if (FindOperationIndexByMessageID (MessageID, &Index)) {
  1704. DebugF (_T("LDAP: 0x%x - an operation with message ID (%u) is already pending.\n"),
  1705. this,
  1706. MessageID);
  1707. return E_FAIL;
  1708. }
  1709. Operation = OperationArray.AllocAtPos (Index);
  1710. if (!Operation) {
  1711. DebugF (_T("LDAP: 0x%x - CreateOperation allocation failure #1.\n"), this);
  1712. return E_OUTOFMEMORY;
  1713. }
  1714. Operation -> Type = Type;
  1715. Operation -> MessageID = MessageID;
  1716. Operation -> ClientAddress = ClientAddress;
  1717. Operation -> ServerAddress = *ServerAddress;
  1718. Operation -> EntryTimeToLive = EntryTimeToLive;
  1719. CopyAnsiString (DirectoryPath, &Operation -> DirectoryPath);
  1720. CopyAnsiString (Alias, &Operation -> Alias);
  1721. if ((Operation -> DirectoryPath.Buffer
  1722. && Operation -> Alias.Buffer)) {
  1723. // all is well
  1724. Result = S_OK;
  1725. }
  1726. else {
  1727. DebugF (_T("LDAP: 0x%x - CreateOperation allocation failure #2.\n"), this);
  1728. FreeAnsiString (&Operation -> DirectoryPath);
  1729. FreeAnsiString (&Operation -> Alias);
  1730. Result = E_OUTOFMEMORY;
  1731. }
  1732. return Result;
  1733. }
  1734. // Processing of LDAP messages ---------------------------------------
  1735. BOOL LDAP_CONNECTION::ProcessAddRequest (
  1736. IN LDAPMessage * Message)
  1737. {
  1738. AddRequest * Request;
  1739. ANSI_STRING DirectoryPath;
  1740. LDAP_PATH_ELEMENTS PathElements;
  1741. ANSI_STRING AttributeTag;
  1742. IN_ADDR OldClientAddress; // the address the client submitted in AddRequest
  1743. IN_ADDR NewClientAddress; // the address we are replacing it with
  1744. LDAP_OPERATION * Operation;
  1745. DWORD OperationInsertionIndex;
  1746. ASN1octetstring_t IPAddressOldValue;
  1747. SOCKADDR_IN LocalToServerAddress;
  1748. SOCKADDR_IN LocalToClientAddress;
  1749. SOCKADDR_IN ServerAddress;
  1750. INT AddressLength;
  1751. BOOL NeedObjectClass;
  1752. ANSI_STRING ClientAlias;
  1753. AddRequest_attrs * Iter;
  1754. AddRequest_attrs_Seq * Attribute;
  1755. AddRequest_attrs_Seq_values * ValueSequence;
  1756. AttributeValue * Attribute_Alias;
  1757. AttributeValue * Attribute_IPAddress;
  1758. AttributeValue * Attribute_ObjectClass;
  1759. AttributeValue * Attribute_Comment;
  1760. AttributeValue Attribute_Comment_Old;
  1761. ANSI_STRING String;
  1762. CHAR IPAddressText [0x20];
  1763. USHORT IPAddressTextLength;
  1764. Request = &Message -> protocolOp.u.addRequest;
  1765. // check to see if an existing operation with the same message id is pending.
  1766. // if so, the client is in violation of the LDAP spec.
  1767. // we'll just ignore the packet in this case.
  1768. // at the same time, compute the insertion position for the new operation (for use later).
  1769. if (FindOperationIndexByMessageID (Message -> messageID, &OperationInsertionIndex)) {
  1770. DebugF (_T("LDAP: 0x%x - client has issued two requests with the same message ID (%u), LDAP protocol violation, packet will not be processed.\n"),
  1771. this,
  1772. Message -> messageID);
  1773. return FALSE;
  1774. }
  1775. // NetMeeting supplies the objectClass in the directory path.
  1776. // TAPI supplies the objectClass in the attribute set.
  1777. // Don't you just love standards?
  1778. InitializeAnsiString (&DirectoryPath, &Request -> entry);
  1779. ParseDirectoryPath (&DirectoryPath, &PathElements);
  1780. // make sure that the alias is present
  1781. if (!PathElements.CN.Buffer) {
  1782. DebugF (_T("LDAP: 0x%x client %08X issued unqualified AddRequest (no alias present).\n"),
  1783. this,
  1784. ntohl (SourceAddress.sin_addr.s_addr));
  1785. return FALSE;
  1786. }
  1787. ClientAlias = PathElements.CN;
  1788. if (PathElements.ObjectClass.Buffer) {
  1789. if (RtlEqualStringConst (&PathElements.ObjectClass, &LdapText_RTPerson, TRUE)) {
  1790. NeedObjectClass = FALSE;
  1791. }
  1792. else {
  1793. DebugF (_T("LDAP: 0x%x client %08X issued unqualified AddRequest (no object class (1)).\n"),
  1794. this,
  1795. ntohl (SourceAddress.sin_addr.s_addr));
  1796. return FALSE;
  1797. }
  1798. }
  1799. else {
  1800. NeedObjectClass = TRUE;
  1801. }
  1802. // first, determine if the attributes of this object
  1803. // match the set of objects we wish to modify.
  1804. // scan through the set of attributes
  1805. // find interesting data
  1806. Attribute_IPAddress = NULL;
  1807. Attribute_ObjectClass = NULL;
  1808. Attribute_Comment = NULL;
  1809. for (Iter = Request -> attrs; Iter; Iter = Iter -> next) {
  1810. Attribute = &Iter -> value;
  1811. InitializeAnsiString (&AttributeTag, &Attribute -> type);
  1812. if (Attribute -> values) {
  1813. // we are only concerned with single-value attributes
  1814. // if it's one of the attributes that we want,
  1815. // then store in local variable
  1816. if (RtlEqualStringConst (&AttributeTag, &LdapText_Attribute_sipaddress, TRUE)
  1817. || RtlEqualStringConst (&AttributeTag, &LdapText_Attribute_ipAddress, TRUE))
  1818. Attribute_IPAddress = &Attribute -> values -> value;
  1819. else if (RtlEqualStringConst (&AttributeTag, &LdapText_ObjectClass, TRUE))
  1820. Attribute_ObjectClass = &Attribute -> values -> value;
  1821. else if (RtlEqualStringConst (&AttributeTag, &LdapText_Attribute_comment, TRUE))
  1822. Attribute_Comment = &Attribute -> values -> value;
  1823. // else, we aren't interested in the attribute
  1824. }
  1825. else {
  1826. // else, the attribute has no values
  1827. }
  1828. }
  1829. // make sure that we found an objectClass value.
  1830. // make sure that the objectClass = RTPerson
  1831. if (NeedObjectClass) {
  1832. if (!Attribute_ObjectClass) {
  1833. DebugF (_T("LDAP: 0x%x client %08X issued unqualified AddRequest (no object class (2)).\n"),
  1834. this,
  1835. ntohl (SourceAddress.sin_addr.s_addr));
  1836. return FALSE;
  1837. }
  1838. InitializeAnsiString (&String, Attribute_ObjectClass);
  1839. if (!RtlEqualStringConst (&String, &LdapText_RTPerson, TRUE)) {
  1840. DebugF (_T("LDAP: 0x%x client %08X issued unqualified AddRequest (not for RTPerson).\n"),
  1841. this,
  1842. ntohl (SourceAddress.sin_addr.s_addr));
  1843. return FALSE;
  1844. }
  1845. }
  1846. // if a comment field is present, and the comment is "Generated by TAPI3"
  1847. // modify it so that it says "Generated by TAPI3, modified by ICS"
  1848. if (Attribute_Comment) {
  1849. Attribute_Comment_Old = *Attribute_Comment;
  1850. InitializeAnsiString (&String, Attribute_Comment);
  1851. if (RtlEqualStringConst (&String, &LdapText_GeneratedByTAPI, TRUE)) {
  1852. Attribute_Comment -> value = (PUCHAR) LdapText_ModifiedByICS.Buffer;
  1853. Attribute_Comment -> length = LdapText_ModifiedByICS.Length * sizeof (CHAR);
  1854. }
  1855. }
  1856. // make sure ip address attribute is present
  1857. // parse the address, build replacement address
  1858. if (!Attribute_IPAddress) {
  1859. DebugF (_T("LDAP: 0x%x client %08X issued unqualified AddRequest (IP address not present).\n"),
  1860. this,
  1861. ntohl (SourceAddress.sin_addr.s_addr));
  1862. return FALSE;
  1863. }
  1864. if (LdapTranslationTable.ReachedMaximumSize ()) {
  1865. LDAPMessage AddRequestFailed;
  1866. DebugF(_T("LDAP: Size of LDAP Address Translation Table exceeded limit. Sending back AddResponse with an error code.\n"));
  1867. AddRequestFailed.messageID = Message -> messageID;
  1868. AddRequestFailed.protocolOp.choice = addResponse_choice;
  1869. AddRequestFailed.protocolOp.u.addResponse.resultCode = sizeLimitExceeded;
  1870. AddRequestFailed.protocolOp.u.addResponse.matchedDN.length = 0;
  1871. AddRequestFailed.protocolOp.u.addResponse.matchedDN.value = NULL;
  1872. AddRequestFailed.protocolOp.u.addResponse.errorMessage.length = LdapText_TableSizeExceededMessage.Length * sizeof (CHAR);
  1873. AddRequestFailed.protocolOp.u.addResponse.errorMessage.value = (PUCHAR) LdapText_TableSizeExceededMessage.Buffer;
  1874. PumpServerToClient.EncodeSendMessage (&AddRequestFailed);
  1875. } else {
  1876. if (!ServerSocket.GetRemoteAddress (&ServerAddress)) {
  1877. return FALSE;
  1878. }
  1879. IPAddressTextLength = min (0x1F, (USHORT) Attribute_IPAddress -> length);
  1880. IPAddressText [IPAddressTextLength] = 0;
  1881. memcpy (IPAddressText, Attribute_IPAddress -> value, IPAddressTextLength * sizeof (CHAR));
  1882. if (RtlCharToInteger (IPAddressText, 10, &OldClientAddress.s_addr) != STATUS_SUCCESS) {
  1883. DebugF (_T("LDAP: 0x%x - AddRequest: bogus IP address value (%.*S).\n"),
  1884. this,
  1885. Attribute_IPAddress -> length,
  1886. Attribute_IPAddress -> value);
  1887. return FALSE;
  1888. }
  1889. // If ILS is running locally, we will not modify AddRequest sent by any private client.
  1890. // Instead, we will later modify SearchResponse PDU if it turned out that
  1891. // the name of the client being searched for is stored in LDAP Address Translation Table, and
  1892. // the matching SearchRequest PDU came from a machine external to the client's local subnet.
  1893. // The address we will put into the modified SearchResponse PDU will be that of the
  1894. // interface on which SearchRequest was received (public interface, or another local interface)
  1895. // If SearchRequest came from a private client located on the same subnet as the client we
  1896. // are registering here, we won't modify it as those two clients can communicate directly
  1897. // and don't require any proxying by the NAT machine.
  1898. if (!::NhIsLocalAddress (ServerAddress.sin_addr.s_addr)) {
  1899. // get the address that we want to substitute (our external interface address)
  1900. if (!ServerSocket.GetLocalAddress (&LocalToServerAddress)) {
  1901. DebugF (_T("LDAP: 0x%x failed to get local address to server -- internal error.\n"), this);
  1902. return FALSE;
  1903. }
  1904. // Convoluted code alert!
  1905. // NetMeeting stores its IP address as an attribute on an LDAP object on an ILS server.
  1906. // Makes sense. The attribute is encoded as a textual string, so they had to convert
  1907. // the IP address to text. Any sane person would have chosen the standard dotted-quad
  1908. // format, but they chose to interpret the IP address as a 32-bit unsigned integer,
  1909. // which is fair enough, and then to convert that integer to a single decimal text string.
  1910. // That's all great, that's just fine. But NetMeeting stores the attribute byte-swapped
  1911. // -- they used ntohl one too many times. Grrrrrrrr.... The value should have been stored
  1912. // without swapping the bytes, since the interpretation was "unsigned integer" and not "octet sequence".
  1913. OldClientAddress.s_addr = htonl (ByteSwap (OldClientAddress.s_addr));
  1914. NewClientAddress = LocalToServerAddress.sin_addr;
  1915. // believe me, this IS CORRECT.
  1916. // see the long note above for more info. -- arlied
  1917. if (RtlIntegerToChar (ByteSwap (ntohl (NewClientAddress.s_addr)),
  1918. 10, 0x1F, IPAddressText) != STATUS_SUCCESS) {
  1919. DebugF (_T("LDAP: 0x%x failed to convert IP address to text -- internal error.\n"), this);
  1920. return FALSE;
  1921. }
  1922. DebugF (_T("LDAP: 0x%x will register %08X on the ILS.\n"), this, ntohl (NewClientAddress.s_addr));
  1923. } else {
  1924. DebugF (_T("LDAP: 0x%x will register %08X on the ILS.\n"), this, ntohl (OldClientAddress.s_addr));
  1925. }
  1926. // allocate and build an LDAP_OPERATION structure.
  1927. DebugF (_T("LDAP: 0x%x inserts valid AddRequest into operation table.\n"), this);
  1928. CreateOperation (
  1929. LDAP_OPERATION_ADD,
  1930. Message -> messageID,
  1931. &DirectoryPath,
  1932. &ClientAlias,
  1933. OldClientAddress,
  1934. &ServerAddress,
  1935. LDAP_TRANSLATION_TABLE_ENTRY_INITIAL_TIME_TO_LIVE);
  1936. // the entry is now in the operation array
  1937. // later, when the server sends the AddResponse,
  1938. // we'll match the response with the request,
  1939. // and modify the LDAP_TRANSLATION_TABLE
  1940. // now, in-place, we modify the PDU structure,
  1941. // reencode it, send it, undo the modification
  1942. // (so ASN1Free_AddRequest doesn't act up)
  1943. assert (Attribute_IPAddress);
  1944. IPAddressOldValue = *Attribute_IPAddress;
  1945. Attribute_IPAddress -> value = (PUCHAR) IPAddressText;
  1946. Attribute_IPAddress -> length = strlen (IPAddressText);
  1947. PumpClientToServer.EncodeSendMessage (Message);
  1948. // switch back so we don't a/v when decoder frees pdu
  1949. *Attribute_IPAddress = IPAddressOldValue;
  1950. if (Attribute_Comment)
  1951. *Attribute_Comment = Attribute_Comment_Old;
  1952. }
  1953. return TRUE;
  1954. }
  1955. BOOL LDAP_CONNECTION::ProcessModifyRequest (
  1956. IN LDAP_MESSAGE_ID MessageID,
  1957. IN ModifyRequest * Request)
  1958. {
  1959. ModifyRequest_modifications * ModificationIterator;
  1960. ModifyRequest_modifications_Seq * Modification;
  1961. PModifyRequest_modifications_Seq_modification_values ModificationValue;
  1962. LPCTSTR Op;
  1963. ANSI_STRING ModificationType;
  1964. ANSI_STRING TimeToLive;
  1965. ANSI_STRING DirectoryPath;
  1966. ANSI_STRING ClientAlias;
  1967. DWORD OperationInsertionIndex;
  1968. LDAP_PATH_ELEMENTS PathElements;
  1969. BOOL IsValidRefreshRequest = FALSE;
  1970. SOCKADDR_IN ServerAddress;
  1971. DWORD EntryTimeToLive = 0;
  1972. CHAR EntryTimeToLiveText [11];
  1973. USHORT EntryTimeToLiveLength;
  1974. // check to see if an existing operation with the same message id is pending.
  1975. // if so, the client is in violation of the LDAP spec.
  1976. // we'll just ignore the packet in this case.
  1977. // at the same time, compute the insertion position for the new operation (for use later).
  1978. if (FindOperationIndexByMessageID (MessageID, &OperationInsertionIndex)) {
  1979. DebugF (_T("LDAP: 0x%x - ModifyRequest: client has issued two requests with the same message ID (%u), LDAP protocol violation, packet will not be processed.\n"),
  1980. this,
  1981. MessageID);
  1982. return FALSE;
  1983. }
  1984. // Cover the case when ModifyRequest does not supply baseObject
  1985. if (Request -> object.value == NULL || Request -> object.length == 0) {
  1986. DebugF (_T("LDAP: 0x%x client %08X issued unqualified ModifyRequest (no base object).\n"),
  1987. this,
  1988. ntohl (SourceAddress.sin_addr.s_addr));
  1989. return FALSE;
  1990. }
  1991. InitializeAnsiString (&DirectoryPath, &Request -> object);
  1992. ParseDirectoryPath (&DirectoryPath, &PathElements);
  1993. ClientAlias = PathElements.CN;
  1994. for (ModificationIterator = Request -> modifications; ModificationIterator; ModificationIterator = ModificationIterator -> next) {
  1995. Modification = &ModificationIterator -> value;
  1996. InitializeAnsiString (&ModificationType, &Modification -> modification.type);
  1997. if (RtlEqualStringConst (&ModificationType, &LdapText_Modify_EntryTTL, TRUE) && Modification -> operation == replace) {
  1998. IsValidRefreshRequest = TRUE;
  1999. assert (Modification -> modification.values);
  2000. ModificationValue = Modification -> modification.values;
  2001. InitializeAnsiString (&TimeToLive, &ModificationValue -> value);
  2002. EntryTimeToLiveLength = min (10, (USHORT) ModificationValue -> value.length);
  2003. EntryTimeToLiveText [EntryTimeToLiveLength] = 0;
  2004. memcpy (EntryTimeToLiveText, ModificationValue -> value.value, EntryTimeToLiveLength * sizeof (CHAR));
  2005. if (RtlCharToInteger (&EntryTimeToLiveText [0], 10, &EntryTimeToLive) != STATUS_SUCCESS) {
  2006. DebugF (_T("LDAP: 0x%x - ModifyRequest: bogus Time-To-Live value (%.*S).\n"),
  2007. this,
  2008. EntryTimeToLiveLength,
  2009. EntryTimeToLiveText);
  2010. return FALSE;
  2011. }
  2012. DebugF (_T("LDAP: 0x%x %08X requested lifetime increase of %d seconds for (%.*S).\n"),
  2013. this,
  2014. ntohl (SourceAddress.sin_addr.s_addr),
  2015. EntryTimeToLive, // in seconds
  2016. ANSI_STRING_PRINTF (&ClientAlias));
  2017. }
  2018. }
  2019. // If type of the modification was 'replace', and the attribute to be modified was 'EntryTTL'
  2020. // then we have just received a valid refresh request from PhoneDialer
  2021. //
  2022. if (!IsValidRefreshRequest) {
  2023. DebugF (_T("LDAP: 0x%x client %08X issued unqualified ModifyRequest (not a refresh request).\n"),
  2024. this,
  2025. ntohl (SourceAddress.sin_addr.s_addr));
  2026. return FALSE;
  2027. }
  2028. if (!ClientAlias.Buffer || ClientAlias.Length == 0) {
  2029. DebugF (_T("LDAP: 0x%x client %08X issued unqualified ModifyRequest (no client alias in refresh request).\n"),
  2030. this,
  2031. ntohl (SourceAddress.sin_addr.s_addr));
  2032. return FALSE;
  2033. }
  2034. if (!ServerSocket.GetRemoteAddress (&ServerAddress)) {
  2035. DebugF (_T("LDAP: 0x%x ModifyRequest: failed to get server address -- internal error.\n"),
  2036. this,
  2037. ntohl (SourceAddress.sin_addr.s_addr));
  2038. return FALSE;
  2039. }
  2040. DebugF (_T("LDAP: 0x%x inserts valid ModifyRequest into operation table.\n"), this);
  2041. // Allocate and build an LDAP_OPERATION structure.
  2042. CreateOperation (
  2043. LDAP_OPERATION_MODIFY,
  2044. MessageID,
  2045. &DirectoryPath,
  2046. &ClientAlias,
  2047. SourceAddress.sin_addr,
  2048. &ServerAddress,
  2049. EntryTimeToLive
  2050. );
  2051. // The entry is now in the operation array
  2052. // later, when the server sends the ModifyResponse,
  2053. // we'll check whether it was successful.
  2054. // If so, we will find and refresh matching
  2055. // entry in the LDAP Address Translation Table
  2056. return FALSE;
  2057. }
  2058. BOOL LDAP_CONNECTION::ProcessDeleteRequest (
  2059. IN LDAP_MESSAGE_ID MessageID,
  2060. IN DelRequest * Request)
  2061. {
  2062. ANSI_STRING DirectoryPath;
  2063. HRESULT Result = S_FALSE;
  2064. LDAP_PATH_ELEMENTS PathElements;
  2065. assert (Request);
  2066. DirectoryPath.Buffer = (PCHAR) Request -> value;
  2067. DirectoryPath.Length = (USHORT) Request -> length;
  2068. DirectoryPath.MaximumLength = (USHORT) Request -> length;
  2069. ParseDirectoryPath (&DirectoryPath, &PathElements);
  2070. if (RtlEqualStringConst (&PathElements.ObjectClass, &LdapText_RTPerson, TRUE)) {
  2071. Result = LdapTranslationTable.RemoveEntryByAliasServer (&PathElements.CN, &DestinationAddress);
  2072. if (Result == S_OK) {
  2073. DebugF (_T("LDAP: 0x%x removed entry (%.*S) from LDAP table.\n"),
  2074. this,
  2075. ANSI_STRING_PRINTF (&DirectoryPath));
  2076. } else {
  2077. DebugF (_T("LDAP: 0x%x attempted to remove entry (%.*S) from LDAP table, but it was not there.\n"),
  2078. this,
  2079. ANSI_STRING_PRINTF (&DirectoryPath));
  2080. }
  2081. } else {
  2082. DebugF (_T("LDAP: 0x%x client %08X issued unqualified DeleteRequest.\n"),
  2083. this,
  2084. ntohl (SourceAddress.sin_addr.s_addr));
  2085. }
  2086. return FALSE;
  2087. }
  2088. BOOL LDAP_CONNECTION::ProcessSearchRequest (
  2089. IN LDAPMessage * Message)
  2090. {
  2091. SearchRequest * Request;
  2092. ANSI_STRING DirectoryPath;
  2093. ANSI_STRING AttributeTag;
  2094. ANSI_STRING AttributeType;
  2095. ANSI_STRING AttributeValue;
  2096. ANSI_STRING RequestedForAlias;
  2097. LDAP_PATH_ELEMENTS PathElements;
  2098. LDAP_OPERATION * Operation;
  2099. Filter * SearchFilter;
  2100. Filter_and * FilterIterator;
  2101. SearchRequest_attributes * Iterator;
  2102. AttributeValueAssertion * EqualityAssertion;
  2103. BOOL IsRequestForIPAddress = FALSE;
  2104. BOOL IsRequestForRTPerson = FALSE;
  2105. BOOL IsRequestForSttl = FALSE;
  2106. BOOL IsQualifiedRequest = FALSE;
  2107. BOOL IsRequestForSpecificAlias = FALSE;
  2108. DWORD EntryTimeToLive = 0;
  2109. CHAR EntryTimeToLiveText [11];
  2110. USHORT EntryTimeToLiveLength;
  2111. DWORD OperationInsertionIndex;
  2112. Request = &Message -> protocolOp.u.searchRequest;
  2113. // check to see if an existing operation with the same message id is pending.
  2114. // if so, the client is in violation of the LDAP spec.
  2115. // we'll just ignore the packet in this case.
  2116. // at the same time, compute the insertion position for the new operation (for use later).
  2117. if (FindOperationIndexByMessageID (Message -> messageID, &OperationInsertionIndex)) {
  2118. DebugF (_T("LDAP: 0x%x - SearchRequest - client has issued two requests with the same message ID (%u), LDAP protocol violation, packet will not be processed.\n"),
  2119. this,
  2120. Message -> messageID);
  2121. return FALSE;
  2122. }
  2123. // Cover the case when SearchRequest does not supply baseObject
  2124. if (Request -> baseObject.value == NULL || Request -> baseObject.length == 0) {
  2125. DebugF (_T("LDAP: 0x%x client %08X issued unqualified SearchRequest (no base object).\n"),
  2126. this,
  2127. ntohl (SourceAddress.sin_addr.s_addr));
  2128. return FALSE;
  2129. }
  2130. InitializeAnsiString (&DirectoryPath, &Request -> baseObject);
  2131. ParseDirectoryPath (&DirectoryPath, &PathElements);
  2132. // Determine whether we are interested in this request.
  2133. //
  2134. // This is what we are interested in from SearchRequests originated by NetMeeting:
  2135. // 1. It searches for IP address (query to the server), or
  2136. // 2. It searches for Sttl attribute, AND for RTPerson attribute (refresh request)
  2137. //
  2138. for (Iterator = Request -> attributes; Iterator; Iterator = Iterator -> next) {
  2139. InitializeAnsiString (&AttributeValue, &Iterator -> value);
  2140. if (RtlEqualStringConst (&AttributeValue, &LdapText_Attribute_sipaddress, TRUE)
  2141. || RtlEqualStringConst (&AttributeValue, &LdapText_Attribute_ipAddress, TRUE)) {
  2142. IsRequestForIPAddress = TRUE;
  2143. }
  2144. // else not interesting attribute
  2145. }
  2146. // Look closer at the composition of the filter.
  2147. //
  2148. // NetMeeting specifies the following filter in SearchRequest:
  2149. //
  2150. // FilterType = AND
  2151. // FilterType = EqualityMatch
  2152. // AttributeType = objectClass
  2153. // AttributeValue = RTPerson
  2154. // FilterType = EqualityMatch
  2155. // AttributeType = cn
  2156. // AttributeValue = <...alias, for which IP address is searched, or refresh is requested...>
  2157. //
  2158. // NetMeeting may also add the following 'EqualityMatch' clause to the filter
  2159. // if a Time-To-Live increase is requested
  2160. //
  2161. // FilterType = EqualityMatch
  2162. // AttributeType = sttl
  2163. // AttributeValue = <...increase in Time-To-Live, in minutes...>
  2164. //
  2165. // Phone Dialer DOES NOT query directory server to determine IP address of the called party.
  2166. // It does the determination by some other means (DNS lookup, most certainly).
  2167. SearchFilter = &Request -> filter;
  2168. switch (SearchFilter -> choice) {
  2169. case and_choice:
  2170. for (FilterIterator = SearchFilter -> u.and; FilterIterator; FilterIterator = FilterIterator -> next) {
  2171. switch (FilterIterator -> value.choice) {
  2172. case equalityMatch_choice:
  2173. EqualityAssertion = &FilterIterator -> value.u.equalityMatch;
  2174. InitializeAnsiString (&AttributeType, &EqualityAssertion -> attributeType);
  2175. InitializeAnsiString (&AttributeValue, &EqualityAssertion -> attributeValue);
  2176. if (RtlEqualStringConst (&AttributeType, &LdapText_Attribute_sttl, TRUE)) {
  2177. IsRequestForSttl = TRUE;
  2178. EntryTimeToLiveLength = min (10, (USHORT) AttributeValue.Length);
  2179. EntryTimeToLiveText [EntryTimeToLiveLength] = 0;
  2180. memcpy (EntryTimeToLiveText, AttributeValue.Buffer, EntryTimeToLiveLength * sizeof (CHAR));
  2181. if (RtlCharToInteger (&EntryTimeToLiveText [0], 10, &EntryTimeToLive) != STATUS_SUCCESS) {
  2182. DebugF (_T("LDAP: 0x%x - SearchRequest: bogus Time-To-Live value (%.*S).\n"),
  2183. this,
  2184. EntryTimeToLiveLength,
  2185. EntryTimeToLiveText);
  2186. return FALSE;
  2187. }
  2188. }
  2189. if (RtlEqualStringConst (&AttributeType, &LdapText_ObjectClass, TRUE)
  2190. || RtlEqualStringConst (&AttributeValue, &LdapText_RTPerson, TRUE)) {
  2191. IsRequestForRTPerson = TRUE;
  2192. }
  2193. if (RtlEqualStringConst (&AttributeType, &LdapText_CN, TRUE)) {
  2194. RequestedForAlias = AttributeValue;
  2195. IsRequestForSpecificAlias = TRUE;
  2196. }
  2197. break;
  2198. default:
  2199. break;
  2200. }
  2201. }
  2202. break;
  2203. default:
  2204. break;
  2205. }
  2206. IsQualifiedRequest = IsRequestForIPAddress || (IsRequestForRTPerson && IsRequestForSttl);
  2207. if (!IsQualifiedRequest) {
  2208. DebugF (_T("LDAP: 0x%x client %08X issued unqualified SearchRequest.\n"),
  2209. this,
  2210. ntohl (SourceAddress.sin_addr.s_addr));
  2211. return FALSE;
  2212. }
  2213. if (IsRequestForSttl) {
  2214. DebugF (_T("LDAP: 0x%x %08X requested lifetime increase of %d seconds for (%.*S).\n"),
  2215. this,
  2216. ntohl (SourceAddress.sin_addr.s_addr),
  2217. EntryTimeToLive * 60, // in seconds
  2218. ANSI_STRING_PRINTF (&RequestedForAlias));
  2219. }
  2220. if (IsRequestForIPAddress) {
  2221. if (IsRequestForSpecificAlias) {
  2222. DebugF (_T("LDAP: 0x%x %08X requested IP address for (%.*S).\n"),
  2223. this,
  2224. ntohl (SourceAddress.sin_addr.s_addr),
  2225. ANSI_STRING_PRINTF (&RequestedForAlias));
  2226. } else {
  2227. DebugF (_T("LDAP: 0x%x %08X issued unspecified request for IP address.\n"),
  2228. this,
  2229. ntohl (SourceAddress.sin_addr.s_addr) );
  2230. }
  2231. }
  2232. DebugF (_T("LDAP: 0x%x inserts valid SearchRequest into operation table.\n"), this);
  2233. // allocate and build an LDAP_OPERATION structure.
  2234. CreateOperation (
  2235. LDAP_OPERATION_SEARCH,
  2236. Message -> messageID,
  2237. &DirectoryPath,
  2238. &PathElements.CN,
  2239. SourceAddress.sin_addr,
  2240. &DestinationAddress,
  2241. EntryTimeToLive * 60); // in seconds
  2242. // the entry is now in the operation array
  2243. // later, when the server sends the SearchResponse,
  2244. // we'll match the response with the request,
  2245. // and modify the IP address if an entry with
  2246. // the matching alias happens to be in the
  2247. // LDAP_TRANSLATION_TABLE. This would mean that
  2248. // the client running on the proxy machine itself
  2249. // wishes to connect to a private subnet client.
  2250. PumpClientToServer.EncodeSendMessage (Message);
  2251. return TRUE;
  2252. }
  2253. // server to client messages
  2254. void LDAP_CONNECTION::ProcessAddResponse (
  2255. IN LDAPMessage * Message)
  2256. {
  2257. AddResponse * Response;
  2258. LDAP_OPERATION * Operation;
  2259. Response = &Message -> protocolOp.u.addResponse;
  2260. AssertLocked();
  2261. if (!FindOperationByMessageID (Message -> messageID, &Operation)) {
  2262. return;
  2263. }
  2264. if (Operation -> Type == LDAP_OPERATION_ADD) {
  2265. if (Response -> resultCode == success) {
  2266. DebugF (_T("LDAP: 0x%x server has approved AddRequest for (%.*S).\n"),
  2267. this, ANSI_STRING_PRINTF (&Operation -> Alias));
  2268. assert (Operation -> Alias.Buffer);
  2269. assert (Operation -> DirectoryPath.Buffer);
  2270. InterfaceArray.StartQ931ReceiveRedirects ();
  2271. LdapTranslationTable.InsertEntry (
  2272. &Operation -> Alias,
  2273. &Operation -> DirectoryPath,
  2274. Operation -> ClientAddress,
  2275. &Operation -> ServerAddress,
  2276. Operation -> EntryTimeToLive);
  2277. }
  2278. else {
  2279. DebugF (_T("LDAP: 0x%x Server has rejected AddRequest, result code (%u).\n"),
  2280. this,
  2281. Response -> resultCode);
  2282. }
  2283. }
  2284. else {
  2285. DebugF (_T("LDAP: 0x%x received AddResponse with message ID (%u), and found matching pending request, but the type of the request does not match (%d).\n"),
  2286. this,
  2287. Message -> messageID,
  2288. Operation -> Type);
  2289. }
  2290. Operation -> FreeContents ();
  2291. OperationArray.DeleteEntry (Operation);
  2292. }
  2293. void LDAP_CONNECTION::ProcessModifyResponse (
  2294. IN LDAP_MESSAGE_ID MessageID,
  2295. IN ModifyResponse * Response)
  2296. {
  2297. LDAP_OPERATION * Operation;
  2298. AssertLocked();
  2299. if (!FindOperationByMessageID (MessageID, &Operation)) {
  2300. return;
  2301. }
  2302. if (Operation -> Type == LDAP_OPERATION_MODIFY) {
  2303. if (Response -> resultCode == success) {
  2304. assert (Operation -> Alias.Buffer);
  2305. assert (Operation -> DirectoryPath.Buffer);
  2306. DebugF (_T("LDAP: 0x%x server %08X has approved increase in lifetime of entry (%.*S) by %d seconds.\n"),
  2307. this,
  2308. ntohl (Operation -> ServerAddress.sin_addr.s_addr),
  2309. ANSI_STRING_PRINTF (&Operation -> Alias),
  2310. Operation -> EntryTimeToLive);
  2311. LdapTranslationTable.RefreshEntry (&Operation -> Alias,
  2312. &Operation -> DirectoryPath,
  2313. Operation -> ClientAddress,
  2314. &Operation -> ServerAddress,
  2315. Operation -> EntryTimeToLive);
  2316. }
  2317. else {
  2318. DebugF (_T("LDAP: 0x%x server %08X has rejected ModifyRequest, result code (%u).\n"),
  2319. this,
  2320. ntohl (Operation -> ServerAddress.sin_addr.s_addr), Response -> resultCode);
  2321. }
  2322. }
  2323. else {
  2324. DebugF (_T("LDAP: 0x%x received with message ID (%u), and found matching pending request, but the type of the request does not match (%d).\n"),
  2325. this,
  2326. MessageID,
  2327. Operation -> Type);
  2328. }
  2329. Operation -> FreeContents ();
  2330. OperationArray.DeleteEntry (Operation);
  2331. }
  2332. void LDAP_CONNECTION::ProcessDeleteResponse (
  2333. IN LDAP_MESSAGE_ID MessageID,
  2334. IN DelResponse * Response)
  2335. {
  2336. }
  2337. BOOL LDAP_CONNECTION::ProcessSearchResponse (
  2338. IN LDAPMessage * Message)
  2339. {
  2340. SearchResponse * Response;
  2341. ANSI_STRING ObjectName;
  2342. LDAP_OBJECT_NAME_ELEMENTS ObjectNameElements = { 0 };
  2343. ANSI_STRING AttributeTag;
  2344. ASN1octetstring_t IPAddressOldValue;
  2345. ANSI_STRING ClientAlias;
  2346. ANSI_STRING String;
  2347. ANSI_STRING ErrorMessage;
  2348. HRESULT TranslationTableLookupResult;
  2349. DWORD LookupAddress; // host order
  2350. SOCKADDR_IN ServerAddress;
  2351. DWORD LocalToRequestedAddress; // host order
  2352. DWORD AddressToReport;
  2353. SearchResponse_entry_attributes * Iter;
  2354. SearchResponse_entry_attributes_Seq_values * ValueSequence;
  2355. SearchResponse_entry_attributes_Seq * Attribute;
  2356. AttributeValue * Attribute_IPAddress;
  2357. AttributeValue * Attribute_Sttl;
  2358. CHAR IPAddressText [0x20];
  2359. BOOL Result = FALSE;
  2360. LDAP_OPERATION * Operation;
  2361. SOCKET UDP_Socket = INVALID_SOCKET;
  2362. assert (Message);
  2363. Response = &Message -> protocolOp.u.searchResponse;
  2364. AssertLocked();
  2365. if (!FindOperationByMessageID (Message -> messageID, &Operation)) {
  2366. return FALSE;
  2367. }
  2368. switch (Response -> choice) {
  2369. case entry_choice:
  2370. // Determine address of the server
  2371. if (!ServerSocket.GetRemoteAddress (&ServerAddress)) {
  2372. return FALSE;
  2373. }
  2374. if(Response -> choice == entry_choice) {
  2375. if (Operation -> Type == LDAP_OPERATION_SEARCH) {
  2376. // Parse this object's name to get alias and IP address
  2377. InitializeAnsiString (&ObjectName, &Response -> u.entry.objectName);
  2378. ParseObjectName (&ObjectName, &ObjectNameElements);
  2379. // scan through the set of attributes
  2380. // find the ones of interest
  2381. Attribute_IPAddress = NULL;
  2382. Attribute_Sttl = NULL;
  2383. for (Iter = Response -> u.entry.attributes; Iter; Iter = Iter -> next) {
  2384. Attribute = &Iter -> value;
  2385. InitializeAnsiString (&AttributeTag, &Attribute -> type);
  2386. if (Attribute -> values) {
  2387. if (RtlEqualStringConst (&AttributeTag, &LdapText_Attribute_sipaddress, TRUE)
  2388. || RtlEqualStringConst (&AttributeTag, &LdapText_Attribute_ipAddress, TRUE)) {
  2389. Attribute_IPAddress = &Attribute -> values -> value;
  2390. } else if (RtlEqualStringConst (&AttributeTag, &LdapText_Attribute_sttl, TRUE)) {
  2391. Attribute_Sttl = &Attribute -> values -> value;
  2392. }
  2393. // else, we aren't interested in the attribute
  2394. }
  2395. else {
  2396. // else, the attribute has no values
  2397. }
  2398. }
  2399. // make sure that the alias is present
  2400. ClientAlias = ObjectNameElements.CN;
  2401. if (ClientAlias.Length == 0) {
  2402. Result = FALSE;
  2403. } else {
  2404. if (Attribute_Sttl) {
  2405. // NetMeeting refreshes its registrations on an ILS by periodically sending a SearchRequest with
  2406. // attribute "sttl"
  2407. DebugF (_T ("LDAP: 0x%x server %08X has approved increase in lifetime of entry (%.*S) by %d seconds.\n"),
  2408. this,
  2409. ntohl (ServerAddress.sin_addr.s_addr),
  2410. ANSI_STRING_PRINTF (&ClientAlias),
  2411. Operation -> EntryTimeToLive);
  2412. LdapTranslationTable.RefreshEntry (&ClientAlias,
  2413. &ObjectName,
  2414. Operation -> ClientAddress,
  2415. &Operation -> ServerAddress,
  2416. Operation -> EntryTimeToLive);
  2417. } else {
  2418. // make sure ip address attribute is present
  2419. if (!Attribute_IPAddress) {
  2420. Result = FALSE;
  2421. } else {
  2422. // see whether there is a registration entry in the translation table
  2423. // with the same alias
  2424. TranslationTableLookupResult = LdapQueryTableByAliasServer (&ClientAlias,
  2425. &Operation -> ServerAddress,
  2426. &LookupAddress);
  2427. // If an entry with the same alias is not in the table,
  2428. // then we send the SearchResponse PDU unmodified to the requestor
  2429. if (S_OK != TranslationTableLookupResult) {
  2430. Result = FALSE;
  2431. } else {
  2432. // Otherwise, we decide what would be the correct address
  2433. // to report to the requestor. We will either report the address
  2434. // read from the Address Translation Table, or the address
  2435. // of the interface requestor used to reach us. The decision will be
  2436. // made based on the interface address requestor used to reach us, and
  2437. // address of the interface we would use to reach the requestee.
  2438. if (INADDR_NONE == SourceInterfaceAddress) {
  2439. DebugF (_T("LDAP: 0x%x failed to get best interface address for the requestor.\n"), this);
  2440. return FALSE;
  2441. }
  2442. // Determine on which interface we would connect to the entity whose address was requested
  2443. if (GetBestInterfaceAddress (LookupAddress, &LocalToRequestedAddress)) {
  2444. DebugF (_T("LDAP: 0x%x failed to get best interface address for the requestee.\n"), this);
  2445. return FALSE;
  2446. }
  2447. // The default reporting behaviour is to report the address of the best interface to reach the requestor,
  2448. // thus shielding the requestor from the knowledge of the network internals.
  2449. //
  2450. // However, there are three exceptions to this rule, when we report the actual address stored
  2451. // in the Address Translation Table. These exceptions are as follows:
  2452. //
  2453. // 1. If the requestor is local.
  2454. // In this case we assume that the requestor can directly reach the requestee, and thus
  2455. // an H.323 call between them doesn't have to be routed via us.
  2456. //
  2457. // 2. If local H323 routing is enabled, AND the requestor and the requestee have the same address
  2458. // This is necessary to allow the requestor to do something special with the calls to itself
  2459. // (NetMeeting, for example, prohibits such calls).
  2460. //
  2461. // 3. If local H323 routing is disabled, and requestor and requestee are reachable through the
  2462. // same interface.
  2463. // In these case we assume that the requestor and the requestee can directly reach one another,
  2464. // and thus an H.323 call between them doesn't have to be routed via us.
  2465. //
  2466. if (::NhIsLocalAddress (SourceAddress.sin_addr.s_addr)) {
  2467. AddressToReport = LookupAddress;
  2468. } else {
  2469. if (EnableLocalH323Routing) {
  2470. AddressToReport = (ntohl (SourceAddress.sin_addr.s_addr) == LookupAddress) ?
  2471. LookupAddress :
  2472. SourceInterfaceAddress;
  2473. } else {
  2474. AddressToReport = (SourceInterfaceAddress == LocalToRequestedAddress) ?
  2475. LookupAddress :
  2476. SourceInterfaceAddress;
  2477. }
  2478. }
  2479. assert (Attribute_IPAddress);
  2480. if (RtlIntegerToChar (htonl (AddressToReport),
  2481. 10, 0x1F, IPAddressText) != STATUS_SUCCESS) {
  2482. DebugF (_T("LDAP: 0x%x failed to convert IP address to text -- internal error.\n"), this);
  2483. Result = FALSE;
  2484. } else {
  2485. DebugF (_T("LDAP: 0x%x read %08X in table. Reporting %08X to requestor %08X.\n"),
  2486. this,
  2487. LookupAddress, AddressToReport, ntohl (SourceAddress.sin_addr.s_addr));
  2488. // Save the old value of the IP address, - we will need to restore
  2489. // the PDU structure later.
  2490. IPAddressOldValue = *Attribute_IPAddress;
  2491. // now, in-place, we modify the PDU structure,
  2492. // reencode it, send it, undo the modification
  2493. // (so ASN1Free_SearchResponse doesn't act up)
  2494. Attribute_IPAddress -> value = (PUCHAR) IPAddressText;
  2495. Attribute_IPAddress -> length = strlen (IPAddressText);
  2496. PumpServerToClient.EncodeSendMessage (Message);
  2497. // switch back so we don't a/v when decoder frees pdu
  2498. *Attribute_IPAddress = IPAddressOldValue;
  2499. Result = TRUE;
  2500. }
  2501. }
  2502. }
  2503. }
  2504. }
  2505. } else {
  2506. DebugF (_T("LDAP: 0x%x received response with message ID (%u), and found matching pending request, but the type of the request does not match (%d).\n"),
  2507. this,
  2508. Message -> messageID,
  2509. Operation -> Type);
  2510. Result = FALSE;
  2511. }
  2512. }
  2513. break;
  2514. case resultCode_choice:
  2515. // We free the operation and associated memory on SearchResponses containing result
  2516. // code, no matter whether the code indicated success or failure
  2517. InitializeAnsiString (&ErrorMessage, &Response -> u.resultCode.errorMessage);
  2518. DebugF (_T("LDAP: 0x%x result in SearchResponse (%d) (code=%d message=(%*.S)).\n"),
  2519. this,
  2520. Message -> messageID,
  2521. Response -> u.resultCode.resultCode,
  2522. ANSI_STRING_PRINTF (&ErrorMessage));
  2523. Operation -> FreeContents ();
  2524. OperationArray.DeleteEntry (Operation);
  2525. break;
  2526. default:
  2527. AssertNeverReached ();
  2528. }
  2529. return Result;
  2530. }
  2531. // this method does not assume ownership of the LdapMessage structure,
  2532. // which has scope only of this call stack.
  2533. BOOL LDAP_CONNECTION::ProcessLdapMessage (
  2534. IN LDAP_PUMP * Pump,
  2535. IN LDAPMessage * LdapMessage)
  2536. {
  2537. assert (Pump);
  2538. assert (LdapMessage);
  2539. if (Pump == &PumpClientToServer) {
  2540. switch (LdapMessage -> protocolOp.choice) {
  2541. case addRequest_choice:
  2542. DebugF (_T("LDAP: 0x%x received AddRequest (%d).\n"), this, LdapMessage -> messageID);
  2543. return ProcessAddRequest (LdapMessage);
  2544. case modifyRequest_choice:
  2545. DebugF (_T("LDAP: 0x%x received ModifyRequest (%d).\n"), this, LdapMessage -> messageID);
  2546. return ProcessModifyRequest (LdapMessage -> messageID, &LdapMessage -> protocolOp.u.modifyRequest);
  2547. case delRequest_choice:
  2548. DebugF (_T("LDAP: 0x%x received DeleteRequest (%d).\n"), this, LdapMessage -> messageID);
  2549. return ProcessDeleteRequest (LdapMessage -> messageID, &LdapMessage -> protocolOp.u.delRequest);
  2550. case searchRequest_choice:
  2551. DebugF (_T("LDAP: 0x%x received SearchRequest (%d).\n"), this, LdapMessage -> messageID);
  2552. return ProcessSearchRequest (LdapMessage);
  2553. case bindRequest_choice:
  2554. DebugF (_T("LDAP: 0x%x received BindRequest (%d).\n"), this, LdapMessage -> messageID);
  2555. return FALSE;
  2556. case abandonRequest_choice:
  2557. DebugF (_T("LDAP: 0x%x received AbandonRequest (%d).\n"), this, LdapMessage -> messageID);
  2558. return FALSE;
  2559. case unbindRequest_choice:
  2560. DebugF (_T("LDAP: 0x%x received UnbindRequest (%d).\n"), this, LdapMessage -> messageID);
  2561. return FALSE;
  2562. case modifyRDNRequest_choice:
  2563. DebugF (_T("LDAP: 0x%x received ModifyRDNRequest (%d).\n"), this, LdapMessage -> messageID);
  2564. return FALSE;
  2565. case compareDNRequest_choice:
  2566. DebugF (_T("LDAP: 0x%x received CompareDNRequest (%d).\n"), this, LdapMessage -> messageID);
  2567. return FALSE;
  2568. default:
  2569. return FALSE;
  2570. }
  2571. return FALSE;
  2572. }
  2573. else if (Pump == &PumpServerToClient) {
  2574. switch (LdapMessage -> protocolOp.choice) {
  2575. case addResponse_choice:
  2576. DebugF (_T("LDAP: 0x%x received AddResponse (%d).\n"), this, LdapMessage -> messageID);
  2577. ProcessAddResponse (LdapMessage);
  2578. break;
  2579. case modifyResponse_choice:
  2580. DebugF (_T("LDAP: 0x%x received ModifyResponse (%d).\n"), this, LdapMessage -> messageID);
  2581. ProcessModifyResponse (LdapMessage -> messageID, &LdapMessage -> protocolOp.u.modifyResponse);
  2582. break;
  2583. case delResponse_choice:
  2584. DebugF (_T("LDAP: 0x%x received DeleteResponse (%d).\n"), this, LdapMessage -> messageID);
  2585. ProcessDeleteResponse (LdapMessage -> messageID, &LdapMessage -> protocolOp.u.delResponse);
  2586. break;
  2587. case searchResponse_choice:
  2588. DebugF (_T("LDAP: 0x%x received SearchResponse (%d).\n"), this, LdapMessage -> messageID);
  2589. return ProcessSearchResponse (LdapMessage);
  2590. break;
  2591. case bindResponse_choice:
  2592. DebugF (_T("LDAP: 0x%x received BindResponse (%d).\n"), this, LdapMessage -> messageID);
  2593. return FALSE;
  2594. case modifyRDNResponse_choice:
  2595. DebugF (_T("LDAP: 0x%x received ModifyRDNResponse (%d).\n"), this, LdapMessage -> messageID);
  2596. return FALSE;
  2597. case compareDNResponse_choice:
  2598. DebugF (_T("LDAP: 0x%x received CompareDNResponse (%d).\n"), this, LdapMessage -> messageID);
  2599. return FALSE;
  2600. default:
  2601. break;
  2602. }
  2603. return FALSE;
  2604. }
  2605. else {
  2606. AssertNeverReached();
  2607. return FALSE;
  2608. }
  2609. }
  2610. void LDAP_CONNECTION::ProcessBuffer (
  2611. IN LDAP_PUMP * Pump,
  2612. IN LDAP_BUFFER * Buffer)
  2613. {
  2614. ASN1error_e Error;
  2615. LDAPMessage * PduStructure;
  2616. ASN1decoding_t Decoder;
  2617. assert (Pump);
  2618. assert (Buffer);
  2619. // decode the PDU
  2620. Error = ASN1_CreateDecoder (LDAP_Module, &Decoder, Buffer -> Data.Data, Buffer -> Data.Length, NULL);
  2621. if (Error == ASN1_SUCCESS) {
  2622. PduStructure = NULL;
  2623. Error = ASN1_Decode (Decoder, (PVOID *) &PduStructure, LDAPMessage_ID, 0, NULL, 0);
  2624. if (ASN1_SUCCEEDED (Error)) {
  2625. if (ProcessLdapMessage (Pump, PduStructure)) {
  2626. // a TRUE return value indicates that ProcessLdapMessage interpreted
  2627. // and acted on the contents of PduStructure. therefore, the
  2628. // original PDU is no longer needed, and is destroyed.
  2629. delete Buffer;
  2630. }
  2631. else {
  2632. // a FALSE return value indicates that ProcessLdapMessage did NOT
  2633. // interpret the contents of PduStructure, and that no data has been
  2634. // sent to the other socket. In this case, we forward the original PDU.
  2635. Pump -> SendQueueBuffer (Buffer);
  2636. }
  2637. ASN1_FreeDecoded (Decoder, PduStructure, LDAPMessage_ID);
  2638. }
  2639. else {
  2640. DebugF (_T("LDAP: 0x%x failed to decode pdu, ASN.1 error %d, forwarding pdu without interpreting contents.\n"),
  2641. this,
  2642. Error);
  2643. #if DBG
  2644. if (DebugLevel > 1) {
  2645. DumpMemory (Buffer -> Data.Data, Buffer -> Data.Length);
  2646. BerDump (Buffer -> Data.Data, Buffer -> Data.Length);
  2647. ASN1_Decode (Decoder, (PVOID *) &PduStructure, LDAPMessage_ID, 0, Buffer -> Data.Data, Buffer -> Data.Length);
  2648. }
  2649. #endif
  2650. Pump -> SendQueueBuffer (Buffer);
  2651. }
  2652. ASN1_CloseDecoder (Decoder);
  2653. }
  2654. else {
  2655. DebugF (_T("LDAP: 0x%x failed to create ASN.1 decoder, ASN.1 error %08X, forwarding pdu without interpreting contents.\n"),
  2656. this,
  2657. Error);
  2658. Pump -> SendQueueBuffer (Buffer);
  2659. }
  2660. }
  2661. // static
  2662. INT LDAP_CONNECTION::BinarySearchOperationByMessageID (
  2663. IN const LDAP_MESSAGE_ID * SearchKey,
  2664. IN const LDAP_OPERATION * Comparand)
  2665. {
  2666. if (*SearchKey < Comparand -> MessageID) return -1;
  2667. if (*SearchKey > Comparand -> MessageID) return 1;
  2668. return 0;
  2669. }
  2670. BOOL LDAP_CONNECTION::FindOperationIndexByMessageID (
  2671. IN LDAP_MESSAGE_ID MessageID,
  2672. OUT DWORD * ReturnIndex)
  2673. {
  2674. return OperationArray.BinarySearch ((SEARCH_FUNC_LDAP_OPERATION)BinarySearchOperationByMessageID, &MessageID, ReturnIndex);
  2675. }
  2676. BOOL LDAP_CONNECTION::FindOperationByMessageID (
  2677. IN LDAP_MESSAGE_ID MessageID,
  2678. OUT LDAP_OPERATION ** ReturnOperation)
  2679. {
  2680. DWORD Index;
  2681. if (OperationArray.BinarySearch ((SEARCH_FUNC_LDAP_OPERATION)BinarySearchOperationByMessageID, &MessageID, &Index)) {
  2682. *ReturnOperation = &OperationArray[Index];
  2683. return TRUE;
  2684. }
  2685. else {
  2686. *ReturnOperation = NULL;
  2687. return FALSE;
  2688. }
  2689. }
  2690. void LDAP_CONNECTION::OnStateChange (
  2691. LDAP_SOCKET * ContainedSocket,
  2692. LDAP_SOCKET::STATE NewSocketState)
  2693. {
  2694. assert (ContainedSocket == &ClientSocket || ContainedSocket == &ServerSocket);
  2695. AssertLocked();
  2696. switch (NewSocketState) {
  2697. case LDAP_SOCKET::STATE_CONNECT_PENDING:
  2698. // Client socket transitions directly from
  2699. // STATE_NONE to STATE_CONNECTED
  2700. assert (ContainedSocket != &ClientSocket);
  2701. State = STATE_CONNECT_PENDING;
  2702. break;
  2703. case LDAP_SOCKET::STATE_CONNECTED:
  2704. if (ClientSocket.GetState() == LDAP_SOCKET::STATE_CONNECTED
  2705. && ServerSocket.GetState() == LDAP_SOCKET::STATE_CONNECTED) {
  2706. State = STATE_CONNECTED;
  2707. StartIo();
  2708. }
  2709. break;
  2710. case LDAP_SOCKET::STATE_TERMINATED:
  2711. Terminate ();
  2712. break;
  2713. }
  2714. }
  2715. void LDAP_CONNECTION::Terminate (void)
  2716. {
  2717. switch (State) {
  2718. case STATE_TERMINATED:
  2719. // nothing to do
  2720. break;
  2721. default:
  2722. State = STATE_TERMINATED;
  2723. ClientSocket.Terminate();
  2724. ServerSocket.Terminate();
  2725. PumpClientToServer.Terminate();
  2726. PumpServerToClient.Terminate();
  2727. LdapConnectionArray.RemoveConnection (this);
  2728. break;
  2729. }
  2730. }
  2731. void LDAP_CONNECTION::TerminateExternal (void)
  2732. {
  2733. Lock ();
  2734. Terminate ();
  2735. Unlock ();
  2736. }
  2737. BOOL
  2738. LDAP_CONNECTION::IsConnectionThrough (
  2739. IN DWORD InterfaceAddress // host order
  2740. )
  2741. /*++
  2742. Routine Description:
  2743. Determines whether the connection goes through the
  2744. interface specified
  2745. Arguments:
  2746. InterfaceAddress - address of the interface for which
  2747. the determination is to be made.
  2748. Return Values:
  2749. TRUE - if the connection being proxied goes through the
  2750. interface specified
  2751. FALSE - if the connection being proxied does not go through the
  2752. interface specified
  2753. Notes:
  2754. --*/
  2755. {
  2756. BOOL IsThrough;
  2757. IsThrough = (InterfaceAddress == SourceInterfaceAddress) ||
  2758. (InterfaceAddress == DestinationInterfaceAddress);
  2759. return IsThrough;
  2760. } // LDAP_CONNECTION::IsConnectionThrough
  2761. // LDAP_CONNECTION_ARRAY ----------------------------------------------
  2762. LDAP_CONNECTION_ARRAY::LDAP_CONNECTION_ARRAY (void) {
  2763. IsEnabled = FALSE;
  2764. }
  2765. void LDAP_CONNECTION_ARRAY::RemoveConnection (
  2766. LDAP_CONNECTION * LdapConnection)
  2767. {
  2768. LDAP_CONNECTION ** Pos;
  2769. LDAP_CONNECTION ** End;
  2770. BOOL DoRelease;
  2771. Lock();
  2772. // linear scan, yick
  2773. DoRelease = FALSE;
  2774. ConnectionArray.GetExtents (&Pos, &End);
  2775. for (; Pos < End; Pos++) {
  2776. if (*Pos == LdapConnection) {
  2777. // swap with last entry
  2778. // quick way to delete entry from table
  2779. *Pos = *(End - 1);
  2780. ConnectionArray.Length--;
  2781. DoRelease = TRUE;
  2782. break;
  2783. }
  2784. }
  2785. Unlock();
  2786. if (DoRelease) {
  2787. LdapConnection -> Release();
  2788. }
  2789. else {
  2790. // when could this happen?
  2791. // perhaps a harmless race condition?
  2792. DebugF (_T("LDAP: 0x%x could not be removed from table -- was not in table to begin with.\n"), LdapConnection);
  2793. }
  2794. }
  2795. void LDAP_CONNECTION_ARRAY::OnInterfaceShutdown (
  2796. IN DWORD InterfaceAddress) { // host order
  2797. DWORD ArrayIndex = 0;
  2798. LDAP_CONNECTION * Connection;
  2799. LDAP_CONNECTION ** ConnectionHolder = NULL;
  2800. DYNAMIC_ARRAY <LDAP_CONNECTION *> TempArray;
  2801. Lock ();
  2802. while (ArrayIndex < ConnectionArray.GetLength ()) {
  2803. Connection = ConnectionArray [ArrayIndex];
  2804. if (Connection -> IsConnectionThrough (InterfaceAddress)) {
  2805. DebugF (_T("LDAP: 0x%x terminating (killing all connections through %08X).\n"),
  2806. Connection, InterfaceAddress);
  2807. ConnectionHolder = TempArray.AllocAtEnd ();
  2808. if (NULL == ConnectionHolder) {
  2809. Debug (_T("LDAP_CONNECTION_ARRAY::OnInterfaceShutdown - unable to grow array.\n"));
  2810. } else {
  2811. Connection -> AddRef ();
  2812. *ConnectionHolder = Connection;
  2813. }
  2814. }
  2815. ArrayIndex++;
  2816. }
  2817. Unlock ();
  2818. ArrayIndex = 0;
  2819. while (ArrayIndex < TempArray.GetLength ()) {
  2820. Connection = TempArray[ArrayIndex];
  2821. Connection -> TerminateExternal ();
  2822. Connection -> Release ();
  2823. ArrayIndex++;
  2824. }
  2825. }
  2826. void LDAP_CONNECTION_ARRAY::Start (void)
  2827. {
  2828. Lock ();
  2829. IsEnabled = TRUE;
  2830. Unlock ();
  2831. }
  2832. void LDAP_CONNECTION_ARRAY::Stop (void)
  2833. {
  2834. LDAP_CONNECTION * LdapConnection;
  2835. Lock ();
  2836. IsEnabled = FALSE;
  2837. while (ConnectionArray.GetLength()) {
  2838. LdapConnection = ConnectionArray[0];
  2839. LdapConnection -> AddRef ();
  2840. Unlock ();
  2841. LdapConnection -> TerminateExternal ();
  2842. Lock ();
  2843. LdapConnection -> Release ();
  2844. }
  2845. ConnectionArray.Free ();
  2846. Unlock ();
  2847. }
  2848. HRESULT LDAP_CONNECTION_ARRAY::InsertConnection (
  2849. LDAP_CONNECTION * LdapConnection)
  2850. {
  2851. LDAP_CONNECTION ** ConnectionHolder = NULL;
  2852. HRESULT Result;
  2853. Lock ();
  2854. if (IsEnabled) {
  2855. if (ConnectionArray.Length <= LDAP_MAX_CONNECTIONS) {
  2856. ConnectionHolder = ConnectionArray.AllocAtEnd ();
  2857. if (NULL == ConnectionHolder) {
  2858. Result = E_OUTOFMEMORY;
  2859. } else {
  2860. LdapConnection -> AddRef ();
  2861. *ConnectionHolder = LdapConnection;
  2862. Result = S_OK;
  2863. }
  2864. } else {
  2865. return E_ABORT;
  2866. }
  2867. } else {
  2868. Result = E_FAIL;
  2869. }
  2870. Unlock ();
  2871. return Result;
  2872. }
  2873. // LDAP_ACCEPT ----------------------------------------------
  2874. LDAP_ACCEPT::LDAP_ACCEPT (void)
  2875. {
  2876. }
  2877. // static
  2878. void
  2879. LDAP_ACCEPT::AsyncAcceptFunction (
  2880. IN PVOID Context,
  2881. IN SOCKET Socket,
  2882. IN SOCKADDR_IN * LocalAddress,
  2883. IN SOCKADDR_IN * RemoteAddress
  2884. )
  2885. {
  2886. HRESULT Result;
  2887. Result = AsyncAcceptFunctionInternal (
  2888. Context,
  2889. Socket,
  2890. LocalAddress,
  2891. RemoteAddress
  2892. );
  2893. if (S_OK != Result) {
  2894. if (INVALID_SOCKET != Socket) {
  2895. closesocket (Socket);
  2896. Socket = INVALID_SOCKET;
  2897. }
  2898. }
  2899. }
  2900. // static
  2901. HRESULT
  2902. LDAP_ACCEPT::AsyncAcceptFunctionInternal (
  2903. IN PVOID Context,
  2904. IN SOCKET Socket,
  2905. IN SOCKADDR_IN * LocalAddress,
  2906. IN SOCKADDR_IN * RemoteAddress
  2907. )
  2908. {
  2909. LDAP_CONNECTION * LdapConnection;
  2910. HRESULT Result;
  2911. NAT_KEY_SESSION_MAPPING_EX_INFORMATION RedirectInformation;
  2912. ULONG RedirectInformationLength;
  2913. ULONG Error;
  2914. DWORD BestInterfaceAddress;
  2915. SOCKADDR_IN DestinationAddress;
  2916. DebugF (_T("LDAP: ----------------------------------------------------------------------\n"));
  2917. #if DBG
  2918. ExposeTimingWindow ();
  2919. #endif
  2920. // a new LDAP connection has been accepted from the network.
  2921. // first, we determine the original addresses of the transport connection.
  2922. // if the connection was redirected to our socket (due to NAT),
  2923. // then the query of the NAT redirect table will yield the original transport addresses.
  2924. // if an errant client has connected to our service, well, we really didn't
  2925. // intend for that to happen, so we just immediately close the socket.
  2926. RedirectInformationLength = sizeof RedirectInformation;
  2927. Result = NatLookupAndQueryInformationSessionMapping (
  2928. NatHandle,
  2929. IPPROTO_TCP,
  2930. LocalAddress -> sin_addr.s_addr,
  2931. LocalAddress -> sin_port,
  2932. RemoteAddress -> sin_addr.s_addr,
  2933. RemoteAddress -> sin_port,
  2934. &RedirectInformation,
  2935. &RedirectInformationLength,
  2936. NatKeySessionMappingExInformation);
  2937. if (STATUS_SUCCESS != Result) {
  2938. DebugErrorF (Result, _T("LDAP: new connection was accepted from (%08X:%04X), but it is not in the NAT redirect table -- rejecting connection.\n"),
  2939. ntohl (RemoteAddress -> sin_addr.s_addr),
  2940. ntohs (RemoteAddress -> sin_port));
  2941. return Result;
  2942. }
  2943. Error = GetBestInterfaceAddress (ntohl (RedirectInformation.DestinationAddress), &BestInterfaceAddress);
  2944. if (ERROR_SUCCESS != Error) {
  2945. if (WSAEHOSTUNREACH == Error) {
  2946. Error = RasAutoDialSharedConnection ();
  2947. if (ERROR_SUCCESS != Error) {
  2948. DebugF (_T("LDAP: RasAutoDialSharedConnection failed. Error=%d\n"), Error);
  2949. }
  2950. } else {
  2951. DebugError (Error, _T("LDAP: Failed to get interface address for the destination.\n"));
  2952. return HRESULT_FROM_WIN32 (Error);
  2953. }
  2954. }
  2955. #if DBG
  2956. BOOL IsPrivateOrLocalSource;
  2957. BOOL IsPublicDestination;
  2958. Result = ::IsPrivateAddress (ntohl (RedirectInformation.SourceAddress), &IsPrivateOrLocalSource);
  2959. if (S_OK != Result) {
  2960. return Result;
  2961. }
  2962. IsPrivateOrLocalSource = IsPrivateOrLocalSource || ::NhIsLocalAddress (RedirectInformation.SourceAddress);
  2963. Result = ::IsPublicAddress (ntohl (RedirectInformation.DestinationAddress), &IsPublicDestination);
  2964. if (S_OK != Result) {
  2965. return Result;
  2966. }
  2967. if (::NhIsLocalAddress (RedirectInformation.SourceAddress) &&
  2968. ::NhIsLocalAddress (RedirectInformation.DestinationAddress)) {
  2969. Debug (_T("LDAP: New LOCAL connection.\n"));
  2970. } else {
  2971. if (IsPrivateOrLocalSource && IsPublicDestination) {
  2972. Debug (_T("LDAP: New OUTBOUND connection.\n"));
  2973. } else {
  2974. Debug (_T("LDAP: New INBOUND connection.\n"));
  2975. }
  2976. }
  2977. #endif // DBG
  2978. DebugF (_T("LDAP: Connection redirected: (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
  2979. ntohl (RedirectInformation.SourceAddress),
  2980. ntohs (RedirectInformation.SourcePort),
  2981. ntohl (RedirectInformation.DestinationAddress),
  2982. ntohs (RedirectInformation.DestinationPort),
  2983. ntohl (RedirectInformation.NewSourceAddress),
  2984. ntohs (RedirectInformation.NewSourcePort),
  2985. ntohl (RedirectInformation.NewDestinationAddress),
  2986. ntohs (RedirectInformation.NewDestinationPort));
  2987. // Create new LDAP_CONNECTION object
  2988. LdapConnection = new LDAP_CONNECTION (&RedirectInformation);
  2989. if (!LdapConnection) {
  2990. DebugF(_T("LDAP: Failed to allocate LDAP_CONNECTION.\n"));
  2991. return E_OUTOFMEMORY;
  2992. }
  2993. LdapConnection -> AddRef ();
  2994. Result = LdapConnection -> Initialize (&RedirectInformation);
  2995. if (S_OK == Result) {
  2996. DestinationAddress.sin_family = AF_INET;
  2997. DestinationAddress.sin_addr.s_addr = RedirectInformation.DestinationAddress;
  2998. DestinationAddress.sin_port = RedirectInformation.DestinationPort;
  2999. if (S_OK == LdapConnectionArray.InsertConnection (LdapConnection)) {
  3000. Result = LdapConnection -> AcceptSocket (Socket,
  3001. LocalAddress,
  3002. RemoteAddress,
  3003. &DestinationAddress);
  3004. if (S_OK != Result) {
  3005. DebugF (_T("LDAP: 0x%x accepted new LDAP client, but failed to proceed.\n"), LdapConnection);
  3006. // Probably there was something wrong with just this
  3007. // Accept failure. Continue to accept more LDAP connections.
  3008. }
  3009. }
  3010. } else {
  3011. DebugF (_T("LDAP: 0x%x failed to initialize.\n"), LdapConnection);
  3012. }
  3013. LdapConnection -> Release ();
  3014. return Result;
  3015. }
  3016. HRESULT LDAP_ACCEPT::StartLoopbackNatRedirects (void) {
  3017. NTSTATUS Status;
  3018. Status = NatCreateDynamicAdapterRestrictedPortRedirect (
  3019. NatRedirectFlagLoopback | NatRedirectFlagSendOnly,
  3020. IPPROTO_TCP,
  3021. htons (LDAP_STANDARD_PORT),
  3022. LdapListenSocketAddress.sin_addr.s_addr,
  3023. LdapListenSocketAddress.sin_port,
  3024. ::NhMapAddressToAdapter (htonl (INADDR_LOOPBACK)),
  3025. MAX_LISTEN_BACKLOG,
  3026. &LoopbackRedirectHandle1);
  3027. if (Status != STATUS_SUCCESS) {
  3028. LoopbackRedirectHandle1 = NULL;
  3029. DebugError (Status, _T("LDAP: Failed to create local dynamic redirect #1.\n"));
  3030. return (HRESULT) Status;
  3031. }
  3032. DebugF (_T ("LDAP: Connections traversing loopback interface to port %04X will be redirected to %08X:%04X.\n"),
  3033. LDAP_STANDARD_PORT,
  3034. ntohl (LdapListenSocketAddress.sin_addr.s_addr),
  3035. ntohs (LdapListenSocketAddress.sin_port));
  3036. Status = NatCreateDynamicAdapterRestrictedPortRedirect (
  3037. NatRedirectFlagLoopback | NatRedirectFlagSendOnly,
  3038. IPPROTO_TCP,
  3039. htons (LDAP_ALTERNATE_PORT),
  3040. LdapListenSocketAddress.sin_addr.s_addr,
  3041. LdapListenSocketAddress.sin_port,
  3042. ::NhMapAddressToAdapter (htonl (INADDR_LOOPBACK)),
  3043. MAX_LISTEN_BACKLOG,
  3044. &LoopbackRedirectHandle2);
  3045. if (Status != STATUS_SUCCESS) {
  3046. NatCancelDynamicRedirect (LoopbackRedirectHandle1);
  3047. LoopbackRedirectHandle1 = NULL;
  3048. LoopbackRedirectHandle2 = NULL;
  3049. DebugError (Status, _T("LDAP: Failed to create local dynamic redirect #2.\n"));
  3050. return (HRESULT) Status;
  3051. }
  3052. DebugF (_T ("LDAP: Connections traversing loopback interface to port %04X will be redirected to %08X:%04X.\n"),
  3053. LDAP_ALTERNATE_PORT,
  3054. ntohl (LdapListenSocketAddress.sin_addr.s_addr),
  3055. ntohs (LdapListenSocketAddress.sin_port));
  3056. return (HRESULT) Status;
  3057. }
  3058. HRESULT LDAP_ACCEPT::CreateBindSocket (
  3059. void) {
  3060. HRESULT Result;
  3061. SOCKADDR_IN SocketAddress;
  3062. SocketAddress.sin_family = AF_INET;
  3063. SocketAddress.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
  3064. SocketAddress.sin_port = htons (0); // request dynamic port
  3065. Result = AsyncAcceptContext.StartIo (
  3066. &SocketAddress,
  3067. AsyncAcceptFunction,
  3068. NULL);
  3069. if (Result != S_OK) {
  3070. DebugError (Result, _T("LDAP: Failed to create and bind socket.\n"));
  3071. return Result;
  3072. }
  3073. DebugF (_T("LDAP: Asynchronous Accept started.\n"));
  3074. Result = AsyncAcceptContext.GetListenSocketAddress (&LdapListenSocketAddress);
  3075. if (Result != S_OK) {
  3076. DebugError (Result, _T("LDAP: Failed to get listen socket address.\n"));
  3077. return Result;
  3078. }
  3079. return S_OK;
  3080. }
  3081. HRESULT LDAP_ACCEPT::Start (void)
  3082. {
  3083. HRESULT Result;
  3084. Result = CreateBindSocket ();
  3085. if (S_OK == Result) {
  3086. Result = StartLoopbackNatRedirects ();
  3087. if (S_OK == Result) {
  3088. return S_OK;
  3089. }
  3090. CloseSocket ();
  3091. }
  3092. return Result;
  3093. }
  3094. void LDAP_ACCEPT::Stop (void) {
  3095. StopLoopbackNatRedirects ();
  3096. CloseSocket ();
  3097. }
  3098. void LDAP_ACCEPT::StopLoopbackNatRedirects (void) {
  3099. if (LoopbackRedirectHandle1) {
  3100. NatCancelDynamicRedirect (LoopbackRedirectHandle1);
  3101. LoopbackRedirectHandle1 = NULL;
  3102. }
  3103. if (LoopbackRedirectHandle2) {
  3104. NatCancelDynamicRedirect (LoopbackRedirectHandle2);
  3105. LoopbackRedirectHandle2 = NULL;
  3106. }
  3107. }
  3108. void LDAP_ACCEPT::CloseSocket (void) {
  3109. ZeroMemory ((PVOID)&LdapListenSocketAddress, sizeof (SOCKADDR_IN));
  3110. AsyncAcceptContext.StopWait ();
  3111. }
  3112. LDAP_BUFFER::LDAP_BUFFER (void)
  3113. {
  3114. }
  3115. LDAP_BUFFER::~LDAP_BUFFER (void)
  3116. {
  3117. }
  3118. // LDAP_CODER ---------------------------------------------------------------------
  3119. LDAP_CODER::LDAP_CODER (void)
  3120. {
  3121. Encoder = NULL;
  3122. Decoder = NULL;
  3123. LDAP_Module_Startup();
  3124. }
  3125. LDAP_CODER::~LDAP_CODER (void)
  3126. {
  3127. Encoder = NULL;
  3128. Decoder = NULL;
  3129. LDAP_Module_Cleanup();
  3130. }
  3131. DWORD LDAP_CODER::Start (void)
  3132. {
  3133. DWORD Status;
  3134. ASN1error_e Error;
  3135. Lock();
  3136. Status = ERROR_SUCCESS;
  3137. Error = ASN1_CreateEncoder (LDAP_Module, &Encoder, NULL, 0, NULL);
  3138. if (ASN1_FAILED (Error)) {
  3139. DebugF (_T("LDAP: Failed to initialize LDAP ASN.1 BER encoder, 0x%08X.\n"), Error);
  3140. Encoder = NULL;
  3141. Status = ERROR_GEN_FAILURE;
  3142. }
  3143. Error = ASN1_CreateDecoder (LDAP_Module, &Decoder, NULL, 0, NULL);
  3144. if (ASN1_FAILED (Error)) {
  3145. DebugF (_T("LDAP: Failed to initialize LDAP ASN.1 BER decoder, 0x%08X.\n"), Error);
  3146. Decoder = NULL;
  3147. Status = ERROR_GEN_FAILURE;
  3148. }
  3149. Unlock();
  3150. return Status;
  3151. }
  3152. void LDAP_CODER::Stop (void)
  3153. {
  3154. Lock();
  3155. if (Encoder) {
  3156. ASN1_CloseEncoder (Encoder);
  3157. Encoder = NULL;
  3158. }
  3159. if (Decoder) {
  3160. ASN1_CloseDecoder (Decoder);
  3161. Decoder = NULL;
  3162. }
  3163. Unlock();
  3164. }
  3165. ASN1error_e LDAP_CODER::Decode (
  3166. IN LPBYTE Data,
  3167. IN DWORD Length,
  3168. OUT LDAPMessage ** ReturnPduStructure,
  3169. OUT DWORD * ReturnIndex)
  3170. {
  3171. ASN1error_e Error;
  3172. assert (Data);
  3173. assert (ReturnPduStructure);
  3174. assert (ReturnIndex);
  3175. Lock();
  3176. if (Decoder) {
  3177. #if DBG
  3178. BerDump (Data, Length);
  3179. #endif
  3180. Error = ASN1_Decode (
  3181. Decoder,
  3182. (PVOID *) ReturnPduStructure,
  3183. LDAPMessage_ID,
  3184. ASN1DECODE_SETBUFFER,
  3185. Data,
  3186. Length);
  3187. switch (Error) {
  3188. case ASN1_SUCCESS:
  3189. // successfully decoded pdu
  3190. *ReturnIndex = Decoder -> len;
  3191. assert (*ReturnPduStructure);
  3192. DebugF (_T("LDAP: Successfully decoded PDU, submitted buffer length %d, used %d bytes.\n"),
  3193. Length,
  3194. *ReturnIndex);
  3195. break;
  3196. case ASN1_ERR_EOD:
  3197. // not enough data has been accumulated yet
  3198. *ReturnIndex = 0;
  3199. *ReturnPduStructure = NULL;
  3200. DebugF (_T("LDAP: Cannot yet decode PDU, not enough data submitted (%d bytes in buffer).\n"),
  3201. Length);
  3202. break;
  3203. default:
  3204. if (ASN1_FAILED (Error)) {
  3205. DebugF (_T("LDAP: Failed to decode PDU, for unknown reasons, 0x%08X.\n"),
  3206. Error);
  3207. }
  3208. else {
  3209. DebugF (_T("LDAP: PDU decoded, but with warning code, 0x%08X.\n"),
  3210. Error);
  3211. *ReturnIndex = Decoder -> len;
  3212. }
  3213. break;
  3214. }
  3215. }
  3216. else {
  3217. Debug (_T("LDAP: cannot decode pdu, because decoder was not initialized.\n"));
  3218. Error = ASN1_ERR_INTERNAL;
  3219. }
  3220. Unlock();
  3221. return Error;
  3222. }
  3223. // LDAP_PUMP --------------------------------------------------------------
  3224. LDAP_PUMP::LDAP_PUMP (
  3225. IN LDAP_CONNECTION * ArgConnection,
  3226. IN LDAP_SOCKET * ArgSource,
  3227. IN LDAP_SOCKET * ArgDest)
  3228. {
  3229. assert (ArgConnection);
  3230. assert (ArgSource);
  3231. assert (ArgDest);
  3232. Connection = ArgConnection;
  3233. Source = ArgSource;
  3234. Dest = ArgDest;
  3235. IsPassiveDataTransfer = FALSE;
  3236. }
  3237. LDAP_PUMP::~LDAP_PUMP (void)
  3238. {
  3239. }
  3240. void LDAP_PUMP::Terminate (void)
  3241. {
  3242. }
  3243. void LDAP_PUMP::Start (void)
  3244. {
  3245. Source -> RecvIssue();
  3246. }
  3247. void LDAP_PUMP::Stop (void)
  3248. {
  3249. }
  3250. // called only by source socket OnRecvComplete
  3251. void LDAP_PUMP::OnRecvBuffer (
  3252. IN LDAP_BUFFER * Buffer)
  3253. {
  3254. if (IsActivelyPassingData ()) {
  3255. Connection -> ProcessBuffer (this, Buffer);
  3256. } else {
  3257. SendQueueBuffer (Buffer);
  3258. }
  3259. }
  3260. void LDAP_PUMP::OnSendDrain (void)
  3261. {
  3262. Source -> RecvIssue();
  3263. }
  3264. BOOL LDAP_PUMP::CanIssueRecv (void)
  3265. {
  3266. return !Dest -> SendOverlapped.IsPending;
  3267. }
  3268. void LDAP_PUMP::SendQueueBuffer (
  3269. IN LDAP_BUFFER * Buffer)
  3270. {
  3271. Dest -> SendQueueBuffer (Buffer);
  3272. }
  3273. void LDAP_PUMP::EncodeSendMessage (
  3274. IN LDAPMessage * Message)
  3275. {
  3276. LDAP_BUFFER * Buffer;
  3277. ASN1encoding_t Encoder;
  3278. ASN1error_e Error;
  3279. Buffer = new LDAP_BUFFER;
  3280. if (!Buffer) {
  3281. Debug (_T("LDAP: EncodeSendMessage: allocation failure.\n"));
  3282. return;
  3283. }
  3284. Error = ASN1_CreateEncoder (LDAP_Module, &Encoder, NULL, 0, NULL);
  3285. if (ASN1_FAILED (Error)) {
  3286. DebugF (_T("LDAP: EncodeSendMessage: failed to create ASN.1 encoder, error 0x%08X.\n"),
  3287. Error);
  3288. delete Buffer;
  3289. return;
  3290. }
  3291. Error = ASN1_Encode (Encoder, Message, LDAPMessage_ID, ASN1ENCODE_ALLOCATEBUFFER, NULL, 0);
  3292. if (ASN1_FAILED (Error)) {
  3293. DebugF (_T("LDAP: Failed to encode LDAP message, error 0x%08X.\n"), Error);
  3294. ASN1_CloseEncoder (Encoder);
  3295. delete Buffer;
  3296. return;
  3297. }
  3298. if (Buffer -> Data.Grow (Encoder -> len)) {
  3299. memcpy (Buffer -> Data.Data, Encoder -> buf, Encoder -> len);
  3300. Buffer -> Data.Length = Encoder -> len;
  3301. ASN1_FreeEncoded (Encoder, Encoder -> buf);
  3302. SendQueueBuffer (Buffer);
  3303. Buffer = NULL;
  3304. }
  3305. else {
  3306. delete Buffer;
  3307. }
  3308. ASN1_CloseEncoder (Encoder);
  3309. }
  3310. BOOL LDAP_PUMP::IsActivelyPassingData (void) const {
  3311. return !IsPassiveDataTransfer;
  3312. }
  3313. void LDAP_PUMP::StartPassiveDataTransfer (void) {
  3314. IsPassiveDataTransfer = TRUE;
  3315. }