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.

1008 lines
26 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1995
  6. //
  7. // File: dgutil.cxx
  8. //
  9. // Contents: Server support routines for datagram 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. #include <nlrepl.h>
  21. }
  22. #include <issched.hxx>
  23. #include "fileno.h"
  24. #define FILENO FILENO_DGUTIL
  25. #define KDC_KEY "System\\CurrentControlSet\\Services\\kdc"
  26. #define KDC_PARAMETERS_KEY KDC_KEY "\\parameters"
  27. #define KDC_MAX_ACCEPT_BUFFER 5000
  28. #define KDC_MAX_ACCEPT_OUTSTANDING 5
  29. #define KDC_ACCEPT_TIMEOUT 100
  30. #define KDC_LISTEN_BACKLOG 10
  31. #define KDC_CONTEXT_TIMEOUT 50
  32. extern BOOLEAN KdcSocketsInitialized;
  33. typedef struct _KDC_DATAGRAM_ENDPOINT {
  34. SOCKADDR LocalAddress;
  35. PKDC_GET_TICKET_ROUTINE EndpointFunction;
  36. PVOID Endpoint;
  37. } KDC_DATAGRAM_ENDPOINT, *PKDC_DATAGRAM_ENDPOINT;
  38. PKDC_DATAGRAM_ENDPOINT DatagramEndpoints = NULL;
  39. ULONG DatagramEndpointCount = 0;
  40. RTL_RESOURCE DatagramEndpointLock;
  41. BOOL DatagramEndpointLockInitialized = FALSE;
  42. SOCKET KdcWinsockPnpSocket = INVALID_SOCKET;
  43. HANDLE KdcWinsockPnpEvent = NULL;
  44. HANDLE KdcPnpEventChangeHandle = NULL;
  45. //+-------------------------------------------------------------------------
  46. //
  47. // Function: KdcAtqDgIoCompletion
  48. //
  49. // Synopsis:
  50. //
  51. // Effects:
  52. //
  53. // Arguments:
  54. //
  55. // Requires:
  56. //
  57. // Returns:
  58. //
  59. // Notes:
  60. //
  61. //
  62. //--------------------------------------------------------------------------
  63. VOID
  64. KdcAtqDgIoCompletion(
  65. IN PVOID Context,
  66. IN DWORD BytesWritten,
  67. IN DWORD CompletionStatus,
  68. IN OVERLAPPED * lpo
  69. )
  70. {
  71. PVOID Buffer;
  72. SOCKADDR * RemoteAddress = NULL;
  73. INT AddressSize;
  74. PATQ_CONTEXT AtqContext = (PATQ_CONTEXT) Context;
  75. SOCKET NewSocket = INVALID_SOCKET;
  76. KERB_MESSAGE_BUFFER InputMessage;
  77. KERB_MESSAGE_BUFFER OutputMessage;
  78. ULONG_PTR KdcContext;
  79. WSABUF SocketBuffer;
  80. PKDC_DATAGRAM_ENDPOINT Endpoint;
  81. TRACE(KDC,KdcAtqDgIoCompletion, DEB_FUNCTION);
  82. if (Context == NULL)
  83. {
  84. return;
  85. }
  86. KdcContext = AtqContextGetInfo(
  87. AtqContext,
  88. ATQ_INFO_COMPLETION_CONTEXT
  89. );
  90. //
  91. // If the context is 1, then this is the completion from a write, so close
  92. // this down.
  93. //
  94. if (KdcContext == 1)
  95. {
  96. lpo = NULL;
  97. }
  98. //
  99. // If a client connects and then disconnects gracefully ,we will get a
  100. // completion with zero bytes and success status.
  101. //
  102. if ((BytesWritten == 0) && (CompletionStatus == NO_ERROR))
  103. {
  104. CompletionStatus = WSAECONNABORTED;
  105. }
  106. if ((CompletionStatus != NO_ERROR) || (lpo == NULL) || !KdcSocketsInitialized)
  107. {
  108. D_DebugLog((DEB_T_SOCK,"IoCompletion: CompletionStatus = 0x%x\n",CompletionStatus));
  109. D_DebugLog((DEB_T_SOCK,"IoCompletion: lpo = %p\n",lpo));
  110. D_DebugLog((DEB_T_SOCK, "Freeing context %p\n",AtqContext));
  111. if (CompletionStatus == ERROR_OPERATION_ABORTED)
  112. {
  113. AtqCloseSocket( AtqContext, TRUE );
  114. AtqFreeContext( (PATQ_CONTEXT) AtqContext, FALSE );
  115. return;
  116. }
  117. else if ( CompletionStatus != ERROR_MORE_DATA )
  118. {
  119. AtqFreeContext( (PATQ_CONTEXT) AtqContext, TRUE );
  120. return;
  121. }
  122. }
  123. //
  124. // Obtain shared access to the global endpoint list
  125. //
  126. RtlAcquireResourceShared( &DatagramEndpointLock , TRUE );
  127. //
  128. // Can not proceed unless there are endpoints registered
  129. //
  130. if ( DatagramEndpointCount == 0 )
  131. {
  132. AtqFreeContext( (PATQ_CONTEXT) AtqContext, TRUE );
  133. goto Cleanup;
  134. }
  135. AtqGetDatagramAddrs(
  136. AtqContext,
  137. &NewSocket,
  138. &Buffer,
  139. (PVOID *) &Endpoint,
  140. &RemoteAddress,
  141. &AddressSize
  142. );
  143. //
  144. // If the remote address is port 88, don't respond, as we don't
  145. // want to be vulnerable to a loopback attack.
  146. //
  147. if ((AddressSize >= sizeof(SOCKADDR_IN) &&
  148. ((((SOCKADDR_IN *) RemoteAddress)->sin_port == KERB_KDC_PORT) ||
  149. (((SOCKADDR_IN *) RemoteAddress)->sin_port == KERB_KPASSWD_PORT))))
  150. {
  151. //
  152. // Just free up the context so it can be reused.
  153. //
  154. AtqFreeContext( (PATQ_CONTEXT) AtqContext, TRUE );
  155. goto Cleanup;
  156. }
  157. //fester
  158. D_DebugLog((DEB_T_SOCK, "Bytes written - %x\n", BytesWritten));
  159. //
  160. // There is a buffer, so use it to do the KDC thang.
  161. //
  162. InputMessage.BufferSize = BytesWritten;
  163. InputMessage.Buffer = (PUCHAR) Buffer;
  164. OutputMessage.Buffer = NULL;
  165. if ( CompletionStatus != ERROR_MORE_DATA )
  166. {
  167. Endpoint->EndpointFunction(
  168. NULL, // no atq context for retries
  169. RemoteAddress,
  170. &Endpoint->LocalAddress,
  171. &InputMessage,
  172. &OutputMessage
  173. );
  174. }
  175. else
  176. {
  177. //
  178. // For now, if client sends us more data over UDP than we can swallow
  179. // (indicated by a completion status of ERROR_MORE_DATA), just send
  180. // a response of "response too big" back to them, which will cause
  181. // the Windows client (and hopefully a future MIT client) to switch
  182. // over to TCP
  183. //
  184. // In a future release, ATQ should be less timid and give us all the
  185. // UDP data that was received, in which case this logic could be pulled
  186. //
  187. KERB_EXT_ERROR ExtendedError = {0,0};
  188. KerbBuildErrorMessageEx(
  189. KRB_ERR_RESPONSE_TOO_BIG,
  190. &ExtendedError,
  191. SecData.KdcDnsRealmName(),
  192. SecData.KdcInternalName(),
  193. NULL,
  194. NULL,
  195. 0,
  196. &OutputMessage.BufferSize,
  197. &OutputMessage.Buffer
  198. );
  199. }
  200. //
  201. // If there is a response, write it back to the sender.
  202. //
  203. if (OutputMessage.Buffer != NULL)
  204. {
  205. DsysAssert(OutputMessage.BufferSize < max( KdcGlobalMaxDatagramReplySize, KDC_MAX_ACCEPT_BUFFER));
  206. RtlCopyMemory(
  207. Buffer,
  208. OutputMessage.Buffer,
  209. OutputMessage.BufferSize
  210. );
  211. KdcFreeEncodedData(OutputMessage.Buffer);
  212. SocketBuffer.buf = (char *) Buffer;
  213. SocketBuffer.len = OutputMessage.BufferSize;
  214. AtqContextSetInfo(
  215. AtqContext,
  216. ATQ_INFO_COMPLETION_CONTEXT,
  217. 1
  218. );
  219. if (!AtqWriteDatagramSocket(
  220. (PATQ_CONTEXT) AtqContext,
  221. &SocketBuffer,
  222. 1, // 1 buffer
  223. NULL // no OVERLAPPED
  224. ))
  225. {
  226. DebugLog((DEB_ERROR,"Datagram write failed for %d bytes: 0x%x\n",OutputMessage.BufferSize,GetLastError()));
  227. AtqCloseSocket( AtqContext, TRUE );
  228. AtqFreeContext( (PATQ_CONTEXT) AtqContext, TRUE );
  229. }
  230. }
  231. else
  232. {
  233. //
  234. // Just free up the context so it can be reused.
  235. //
  236. AtqFreeContext( (PATQ_CONTEXT) AtqContext, TRUE );
  237. }
  238. Cleanup:
  239. RtlReleaseResource( &DatagramEndpointLock );
  240. }
  241. //+-------------------------------------------------------------------------
  242. //
  243. // Function: KdcCreateDgAtqEndpoint
  244. //
  245. // Synopsis: Sets up a datagram endpoint
  246. //
  247. // Effects:
  248. //
  249. // Arguments:
  250. //
  251. // Requires:
  252. //
  253. // Returns:
  254. //
  255. // Notes:
  256. //
  257. //
  258. //--------------------------------------------------------------------------
  259. NTSTATUS
  260. KdcCreateDgAtqEndpoint(
  261. IN USHORT Port,
  262. IN PVOID EndpointContext,
  263. IN ULONG IpAddress,
  264. OUT PVOID * Endpoint
  265. )
  266. {
  267. NTSTATUS Status = STATUS_SUCCESS;
  268. ATQ_ENDPOINT_CONFIGURATION EndpointConfig;
  269. SOCKET EndpointSocket = INVALID_SOCKET;
  270. int RecvBufSize;
  271. //
  272. // Create the endpoint config
  273. //
  274. EndpointConfig.ListenPort = Port;
  275. EndpointConfig.IpAddress = IpAddress;
  276. EndpointConfig.cbAcceptExRecvBuffer = max( KdcGlobalMaxDatagramReplySize, KDC_MAX_ACCEPT_BUFFER);
  277. EndpointConfig.nAcceptExOutstanding = KDC_MAX_ACCEPT_OUTSTANDING;
  278. EndpointConfig.AcceptExTimeout = KDC_ACCEPT_TIMEOUT;
  279. EndpointConfig.pfnConnect = NULL;
  280. EndpointConfig.pfnConnectEx = KdcAtqDgIoCompletion;
  281. EndpointConfig.pfnIoCompletion = KdcAtqDgIoCompletion;
  282. EndpointConfig.fDatagram = TRUE;
  283. EndpointConfig.fLockDownPort = TRUE;
  284. EndpointConfig.fReverseQueuing = FALSE;
  285. EndpointConfig.cbDatagramWSBufSize = 0; // means use the default.
  286. *Endpoint = AtqCreateEndpoint(
  287. &EndpointConfig,
  288. EndpointContext
  289. );
  290. if (*Endpoint == NULL)
  291. {
  292. DebugLog((DEB_ERROR,"Failed to create ATQ endpoint\n"));
  293. Status = STATUS_UNSUCCESSFUL;
  294. goto Cleanup;
  295. }
  296. //
  297. // Get the socket so we can change the recieve buffer size
  298. //
  299. EndpointSocket = (SOCKET) AtqEndpointGetInfo(
  300. *Endpoint,
  301. EndpointInfoListenSocket
  302. );
  303. RecvBufSize = 0x8000; // 32 k buffers
  304. if (setsockopt(
  305. EndpointSocket,
  306. SOL_SOCKET,
  307. SO_RCVBUF,
  308. (const char *) &RecvBufSize,
  309. sizeof(int)
  310. ))
  311. {
  312. DebugLog((DEB_ERROR,"Failed to set recv buf size to 32k: 0x%x, %d\n",
  313. WSAGetLastError(),WSAGetLastError()));
  314. }
  315. //
  316. // Start the endpoint
  317. //
  318. if (!AtqStartEndpoint(*Endpoint))
  319. {
  320. DebugLog((DEB_ERROR, "Failed to add ATQ endpoint\n"));
  321. Status = STATUS_UNSUCCESSFUL;
  322. goto Cleanup;
  323. }
  324. Cleanup:
  325. return(Status);
  326. }
  327. //+-------------------------------------------------------------------------
  328. //
  329. // Function: KdcGetAddressListFromWinsock
  330. //
  331. // Synopsis: gets the list of addresses from a winsock ioctl
  332. //
  333. // Effects:
  334. //
  335. // Arguments:
  336. //
  337. // Requires:
  338. //
  339. // Returns:
  340. //
  341. // Notes:
  342. //
  343. //
  344. //--------------------------------------------------------------------------
  345. NTSTATUS
  346. KdcGetAddressListFromWinsock(
  347. OUT LPSOCKET_ADDRESS_LIST * SocketAddressList
  348. )
  349. {
  350. ULONG BytesReturned = 150;
  351. LPSOCKET_ADDRESS_LIST AddressList = NULL;
  352. INT i,j;
  353. ULONG NetStatus = STATUS_SUCCESS;
  354. for (;;) {
  355. //
  356. // Allocate a buffer that should be big enough.
  357. //
  358. if ( AddressList != NULL ) {
  359. MIDL_user_free( AddressList );
  360. }
  361. AddressList = (LPSOCKET_ADDRESS_LIST) MIDL_user_allocate( BytesReturned );
  362. if ( AddressList == NULL ) {
  363. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  364. goto Cleanup;
  365. }
  366. //
  367. // Get the list of IP addresses
  368. //
  369. NetStatus = WSAIoctl( KdcWinsockPnpSocket,
  370. SIO_ADDRESS_LIST_QUERY,
  371. NULL, // No input buffer
  372. 0, // No input buffer
  373. (PVOID) AddressList,
  374. BytesReturned,
  375. &BytesReturned,
  376. NULL, // No overlapped,
  377. NULL ); // Not async
  378. if ( NetStatus != 0 ) {
  379. NetStatus = WSAGetLastError();
  380. //
  381. // If the buffer isn't big enough, try again.
  382. //
  383. if ( NetStatus == WSAEFAULT ) {
  384. continue;
  385. }
  386. DebugLog((DEB_ERROR,"LdapUdpPnpBind: Cannot WSAIoctl SIO_ADDRESS_LIST_QUERY %ld %ld\n",
  387. NetStatus, BytesReturned));
  388. goto Cleanup;
  389. }
  390. break;
  391. }
  392. //
  393. // Weed out any zero IP addresses and other invalid addresses
  394. //
  395. for ( i = 0, j = 0; i < AddressList->iAddressCount; i++ ) {
  396. PSOCKET_ADDRESS SocketAddress;
  397. //
  398. // Copy this address to the front of the list.
  399. //
  400. AddressList->Address[j] = AddressList->Address[i];
  401. //
  402. // If the address isn't valid,
  403. // skip it.
  404. //
  405. SocketAddress = &AddressList->Address[j];
  406. if ( SocketAddress->iSockaddrLength == 0 ||
  407. SocketAddress->lpSockaddr == NULL ||
  408. SocketAddress->lpSockaddr->sa_family != AF_INET ||
  409. ((PSOCKADDR_IN)(SocketAddress->lpSockaddr))->sin_addr.s_addr == 0 ) {
  410. } else {
  411. //
  412. // Otherwise keep it.
  413. //
  414. j++;
  415. }
  416. }
  417. AddressList->iAddressCount = j;
  418. *SocketAddressList = AddressList;
  419. AddressList = NULL;
  420. Cleanup:
  421. if (AddressList != NULL)
  422. {
  423. MIDL_user_free(AddressList);
  424. }
  425. if (NetStatus != ERROR_SUCCESS)
  426. {
  427. return(STATUS_UNSUCCESSFUL);
  428. }
  429. else
  430. {
  431. return(STATUS_SUCCESS);
  432. }
  433. }
  434. //+-------------------------------------------------------------------------
  435. //
  436. // Function: KdcUpdateAddressesWorker
  437. //
  438. // Synopsis: Updates the IP addresses used for datagram sockest by
  439. // stopping the endpoints and then starting them with the
  440. // new addresses
  441. //
  442. // Effects:
  443. //
  444. // Arguments:
  445. //
  446. // Requires:
  447. //
  448. // Returns:
  449. //
  450. // Notes:
  451. //
  452. //
  453. //--------------------------------------------------------------------------
  454. ULONG
  455. KdcUpdateAddressesWorker(
  456. IN PVOID IgnoredParameter
  457. )
  458. {
  459. ULONG Index;
  460. INT IntIndex;
  461. NTSTATUS Status = STATUS_SUCCESS;
  462. LPSOCKET_ADDRESS_LIST AddressList = NULL;
  463. DWORD NetStatus;
  464. DWORD BytesReturned ;
  465. BOOL DatagramEndpointsLocked = FALSE;
  466. D_DebugLog(( DEB_TRACE, "KdcUpdateAddressesWorker\n" ));
  467. //
  468. // Tell winsock we want address list changes on this socket:
  469. //
  470. if ( KdcWinsockPnpSocket != INVALID_SOCKET )
  471. {
  472. NetStatus = WSAIoctl(
  473. KdcWinsockPnpSocket,
  474. SIO_ADDRESS_LIST_CHANGE,
  475. NULL,
  476. 0,
  477. NULL,
  478. 0,
  479. &BytesReturned,
  480. NULL,
  481. NULL );
  482. if ( NetStatus != 0 )
  483. {
  484. NetStatus = WSAGetLastError();
  485. if ( NetStatus != WSAEWOULDBLOCK )
  486. {
  487. DebugLog((DEB_ERROR,"WSASocket failed with %ld\n", NetStatus ));
  488. Status = STATUS_UNSUCCESSFUL;
  489. goto Cleanup;
  490. }
  491. }
  492. }
  493. //
  494. // Get the list of socket addresses
  495. //
  496. Status = KdcGetAddressListFromWinsock(
  497. &AddressList
  498. );
  499. if ( !NT_SUCCESS( Status ))
  500. {
  501. goto Cleanup;
  502. }
  503. //
  504. // Cleanup any old endpoints
  505. //
  506. if (DatagramEndpoints != NULL)
  507. {
  508. for (Index = 0; Index < DatagramEndpointCount ; Index++ )
  509. {
  510. if (DatagramEndpoints[Index].Endpoint != NULL)
  511. {
  512. //
  513. // Stopping the endpoint prevents future completions
  514. //
  515. while ( FALSE == AtqStopEndpoint( DatagramEndpoints[Index].Endpoint ))
  516. {
  517. Sleep( 5000 );
  518. }
  519. //
  520. // The endpoint won't close until all outstanding operations on it
  521. // have completed
  522. //
  523. while ( FALSE == AtqCloseEndpoint( DatagramEndpoints[Index].Endpoint ))
  524. {
  525. Sleep( 5000 );
  526. }
  527. }
  528. }
  529. }
  530. //
  531. // Must acquire the lock now since we're manipulating global variables
  532. // that this lock protects.
  533. //
  534. RtlAcquireResourceExclusive( &DatagramEndpointLock, TRUE );
  535. DatagramEndpointsLocked = TRUE;
  536. MIDL_user_free(DatagramEndpoints);
  537. DatagramEndpoints = NULL;
  538. DatagramEndpointCount = 0;
  539. //
  540. // Create new endpoints
  541. //
  542. DatagramEndpoints = (PKDC_DATAGRAM_ENDPOINT) MIDL_user_allocate(
  543. sizeof(KDC_DATAGRAM_ENDPOINT) * AddressList->iAddressCount * 2
  544. );
  545. if (DatagramEndpoints == NULL)
  546. {
  547. Status = STATUS_INSUFFICIENT_RESOURCES;
  548. goto Cleanup;
  549. }
  550. RtlZeroMemory(
  551. DatagramEndpoints,
  552. sizeof(KDC_DATAGRAM_ENDPOINT) * AddressList->iAddressCount * 2
  553. );
  554. //
  555. // Create an endpoint for the KDC and for KPASSWD for each transport
  556. //
  557. for (IntIndex = 0; IntIndex < AddressList->iAddressCount ; IntIndex++ )
  558. {
  559. RtlCopyMemory(
  560. &DatagramEndpoints[DatagramEndpointCount].LocalAddress,
  561. AddressList->Address[IntIndex].lpSockaddr,
  562. sizeof(SOCKADDR_IN)
  563. );
  564. DatagramEndpoints[DatagramEndpointCount].EndpointFunction = KdcGetTicket;
  565. Status = KdcCreateDgAtqEndpoint(
  566. KERB_KDC_PORT,
  567. &DatagramEndpoints[DatagramEndpointCount],
  568. ((PSOCKADDR_IN) &DatagramEndpoints[DatagramEndpointCount].LocalAddress)->sin_addr.s_addr,
  569. &DatagramEndpoints[DatagramEndpointCount].Endpoint
  570. );
  571. if (!NT_SUCCESS(Status))
  572. {
  573. goto Cleanup;
  574. }
  575. DatagramEndpointCount++;
  576. //
  577. // Create the KPASSWD endpoint
  578. //
  579. RtlCopyMemory(
  580. &DatagramEndpoints[DatagramEndpointCount].LocalAddress,
  581. AddressList->Address[IntIndex].lpSockaddr,
  582. sizeof(SOCKADDR_IN)
  583. );
  584. DatagramEndpoints[DatagramEndpointCount].EndpointFunction = KdcChangePassword;
  585. Status = KdcCreateDgAtqEndpoint(
  586. KERB_KPASSWD_PORT,
  587. &DatagramEndpoints[DatagramEndpointCount],
  588. ((PSOCKADDR_IN) &DatagramEndpoints[DatagramEndpointCount].LocalAddress)->sin_addr.s_addr,
  589. &DatagramEndpoints[DatagramEndpointCount].Endpoint
  590. );
  591. if (!NT_SUCCESS(Status))
  592. {
  593. goto Cleanup;
  594. }
  595. DatagramEndpointCount++;
  596. }
  597. Cleanup:
  598. if (!NT_SUCCESS(Status))
  599. {
  600. if (DatagramEndpoints != NULL)
  601. {
  602. //
  603. // Allow completion routines to fire while the endpoints are being closed
  604. // by releasing the lock for the duration of the 'stop' operation
  605. //
  606. if ( DatagramEndpointsLocked )
  607. {
  608. RtlReleaseResource( &DatagramEndpointLock );
  609. DatagramEndpointsLocked = FALSE;
  610. }
  611. for (Index = 0; Index < DatagramEndpointCount ; Index++ )
  612. {
  613. if (DatagramEndpoints[Index].Endpoint != NULL)
  614. {
  615. while ( FALSE == AtqStopEndpoint( DatagramEndpoints[Index].Endpoint ))
  616. {
  617. Sleep( 5000 );
  618. }
  619. while ( FALSE == AtqCloseEndpoint( DatagramEndpoints[Index].Endpoint ))
  620. {
  621. Sleep( 5000 );
  622. }
  623. }
  624. }
  625. //
  626. // Must re-acquire the lock now since we're manipulating global variables
  627. // that this lock protects.
  628. //
  629. RtlAcquireResourceExclusive( &DatagramEndpointLock, TRUE );
  630. DatagramEndpointsLocked = TRUE;
  631. MIDL_user_free(DatagramEndpoints);
  632. DatagramEndpoints = NULL;
  633. DatagramEndpointCount = 0;
  634. }
  635. }
  636. if ( DatagramEndpointsLocked )
  637. {
  638. RtlReleaseResource( &DatagramEndpointLock );
  639. }
  640. MIDL_user_free(AddressList);
  641. return((ULONG) Status);
  642. }
  643. //+-------------------------------------------------------------------------
  644. //
  645. // Function: KdcInitializeSockets
  646. //
  647. // Synopsis: Initializes the KDCs socket handling code
  648. //
  649. // Effects:
  650. //
  651. // Arguments: none
  652. //
  653. // Requires:
  654. //
  655. // Returns:
  656. //
  657. // Notes:
  658. //
  659. //
  660. //--------------------------------------------------------------------------
  661. NTSTATUS
  662. KdcInitializeDatagramSockets(
  663. VOID
  664. )
  665. {
  666. NTSTATUS Status = STATUS_SUCCESS;
  667. DWORD NetStatus;
  668. __try
  669. {
  670. RtlInitializeResource(&DatagramEndpointLock);
  671. }
  672. __except( EXCEPTION_EXECUTE_HANDLER )
  673. {
  674. Status = GetExceptionCode();
  675. }
  676. if (!NT_SUCCESS(Status))
  677. {
  678. goto Cleanup;
  679. }
  680. else
  681. {
  682. DatagramEndpointLockInitialized = TRUE;
  683. }
  684. //
  685. // Initialize the asynchronous thread queue.
  686. //
  687. if (!AtqInitialize(0))
  688. {
  689. DebugLog((DEB_ERROR,"Failed to initialize ATQ\n"));
  690. Status = STATUS_UNSUCCESSFUL;
  691. goto Cleanup;
  692. }
  693. //
  694. // Open a socket to get winsock PNP notifications on.
  695. //
  696. KdcWinsockPnpSocket = WSASocket( AF_INET,
  697. SOCK_DGRAM,
  698. 0, // PF_INET,
  699. NULL,
  700. 0,
  701. 0 );
  702. if ( KdcWinsockPnpSocket == INVALID_SOCKET ) {
  703. NetStatus = WSAGetLastError();
  704. DebugLog((DEB_ERROR,"WSASocket failed with %ld\n", NetStatus ));
  705. Status = STATUS_UNSUCCESSFUL;
  706. goto Cleanup;
  707. }
  708. //
  709. // Open an event to wait on.
  710. //
  711. KdcWinsockPnpEvent = CreateEvent(
  712. NULL, // No security ettibutes
  713. FALSE, // Auto reset
  714. FALSE, // Initially not signaled
  715. NULL); // No Name
  716. if ( KdcWinsockPnpEvent == NULL ) {
  717. NetStatus = GetLastError();
  718. DebugLog((DEB_ERROR,"Cannot create Winsock PNP event %ld\n", NetStatus ));
  719. Status = STATUS_UNSUCCESSFUL;
  720. goto Cleanup;
  721. }
  722. //
  723. // Associate the event with new addresses becoming available on the socket.
  724. //
  725. NetStatus = WSAEventSelect( KdcWinsockPnpSocket, KdcWinsockPnpEvent, FD_ADDRESS_LIST_CHANGE );
  726. if ( NetStatus != 0 ) {
  727. NetStatus = WSAGetLastError();
  728. DebugLog((DEB_ERROR,"Can't WSAEventSelect %ld\n", NetStatus ));
  729. Status = STATUS_UNSUCCESSFUL;
  730. goto Cleanup;
  731. }
  732. Status = (NTSTATUS) KdcUpdateAddressesWorker( NULL );
  733. if (!NT_SUCCESS(Status))
  734. {
  735. DebugLog((DEB_ERROR,"Failed to udpate datagram addresses\n"));
  736. goto Cleanup;
  737. }
  738. D_DebugLog((DEB_TRACE, "Successfully started ATQ listening\n"));
  739. if ( KdcPnpEventChangeHandle == NULL ) {
  740. KdcPnpEventChangeHandle = LsaIRegisterNotification(
  741. KdcUpdateAddressesWorker,
  742. NULL, // no parameter,
  743. NOTIFIER_TYPE_HANDLE_WAIT,
  744. 0, // no class
  745. 0, // no flags
  746. 0, // no interval
  747. KdcWinsockPnpEvent
  748. );
  749. if (KdcPnpEventChangeHandle == NULL)
  750. {
  751. DebugLog((DEB_ERROR,"Failed to register KDC pnp event change handle.\n"));
  752. }
  753. }
  754. Cleanup:
  755. if (!NT_SUCCESS(Status))
  756. {
  757. KdcShutdownSockets();
  758. }
  759. return(Status);
  760. }
  761. //+-------------------------------------------------------------------------
  762. //
  763. // Function: KdcShutdownDatagramSockets
  764. //
  765. // Synopsis: Shuts down the KDC socket handling code
  766. //
  767. // Effects:
  768. //
  769. // Arguments:
  770. //
  771. // Requires:
  772. //
  773. // Returns:
  774. //
  775. // Notes:
  776. //
  777. //
  778. //--------------------------------------------------------------------------
  779. NTSTATUS
  780. KdcShutdownDatagramSockets(
  781. VOID
  782. )
  783. {
  784. ULONG Index;
  785. TRACE(KDC,KdcShutdownSockets, DEB_FUNCTION);
  786. if ( KdcPnpEventChangeHandle != NULL )
  787. {
  788. LsaICancelNotification(KdcPnpEventChangeHandle);
  789. KdcPnpEventChangeHandle = NULL;
  790. }
  791. if ( KdcWinsockPnpEvent != NULL )
  792. {
  793. CloseHandle(KdcWinsockPnpEvent);
  794. KdcWinsockPnpEvent = NULL;
  795. }
  796. if ( KdcWinsockPnpSocket != INVALID_SOCKET ) {
  797. closesocket(KdcWinsockPnpSocket);
  798. KdcWinsockPnpSocket = INVALID_SOCKET;
  799. }
  800. //
  801. // Go through the list of contexts and close them all.
  802. //
  803. if (DatagramEndpoints != NULL)
  804. {
  805. for (Index = 0; Index < DatagramEndpointCount ; Index++ )
  806. {
  807. if (DatagramEndpoints[Index].Endpoint != NULL)
  808. {
  809. while ( FALSE == AtqStopEndpoint( DatagramEndpoints[Index].Endpoint ))
  810. {
  811. Sleep( 5000 );
  812. }
  813. while ( FALSE == AtqCloseEndpoint( DatagramEndpoints[Index].Endpoint ))
  814. {
  815. Sleep( 5000 );
  816. }
  817. }
  818. }
  819. RtlAcquireResourceExclusive( &DatagramEndpointLock, TRUE );
  820. MIDL_user_free(DatagramEndpoints);
  821. DatagramEndpoints = NULL;
  822. DatagramEndpointCount = 0;
  823. RtlReleaseResource( &DatagramEndpointLock );
  824. }
  825. if (!AtqTerminate())
  826. {
  827. DebugLog((DEB_ERROR, "Failed to terminate ATQ!!!\n"));
  828. }
  829. if ( DatagramEndpointLockInitialized )
  830. {
  831. RtlDeleteResource(&DatagramEndpointLock);
  832. DatagramEndpointLockInitialized = FALSE;
  833. }
  834. return(STATUS_SUCCESS);
  835. }