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

763 lines
19 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: sockets.cxx
  7. //
  8. // Contents: Code for kerberos client sockets
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 26-Jul-1996 MikeSw Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #ifdef WIN32_CHICAGO
  18. #include <kerb.hxx>
  19. #include <kerbp.h>
  20. #endif // WIN32_CHICAGO
  21. #ifndef WIN32_CHICAGO
  22. extern "C"
  23. {
  24. #include <nt.h>
  25. #include <ntrtl.h>
  26. #include <nturtl.h>
  27. #ifndef WIN32_CHICAGO
  28. #include <winsock2.h>
  29. #else // WIN32_CHICAGO
  30. #include <winsock.h>
  31. #endif // WIN32_CHICAGO
  32. #include <dsgetdc.h>
  33. }
  34. #include <kerbcomm.h>
  35. #include <kerberr.h>
  36. #include <kerbcon.h>
  37. #include <midles.h>
  38. #include <authen.hxx>
  39. #include "debug.h"
  40. #else // WIN32_CHICAGO
  41. extern "C"
  42. {
  43. #include <winsock.h>
  44. }
  45. #endif // WIN32_CHICAGO
  46. LONG SocketStarts = -1;
  47. ULONG TcpFragLength = 0x7fffffff ;
  48. ULONG TcpFragDelay = 0 ;
  49. //+-------------------------------------------------------------------------
  50. //
  51. // Function: KerbInitializeSockets
  52. //
  53. // Synopsis:
  54. //
  55. // Effects:
  56. //
  57. // Arguments:
  58. //
  59. // Requires:
  60. //
  61. // Returns:
  62. //
  63. // Notes:
  64. //
  65. //
  66. //--------------------------------------------------------------------------
  67. NTSTATUS
  68. KerbInitializeSockets(
  69. IN WORD VersionRequired,
  70. IN ULONG MinSockets,
  71. OUT BOOLEAN *TcpNotInstalled
  72. )
  73. {
  74. NTSTATUS Status = STATUS_SUCCESS;
  75. int Error;
  76. WSADATA SocketData;
  77. #ifndef WIN32_CHICAGO
  78. WSAPROTOCOL_INFO *lpProtocolBuf = NULL;
  79. DWORD dwBufLen = 0;
  80. INT protocols[2];
  81. int nRet = 0;
  82. #endif // WIN32_CHICAGO
  83. //
  84. // Initialze sockets
  85. //
  86. *TcpNotInstalled = FALSE;
  87. if (InterlockedIncrement(&SocketStarts) != 0)
  88. {
  89. return(STATUS_SUCCESS);
  90. }
  91. Error = WSAStartup(VersionRequired, &SocketData);
  92. if (Error != 0)
  93. {
  94. DebugLog((DEB_ERROR,"WSAStartup failed: 0x%x\n",Error));
  95. Status = STATUS_NO_LOGON_SERVERS;
  96. goto Cleanup;
  97. }
  98. //
  99. // Make sure the version is high enough for us
  100. //
  101. if ((LOBYTE(SocketData.wVersion) < HIBYTE(VersionRequired)) ||
  102. (((LOBYTE(SocketData.wVersion) == HIBYTE(VersionRequired)) &&
  103. (HIBYTE(SocketData.wVersion) < LOBYTE(VersionRequired)))))
  104. {
  105. DebugLog((DEB_ERROR,"Invalid socket version: wanted 0x%x, got 0x%x\n",
  106. VersionRequired, SocketData.wVersion));
  107. Status = STATUS_NO_LOGON_SERVERS;
  108. goto Cleanup;
  109. }
  110. if (SocketData.iMaxSockets < MinSockets)
  111. {
  112. DebugLog((DEB_ERROR,"Not enough sockets available: wanted %d, got %d\n",
  113. MinSockets, SocketData.iMaxSockets ));
  114. Status = STATUS_NO_LOGON_SERVERS;
  115. goto Cleanup;
  116. }
  117. #ifndef WIN32_CHICAGO
  118. //
  119. // Check if TCP is an available xport
  120. //
  121. protocols[0] = IPPROTO_TCP;
  122. protocols[1] = NULL;
  123. nRet = WSAEnumProtocols(protocols, lpProtocolBuf, &dwBufLen);
  124. if (nRet == 0)
  125. {
  126. //
  127. // Tcp is not installed as a xport.
  128. //
  129. D_DebugLog((DEB_T_SOCK,"WSAEnumProtocols returned 0x%x.\n", nRet));
  130. *TcpNotInstalled = TRUE;
  131. }
  132. #endif // WIN32_CHICAGO
  133. Cleanup:
  134. if (!NT_SUCCESS(Status))
  135. {
  136. if (SocketStarts != -1)
  137. {
  138. WSACleanup();
  139. InterlockedDecrement(&SocketStarts);
  140. }
  141. }
  142. return(Status);
  143. }
  144. //+-------------------------------------------------------------------------
  145. //
  146. // Function: KerbCleanupSockets
  147. //
  148. // Synopsis: Cleansup socket handling code
  149. //
  150. // Effects: calls WSACleanup()
  151. //
  152. // Arguments:
  153. //
  154. // Requires:
  155. //
  156. // Returns:
  157. //
  158. // Notes:
  159. //
  160. //
  161. //--------------------------------------------------------------------------
  162. VOID
  163. KerbCleanupSockets(
  164. )
  165. {
  166. if (InterlockedDecrement(&SocketStarts) < 0)
  167. {
  168. WSACleanup();
  169. }
  170. }
  171. //+-------------------------------------------------------------------------
  172. //
  173. // Function: KerbCloseSocket
  174. //
  175. // Synopsis: Closes a socket binding handle
  176. //
  177. // Effects: calls closesocket on the handle
  178. //
  179. // Arguments: SocketHandle - handle to close
  180. //
  181. // Requires:
  182. //
  183. // Returns: none
  184. //
  185. // Notes:
  186. //
  187. //
  188. //--------------------------------------------------------------------------
  189. VOID
  190. KerbCloseSocket(
  191. IN SOCKET SocketHandle
  192. )
  193. {
  194. int SockError;
  195. if (SocketHandle != 0)
  196. {
  197. SockError = closesocket(SocketHandle);
  198. if (SockError != 0)
  199. {
  200. DebugLog((DEB_ERROR,"CloseSocket failed: last error = %d\n",WSAGetLastError()));
  201. }
  202. }
  203. }
  204. //+-------------------------------------------------------------------------
  205. //
  206. // Function: KerbBindSocketByAddress
  207. //
  208. // Synopsis: Binds to the KDC socket on the specified address
  209. //
  210. // Effects:
  211. //
  212. // Arguments: Address - Address to bind to
  213. // AddressType - Address type, as specified by DC locator
  214. // ContextHandle - Receives bound socket
  215. //
  216. // Requires:
  217. //
  218. // Returns:
  219. //
  220. // Notes:
  221. //
  222. //
  223. //--------------------------------------------------------------------------
  224. NTSTATUS
  225. KerbBindSocketByAddress(
  226. IN PUNICODE_STRING Address,
  227. IN ULONG AddressType,
  228. IN BOOLEAN UseDatagram,
  229. IN USHORT PortNumber,
  230. OUT SOCKET * ContextHandle
  231. )
  232. {
  233. NTSTATUS Status = STATUS_SUCCESS;
  234. SOCKET ClientSocket = INVALID_SOCKET;
  235. struct sockaddr_in ServerAddress;
  236. struct sockaddr_in ClientAddress;
  237. LPHOSTENT ServerInfo = NULL;
  238. STRING AnsiAddress = {0};
  239. AnsiAddress.Buffer = NULL;
  240. Status = RtlUnicodeStringToAnsiString(
  241. &AnsiAddress,
  242. Address,
  243. TRUE
  244. );
  245. if (!NT_SUCCESS(Status))
  246. {
  247. goto Cleanup;
  248. }
  249. ClientSocket = socket(
  250. PF_INET,
  251. (UseDatagram ? SOCK_DGRAM : SOCK_STREAM),
  252. 0
  253. );
  254. if (ClientSocket == INVALID_SOCKET)
  255. {
  256. DebugLog((DEB_ERROR,"Failed to create socket: %d\n",WSAGetLastError()));
  257. Status = STATUS_NO_LOGON_SERVERS;
  258. goto Cleanup;
  259. }
  260. if (UseDatagram)
  261. {
  262. //
  263. // Bind client socket to any local interface and port
  264. //
  265. ClientAddress.sin_family = AF_INET;
  266. ClientAddress.sin_addr.s_addr = INADDR_ANY;
  267. ClientAddress.sin_port = 0; // no specific port
  268. if (bind(
  269. ClientSocket,
  270. (LPSOCKADDR) &ClientAddress,
  271. sizeof(ClientAddress)
  272. ) == SOCKET_ERROR )
  273. {
  274. DebugLog((DEB_ERROR,"Failed to bind client socket: %d\n",WSAGetLastError()));
  275. Status = STATUS_NO_LOGON_SERVERS;
  276. goto Cleanup;
  277. }
  278. }
  279. if (AddressType == DS_INET_ADDRESS)
  280. {
  281. ULONG InetAddress;
  282. //
  283. // Get the address of the server
  284. //
  285. InetAddress = inet_addr(AnsiAddress.Buffer);
  286. if (InetAddress == SOCKET_ERROR)
  287. {
  288. DebugLog((DEB_ERROR,"Failed to convert %Z to address: %d\n", &AnsiAddress, WSAGetLastError()));
  289. Status = STATUS_NO_LOGON_SERVERS;
  290. goto Cleanup;
  291. }
  292. ServerAddress.sin_family = AF_INET;
  293. RtlCopyMemory(
  294. &ServerAddress.sin_addr,
  295. &InetAddress,
  296. sizeof(ULONG)
  297. );
  298. }
  299. else
  300. {
  301. //
  302. // Get the address of the server
  303. //
  304. ServerInfo = gethostbyname(AnsiAddress.Buffer);
  305. if (ServerInfo == NULL)
  306. {
  307. DebugLog((DEB_ERROR,"Failed to get host %Z by name: %d\n", &AnsiAddress, WSAGetLastError()));
  308. Status = STATUS_NO_LOGON_SERVERS;
  309. goto Cleanup;
  310. }
  311. ServerAddress.sin_family = ServerInfo->h_addrtype;
  312. RtlCopyMemory(
  313. &ServerAddress.sin_addr,
  314. ServerInfo->h_addr,
  315. sizeof(ULONG)
  316. );
  317. }
  318. ServerAddress.sin_port = htons(PortNumber);
  319. if (connect(
  320. ClientSocket,
  321. (LPSOCKADDR) &ServerAddress,
  322. sizeof(ServerAddress)
  323. ) == SOCKET_ERROR)
  324. {
  325. DebugLog((DEB_ERROR,"Failed to connect to server %Z: %d\n",&AnsiAddress, WSAGetLastError()));
  326. Status = STATUS_NO_LOGON_SERVERS;
  327. goto Cleanup;
  328. }
  329. *ContextHandle = ClientSocket;
  330. D_DebugLog((DEB_TRACE,"Successfully bound to %Z\n",&AnsiAddress));
  331. Cleanup:
  332. if (AnsiAddress.Buffer != NULL)
  333. {
  334. RtlFreeAnsiString(&AnsiAddress);
  335. }
  336. if (!NT_SUCCESS(Status))
  337. {
  338. if (ClientSocket != INVALID_SOCKET)
  339. {
  340. closesocket(ClientSocket);
  341. }
  342. }
  343. return(Status);
  344. }
  345. //+-------------------------------------------------------------------------
  346. //
  347. // Function: KerbCallKdc
  348. //
  349. // Synopsis: Socket client stub for calling the KDC.
  350. //
  351. // Effects:
  352. //
  353. // Arguments:
  354. //
  355. // Requires:
  356. //
  357. // Returns:
  358. //
  359. // Notes:
  360. //
  361. //
  362. //--------------------------------------------------------------------------
  363. extern ULONG KerbGlobalMaxDatagramSize;
  364. NTSTATUS
  365. KerbCallKdc(
  366. IN PUNICODE_STRING KdcAddress,
  367. IN ULONG AddressType,
  368. IN ULONG Timeout,
  369. IN BOOLEAN UseDatagram,
  370. IN USHORT PortNumber,
  371. IN PKERB_MESSAGE_BUFFER Input,
  372. OUT PKERB_MESSAGE_BUFFER Output
  373. )
  374. {
  375. NTSTATUS Status = STATUS_SUCCESS;
  376. ULONG Bytes;
  377. int NumberReady;
  378. SOCKET Socket = 0;
  379. PUCHAR RemainingBuffer;
  380. ULONG RemainingSize;
  381. fd_set ReadHandles;
  382. struct timeval TimeoutTime;
  383. ULONG NetworkSize;
  384. BOOLEAN RetriedOnce = FALSE;
  385. #ifndef WIN32_CHICAGO
  386. WSABUF Buffers[2] = {0};
  387. LPWSABUF SendBuffers = NULL;
  388. ULONG BufferCount = 0;
  389. int SendStatus;
  390. #endif // WIN32_CHICAGO
  391. //
  392. // Start out by binding to the KDC
  393. //
  394. DebugLog((DEB_TRACE, "Calling KDC: %S\n", KdcAddress->Buffer));
  395. Status = KerbBindSocketByAddress(
  396. KdcAddress,
  397. AddressType,
  398. UseDatagram,
  399. PortNumber,
  400. &Socket
  401. );
  402. if (!NT_SUCCESS(Status))
  403. {
  404. goto Cleanup;
  405. }
  406. RemainingBuffer = Input->Buffer;
  407. RemainingSize = Input->BufferSize;
  408. #ifndef WIN32_CHICAGO
  409. //
  410. // Use winsock2
  411. //
  412. Buffers[0].len = sizeof(ULONG);
  413. NetworkSize = htonl(RemainingSize);
  414. Buffers[0].buf = (PCHAR) &NetworkSize;
  415. Buffers[1].len = Input->BufferSize;
  416. Buffers[1].buf = (PCHAR) Input->Buffer;
  417. if (UseDatagram)
  418. {
  419. BufferCount = 1;
  420. SendBuffers = &Buffers[1];
  421. RemainingSize = Buffers[1].len;
  422. }
  423. else
  424. {
  425. BufferCount = 2;
  426. SendBuffers = &Buffers[0];
  427. RemainingSize = Buffers[0].len + Buffers[1].len;
  428. }
  429. RetrySend:
  430. SendStatus = WSASend(
  431. Socket,
  432. SendBuffers,
  433. BufferCount,
  434. &Bytes,
  435. 0, // no flags
  436. NULL, // no overlapped
  437. NULL // no completion routine
  438. );
  439. if ((SendStatus != 0) || (Bytes == 0))
  440. {
  441. DsysAssert(SendStatus == SOCKET_ERROR);
  442. DebugLog((DEB_ERROR,"Failed to send data: %d\n",WSAGetLastError()));
  443. Status = SEC_E_NO_AUTHENTICATING_AUTHORITY;
  444. goto Cleanup;
  445. }
  446. if (Bytes < RemainingSize)
  447. {
  448. RemainingSize -= Bytes;
  449. if (Bytes > SendBuffers->len)
  450. {
  451. //
  452. // We sent the whole of a buffer, so move on to the next
  453. //
  454. Bytes -= SendBuffers->len;
  455. DsysAssert(BufferCount > 1);
  456. BufferCount--;
  457. SendBuffers++;
  458. SendBuffers->len -= Bytes;
  459. SendBuffers->buf += Bytes;
  460. }
  461. else
  462. {
  463. SendBuffers->len -= Bytes;
  464. SendBuffers->buf += Bytes;
  465. }
  466. goto RetrySend;
  467. }
  468. #else // WIN32_CHICAGO
  469. //
  470. // Use winsock1 for win9x
  471. //
  472. //
  473. // For TCP, send length first
  474. //
  475. RetrySend:
  476. if (!UseDatagram)
  477. {
  478. NetworkSize = htonl(RemainingSize);
  479. Bytes = send(Socket, (char *)&NetworkSize,sizeof(ULONG), 0);
  480. if (Bytes != sizeof(ULONG) )
  481. {
  482. DebugLog((DEB_ERROR,"Failed to send TCP packet length: bytes sent = %d, last err = %d\n",
  483. Bytes,
  484. WSAGetLastError()));
  485. Status = SEC_E_NO_AUTHENTICATING_AUTHORITY;
  486. goto Cleanup;
  487. }
  488. }
  489. do
  490. {
  491. if (!UseDatagram)
  492. {
  493. if ( RemainingSize > TcpFragLength )
  494. {
  495. SendSize = TcpFragLength ;
  496. }
  497. else
  498. {
  499. SendSize = RemainingSize ;
  500. }
  501. if ( TcpFragDelay )
  502. {
  503. Sleep( TcpFragDelay );
  504. }
  505. }
  506. else
  507. {
  508. SendSize = RemainingSize ;
  509. }
  510. D_DebugLog(( DEB_T_SOCK, "Sending %x bytes to %wZ\n",
  511. SendSize, KdcAddress ));
  512. Bytes = send(Socket, (char *) RemainingBuffer, SendSize, 0);
  513. if (Bytes == SOCKET_ERROR)
  514. {
  515. DebugLog((DEB_ERROR,"Failed to send data: %d\n",WSAGetLastError()));
  516. Status = SEC_E_NO_AUTHENTICATING_AUTHORITY;
  517. goto Cleanup;
  518. }
  519. if (Bytes != SendSize)
  520. {
  521. DebugLog((DEB_ERROR,"Failed to send all data - only send %d out of %d\n",
  522. Bytes, RemainingSize ));
  523. Status = SEC_E_NO_AUTHENTICATING_AUTHORITY;
  524. goto Cleanup;
  525. }
  526. RemainingBuffer += Bytes;
  527. RemainingSize -= Bytes;
  528. } while ((Bytes != 0) && (RemainingSize != 0));
  529. #endif
  530. //
  531. // Now select on the socket and wait for a response
  532. // ReadHandles and TimeoutTime must be reset each time, cause winsock
  533. // zeroes them out in case of error
  534. ReadHandles.fd_count = 1;
  535. ReadHandles.fd_array[0] = Socket;
  536. TimeoutTime.tv_sec = Timeout;
  537. TimeoutTime.tv_usec = 0;
  538. D_DebugLog(( DEB_T_SOCK, "Socket being used for select is 0x%x\n", ReadHandles.fd_array[0] ));
  539. NumberReady = select(
  540. 1,
  541. &ReadHandles,
  542. NULL,
  543. NULL,
  544. &TimeoutTime
  545. );
  546. if ((NumberReady == SOCKET_ERROR) ||
  547. (NumberReady == 0))
  548. {
  549. DebugLog((DEB_ERROR,"Failed to select on response on socket 0x%x from kdc: %d\n", ReadHandles.fd_array[0], WSAGetLastError()));
  550. DebugLog((DEB_ERROR,"select returned %d\n",NumberReady));
  551. //
  552. // Retry again and wait.
  553. //
  554. if ((NumberReady == 0) && (!RetriedOnce))
  555. {
  556. RetriedOnce = TRUE;
  557. goto RetrySend;
  558. }
  559. Status = STATUS_NO_LOGON_SERVERS;
  560. goto Cleanup;
  561. }
  562. //
  563. // Now receive the data
  564. //
  565. if (UseDatagram)
  566. {
  567. Output->BufferSize = max( KerbGlobalMaxDatagramSize, KERB_MAX_KDC_RESPONSE_SIZE );
  568. Output->Buffer = (PUCHAR) MIDL_user_allocate(Output->BufferSize);
  569. if (Output->Buffer == NULL)
  570. {
  571. Status = STATUS_INSUFFICIENT_RESOURCES;
  572. goto Cleanup;
  573. }
  574. Bytes = recv(
  575. Socket,
  576. (char *) Output->Buffer,
  577. Output->BufferSize,
  578. 0
  579. );
  580. if ((Bytes == SOCKET_ERROR) || (Bytes == 0))
  581. {
  582. DebugLog((DEB_ERROR,"Failed to receive socket data: %d\n",WSAGetLastError()));
  583. Status = SEC_E_NO_AUTHENTICATING_AUTHORITY;
  584. goto Cleanup;
  585. }
  586. Output->BufferSize = Bytes;
  587. }
  588. else
  589. {
  590. Bytes = recv(
  591. Socket,
  592. (char *) &NetworkSize,
  593. sizeof(ULONG),
  594. 0
  595. );
  596. if (Bytes != sizeof(ULONG) )
  597. {
  598. DebugLog((DEB_ERROR,"Failed to receive socket data: %d\n",WSAGetLastError()));
  599. Status = SEC_E_NO_AUTHENTICATING_AUTHORITY;
  600. goto Cleanup;
  601. }
  602. RemainingSize = ntohl(NetworkSize);
  603. Output->BufferSize = RemainingSize;
  604. Output->Buffer = (PUCHAR) MIDL_user_allocate(RemainingSize);
  605. if (Output->Buffer == NULL)
  606. {
  607. Status = STATUS_INSUFFICIENT_RESOURCES;
  608. goto Cleanup;
  609. }
  610. while (RemainingSize != 0)
  611. {
  612. //
  613. // Make sure there is data ready
  614. //
  615. D_DebugLog(( DEB_T_SOCK, "Socket being used for select is 0x%x\n", ReadHandles.fd_array[0] ));
  616. NumberReady = select(
  617. 1,
  618. &ReadHandles,
  619. NULL,
  620. NULL,
  621. &TimeoutTime
  622. );
  623. if ((NumberReady == SOCKET_ERROR) ||
  624. (NumberReady == 0))
  625. {
  626. DebugLog((DEB_ERROR,"Failed to select on response on socket 0x%x from kdc: %d\n", ReadHandles.fd_array[0], WSAGetLastError()));
  627. DebugLog((DEB_ERROR,"select returned %d\n",NumberReady));
  628. Status = STATUS_NO_LOGON_SERVERS;
  629. goto Cleanup;
  630. }
  631. //
  632. // Receive the data
  633. //
  634. Bytes = recv(
  635. Socket,
  636. (char *) Output->Buffer + Output->BufferSize - RemainingSize,
  637. RemainingSize,
  638. 0
  639. );
  640. if ((Bytes == SOCKET_ERROR) || (Bytes == 0))
  641. {
  642. DebugLog((DEB_ERROR,"Failed to receive socket data: %d\n",WSAGetLastError()));
  643. Status = SEC_E_NO_AUTHENTICATING_AUTHORITY;
  644. goto Cleanup;
  645. }
  646. RemainingSize -= Bytes;
  647. }
  648. }
  649. Cleanup:
  650. if (Socket != 0)
  651. {
  652. KerbCloseSocket(Socket);
  653. }
  654. if (!NT_SUCCESS(Status))
  655. {
  656. if (Output->Buffer != NULL)
  657. {
  658. MIDL_user_free(Output->Buffer);
  659. Output->Buffer = NULL;
  660. }
  661. }
  662. return(Status);
  663. }