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.

895 lines
22 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_CRITICAL_SECTION DatagramEndpointLock;
  41. SOCKET KdcWinsockPnpSocket = INVALID_SOCKET;
  42. HANDLE KdcWinsockPnpEvent = NULL;
  43. HANDLE KdcPnpEventChangeHandle = NULL;
  44. //+-------------------------------------------------------------------------
  45. //
  46. // Function: KdcAtqDgIoCompletion
  47. //
  48. // Synopsis:
  49. //
  50. // Effects:
  51. //
  52. // Arguments:
  53. //
  54. // Requires:
  55. //
  56. // Returns:
  57. //
  58. // Notes:
  59. //
  60. //
  61. //--------------------------------------------------------------------------
  62. VOID
  63. KdcAtqDgIoCompletion(
  64. IN PVOID Context,
  65. IN DWORD BytesWritten,
  66. IN DWORD CompletionStatus,
  67. IN OVERLAPPED * lpo
  68. )
  69. {
  70. PVOID Buffer;
  71. SOCKADDR * RemoteAddress = NULL;
  72. INT AddressSize;
  73. PATQ_CONTEXT AtqContext = (PATQ_CONTEXT) Context;
  74. SOCKET NewSocket = INVALID_SOCKET;
  75. KERB_MESSAGE_BUFFER InputMessage;
  76. KERB_MESSAGE_BUFFER OutputMessage;
  77. ULONG_PTR KdcContext;
  78. WSABUF SocketBuffer;
  79. PKDC_DATAGRAM_ENDPOINT Endpoint;
  80. TRACE(KDC,KdcAtqDgIoCompletion, DEB_FUNCTION);
  81. if (Context == NULL)
  82. {
  83. return;
  84. }
  85. KdcContext = AtqContextGetInfo(
  86. AtqContext,
  87. ATQ_INFO_COMPLETION_CONTEXT
  88. );
  89. //
  90. // If the context is 1, then this is the completion from a write, so close
  91. // this down.
  92. //
  93. if (KdcContext == 1)
  94. {
  95. lpo = NULL;
  96. }
  97. //
  98. // If a client connects and then disconnects gracefully ,we will get a
  99. // completion with zero bytes and success status.
  100. //
  101. if ((BytesWritten == 0) && (CompletionStatus == NO_ERROR))
  102. {
  103. CompletionStatus = WSAECONNABORTED;
  104. }
  105. if ((CompletionStatus != NO_ERROR) || (lpo == NULL) || !KdcSocketsInitialized)
  106. {
  107. D_DebugLog((DEB_T_SOCK,"IoCompletion: CompletionStatus = 0x%x\n",CompletionStatus));
  108. D_DebugLog((DEB_T_SOCK,"IoCompletion: lpo = %p\n",lpo));
  109. D_DebugLog((DEB_T_SOCK, "Freeing context %p\n",AtqContext));
  110. if (CompletionStatus == ERROR_OPERATION_ABORTED)
  111. {
  112. AtqCloseSocket( AtqContext, TRUE );
  113. AtqFreeContext( (PATQ_CONTEXT) AtqContext, FALSE );
  114. }
  115. else
  116. {
  117. AtqFreeContext( (PATQ_CONTEXT) AtqContext, TRUE );
  118. }
  119. return;
  120. }
  121. AtqGetDatagramAddrs(
  122. AtqContext,
  123. &NewSocket,
  124. &Buffer,
  125. (PVOID *) &Endpoint,
  126. &RemoteAddress,
  127. &AddressSize
  128. );
  129. //
  130. // If the remote address is port 88, don't respond, as we don't
  131. // want to be vulnerable to a loopback attack.
  132. //
  133. if ((AddressSize >= sizeof(SOCKADDR_IN) &&
  134. ((((SOCKADDR_IN *) RemoteAddress)->sin_port == KERB_KDC_PORT) ||
  135. (((SOCKADDR_IN *) RemoteAddress)->sin_port == KERB_KPASSWD_PORT))))
  136. {
  137. //
  138. // Just free up the context so it can be reused.
  139. //
  140. AtqFreeContext( (PATQ_CONTEXT) AtqContext, TRUE );
  141. return;
  142. }
  143. //fester
  144. D_DebugLog((DEB_T_SOCK, "Bytes written - %x\n", BytesWritten));
  145. //
  146. // There is a buffer, so use it to do the KDC thang.
  147. //
  148. InputMessage.BufferSize = BytesWritten;
  149. InputMessage.Buffer = (PUCHAR) Buffer;
  150. OutputMessage.Buffer = NULL;
  151. //
  152. // This assert is here to help locate bug 154963.
  153. // If it fires, contact Todds
  154. //
  155. DsysAssert(DatagramEndpointCount != 0);
  156. Endpoint->EndpointFunction(
  157. NULL, // no atq context for retries
  158. RemoteAddress,
  159. &Endpoint->LocalAddress,
  160. &InputMessage,
  161. &OutputMessage
  162. );
  163. //
  164. // If there is a response, write it back to the sender.
  165. //
  166. if (OutputMessage.Buffer != NULL)
  167. {
  168. DsysAssert(OutputMessage.BufferSize < KDC_MAX_ACCEPT_BUFFER);
  169. RtlCopyMemory(
  170. Buffer,
  171. OutputMessage.Buffer,
  172. OutputMessage.BufferSize
  173. );
  174. KdcFreeEncodedData(OutputMessage.Buffer);
  175. SocketBuffer.buf = (char *) Buffer;
  176. SocketBuffer.len = OutputMessage.BufferSize;
  177. AtqContextSetInfo(
  178. AtqContext,
  179. ATQ_INFO_COMPLETION_CONTEXT,
  180. 1
  181. );
  182. AtqWriteDatagramSocket(
  183. (PATQ_CONTEXT) AtqContext,
  184. &SocketBuffer,
  185. 1, // 1 buffer
  186. NULL // no OVERLAPPED
  187. );
  188. }
  189. else
  190. {
  191. //
  192. // Just free up the context so it can be reused.
  193. //
  194. AtqFreeContext( (PATQ_CONTEXT) AtqContext, TRUE );
  195. }
  196. }
  197. //+-------------------------------------------------------------------------
  198. //
  199. // Function: KdcCreateDgAtqEndpoint
  200. //
  201. // Synopsis: Sets up a datagram endpoint
  202. //
  203. // Effects:
  204. //
  205. // Arguments:
  206. //
  207. // Requires:
  208. //
  209. // Returns:
  210. //
  211. // Notes:
  212. //
  213. //
  214. //--------------------------------------------------------------------------
  215. NTSTATUS
  216. KdcCreateDgAtqEndpoint(
  217. IN USHORT Port,
  218. IN PVOID EndpointContext,
  219. IN ULONG IpAddress,
  220. OUT PVOID * Endpoint
  221. )
  222. {
  223. NTSTATUS Status = STATUS_SUCCESS;
  224. ATQ_ENDPOINT_CONFIGURATION EndpointConfig;
  225. SOCKET EndpointSocket = INVALID_SOCKET;
  226. int RecvBufSize;
  227. //
  228. // Create the endpoint config
  229. //
  230. EndpointConfig.ListenPort = Port;
  231. EndpointConfig.IpAddress = IpAddress;
  232. EndpointConfig.cbAcceptExRecvBuffer = KDC_MAX_ACCEPT_BUFFER;
  233. EndpointConfig.nAcceptExOutstanding = KDC_MAX_ACCEPT_OUTSTANDING;
  234. EndpointConfig.AcceptExTimeout = KDC_ACCEPT_TIMEOUT;
  235. EndpointConfig.pfnConnect = NULL;
  236. EndpointConfig.pfnConnectEx = KdcAtqDgIoCompletion;
  237. EndpointConfig.pfnIoCompletion = KdcAtqDgIoCompletion;
  238. EndpointConfig.fDatagram = TRUE;
  239. EndpointConfig.fLockDownPort = TRUE;
  240. EndpointConfig.fReverseQueuing = FALSE;
  241. EndpointConfig.cbDatagramWSBufSize = 0; // means use the default.
  242. *Endpoint = AtqCreateEndpoint(
  243. &EndpointConfig,
  244. EndpointContext
  245. );
  246. if (*Endpoint == NULL)
  247. {
  248. DebugLog((DEB_ERROR,"Failed to create ATQ endpoint\n"));
  249. Status = STATUS_UNSUCCESSFUL;
  250. goto Cleanup;
  251. }
  252. //
  253. // Get the socket so we can change the recieve buffer size
  254. //
  255. EndpointSocket = (SOCKET) AtqEndpointGetInfo(
  256. *Endpoint,
  257. EndpointInfoListenSocket
  258. );
  259. RecvBufSize = 0x8000; // 32 k buffers
  260. if (setsockopt(
  261. EndpointSocket,
  262. SOL_SOCKET,
  263. SO_RCVBUF,
  264. (const char *) &RecvBufSize,
  265. sizeof(int)
  266. ))
  267. {
  268. DebugLog((DEB_ERROR,"Failed to set recv buf size to 32k: 0x%x, %d\n",
  269. WSAGetLastError(),WSAGetLastError()));
  270. }
  271. //
  272. // Start the endpoint
  273. //
  274. if (!AtqStartEndpoint(*Endpoint))
  275. {
  276. DebugLog((DEB_ERROR, "Failed to add ATQ endpoint\n"));
  277. Status = STATUS_UNSUCCESSFUL;
  278. goto Cleanup;
  279. }
  280. Cleanup:
  281. return(Status);
  282. }
  283. //+-------------------------------------------------------------------------
  284. //
  285. // Function: KdcGetAddressListFromWinsock
  286. //
  287. // Synopsis: gets the list of addresses from a winsock ioctl
  288. //
  289. // Effects:
  290. //
  291. // Arguments:
  292. //
  293. // Requires:
  294. //
  295. // Returns:
  296. //
  297. // Notes:
  298. //
  299. //
  300. //--------------------------------------------------------------------------
  301. NTSTATUS
  302. KdcGetAddressListFromWinsock(
  303. OUT LPSOCKET_ADDRESS_LIST * SocketAddressList
  304. )
  305. {
  306. ULONG BytesReturned = 150;
  307. LPSOCKET_ADDRESS_LIST AddressList = NULL;
  308. INT i,j;
  309. ULONG NetStatus = STATUS_SUCCESS;
  310. for (;;) {
  311. //
  312. // Allocate a buffer that should be big enough.
  313. //
  314. if ( AddressList != NULL ) {
  315. MIDL_user_free( AddressList );
  316. }
  317. AddressList = (LPSOCKET_ADDRESS_LIST) MIDL_user_allocate( BytesReturned );
  318. if ( AddressList == NULL ) {
  319. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  320. goto Cleanup;
  321. }
  322. //
  323. // Get the list of IP addresses
  324. //
  325. NetStatus = WSAIoctl( KdcWinsockPnpSocket,
  326. SIO_ADDRESS_LIST_QUERY,
  327. NULL, // No input buffer
  328. 0, // No input buffer
  329. (PVOID) AddressList,
  330. BytesReturned,
  331. &BytesReturned,
  332. NULL, // No overlapped,
  333. NULL ); // Not async
  334. if ( NetStatus != 0 ) {
  335. NetStatus = WSAGetLastError();
  336. //
  337. // If the buffer isn't big enough, try again.
  338. //
  339. if ( NetStatus == WSAEFAULT ) {
  340. continue;
  341. }
  342. DebugLog((DEB_ERROR,"LdapUdpPnpBind: Cannot WSAIoctl SIO_ADDRESS_LIST_QUERY %ld %ld\n",
  343. NetStatus, BytesReturned));
  344. goto Cleanup;
  345. }
  346. break;
  347. }
  348. //
  349. // Weed out any zero IP addresses and other invalid addresses
  350. //
  351. for ( i = 0, j = 0; i < AddressList->iAddressCount; i++ ) {
  352. PSOCKET_ADDRESS SocketAddress;
  353. //
  354. // Copy this address to the front of the list.
  355. //
  356. AddressList->Address[j] = AddressList->Address[i];
  357. //
  358. // If the address isn't valid,
  359. // skip it.
  360. //
  361. SocketAddress = &AddressList->Address[j];
  362. if ( SocketAddress->iSockaddrLength == 0 ||
  363. SocketAddress->lpSockaddr == NULL ||
  364. SocketAddress->lpSockaddr->sa_family != AF_INET ||
  365. ((PSOCKADDR_IN)(SocketAddress->lpSockaddr))->sin_addr.s_addr == 0 ) {
  366. } else {
  367. //
  368. // Otherwise keep it.
  369. //
  370. j++;
  371. }
  372. }
  373. AddressList->iAddressCount = j;
  374. *SocketAddressList = AddressList;
  375. AddressList = NULL;
  376. Cleanup:
  377. if (AddressList != NULL)
  378. {
  379. MIDL_user_free(AddressList);
  380. }
  381. if (NetStatus != ERROR_SUCCESS)
  382. {
  383. return(STATUS_UNSUCCESSFUL);
  384. }
  385. else
  386. {
  387. return(STATUS_SUCCESS);
  388. }
  389. }
  390. //+-------------------------------------------------------------------------
  391. //
  392. // Function: KdcUpdateAddressesWorker
  393. //
  394. // Synopsis: Updates the IP addresses used for datagram sockest by
  395. // stopping the endpoints and then starting them with the
  396. // new addresses
  397. //
  398. // Effects:
  399. //
  400. // Arguments:
  401. //
  402. // Requires:
  403. //
  404. // Returns:
  405. //
  406. // Notes:
  407. //
  408. //
  409. //--------------------------------------------------------------------------
  410. ULONG
  411. KdcUpdateAddressesWorker(
  412. IN PVOID IgnoredParameter
  413. )
  414. {
  415. ULONG Index;
  416. INT IntIndex;
  417. ULONG EndpointIndex = 0;
  418. NTSTATUS Status = STATUS_SUCCESS;
  419. LPSOCKET_ADDRESS_LIST AddressList = NULL;
  420. DWORD NetStatus;
  421. DWORD BytesReturned ;
  422. RtlEnterCriticalSection(&DatagramEndpointLock);
  423. D_DebugLog(( DEB_TRACE, "KdcUpdateAddressesWorker\n" ));
  424. //
  425. // Tell winsock we want address list changes on this socket:
  426. //
  427. if ( KdcWinsockPnpSocket != INVALID_SOCKET )
  428. {
  429. NetStatus = WSAIoctl(
  430. KdcWinsockPnpSocket,
  431. SIO_ADDRESS_LIST_CHANGE,
  432. NULL,
  433. 0,
  434. NULL,
  435. 0,
  436. &BytesReturned,
  437. NULL,
  438. NULL );
  439. if ( NetStatus != 0 )
  440. {
  441. NetStatus = WSAGetLastError();
  442. if ( NetStatus != WSAEWOULDBLOCK )
  443. {
  444. DebugLog((DEB_ERROR,"WSASocket failed with %ld\n", NetStatus ));
  445. Status = STATUS_UNSUCCESSFUL;
  446. goto Cleanup;
  447. }
  448. }
  449. }
  450. //
  451. // Cleanup any old endpoints
  452. //
  453. if (DatagramEndpoints != NULL)
  454. {
  455. for (Index = 0; Index < DatagramEndpointCount ; Index++ )
  456. {
  457. if (DatagramEndpoints[Index].Endpoint != NULL)
  458. {
  459. (VOID) AtqStopEndpoint( DatagramEndpoints[Index].Endpoint );
  460. (VOID) AtqCloseEndpoint( DatagramEndpoints[Index].Endpoint );
  461. }
  462. }
  463. MIDL_user_free(DatagramEndpoints);
  464. DatagramEndpoints = NULL;
  465. DatagramEndpointCount = 0;
  466. }
  467. //
  468. // Get the list of socket addresses
  469. //
  470. Status = KdcGetAddressListFromWinsock(
  471. &AddressList
  472. );
  473. if (!NT_SUCCESS(Status))
  474. {
  475. goto Cleanup;
  476. }
  477. //
  478. // Create new endpoints
  479. //
  480. DatagramEndpoints = (PKDC_DATAGRAM_ENDPOINT) MIDL_user_allocate(
  481. sizeof(KDC_DATAGRAM_ENDPOINT) * AddressList->iAddressCount * 2
  482. );
  483. if (DatagramEndpoints == NULL)
  484. {
  485. Status = STATUS_INSUFFICIENT_RESOURCES;
  486. goto Cleanup;
  487. }
  488. RtlZeroMemory(
  489. DatagramEndpoints,
  490. sizeof(KDC_DATAGRAM_ENDPOINT) * AddressList->iAddressCount * 2
  491. );
  492. //
  493. // Create an endpoint for the KDC and for KPASSWD for each transport
  494. //
  495. for (IntIndex = 0; IntIndex < AddressList->iAddressCount ; IntIndex++ )
  496. {
  497. RtlCopyMemory(
  498. &DatagramEndpoints[EndpointIndex].LocalAddress,
  499. AddressList->Address[IntIndex].lpSockaddr,
  500. sizeof(SOCKADDR_IN)
  501. );
  502. DatagramEndpoints[EndpointIndex].EndpointFunction = KdcGetTicket;
  503. Status = KdcCreateDgAtqEndpoint(
  504. KERB_KDC_PORT,
  505. &DatagramEndpoints[EndpointIndex],
  506. ((PSOCKADDR_IN) &DatagramEndpoints[EndpointIndex].LocalAddress)->sin_addr.s_addr,
  507. &DatagramEndpoints[EndpointIndex].Endpoint
  508. );
  509. if (!NT_SUCCESS(Status))
  510. {
  511. goto Cleanup;
  512. }
  513. EndpointIndex++;
  514. //
  515. // Create the KPASSWD endpoint
  516. //
  517. RtlCopyMemory(
  518. &DatagramEndpoints[EndpointIndex].LocalAddress,
  519. AddressList->Address[IntIndex].lpSockaddr,
  520. sizeof(SOCKADDR_IN)
  521. );
  522. DatagramEndpoints[EndpointIndex].EndpointFunction = KdcChangePassword;
  523. Status = KdcCreateDgAtqEndpoint(
  524. KERB_KPASSWD_PORT,
  525. &DatagramEndpoints[EndpointIndex],
  526. ((PSOCKADDR_IN) &DatagramEndpoints[EndpointIndex].LocalAddress)->sin_addr.s_addr,
  527. &DatagramEndpoints[EndpointIndex].Endpoint
  528. );
  529. if (!NT_SUCCESS(Status))
  530. {
  531. goto Cleanup;
  532. }
  533. EndpointIndex++;
  534. }
  535. DatagramEndpointCount = EndpointIndex;
  536. Cleanup:
  537. if (!NT_SUCCESS(Status))
  538. {
  539. if (DatagramEndpoints != NULL)
  540. {
  541. for (Index = 0; Index < EndpointIndex ; Index++ )
  542. {
  543. if (DatagramEndpoints[Index].Endpoint != NULL)
  544. {
  545. (VOID) AtqStopEndpoint( DatagramEndpoints[Index].Endpoint );
  546. (VOID) AtqCloseEndpoint( DatagramEndpoints[Index].Endpoint );
  547. }
  548. }
  549. MIDL_user_free(DatagramEndpoints);
  550. DatagramEndpoints = NULL;
  551. DatagramEndpointCount = 0;
  552. }
  553. }
  554. if (AddressList != NULL)
  555. {
  556. MIDL_user_free(AddressList);
  557. }
  558. RtlLeaveCriticalSection(&DatagramEndpointLock);
  559. return((ULONG) Status);
  560. }
  561. //+-------------------------------------------------------------------------
  562. //
  563. // Function: KdcInitializeSockets
  564. //
  565. // Synopsis: Initializes the KDCs socket handling code
  566. //
  567. // Effects:
  568. //
  569. // Arguments: none
  570. //
  571. // Requires:
  572. //
  573. // Returns:
  574. //
  575. // Notes:
  576. //
  577. //
  578. //--------------------------------------------------------------------------
  579. NTSTATUS
  580. KdcInitializeDatagramSockets(
  581. VOID
  582. )
  583. {
  584. NTSTATUS Status = STATUS_SUCCESS;
  585. DWORD NetStatus;
  586. PATQ_CONTEXT EndpointContext = NULL;
  587. DWORD BytesReturned ;
  588. TRACE(KDC,KdcDatagramInitializeSockets, DEB_FUNCTION);
  589. Status = RtlInitializeCriticalSection(&DatagramEndpointLock);
  590. if (!NT_SUCCESS(Status))
  591. {
  592. goto Cleanup;
  593. }
  594. //
  595. // Initialize the asynchronous thread queue.
  596. //
  597. if (!AtqInitialize(0))
  598. {
  599. DebugLog((DEB_ERROR,"Failed to initialize ATQ\n"));
  600. Status = STATUS_UNSUCCESSFUL;
  601. goto Cleanup;
  602. }
  603. //
  604. // Open a socket to get winsock PNP notifications on.
  605. //
  606. KdcWinsockPnpSocket = WSASocket( AF_INET,
  607. SOCK_DGRAM,
  608. 0, // PF_INET,
  609. NULL,
  610. 0,
  611. 0 );
  612. if ( KdcWinsockPnpSocket == INVALID_SOCKET ) {
  613. NetStatus = WSAGetLastError();
  614. DebugLog((DEB_ERROR,"WSASocket failed with %ld\n", NetStatus ));
  615. Status = STATUS_UNSUCCESSFUL;
  616. goto Cleanup;
  617. }
  618. //
  619. // Open an event to wait on.
  620. //
  621. KdcWinsockPnpEvent = CreateEvent(
  622. NULL, // No security ettibutes
  623. FALSE, // Auto reset
  624. FALSE, // Initially not signaled
  625. NULL); // No Name
  626. if ( KdcWinsockPnpEvent == NULL ) {
  627. NetStatus = GetLastError();
  628. DebugLog((DEB_ERROR,"Cannot create Winsock PNP event %ld\n", NetStatus ));
  629. Status = STATUS_UNSUCCESSFUL;
  630. goto Cleanup;
  631. }
  632. //
  633. // Associate the event with new addresses becoming available on the socket.
  634. //
  635. NetStatus = WSAEventSelect( KdcWinsockPnpSocket, KdcWinsockPnpEvent, FD_ADDRESS_LIST_CHANGE );
  636. if ( NetStatus != 0 ) {
  637. NetStatus = WSAGetLastError();
  638. DebugLog((DEB_ERROR,"Can't WSAEventSelect %ld\n", NetStatus ));
  639. Status = STATUS_UNSUCCESSFUL;
  640. goto Cleanup;
  641. }
  642. Status = (NTSTATUS) KdcUpdateAddressesWorker( NULL );
  643. if (!NT_SUCCESS(Status))
  644. {
  645. DebugLog((DEB_ERROR,"Failed to udpate datagram addresses\n"));
  646. goto Cleanup;
  647. }
  648. D_DebugLog((DEB_TRACE, "Successfully started ATQ listening\n"));
  649. if ( KdcPnpEventChangeHandle == NULL ) {
  650. KdcPnpEventChangeHandle = LsaIRegisterNotification(
  651. KdcUpdateAddressesWorker,
  652. NULL, // no parameter,
  653. NOTIFIER_TYPE_HANDLE_WAIT,
  654. 0, // no class
  655. 0, // no flags
  656. 0, // no interval
  657. KdcWinsockPnpEvent
  658. );
  659. if (KdcPnpEventChangeHandle == NULL)
  660. {
  661. DebugLog((DEB_ERROR,"Failed to register KDC pnp event change handle.\n"));
  662. }
  663. }
  664. Cleanup:
  665. if (!NT_SUCCESS(Status))
  666. {
  667. KdcShutdownSockets();
  668. }
  669. return(Status);
  670. }
  671. //+-------------------------------------------------------------------------
  672. //
  673. // Function: KdcShutdownDatagramSockets
  674. //
  675. // Synopsis: Shuts down the KDC socket handling code
  676. //
  677. // Effects:
  678. //
  679. // Arguments:
  680. //
  681. // Requires:
  682. //
  683. // Returns:
  684. //
  685. // Notes:
  686. //
  687. //
  688. //--------------------------------------------------------------------------
  689. NTSTATUS
  690. KdcShutdownDatagramSockets(
  691. VOID
  692. )
  693. {
  694. PKDC_ATQ_CONTEXT Context;
  695. PLIST_ENTRY ListEntry;
  696. ULONG Index;
  697. TRACE(KDC,KdcShutdownSockets, DEB_FUNCTION);
  698. RtlEnterCriticalSection(&DatagramEndpointLock);
  699. if ( KdcPnpEventChangeHandle != NULL ) {
  700. LsaICancelNotification(KdcPnpEventChangeHandle);
  701. KdcPnpEventChangeHandle = NULL;
  702. }
  703. if ( KdcWinsockPnpEvent != NULL ) {
  704. CloseHandle(KdcWinsockPnpEvent);
  705. KdcWinsockPnpEvent = NULL;
  706. }
  707. if ( KdcWinsockPnpSocket != INVALID_SOCKET ) {
  708. closesocket(KdcWinsockPnpSocket);
  709. KdcWinsockPnpSocket = INVALID_SOCKET;
  710. }
  711. //
  712. // Go through the list of contexts and close them all.
  713. //
  714. if (DatagramEndpoints != NULL)
  715. {
  716. for (Index = 0; Index < DatagramEndpointCount ; Index++ )
  717. {
  718. if (DatagramEndpoints[Index].Endpoint != NULL)
  719. {
  720. (VOID) AtqStopEndpoint( DatagramEndpoints[Index].Endpoint );
  721. (VOID) AtqCloseEndpoint( DatagramEndpoints[Index].Endpoint );
  722. }
  723. }
  724. MIDL_user_free(DatagramEndpoints);
  725. DatagramEndpoints = NULL;
  726. DatagramEndpointCount = 0;
  727. }
  728. if (!AtqTerminate())
  729. {
  730. DebugLog((DEB_ERROR, "Failed to terminate ATQ!!!\n"));
  731. }
  732. RtlLeaveCriticalSection(&DatagramEndpointLock);
  733. RtlDeleteCriticalSection(&DatagramEndpointLock);
  734. return(STATUS_SUCCESS);
  735. }