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.

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