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.

1169 lines
31 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1995
  6. //
  7. // File: sockutil.cxx
  8. //
  9. // Contents: Server support routines for sockets
  10. //
  11. //
  12. // History: 10-July-1996 MikeSw Created
  13. //
  14. //------------------------------------------------------------------------
  15. #include "kdcsvr.hxx"
  16. #include "sockutil.h"
  17. extern "C"
  18. {
  19. #include <atq.h>
  20. }
  21. #include <issched.hxx>
  22. #define KDC_KEY "System\\CurrentControlSet\\Services\\kdc"
  23. #define KDC_PARAMETERS_KEY KDC_KEY "\\parameters"
  24. #define KDC_MAX_ACCEPT_BUFFER 5000
  25. #define KDC_MAX_ACCEPT_OUTSTANDING 16
  26. #define KDC_ACCEPT_TIMEOUT 100
  27. #define KDC_LISTEN_BACKLOG 10
  28. BOOLEAN KdcSocketsInitialized = FALSE;
  29. PVOID KdcEndpoint = NULL;
  30. PVOID KpasswdEndpoint = NULL;
  31. RTL_CRITICAL_SECTION KdcAtqContextLock;
  32. LIST_ENTRY KdcAtqContextList;
  33. NTSTATUS
  34. KdcInitializeDatagramSockets(
  35. VOID
  36. );
  37. NTSTATUS
  38. KdcShutdownDatagramSockets(
  39. VOID
  40. );
  41. KERBERR
  42. KdcAtqRetrySocketRead(
  43. IN PKDC_ATQ_CONTEXT Context,
  44. IN ULONG NewBytes
  45. );
  46. //+-------------------------------------------------------------------------
  47. //
  48. // Function: KdcAtqCloseSocket
  49. //
  50. // Synopsis: Wrapper to close socket to avoid socket leaks
  51. //
  52. // Effects:
  53. //
  54. // Arguments:
  55. //
  56. // Requires:
  57. //
  58. // Returns:
  59. //
  60. // Notes:
  61. //
  62. //
  63. //--------------------------------------------------------------------------
  64. VOID
  65. KdcAtqCloseSocket(
  66. IN PKDC_ATQ_CONTEXT Context
  67. )
  68. {
  69. D_DebugLog ((DEB_T_SOCK, "Closing socket for %p\n", Context));
  70. AtqCloseSocket((PATQ_CONTEXT) Context->AtqContext, FALSE);
  71. Context->Flags |= KDC_ATQ_SOCKET_CLOSED;
  72. }
  73. //+-------------------------------------------------------------------------
  74. //
  75. // Function: KdcAtqReferenceContext
  76. //
  77. // Synopsis: References a kdc ATQ context by one
  78. //
  79. // Effects:
  80. //
  81. // Arguments:
  82. //
  83. // Requires:
  84. //
  85. // Returns:
  86. //
  87. // Notes:
  88. //
  89. //
  90. //--------------------------------------------------------------------------
  91. VOID
  92. KdcReferenceContext(
  93. IN PKDC_ATQ_CONTEXT KdcContext
  94. #if DBG
  95. , IN UINT Line
  96. #endif
  97. )
  98. {
  99. D_DebugLog ((DEB_T_SOCK, "Referencing KdcContext %p on line %d\n", KdcContext, Line));
  100. RtlEnterCriticalSection(&KdcAtqContextLock);
  101. KdcContext->References++;
  102. RtlLeaveCriticalSection(&KdcAtqContextLock);
  103. }
  104. //+-------------------------------------------------------------------------
  105. //
  106. // Function: KdcAtqDereferenceContext
  107. //
  108. // Synopsis: Dereferences a context & unlinks & frees it when the
  109. // ref count goes to zero
  110. //
  111. // Effects:
  112. //
  113. // Arguments:
  114. //
  115. // Requires:
  116. //
  117. // Returns: TRUE if this was the last release and the object was unlinked
  118. // and deleted, FALSE otherwise
  119. //
  120. // Notes:
  121. //
  122. //
  123. //--------------------------------------------------------------------------
  124. BOOLEAN
  125. KdcDereferenceContext(
  126. IN PKDC_ATQ_CONTEXT KdcContext
  127. #if DBG
  128. ,
  129. IN UINT Line
  130. #endif
  131. )
  132. {
  133. BOOLEAN Deleted = FALSE;
  134. D_DebugLog ((DEB_T_SOCK, "Dereferencing KdcContext 0x%p on line %d\n", KdcContext, Line));
  135. DsysAssert( KdcContext );
  136. DsysAssert( KdcContext->References > 0 );
  137. RtlEnterCriticalSection(&KdcAtqContextLock);
  138. KdcContext->References--;
  139. if (KdcContext->References == 0)
  140. {
  141. Deleted = TRUE;
  142. RemoveEntryList(
  143. &KdcContext->Next
  144. );
  145. }
  146. RtlLeaveCriticalSection(&KdcAtqContextLock);
  147. if (Deleted)
  148. {
  149. if (((KdcContext->Flags & KDC_ATQ_SOCKET_USED) != 0) &&
  150. ((KdcContext->Flags & KDC_ATQ_SOCKET_CLOSED) == 0))
  151. {
  152. KdcAtqCloseSocket( KdcContext );
  153. }
  154. D_DebugLog ((DEB_T_SOCK, "Deleting KdcContext %p\n", KdcContext));
  155. AtqFreeContext( (PATQ_CONTEXT) KdcContext->AtqContext, TRUE );
  156. if (KdcContext->WriteBuffer != NULL)
  157. {
  158. KdcFreeEncodedData(KdcContext->WriteBuffer);
  159. }
  160. if (KdcContext->Buffer != NULL)
  161. {
  162. RtlFreeHeap(RtlProcessHeap(), 0, KdcContext->Buffer);
  163. }
  164. MIDL_user_free(KdcContext);
  165. }
  166. return(Deleted);
  167. }
  168. #if DBG
  169. #define KdcAtqReferenceContext( _Context ) KdcReferenceContext( _Context, __LINE__ )
  170. #define KdcAtqDereferenceContext( _Context ) KdcDereferenceContext( _Context, __LINE__ )
  171. #else
  172. #define KdcAtqReferenceContext( _Context ) KdcReferenceContext( _Context )
  173. #define KdcAtqDereferenceContext( _Context ) KdcDereferenceContext( _Context )
  174. #endif
  175. //+-------------------------------------------------------------------------
  176. //
  177. // Function: KdcAtqCreateContext
  178. //
  179. // Synopsis: Creates & links an ATQ context
  180. //
  181. // Effects:
  182. //
  183. // Arguments:
  184. //
  185. // Requires:
  186. //
  187. // Returns:
  188. //
  189. // Notes:
  190. //
  191. //
  192. //--------------------------------------------------------------------------
  193. PKDC_ATQ_CONTEXT
  194. KdcAtqCreateContext(
  195. IN PATQ_CONTEXT AtqContext,
  196. IN PVOID EndpointContext,
  197. IN LPOVERLAPPED lpo,
  198. IN PSOCKADDR ClientAddress,
  199. IN PSOCKADDR ServerAddress
  200. )
  201. {
  202. PKDC_ATQ_CONTEXT KdcContext;
  203. if (!KdcSocketsInitialized)
  204. {
  205. return(NULL);
  206. }
  207. KdcContext = (PKDC_ATQ_CONTEXT) MIDL_user_allocate(sizeof(KDC_ATQ_CONTEXT));
  208. if (KdcContext != NULL)
  209. {
  210. KdcContext->References = 1; // Keepalive reference count
  211. KdcContext->AtqContext = AtqContext;
  212. KdcContext->EndpointContext = EndpointContext;
  213. KdcContext->lpo = lpo;
  214. KdcContext->Address = *ClientAddress;
  215. KdcContext->LocalAddress = *ServerAddress;
  216. KdcContext->WriteBuffer = NULL;
  217. KdcContext->WriteBufferLength = 0;
  218. KdcContext->Flags = KDC_ATQ_WRITE_CONTEXT;
  219. KdcContext->UsedBufferLength = 0;
  220. KdcContext->BufferLength = 0;
  221. KdcContext->ExpectedMessageSize = 0;
  222. KdcContext->Buffer = NULL;
  223. RtlEnterCriticalSection( &KdcAtqContextLock );
  224. InsertHeadList(&KdcAtqContextList, &KdcContext->Next);
  225. RtlLeaveCriticalSection( &KdcAtqContextLock );
  226. }
  227. D_DebugLog ((DEB_T_SOCK, "Creating KdcContext %p\n", KdcContext));
  228. return(KdcContext);
  229. }
  230. //+-------------------------------------------------------------------------
  231. //
  232. // Function: KdcAtqConnectEx
  233. //
  234. // Synopsis:
  235. //
  236. // Effects:
  237. //
  238. // Arguments:
  239. //
  240. // Requires:
  241. //
  242. // Returns:
  243. //
  244. // Notes:
  245. //
  246. //
  247. //--------------------------------------------------------------------------
  248. VOID
  249. KdcAtqConnectEx(
  250. IN PVOID Context,
  251. IN DWORD BytesWritten,
  252. IN DWORD CompletionStatus,
  253. IN OVERLAPPED * lpo
  254. )
  255. {
  256. KERBERR KerbErr;
  257. PKDC_ATQ_CONTEXT KdcContext = NULL;
  258. PATQ_CONTEXT AtqContext = (PATQ_CONTEXT) Context;
  259. SOCKADDR * LocalAddress = NULL;
  260. SOCKADDR * RemoteAddress = NULL;
  261. SOCKET NewSocket = INVALID_SOCKET;
  262. PKDC_GET_TICKET_ROUTINE EndpointFunction = NULL;
  263. PVOID Buffer;
  264. TRACE(KDC, KdcAtqConnectEx, DEB_FUNCTION);
  265. //
  266. // Turning on hard closes on sockets. We believe that we properly send
  267. // all the data to the client prior to closing the connection, otherwise
  268. // this won't work.
  269. //
  270. AtqContextSetInfo(
  271. AtqContext,
  272. ATQ_INFO_ABORTIVE_CLOSE,
  273. TRUE
  274. );
  275. if ((CompletionStatus != NO_ERROR) || !KdcSocketsInitialized || !lpo )
  276. {
  277. D_DebugLog((DEB_T_SOCK, "ConnectEx: CompletionStatus = 0x%x\n", CompletionStatus));
  278. AtqCloseSocket( AtqContext, TRUE );
  279. D_DebugLog((DEB_T_SOCK, "Freeing context %p\n", AtqContext));
  280. AtqFreeContext( AtqContext, TRUE );
  281. return;
  282. }
  283. //
  284. // Get the address information including the first write buffer
  285. //
  286. AtqGetAcceptExAddrs(
  287. AtqContext,
  288. &NewSocket,
  289. &Buffer,
  290. (PVOID *) &EndpointFunction,
  291. &LocalAddress,
  292. &RemoteAddress
  293. );
  294. //
  295. // New connection requests are guaranteed to always come in with BytesWritten == 0
  296. //
  297. DsysAssert( BytesWritten == 0 );
  298. //
  299. // If the remote address is port 88 or 464, don't respond, as we don't
  300. // want to be vulnerable to a loopback attack.
  301. //
  302. if ((((SOCKADDR_IN *) RemoteAddress)->sin_port == KERB_KDC_PORT) ||
  303. (((SOCKADDR_IN *) RemoteAddress)->sin_port == KERB_KPASSWD_PORT))
  304. {
  305. //
  306. // Just free up the context so it can be reused.
  307. //
  308. AtqCloseSocket( AtqContext, TRUE );
  309. AtqFreeContext( AtqContext, TRUE );
  310. return;
  311. }
  312. //
  313. // Create a context
  314. //
  315. KdcContext = KdcAtqCreateContext(
  316. AtqContext,
  317. EndpointFunction,
  318. lpo,
  319. RemoteAddress,
  320. LocalAddress
  321. );
  322. if (KdcContext == NULL)
  323. {
  324. AtqCloseSocket( AtqContext, TRUE );
  325. AtqFreeContext( AtqContext, TRUE );
  326. return;
  327. }
  328. //
  329. // Associate "our" KDC context with "their" ATQ context
  330. //
  331. AtqContextSetInfo(
  332. AtqContext,
  333. ATQ_INFO_COMPLETION_CONTEXT,
  334. (ULONG_PTR) KdcContext
  335. );
  336. //
  337. // Set the timeout for IOs on this context until the first byte of data is received
  338. // This timeout is shorter than the "subsequent" timeout to prevent
  339. // too many open and idle connections against the KDC
  340. //
  341. D_DebugLog((DEB_T_SOCK, "KdcAtqConnectEx: set timeout for KdcContext %p to KdcNewConnectionTimeout %#x\n", KdcContext, KdcNewConnectionTimeout));
  342. AtqContextSetInfo(
  343. AtqContext,
  344. ATQ_INFO_TIMEOUT,
  345. KdcNewConnectionTimeout
  346. );
  347. //
  348. // Post a read right away - we expect the client to send us the request now
  349. //
  350. KerbErr = KdcAtqRetrySocketRead(
  351. KdcContext,
  352. 0
  353. );
  354. //
  355. // At this point, ownership of KdcContext was taken over by ATQ
  356. // If there was an error, the socket was closed and the context deleted
  357. //
  358. return;
  359. }
  360. //+-------------------------------------------------------------------------
  361. //
  362. // Function: KdcAtqIoCompletion
  363. //
  364. // Synopsis: Callback routine for an io completion on a TCP socket
  365. // for the KDC
  366. //
  367. // Effects:
  368. //
  369. // Arguments:
  370. //
  371. // Requires:
  372. //
  373. // Returns:
  374. //
  375. // Notes: The reference count when this routine is called should always
  376. // be equal to 2 (one keepalive ref count and one ref count for
  377. // the outstanding IO operation). Note that this is a 'should'
  378. // and therefore there are no asserts in the code.
  379. //
  380. // When the routine is left, either another IO operation was
  381. // enqueued (in which case the refcount is again 2) or the
  382. // connection has been closed (in which case the context is destroyed)
  383. //
  384. //--------------------------------------------------------------------------
  385. VOID
  386. KdcAtqIoCompletion(
  387. IN PVOID Context,
  388. IN DWORD BytesWritten,
  389. IN DWORD CompletionStatus,
  390. IN OVERLAPPED * lpo
  391. )
  392. {
  393. PKDC_ATQ_CONTEXT KdcContext;
  394. KERB_MESSAGE_BUFFER InputMessage;
  395. KERB_MESSAGE_BUFFER OutputMessage;
  396. PKDC_GET_TICKET_ROUTINE EndpointFunction = NULL;
  397. TRACE(KDC,KdcAtqIoCompletion, DEB_FUNCTION);
  398. if (Context == NULL)
  399. {
  400. return;
  401. }
  402. //
  403. // If a client connects and then disconnects gracefully ,we will get a
  404. // completion with zero bytes and success status.
  405. //
  406. if ((BytesWritten == 0) && (CompletionStatus == NO_ERROR))
  407. {
  408. CompletionStatus = WSAECONNABORTED;
  409. }
  410. KdcContext = (PKDC_ATQ_CONTEXT) Context;
  411. if ((CompletionStatus != NO_ERROR) || (lpo == NULL) || !KdcSocketsInitialized)
  412. {
  413. //
  414. // This includes timeout processing (CompletionStatus == ERROR_SEM_TIMEOUT)
  415. //
  416. D_DebugLog((DEB_T_SOCK, "KdcAtqIoCompletion: CompletionStatus = 0x%x\n", CompletionStatus));
  417. D_DebugLog((DEB_T_SOCK, "KdcAtqIoCompletion: lpo = %p\n", lpo));
  418. KdcAtqCloseSocket( KdcContext );
  419. //
  420. // If the overlapped structure is not null, then there is an
  421. // outstanding IO that just completed, so dereference the context
  422. // to remove that i/o. Otherwise leave the reference there, as we will
  423. // probably be called back when the io terminates.
  424. //
  425. if (lpo != NULL)
  426. {
  427. //
  428. // Drop the keepalive ref count - the connection has been closed
  429. //
  430. KdcAtqDereferenceContext(KdcContext);
  431. goto Cleanup;
  432. }
  433. else
  434. {
  435. //
  436. // The keepalive refcount will be dropped when the outstanding IO
  437. // completes (now with an error, since the socket has been closed)
  438. //
  439. D_DebugLog((DEB_T_SOCK, "KdcAtqIoCompletion context %p not dereferenced because lpo is NULL, CompletionStatus is 0x%x\n", KdcContext, CompletionStatus));
  440. goto CleanupNoRelease;
  441. }
  442. }
  443. //
  444. // NOTE: after reading or writing to a context, the context should
  445. // not be touched because a completion may have occurred on another
  446. // thread that may delete the context.
  447. //
  448. if ((KdcContext->Flags & KDC_ATQ_READ_CONTEXT) != 0)
  449. {
  450. KERBERR KerbErr;
  451. D_DebugLog((DEB_T_SOCK, "KdcAtqIoCompletion: %d bytes read\n", BytesWritten));
  452. //
  453. // Read the number of bytes off the front of the message
  454. //
  455. if (KdcContext->UsedBufferLength == 0)
  456. {
  457. if (BytesWritten >= sizeof(ULONG))
  458. {
  459. KdcContext->ExpectedMessageSize = ntohl(*(PULONG)KdcContext->Buffer) + sizeof( ULONG );
  460. D_DebugLog((DEB_T_SOCK, "KdcAtqIoCompletion: Expected msg size = %d\n", KdcContext->ExpectedMessageSize));
  461. //
  462. // Set the timeout for IOs on this context until the first byte of data is received
  463. //
  464. D_DebugLog((DEB_T_SOCK, "KdcAtqIoCompletion: first completion, increasing timeout for KdcContext %p to KdcExistingConnectionTimeout %#x\n", KdcContext, KdcExistingConnectionTimeout));
  465. AtqContextSetInfo(
  466. KdcContext->AtqContext,
  467. ATQ_INFO_TIMEOUT,
  468. KdcExistingConnectionTimeout
  469. );
  470. }
  471. else
  472. {
  473. //
  474. // Blow away this connection - we require at least 4 bytes upfront
  475. //
  476. D_DebugLog((DEB_T_SOCK, "KdcAtqIoCompletion ERROR: Read completion on context %p with less than 4 bytes!\n", KdcContext));
  477. KdcAtqCloseSocket(KdcContext);
  478. //
  479. // Drop the keepalive ref count
  480. //
  481. KdcAtqDereferenceContext( KdcContext );
  482. goto Cleanup;
  483. }
  484. }
  485. if ( KdcContext->UsedBufferLength + BytesWritten < KdcContext->ExpectedMessageSize )
  486. {
  487. //
  488. // This will either enqueue another I/O on this context and bump
  489. // up the ref count, or, on failure, close the socket and drop
  490. // the keepalive ref count
  491. //
  492. KerbErr = KdcAtqRetrySocketRead(
  493. KdcContext,
  494. BytesWritten
  495. );
  496. goto Cleanup;
  497. }
  498. //
  499. // There is a buffer, so use it to do the KDC thang.
  500. //
  501. KdcContext->lpo = lpo;
  502. InputMessage.BufferSize = (KdcContext->UsedBufferLength + BytesWritten) - sizeof(ULONG);
  503. InputMessage.Buffer = KdcContext->Buffer + sizeof(ULONG);
  504. OutputMessage.Buffer = NULL;
  505. EndpointFunction = (PKDC_GET_TICKET_ROUTINE) KdcContext->EndpointContext;
  506. KerbErr = EndpointFunction(
  507. &KdcContext,
  508. &KdcContext->Address,
  509. &KdcContext->LocalAddress,
  510. &InputMessage,
  511. &OutputMessage
  512. );
  513. if ((KerbErr != KDC_ERR_NONE) || (OutputMessage.BufferSize != 0))
  514. {
  515. //
  516. // We expect at least some level of message validity before
  517. // we'll return anything.
  518. //
  519. if (KerbErr == KDC_ERR_NO_RESPONSE)
  520. {
  521. // TBD: Log an "attack" event here.
  522. KdcAtqCloseSocket(KdcContext);
  523. //
  524. // Drop the keepalive ref count
  525. //
  526. KdcAtqDereferenceContext(KdcContext);
  527. }
  528. else
  529. {
  530. ULONG NetworkSize;
  531. WSABUF Buffers[2];
  532. NetworkSize = htonl(OutputMessage.BufferSize);
  533. Buffers[0].len = sizeof(DWORD);
  534. Buffers[0].buf = (PCHAR) &NetworkSize;
  535. Buffers[1].len = OutputMessage.BufferSize;
  536. Buffers[1].buf = (PCHAR) OutputMessage.Buffer;
  537. KdcContext->WriteBufferLength = OutputMessage.BufferSize;
  538. KdcContext->WriteBuffer = OutputMessage.Buffer;
  539. OutputMessage.Buffer = NULL;
  540. //
  541. // If there was no output message, don't send one.
  542. //
  543. KdcContext->Flags |= KDC_ATQ_WRITE_CONTEXT;
  544. KdcContext->Flags &= ~KDC_ATQ_READ_CONTEXT;
  545. //
  546. // Refernce the context for the write.
  547. //
  548. KdcAtqReferenceContext(KdcContext);
  549. if (!AtqWriteSocket(
  550. KdcContext->AtqContext,
  551. Buffers,
  552. 2,
  553. lpo
  554. ))
  555. {
  556. DebugLog((DEB_ERROR, "Failed to write KDC reply: 0x%x\n", GetLastError()));
  557. KdcAtqCloseSocket( KdcContext );
  558. //
  559. // Remove the reference we have just applied
  560. //
  561. KdcAtqDereferenceContext(KdcContext);
  562. //
  563. // Drop the keepalive ref count
  564. //
  565. KdcAtqDereferenceContext(KdcContext);
  566. }
  567. }
  568. if (OutputMessage.Buffer != NULL)
  569. {
  570. KdcFreeEncodedData(OutputMessage.Buffer);
  571. }
  572. }
  573. else
  574. {
  575. //
  576. // Bizarre situation - nothing to send to the client
  577. // In the kerberos world, this connection has no business existing
  578. //
  579. DebugLog((DEB_ERROR, "Endpoint function returned but nothing to send, Context = %p\n", Context ));
  580. KdcAtqCloseSocket( KdcContext );
  581. //
  582. // Drop the keepalive ref count
  583. //
  584. KdcAtqDereferenceContext(KdcContext);
  585. }
  586. }
  587. else
  588. {
  589. D_DebugLog((DEB_T_SOCK, "IoCompletion: %d bytes written\n", BytesWritten));
  590. KdcContext->Flags |= KDC_ATQ_READ_CONTEXT;
  591. KdcContext->Flags &= ~KDC_ATQ_WRITE_CONTEXT;
  592. //
  593. // Reset the buffer for a brand new read
  594. //
  595. KdcContext->UsedBufferLength = 0;
  596. KdcContext->ExpectedMessageSize = 0;
  597. if (KdcContext->WriteBuffer != NULL)
  598. {
  599. KdcFreeEncodedData(KdcContext->WriteBuffer);
  600. KdcContext->WriteBuffer = NULL;
  601. }
  602. //
  603. // Reference the context for the read
  604. //
  605. KdcAtqReferenceContext(KdcContext);
  606. if (!AtqReadFile(
  607. KdcContext->AtqContext,
  608. KdcContext->Buffer,
  609. KdcContext->BufferLength,
  610. lpo
  611. ))
  612. {
  613. DebugLog((DEB_ERROR, "Failed to read file for %d bytes: 0x%x\n", KERB_MAX_KDC_REQUEST_SIZE,GetLastError()));
  614. KdcAtqCloseSocket( KdcContext );
  615. //
  616. // Dereference the reference we just added
  617. //
  618. KdcAtqDereferenceContext(KdcContext);
  619. //
  620. // Drop the keepalive ref count
  621. //
  622. KdcAtqDereferenceContext(KdcContext);
  623. }
  624. }
  625. Cleanup:
  626. //
  627. // Drop the reference count associated with an outstanding I/O operation
  628. //
  629. KdcAtqDereferenceContext(KdcContext);
  630. CleanupNoRelease:
  631. return;
  632. }
  633. //+-------------------------------------------------------------------------
  634. //
  635. // Function: KdcAtqRetrySocketRead
  636. //
  637. // Synopsis: Retries a read if not all the data was read
  638. //
  639. // Effects: posts an AtqReadSocket
  640. // Closes and dereferences the context on error
  641. //
  642. // Arguments: Context - The KDC context to retry the read on
  643. //
  644. // Requires:
  645. //
  646. // Returns:
  647. //
  648. // Notes:
  649. //
  650. //
  651. //--------------------------------------------------------------------------
  652. KERBERR
  653. KdcAtqRetrySocketRead(
  654. IN PKDC_ATQ_CONTEXT KdcContext,
  655. IN ULONG NewBytes
  656. )
  657. {
  658. KERBERR KerbErr = KDC_ERR_NONE;
  659. PBYTE NewBuffer = NULL;
  660. ULONG NewBufferLength;
  661. D_DebugLog(( DEB_T_SOCK, "RetrySocketRead: Expected size = %#x, current size %#x\n",
  662. KdcContext->ExpectedMessageSize,
  663. KdcContext->UsedBufferLength));
  664. if (KdcContext->ExpectedMessageSize != 0)
  665. {
  666. NewBufferLength = KdcContext->ExpectedMessageSize;
  667. }
  668. else
  669. {
  670. //
  671. // Set max buffer length at 128k
  672. //
  673. if (KdcContext->BufferLength < KDC_MAX_BUFFER_LENGTH)
  674. {
  675. NewBufferLength = KdcContext->BufferLength + KERB_MAX_KDC_REQUEST_SIZE;
  676. }
  677. else
  678. {
  679. KerbErr = KRB_ERR_GENERIC;
  680. goto Cleanup;
  681. }
  682. }
  683. if (NewBufferLength > KDC_MAX_BUFFER_LENGTH)
  684. {
  685. KerbErr = KRB_ERR_GENERIC;
  686. goto Cleanup;
  687. }
  688. //
  689. // If the expected message size doesn't fit in the current buffer,
  690. // allocate a new one.
  691. //
  692. if (NewBufferLength > KdcContext->BufferLength)
  693. {
  694. D_DebugLog(( DEB_T_SOCK, "Allocating a new buffer for context %p\n", KdcContext ));
  695. //
  696. // Do not use MIDL_user_allocate here since that would zero the memory
  697. // out which amounts to waste of CPU cycles
  698. //
  699. NewBuffer = (PBYTE)RtlAllocateHeap(
  700. RtlProcessHeap(),
  701. 0,
  702. NewBufferLength
  703. );
  704. if (NewBuffer == NULL)
  705. {
  706. KerbErr = KRB_ERR_GENERIC;
  707. goto Cleanup;
  708. }
  709. //
  710. // we resized while the buffer was in use. Copy the data and touch up
  711. // the pointers below
  712. //
  713. RtlCopyMemory(
  714. NewBuffer,
  715. KdcContext->Buffer,
  716. KdcContext->BufferLength
  717. );
  718. RtlFreeHeap(
  719. RtlProcessHeap(),
  720. 0,
  721. KdcContext->Buffer
  722. );
  723. KdcContext->Buffer = NewBuffer;
  724. KdcContext->BufferLength = NewBufferLength;
  725. NewBuffer = NULL;
  726. }
  727. KdcContext->UsedBufferLength += NewBytes;
  728. KdcContext->Flags |= KDC_ATQ_READ_CONTEXT;
  729. KdcContext->Flags &= ~(KDC_ATQ_WRITE_CONTEXT);
  730. //
  731. // Reference the context for the read
  732. //
  733. KdcAtqReferenceContext(KdcContext);
  734. if (!AtqReadFile(
  735. KdcContext->AtqContext,
  736. (PUCHAR) KdcContext->Buffer + KdcContext->UsedBufferLength,
  737. KdcContext->BufferLength - KdcContext->UsedBufferLength,
  738. KdcContext->lpo
  739. ))
  740. {
  741. DebugLog((DEB_ERROR, "Failed to read file for %d bytes: 0x%x\n", KdcContext->BufferLength - KdcContext->UsedBufferLength, GetLastError()));
  742. //
  743. // Dereference the reference we just added
  744. //
  745. KdcAtqDereferenceContext(KdcContext);
  746. KerbErr = KRB_ERR_GENERIC;
  747. goto Cleanup;
  748. }
  749. Cleanup:
  750. if (!KERB_SUCCESS(KerbErr))
  751. {
  752. DebugLog((DEB_ERROR, "Closing connection to %p due to RetrySocketRead error\n", KdcContext));
  753. KdcAtqCloseSocket( KdcContext );
  754. //
  755. // Drop the keepalive ref count
  756. //
  757. KdcAtqDereferenceContext(KdcContext);
  758. }
  759. return(KerbErr);
  760. }
  761. //+-------------------------------------------------------------------------
  762. //
  763. // Function: KdcInitializeSockets
  764. //
  765. // Synopsis: Initializes the KDCs socket handling code
  766. //
  767. // Effects:
  768. //
  769. // Arguments: none
  770. //
  771. // Requires:
  772. //
  773. // Returns:
  774. //
  775. // Notes:
  776. //
  777. //
  778. //--------------------------------------------------------------------------
  779. NTSTATUS
  780. KdcInitializeSockets(
  781. VOID
  782. )
  783. {
  784. NTSTATUS Status = STATUS_SUCCESS;
  785. ATQ_ENDPOINT_CONFIGURATION EndpointConfig;
  786. BOOLEAN AtqInitCalled = FALSE;
  787. BOOLEAN ContextLockInited = FALSE;
  788. TRACE(KDC,KdcInitializeSockets, DEB_FUNCTION);
  789. //
  790. // Initialize the asynchronous thread queue.
  791. //
  792. if (!AtqInitialize(0))
  793. {
  794. DebugLog((DEB_ERROR, "Failed to initialize ATQ\n"));
  795. Status = STATUS_UNSUCCESSFUL;
  796. goto Cleanup;
  797. }
  798. AtqInitCalled = TRUE;
  799. Status = RtlInitializeCriticalSection(&KdcAtqContextLock);
  800. if (!NT_SUCCESS(Status))
  801. {
  802. goto Cleanup;
  803. }
  804. ContextLockInited = TRUE;
  805. InitializeListHead(&KdcAtqContextList);
  806. //
  807. // Create the KDC endpoint
  808. //
  809. EndpointConfig.ListenPort = KERB_KDC_PORT;
  810. EndpointConfig.fDatagram = FALSE;
  811. EndpointConfig.fReverseQueuing = FALSE; // ignored (datagram only)
  812. EndpointConfig.cbDatagramWSBufSize = 0; // ignored (datagram only)
  813. EndpointConfig.fLockDownPort = TRUE;
  814. EndpointConfig.IpAddress = INADDR_ANY;
  815. EndpointConfig.cbAcceptExRecvBuffer = 0; // do not wait for data to be received
  816. // prior to notifying us of a new connection
  817. EndpointConfig.nAcceptExOutstanding = KDC_MAX_ACCEPT_OUTSTANDING;
  818. EndpointConfig.AcceptExTimeout = (unsigned long)-1; // Forever;
  819. EndpointConfig.pfnConnect = NULL;
  820. EndpointConfig.pfnConnectEx = KdcAtqConnectEx;
  821. EndpointConfig.pfnIoCompletion = KdcAtqIoCompletion;
  822. KdcEndpoint = AtqCreateEndpoint(
  823. &EndpointConfig,
  824. KdcGetTicket
  825. );
  826. if (KdcEndpoint == NULL)
  827. {
  828. DebugLog((DEB_ERROR, "Failed to create ATQ endpoint\n"));
  829. Status = STATUS_UNSUCCESSFUL;
  830. goto Cleanup;
  831. }
  832. //
  833. // Start the endpoint
  834. //
  835. if (!AtqStartEndpoint(KdcEndpoint))
  836. {
  837. DebugLog((DEB_ERROR, "Failed to add ATQ endpoint\n"));
  838. Status = STATUS_UNSUCCESSFUL;
  839. goto Cleanup;
  840. }
  841. //
  842. // Create the KPASSWD endpoint
  843. //
  844. EndpointConfig.ListenPort = KERB_KPASSWD_PORT;
  845. KpasswdEndpoint = AtqCreateEndpoint(
  846. &EndpointConfig,
  847. KdcChangePassword
  848. );
  849. if (KpasswdEndpoint == NULL)
  850. {
  851. DebugLog((DEB_ERROR, "Failed to create ATQ endpoint for kpasswd\n"));
  852. Status = STATUS_UNSUCCESSFUL;
  853. goto Cleanup;
  854. }
  855. //
  856. // Start the endpoint
  857. //
  858. if (!AtqStartEndpoint(KpasswdEndpoint))
  859. {
  860. DebugLog((DEB_ERROR, "Failed to add ATQ endpoint\n"));
  861. Status = STATUS_UNSUCCESSFUL;
  862. goto Cleanup;
  863. }
  864. D_DebugLog((DEB_TRACE, "Successfully started ATQ listening for kpasswd\n"));
  865. Status = KdcInitializeDatagramSockets( );
  866. if (!NT_SUCCESS(Status))
  867. {
  868. goto Cleanup;
  869. }
  870. KdcSocketsInitialized = TRUE;
  871. Cleanup:
  872. if (!NT_SUCCESS(Status))
  873. {
  874. if (KdcEndpoint != NULL)
  875. {
  876. (VOID) AtqStopEndpoint( KdcEndpoint );
  877. (VOID) AtqCloseEndpoint( KdcEndpoint );
  878. KdcEndpoint = NULL;
  879. }
  880. if (KpasswdEndpoint != NULL)
  881. {
  882. (VOID) AtqStopEndpoint( KpasswdEndpoint );
  883. (VOID) AtqCloseEndpoint( KpasswdEndpoint );
  884. KpasswdEndpoint = NULL;
  885. }
  886. if ( ContextLockInited ) {
  887. RtlDeleteCriticalSection( &KdcAtqContextLock );
  888. }
  889. if (AtqInitCalled)
  890. {
  891. AtqTerminate();
  892. }
  893. }
  894. return(Status);
  895. }
  896. //+-------------------------------------------------------------------------
  897. //
  898. // Function: KdcShutdownSockets
  899. //
  900. // Synopsis: Shuts down the KDC socket handling code
  901. //
  902. // Effects:
  903. //
  904. // Arguments:
  905. //
  906. // Requires:
  907. //
  908. // Returns:
  909. //
  910. // Notes:
  911. //
  912. //
  913. //--------------------------------------------------------------------------
  914. NTSTATUS
  915. KdcShutdownSockets(
  916. VOID
  917. )
  918. {
  919. PKDC_ATQ_CONTEXT Context;
  920. PLIST_ENTRY ListEntry;
  921. BOOLEAN KdcSocketsWasInitialized = KdcSocketsInitialized;
  922. TRACE(KDC,KdcShutdownSockets, DEB_FUNCTION);
  923. if (!KdcSocketsInitialized)
  924. {
  925. return(STATUS_SUCCESS);
  926. }
  927. //
  928. // Go through the list of contexts and close them all.
  929. //
  930. RtlEnterCriticalSection( &KdcAtqContextLock );
  931. KdcSocketsInitialized = FALSE;
  932. for (ListEntry = KdcAtqContextList.Flink;
  933. (ListEntry != &KdcAtqContextList) && (ListEntry != NULL) ;
  934. ListEntry = ListEntry->Flink )
  935. {
  936. Context = CONTAINING_RECORD(ListEntry, KDC_ATQ_CONTEXT, Next);
  937. //
  938. // If this is a read or write context, free close the associated
  939. // socket. (Endpoint contexts don't have sockets).
  940. //
  941. if (Context->Flags & ( KDC_ATQ_WRITE_CONTEXT | KDC_ATQ_READ_CONTEXT))
  942. {
  943. KdcAtqCloseSocket( Context );
  944. }
  945. }
  946. RtlLeaveCriticalSection( &KdcAtqContextLock );
  947. if (KdcEndpoint != NULL)
  948. {
  949. (VOID) AtqStopEndpoint( KdcEndpoint );
  950. (VOID) AtqCloseEndpoint( KdcEndpoint );
  951. KdcEndpoint = NULL;
  952. }
  953. if (KpasswdEndpoint != NULL)
  954. {
  955. (VOID) AtqStopEndpoint( KpasswdEndpoint );
  956. (VOID) AtqCloseEndpoint( KpasswdEndpoint );
  957. KpasswdEndpoint = NULL;
  958. }
  959. KdcShutdownDatagramSockets();
  960. if (KdcSocketsWasInitialized)
  961. {
  962. if (!AtqTerminate())
  963. {
  964. DebugLog((DEB_ERROR, "Failed to terminate ATQ!!!\n"));
  965. }
  966. RtlDeleteCriticalSection(&KdcAtqContextLock);
  967. }
  968. return(STATUS_SUCCESS);
  969. }