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.

1739 lines
40 KiB

  1. /*++
  2. Copyright (c) 1992,1993 Microsoft Corporation
  3. Module Name:
  4. lmhsvc.c
  5. Abstract:
  6. This module implements the LmHosts Service, which is part of the LmSvc
  7. process.
  8. One purpose of the LmHosts Service is to send down a NBT_RESYNC
  9. ioctl command to netbt.sys, after the LanmanWorkstation service has been
  10. started. To accomplish this, the NT Registry is primed so that the
  11. LmHosts service is dependent on the LanmanWorkStation service.
  12. This service also handle name query requests from netbt destined for
  13. DNS by way of gethostbyname.
  14. Author:
  15. Jim Stewart November 18 22, 1993
  16. Revision History:
  17. ArnoldM 14-May-1996 Use winsock2 name resolution
  18. instead of gethostbyname
  19. Notes:
  20. --*/
  21. //
  22. // Standard NT Headers
  23. //
  24. #include <nt.h>
  25. #include <ntrtl.h>
  26. #include <nturtl.h>
  27. //
  28. // C Runtime Library Headers
  29. //
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <assert.h>
  34. //
  35. // Transport Specific Header Files
  36. //
  37. #include <nbtioctl.h>
  38. //
  39. // Standard Windows Headers
  40. //
  41. #include <windows.h>
  42. #include <tdi.h>
  43. //
  44. // LAN Manager Headers
  45. //
  46. #include <lm.h>
  47. #include <netlib.h>
  48. #include <netevent.h>
  49. //
  50. // Sockets Headers
  51. //
  52. #include <winsock2.h>
  53. #include <svcguid.h>
  54. #include <wsahelp.h>
  55. //
  56. // Private Definitions
  57. //
  58. #define NBT_DEVICE "\\Device\\Streams\\Nbt"
  59. #define WSA_QUERY_BUFFER_LENGTH (3*1024)
  60. BYTE pWSABuffer[WSA_QUERY_BUFFER_LENGTH];
  61. //
  62. // We currently have two threads; one for DNS names, the other for checking IP addresses
  63. // for reachability.
  64. //
  65. #define NUM_THREADS 2
  66. //
  67. // Function Prototypes
  68. //
  69. VOID
  70. announceStatus (
  71. IN LPSERVICE_STATUS svcstatus
  72. );
  73. VOID
  74. lmhostsHandler (
  75. IN DWORD opcode
  76. );
  77. VOID
  78. lmhostsSvc (
  79. IN DWORD argc,
  80. IN LPTSTR *argv
  81. );
  82. NTSTATUS
  83. prepareData (
  84. IN DWORD argc,
  85. IN LPTSTR argv[]
  86. );
  87. LONG
  88. DeviceIoCtrl(
  89. IN HANDLE fd,
  90. IN PVOID ReturnBuffer,
  91. IN ULONG BufferSize,
  92. IN ULONG Ioctl,
  93. IN ULONG i
  94. );
  95. LONG
  96. PrimeCacheNbt(
  97. OUT PHANDLE pHandle,
  98. IN ULONG index
  99. );
  100. NTSTATUS
  101. Resync(
  102. IN HANDLE fd
  103. );
  104. LONG
  105. ReadRegistry(
  106. IN WCHAR *pDeviceName[]
  107. );
  108. NTSTATUS
  109. OpenNbt(
  110. IN WCHAR *path[],
  111. OUT PHANDLE pHandle
  112. );
  113. LONG
  114. GetHostName(
  115. IN HANDLE fd,
  116. IN tIPADDR_BUFFER_DNS *pIpAddrBuffer
  117. );
  118. LONG
  119. PostForGetHostByName(
  120. IN HANDLE fd
  121. );
  122. VOID
  123. CheckIPAddrWorkerRtn(
  124. IN LPVOID lpParam
  125. );
  126. LONG
  127. CheckIPAddresses(
  128. IN tIPADDR_BUFFER_DNS *pIpAddrBuffer,
  129. IN ULONG *IpAddr,
  130. IN BOOLEAN fOrdered
  131. );
  132. //
  133. // Global Variables
  134. //
  135. PUCHAR EventSource = "LmHostsService";
  136. HANDLE Poison[NUM_THREADS]; // set to kill this service
  137. HANDLE NbtEvent[NUM_THREADS]; // set when Nbt returns the Irp
  138. SERVICE_STATUS_HANDLE SvcHandle;
  139. SERVICE_STATUS SvcStatus;
  140. BOOLEAN Trace = FALSE; // TRUE for debugging
  141. tIPADDR_BUFFER_DNS *pIpAddrBuffer;
  142. tIPADDR_BUFFER_DNS *pIpAddrBufferChkIP;
  143. BOOLEAN SocketsUp;
  144. #if DBG
  145. #define DBG_PRINT DbgPrint
  146. #else
  147. #define DBG_PRINT
  148. #endif // DBG
  149. //------------------------------------------------------------------------
  150. VOID
  151. ServiceMain (
  152. IN DWORD argc,
  153. IN LPTSTR *argv
  154. )
  155. /*++
  156. Routine Description:
  157. This is the SERVICE_MAIN_FUNCTION.
  158. Arguments:
  159. argc, argv
  160. Return Value:
  161. None.
  162. --*/
  163. {
  164. DWORD status;
  165. HANDLE hNbt;
  166. HANDLE EventList[2];
  167. ULONG EventCount;
  168. LONG err;
  169. WSADATA WsaData;
  170. LONG Value;
  171. HANDLE hThread;
  172. ULONG Tid;
  173. ULONG *pIndex;
  174. LARGE_INTEGER Timeout = RtlEnlargedIntegerMultiply (-10 * 60, 1000 * 1000 * 10); // 10 minutes
  175. if (STATUS_SUCCESS != (prepareData(argc, argv)))
  176. {
  177. ExitThread(NO_ERROR);
  178. }
  179. pIpAddrBuffer = NULL;
  180. pIpAddrBufferChkIP = NULL;
  181. if (Trace)
  182. {
  183. DbgPrint("LMHSVC: calling RegisterServiceCtrlHandler()\n");
  184. }
  185. SvcHandle = RegisterServiceCtrlHandler(SERVICE_LMHOSTS, // ServiceName
  186. lmhostsHandler); // HandlerProc
  187. if (SvcHandle == (SERVICE_STATUS_HANDLE) 0)
  188. {
  189. DBG_PRINT ("LMHSVC: RegisterServiceCtrlHandler failed %d\n", GetLastError());
  190. ExitThread(NO_ERROR);
  191. return;
  192. }
  193. SvcStatus.dwServiceType = SERVICE_WIN32;
  194. SvcStatus.dwCurrentState = SERVICE_START_PENDING;
  195. SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  196. SvcStatus.dwWin32ExitCode = 0;
  197. SvcStatus.dwServiceSpecificExitCode = 0;
  198. SvcStatus.dwCheckPoint = 0;
  199. SvcStatus.dwWaitHint = 20000; // 20 seconds
  200. SET_SERVICE_EXITCODE(NO_ERROR, // SomeApiStatus
  201. SvcStatus.dwWin32ExitCode, // Win32CodeVariable
  202. SvcStatus.dwServiceSpecificExitCode); // NetCodeVariable
  203. announceStatus(&SvcStatus);
  204. SvcStatus.dwCurrentState = SERVICE_RUNNING;
  205. SvcStatus.dwCheckPoint = 0;
  206. SvcStatus.dwWaitHint = 0;
  207. announceStatus(&SvcStatus);
  208. //
  209. // startup the sockets interface
  210. //
  211. err = WSAStartup( 0x0101, &WsaData );
  212. if ( err == SOCKET_ERROR )
  213. {
  214. //s_perror("nbtstat: WSAStartup:", GetLastError());
  215. #if 0
  216. NetdLogEventA(
  217. EventSource, // EventSource
  218. EVENT_NBTSVC_LMHOST_SYNC_FAIL, // MessageId
  219. EVENTLOG_WARNING_TYPE, // EventType
  220. 0, // NumberofSubStrings
  221. NULL); // SubStrings
  222. #endif
  223. SocketsUp = FALSE;
  224. }
  225. else
  226. {
  227. SocketsUp = TRUE;
  228. }
  229. if ((pIndex = LocalAlloc(LMEM_FIXED, sizeof(ULONG))) == NULL)
  230. {
  231. DBG_PRINT ("LMHSVC: malloc of index failed %d\n", GetLastError());
  232. ExitThread(NO_ERROR);
  233. return;
  234. }
  235. if (Trace)
  236. {
  237. DbgPrint("LMHSVC: CreateThread attempting...\n");
  238. }
  239. *pIndex = 1;
  240. hThread = CreateThread (NULL, // lpThreadAttributes
  241. 0, // dwStackSize
  242. (LPTHREAD_START_ROUTINE) CheckIPAddrWorkerRtn, // lpStartAddress
  243. &pIndex, // lpParameter
  244. 0, // dwCreationFlags
  245. &Tid); // lpThreadId
  246. if (hThread == NULL)
  247. {
  248. DBG_PRINT ("LMHSVC: CreateThread failed %d\n", GetLastError());
  249. ExitThread(NO_ERROR);
  250. return;
  251. }
  252. //
  253. // ignore the return code from resyncNbt().
  254. //
  255. // In most cases (no domains spanning an ip router), it is not a
  256. // catastrophe if nbt.sys couldn't successfully process the NBT_RESYNC
  257. // ioctl command. Since I'm ignoring the return, I announce I'm running
  258. // before I call it to allow other dependent services to start.
  259. //
  260. //
  261. status = PrimeCacheNbt(&hNbt, 0);
  262. if (Trace)
  263. {
  264. DbgPrint("LMHSVC: Thread 0, hNbt %lx\n", hNbt);
  265. }
  266. if (hNbt != (HANDLE)-1)
  267. {
  268. status = PostForGetHostByName(hNbt);
  269. if (status == NO_ERROR)
  270. {
  271. EventCount = 2;
  272. }
  273. else
  274. {
  275. if (Trace)
  276. {
  277. DbgPrint("Lmhsvc: Error posting Irp for get host by name\n");
  278. }
  279. EventCount = 1;
  280. }
  281. }
  282. else
  283. {
  284. EventCount = 1;
  285. }
  286. //
  287. // "A SERVICE_MAIN_FUNCTION does not return until the service is ready
  288. // to terminate."
  289. //
  290. // (ref: api32wh.hlp, SERVICE_MAIN_FUNCTION)
  291. //
  292. //
  293. assert(Poison[0]);
  294. EventList[0] = Poison[0];
  295. EventList[1] = NbtEvent[0];
  296. while (TRUE)
  297. {
  298. status = NtWaitForMultipleObjects(EventCount,
  299. EventList,
  300. WaitAny, // wait for any event
  301. FALSE,
  302. (EventCount == 1)? &Timeout: NULL);
  303. if (status == WAIT_TIMEOUT)
  304. {
  305. if (hNbt == (HANDLE)-1)
  306. {
  307. PrimeCacheNbt(&hNbt, 0);
  308. if (hNbt == (HANDLE)-1)
  309. {
  310. continue; // to wait
  311. }
  312. }
  313. status = PostForGetHostByName(hNbt); // try again
  314. if (status == NO_ERROR)
  315. {
  316. EventCount = 2;
  317. }
  318. }
  319. else if (status == 1)
  320. {
  321. if (Trace)
  322. {
  323. DbgPrint("LMHSVC: Doing GetHostName\n");
  324. }
  325. // the irp used for gethostby name has returned
  326. status = GetHostName(hNbt,pIpAddrBuffer);
  327. //
  328. // disable the get host by name stuff if we have an error
  329. // posting a buffer to the transport
  330. //
  331. if (status != NO_ERROR)
  332. {
  333. EventCount = 1;
  334. }
  335. }
  336. else
  337. {
  338. // it must have been a the Poison event signalling the end of the
  339. // the service, so exit after getting the Irp back from the
  340. // transport. This system will look after canceling the IO and
  341. // getting the Irp back.
  342. NtClose(Poison[0]);
  343. NtClose(NbtEvent[0]);
  344. NtClose(hNbt);
  345. break;
  346. }
  347. }
  348. if (pIpAddrBuffer)
  349. {
  350. LocalFree (pIpAddrBuffer);
  351. }
  352. if (pIpAddrBufferChkIP)
  353. {
  354. LocalFree (pIpAddrBufferChkIP);
  355. }
  356. if (Trace)
  357. {
  358. DBG_PRINT ("LMHSVC: [LMSVCS_ENTRY_POINT] Exiting now!\n");
  359. }
  360. ExitThread(NO_ERROR);
  361. return;
  362. } // lmhostsSvc
  363. //------------------------------------------------------------------------
  364. VOID
  365. announceStatus (
  366. IN LPSERVICE_STATUS status
  367. )
  368. /*++
  369. Routine Description:
  370. This procedure announces the service's status to the service controller.
  371. Arguments:
  372. None.
  373. Return Value:
  374. None.
  375. --*/
  376. {
  377. if (!SvcHandle) {
  378. return;
  379. }
  380. #if DBG
  381. if (Trace)
  382. {
  383. DbgPrint( "LMHSVC: announceStatus:\n"
  384. " CurrentState %lx\n"
  385. " ControlsAccepted %lx\n"
  386. " Win32ExitCode %lu\n"
  387. " ServiceSpecificExitCode %lu\n"
  388. " CheckPoint %lu\n"
  389. " WaitHint %lu\n",
  390. status->dwCurrentState,
  391. status->dwControlsAccepted,
  392. status->dwWin32ExitCode,
  393. status->dwServiceSpecificExitCode,
  394. status->dwCheckPoint,
  395. status->dwWaitHint);
  396. }
  397. #endif // DBG
  398. SetServiceStatus(SvcHandle, status);
  399. } // announceStatus
  400. //------------------------------------------------------------------------
  401. VOID
  402. lmhostsHandler (
  403. IN DWORD controlcode
  404. )
  405. /*++
  406. Routine Description:
  407. This is the HANDLER_FUNCTION of the LmHosts service.
  408. It only responds to two Service Controller directives: to stop, and
  409. to announce the current status of the service.
  410. Arguments:
  411. opcode
  412. Return Value:
  413. None.
  414. --*/
  415. {
  416. BOOL retval;
  417. ULONG i;
  418. switch (controlcode) {
  419. case SERVICE_CONTROL_STOP:
  420. for (i=0; i<NUM_THREADS; i++) {
  421. assert(Poison[i]);
  422. retval = PulseEvent(Poison[i]);
  423. assert(retval);
  424. }
  425. SvcStatus.dwCurrentState = SERVICE_STOPPED;
  426. SvcStatus.dwCheckPoint = 0;
  427. SvcStatus.dwWaitHint = 0;
  428. /* fall through */
  429. case SERVICE_CONTROL_INTERROGATE:
  430. announceStatus(&SvcStatus);
  431. break;
  432. case SERVICE_CONTROL_CONTINUE:
  433. case SERVICE_CONTROL_PAUSE:
  434. case SERVICE_CONTROL_SHUTDOWN:
  435. default:
  436. assert(0);
  437. break;
  438. }
  439. } // lmhostsHandler
  440. //------------------------------------------------------------------------
  441. NTSTATUS
  442. prepareData (
  443. IN DWORD argc,
  444. IN LPTSTR argv[]
  445. )
  446. /*++
  447. Routine Description:
  448. Arguments:
  449. argc, argv
  450. Return Value:
  451. None.
  452. --*/
  453. {
  454. DWORD i;
  455. DWORD status;
  456. for (i=0; i<NUM_THREADS; i++)
  457. {
  458. Poison[i] = CreateEvent(NULL, // security attributes
  459. FALSE, // ManualReset
  460. FALSE, // InitialState
  461. NULL); // EventName
  462. if (!Poison[i])
  463. {
  464. DBG_PRINT ("LMHSVC: couldn't CreateEvent()\n");
  465. return (STATUS_INSUFFICIENT_RESOURCES);
  466. }
  467. NbtEvent[i] = CreateEvent(NULL, // security attributes
  468. FALSE, // ManualReset
  469. FALSE, // InitialState
  470. NULL); // EventName
  471. if (!NbtEvent[i])
  472. {
  473. DBG_PRINT ("LMHSVC: couldn't CreateEvent()\n");
  474. return (STATUS_INSUFFICIENT_RESOURCES);
  475. }
  476. }
  477. return STATUS_SUCCESS;
  478. } // prepareData
  479. //------------------------------------------------------------------------
  480. LONG
  481. DeviceIoCtrl(
  482. IN HANDLE fd,
  483. IN PVOID ReturnBuffer,
  484. IN ULONG BufferSize,
  485. IN ULONG Ioctl,
  486. IN ULONG index
  487. )
  488. /*++
  489. Routine Description:
  490. This procedure performs an ioctl(I_STR) on a stream.
  491. Arguments:
  492. fd - NT file handle
  493. iocp - pointer to a strioctl structure
  494. Return Value:
  495. 0 if successful, -1 otherwise.
  496. --*/
  497. {
  498. NTSTATUS status;
  499. int retval;
  500. ULONG QueryType;
  501. TDI_REQUEST_QUERY_INFORMATION QueryInfo;
  502. IO_STATUS_BLOCK iosb;
  503. PVOID pInput;
  504. ULONG SizeInput;
  505. pInput = NULL;
  506. SizeInput = 0;
  507. status = NtDeviceIoControlFile(
  508. fd, // Handle
  509. NbtEvent[index], // Event
  510. NULL, // ApcRoutine
  511. NULL, // ApcContext
  512. &iosb, // IoStatusBlock
  513. Ioctl, // IoControlCode
  514. pInput, // InputBuffer
  515. SizeInput, // InputBufferSize
  516. (PVOID) ReturnBuffer, // OutputBuffer
  517. BufferSize); // OutputBufferSize
  518. if (status == STATUS_PENDING)
  519. {
  520. // do not wait for this to complete since it could complete
  521. // at any time in the future.
  522. //
  523. if ((Ioctl == IOCTL_NETBT_DNS_NAME_RESOLVE) ||
  524. (Ioctl == IOCTL_NETBT_CHECK_IP_ADDR))
  525. {
  526. return(NO_ERROR);
  527. }
  528. else
  529. {
  530. status = NtWaitForSingleObject(
  531. fd, // Handle
  532. TRUE, // Alertable
  533. NULL); // Timeout
  534. }
  535. }
  536. if (NT_SUCCESS(status))
  537. {
  538. return(NO_ERROR);
  539. }
  540. else
  541. return(ERROR_FILE_NOT_FOUND);
  542. }
  543. //------------------------------------------------------------------------
  544. NTSTATUS
  545. Resync(
  546. IN HANDLE fd
  547. )
  548. /*++
  549. Routine Description:
  550. This procedure tells NBT to purge all names from its remote hash
  551. table cache.
  552. Arguments:
  553. Return Value:
  554. 0 if successful, -1 otherwise.
  555. --*/
  556. {
  557. NTSTATUS status;
  558. CHAR Buffer;
  559. status = DeviceIoCtrl(fd,
  560. &Buffer,
  561. 1,
  562. IOCTL_NETBT_PURGE_CACHE,
  563. 0); // pass 0 since we know that we are called only for the first thread
  564. return(status);
  565. }
  566. #if 0
  567. //------------------------------------------------------------------------
  568. PCHAR
  569. GetHost(ULONG addr,BOOLEAN Convert)
  570. {
  571. static char string[32];
  572. union inet
  573. {
  574. unsigned long l;
  575. char c[4];
  576. }in;
  577. struct hostent *hp;
  578. int i;
  579. if (addr == 0L)
  580. return(" ");
  581. /*
  582. * Look up the address in the in-core host table.
  583. * If it's there, that'll do the trick.
  584. */
  585. if (Convert)
  586. {
  587. if ( hp = gethostbyname((char *) &addr,sizeof(addr),2) )
  588. {
  589. return( hp->h_name );
  590. }
  591. }
  592. in.l = addr;
  593. sprintf(string, "%u.%u.%u.%u", (unsigned char) in.c[0],
  594. (unsigned char) in.c[1], (unsigned char) in.c[2],
  595. (unsigned char) in.c[3]);
  596. return(string);
  597. }
  598. #endif
  599. //------------------------------------------------------------------------
  600. NTSTATUS
  601. PrimeCacheNbt(
  602. OUT PHANDLE pHandle,
  603. IN ULONG index
  604. )
  605. /*++
  606. Routine Description:
  607. This procedure sends a NBT_PURGE ioctl command down to netbt.sys.
  608. Arguments:
  609. None.
  610. Return Value:
  611. 0 if successful, an error code otherwise.
  612. --*/
  613. {
  614. LONG status;
  615. HANDLE Handle;
  616. int i;
  617. //
  618. // In PnP, the Netbt device is not created until the first IP address has
  619. // appeared on that adapter. We need to open all available devices until
  620. // an open succeeds.
  621. //
  622. WCHAR *DeviceName[NBT_MAXIMUM_BINDINGS];
  623. UCHAR stringbuf[24];
  624. UCHAR *subStrings[1];
  625. *pHandle = (HANDLE)-1;
  626. for (i=0; i<NBT_MAXIMUM_BINDINGS; i++)
  627. {
  628. DeviceName[i] = NULL;
  629. }
  630. #ifdef USE_REGISTRY
  631. status = ReadRegistry(DeviceName);
  632. if (status == NO_ERROR)
  633. {
  634. status = OpenNbt(DeviceName,&Handle);
  635. #else
  636. {
  637. PWCHAR ExportDevice[ ] = { L"\\Device\\NetBt_Wins_Export", 0 };
  638. status = OpenNbt(ExportDevice,&Handle);
  639. #endif
  640. if (status == NO_ERROR)
  641. {
  642. //
  643. // Resync only once...
  644. //
  645. if (index == 0) {
  646. Resync(Handle);
  647. }
  648. *pHandle = Handle;
  649. }
  650. }
  651. for (i=0; i<NBT_MAXIMUM_BINDINGS; i++)
  652. {
  653. if (DeviceName[i])
  654. {
  655. free (DeviceName[i]);
  656. }
  657. else
  658. {
  659. break;
  660. }
  661. }
  662. if (status != NO_ERROR)
  663. {
  664. sprintf(stringbuf, "%lu", status);
  665. subStrings[0] = stringbuf;
  666. #if 0
  667. NetdLogEventA(
  668. EventSource, // EventSource
  669. EVENT_NBTSVC_LMHOST_SYNC_FAIL, // MessageId
  670. EVENTLOG_WARNING_TYPE, // EventType
  671. 1, // NumberofSubStrings
  672. (UCHAR **) subStrings); // SubStrings
  673. #endif
  674. }
  675. return(status);
  676. }
  677. //------------------------------------------------------------------------
  678. LONG
  679. ReadRegistry(
  680. IN WCHAR *pDeviceName[]
  681. )
  682. /*++
  683. Routine Description:
  684. This procedure reads the registry to get the name of NBT to bind to.
  685. That name is stored in the Linkage/Exports section under the Netbt key.
  686. Arguments:
  687. Return Value:
  688. 0 if successful, -1 otherwise.
  689. --*/
  690. {
  691. PWCHAR SubKeyLinkage=L"system\\currentcontrolset\\services\\netbt\\linkage";
  692. HKEY Key;
  693. PWCHAR Linkage=L"Export";
  694. LONG Type;
  695. UCHAR *pBuffer;
  696. LONG status;
  697. LONG status2;
  698. ULONG size = 512;
  699. pBuffer = malloc(size);
  700. if (!pBuffer)
  701. {
  702. return (STATUS_INSUFFICIENT_RESOURCES);
  703. }
  704. status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  705. SubKeyLinkage,
  706. 0,
  707. KEY_READ,
  708. &Key);
  709. if (status == ERROR_SUCCESS)
  710. {
  711. // now read the linkage values
  712. while (pBuffer && ((status = RegQueryValueEx( Key,
  713. Linkage,
  714. NULL,
  715. &Type,
  716. pBuffer,
  717. &size)) == ERROR_MORE_DATA))
  718. {
  719. // Get a buffer that is big enough.
  720. size += 512;
  721. pBuffer = realloc( pBuffer, size );
  722. }
  723. if (status == ERROR_SUCCESS)
  724. {
  725. PUCHAR curPtr=pBuffer;
  726. LONG index=0;
  727. //
  728. // Copy over all the export keys
  729. //
  730. while((*curPtr) && (index < NBT_MAXIMUM_BINDINGS))
  731. {
  732. if (!(pDeviceName[index] = malloc (sizeof(WCHAR) * (wcslen((PWCHAR)curPtr) + 1))))
  733. {
  734. break;
  735. }
  736. wcscpy(pDeviceName[index],(PWCHAR)curPtr);
  737. ++index;
  738. curPtr += sizeof(WCHAR) * (wcslen((PWCHAR)curPtr) + 1);
  739. }
  740. }
  741. status2 = RegCloseKey(Key);
  742. }
  743. if (pBuffer)
  744. {
  745. free (pBuffer);
  746. }
  747. return(status);
  748. }
  749. //------------------------------------------------------------------------
  750. NTSTATUS
  751. OpenNbt(
  752. IN WCHAR *path[],
  753. OUT PHANDLE pHandle
  754. )
  755. /*++
  756. Routine Description:
  757. This function opens a stream.
  758. Arguments:
  759. path - path to the STREAMS driver
  760. oflag - currently ignored. In the future, O_NONBLOCK will be
  761. relevant.
  762. ignored - not used
  763. Return Value:
  764. An NT handle for the stream, or INVALID_HANDLE_VALUE if unsuccessful.
  765. --*/
  766. {
  767. HANDLE StreamHandle;
  768. OBJECT_ATTRIBUTES ObjectAttributes;
  769. IO_STATUS_BLOCK IoStatusBlock;
  770. STRING name_string;
  771. UNICODE_STRING uc_name_string;
  772. NTSTATUS status;
  773. LONG index=0;
  774. while ((path[index]) && (index < NBT_MAXIMUM_BINDINGS))
  775. {
  776. RtlInitUnicodeString(&uc_name_string,path[index]);
  777. InitializeObjectAttributes(
  778. &ObjectAttributes,
  779. &uc_name_string,
  780. OBJ_CASE_INSENSITIVE,
  781. (HANDLE) NULL,
  782. (PSECURITY_DESCRIPTOR) NULL
  783. );
  784. status =
  785. NtCreateFile(
  786. &StreamHandle,
  787. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  788. &ObjectAttributes,
  789. &IoStatusBlock,
  790. NULL,
  791. FILE_ATTRIBUTE_NORMAL,
  792. FILE_SHARE_READ | FILE_SHARE_WRITE,
  793. FILE_OPEN_IF,
  794. 0,
  795. NULL,
  796. 0);
  797. if (NT_SUCCESS(status))
  798. {
  799. *pHandle = StreamHandle;
  800. return(NO_ERROR);
  801. }
  802. ++index;
  803. }
  804. return(ERROR_FILE_NOT_FOUND);
  805. }
  806. //------------------------------------------------------------------------
  807. LONG
  808. PostForGetHostByName(
  809. IN HANDLE fd
  810. )
  811. /*++
  812. Routine Description:
  813. This procedure passes a buffer down to Netbt for it to return when it
  814. wants a name resolved via DNS.
  815. Arguments:
  816. Return Value:
  817. 0 if successful, -1 otherwise.
  818. --*/
  819. {
  820. LONG status = ERROR_FILE_NOT_FOUND;
  821. CHAR Buffer;
  822. if (!pIpAddrBuffer)
  823. {
  824. if (!(pIpAddrBuffer = LocalAlloc(LMEM_FIXED,sizeof(tIPADDR_BUFFER_DNS))))
  825. {
  826. DBG_PRINT ("lmhsvc: failed to send irp due to error = %x\n",status);
  827. return(ERROR_NOT_ENOUGH_MEMORY);
  828. }
  829. pIpAddrBuffer->Resolved = FALSE;
  830. pIpAddrBuffer->IpAddrsList[0] = 0; // for DBG
  831. }
  832. status = DeviceIoCtrl (fd,
  833. pIpAddrBuffer,
  834. sizeof(tIPADDR_BUFFER_DNS),
  835. IOCTL_NETBT_DNS_NAME_RESOLVE,
  836. 0); // hard coded thread Index
  837. return(status);
  838. }
  839. LONG
  840. PostForCheckIPAddr(
  841. IN HANDLE fd
  842. )
  843. /*++
  844. Routine Description:
  845. This procedure passes a buffer down to Netbt for it to return when it
  846. wants a name resolved via DNS.
  847. Arguments:
  848. Return Value:
  849. 0 if successful, -1 otherwise.
  850. --*/
  851. {
  852. LONG status = ERROR_FILE_NOT_FOUND;
  853. CHAR Buffer;
  854. if (!pIpAddrBufferChkIP)
  855. {
  856. if (!(pIpAddrBufferChkIP = LocalAlloc(LMEM_FIXED,sizeof(tIPADDR_BUFFER_DNS))))
  857. {
  858. DBG_PRINT ("lmhsvc: failed to send irp due to error = %x\n",status);
  859. return(ERROR_NOT_ENOUGH_MEMORY);
  860. }
  861. pIpAddrBufferChkIP->Resolved = FALSE;
  862. pIpAddrBufferChkIP->IpAddrsList[0] = 0; // for DBG
  863. }
  864. status = DeviceIoCtrl (fd,
  865. pIpAddrBufferChkIP,
  866. sizeof(tIPADDR_BUFFER_DNS),
  867. IOCTL_NETBT_CHECK_IP_ADDR,
  868. 1); // hard coded thread Index
  869. if (Trace)
  870. {
  871. DbgPrint("LMHSVC: Entered PostForCheckIPAddr. status: %lx\n", status);
  872. }
  873. return(status);
  874. }
  875. GUID HostnameGuid = SVCID_INET_HOSTADDRBYNAME;
  876. VOID
  877. GetHostNameCopyBack(
  878. tIPADDR_BUFFER_DNS *pIpAddrBuffer,
  879. PWSAQUERYSETW pwsaq
  880. )
  881. {
  882. //
  883. // success, fetch the CSADDR structure
  884. //
  885. PCSADDR_INFO pcsadr;
  886. ULONG GoodAddr;
  887. NTSTATUS Status;
  888. int i = 0;
  889. int imax = min(MAX_IPADDRS_PER_HOST, pwsaq->dwNumberOfCsAddrs);
  890. pcsadr = pwsaq->lpcsaBuffer;
  891. if (pwsaq->lpszServiceInstanceName) {
  892. wcsncpy(pIpAddrBuffer->pwName, pwsaq->lpszServiceInstanceName, DNS_NAME_BUFFER_LENGTH);
  893. pIpAddrBuffer->pwName[DNS_NAME_BUFFER_LENGTH-1] = 0;
  894. pIpAddrBuffer->NameLen = wcslen(pIpAddrBuffer->pwName) * sizeof(WCHAR);
  895. if (Trace) {
  896. DbgPrint("Lmhsvc: Resolved name = \"%ws\"\n", pIpAddrBuffer->pwName);
  897. }
  898. }
  899. if (pIpAddrBuffer->Resolved) {
  900. /* In this case, we have been called before. No need to copy the IPs back again. */
  901. /* But we do need to copy the name back since it is the alias name that KsecDD requires */
  902. return;
  903. }
  904. for(i=0; i<imax; i++, pcsadr++)
  905. {
  906. PSOCKADDR_IN sockaddr;
  907. sockaddr = (PSOCKADDR_IN)pcsadr->RemoteAddr.lpSockaddr;
  908. pIpAddrBuffer->IpAddrsList[i] = htonl( sockaddr->sin_addr.s_addr);
  909. if (Trace)
  910. {
  911. DbgPrint("LmhSvc: Dns IpAddrsList[%d/%d] =%x\n",
  912. (i+1),imax,pIpAddrBuffer->IpAddrsList[i]);
  913. }
  914. }
  915. pIpAddrBuffer->IpAddrsList[i] = 0;
  916. //
  917. // Check the IP addr list.
  918. //
  919. Status = CheckIPAddresses(pIpAddrBuffer, &GoodAddr, FALSE);
  920. if (Status == NO_ERROR)
  921. {
  922. pIpAddrBuffer->Resolved = TRUE;
  923. pIpAddrBuffer->IpAddrsList[0] = htonl(GoodAddr);
  924. pIpAddrBuffer->IpAddrsList[1] = 0;
  925. if (Trace)
  926. {
  927. DbgPrint("LmhSvc: SUCCESS -- Dns address = <%x>\n", pIpAddrBuffer->IpAddrsList[0]);
  928. }
  929. }
  930. else
  931. {
  932. pIpAddrBuffer->IpAddrsList[0] = 0;
  933. if (Trace)
  934. {
  935. DbgPrint("LmhSvc: CheckIPAddresses returned <%x>\n", Status);
  936. }
  937. }
  938. }
  939. //------------------------------------------------------------------------
  940. LONG
  941. GetHostName(
  942. IN HANDLE fd,
  943. IN tIPADDR_BUFFER_DNS *pIpAddrBuffer
  944. )
  945. /*++
  946. Routine Description:
  947. This procedure attempts to resolve a name using the Resolver through
  948. the Sockets interface to DNS.
  949. Arguments:
  950. Return Value:
  951. 0 if successful, -1 otherwise.
  952. --*/
  953. {
  954. LONG status;
  955. ULONG NameLen;
  956. ULONG IpAddr;
  957. PWSAQUERYSETW pwsaq = (PWSAQUERYSETW) pWSABuffer;
  958. INT err;
  959. HANDLE hRnR;
  960. PWSTR szHostnameW;
  961. BYTE *pAllocatedBuffer = NULL;
  962. DWORD dwLength;
  963. pIpAddrBuffer->Resolved = FALSE;
  964. // Hostname is encoded with OEMCP, so we convert from OEMCP->Unicode
  965. if (pIpAddrBuffer->bUnicode) {
  966. NameLen = pIpAddrBuffer->NameLen;
  967. ASSERT((NameLen % sizeof(WCHAR)) == 0);
  968. NameLen /= sizeof(WCHAR);
  969. } else {
  970. WCHAR uncName[DNS_NAME_BUFFER_LENGTH];
  971. ASSERT(pIpAddrBuffer->NameLen < DNS_NAME_BUFFER_LENGTH);
  972. pIpAddrBuffer->pName[pIpAddrBuffer->NameLen] = 0;
  973. MultiByteToWideChar (CP_OEMCP, 0, pIpAddrBuffer->pName, -1, uncName, sizeof(uncName)/sizeof(WCHAR));
  974. NameLen = wcslen(uncName);
  975. memcpy (pIpAddrBuffer->pwName, uncName, NameLen * sizeof(WCHAR));
  976. pIpAddrBuffer->pwName[NameLen] = 0;
  977. }
  978. szHostnameW = pIpAddrBuffer->pwName;
  979. // truncate spaces from the end for netbios names
  980. //
  981. if (NameLen < NETBIOS_NAMESIZE)
  982. {
  983. //
  984. // Start from the end and find the first non-space character
  985. //
  986. NameLen = NETBIOS_NAMESIZE-1;
  987. while ((NameLen) && (szHostnameW[NameLen-1] == 0x20))
  988. {
  989. NameLen--;
  990. }
  991. szHostnameW[NameLen] = '\0';
  992. }
  993. if (!NameLen || !SocketsUp) {
  994. if (Trace) {
  995. DbgPrint("Lmhsvc: Failed to Resolve name, NameLen=<%d>\n", NameLen);
  996. }
  997. goto label_exit;
  998. }
  999. //
  1000. // do a lookup using RNR
  1001. //
  1002. if (Trace) {
  1003. DbgPrint("Lmhsvc: Resolving name = \"%ws\", NameLen=<%d>\n", szHostnameW, NameLen);
  1004. }
  1005. RtlZeroMemory(pwsaq, sizeof(*pwsaq));
  1006. pwsaq->dwSize = sizeof(*pwsaq);
  1007. pwsaq->lpszServiceInstanceName = szHostnameW;
  1008. pwsaq->lpServiceClassId = &HostnameGuid;
  1009. pwsaq->dwNameSpace = NS_DNS;
  1010. err = WSALookupServiceBeginW (pwsaq, LUP_RETURN_NAME| LUP_RETURN_ADDR| LUP_RETURN_ALIASES, &hRnR);
  1011. if(err != NO_ERROR) {
  1012. if (Trace) {
  1013. DbgPrint("LmhSvc: WSALookupServiceBeginA returned <%x>, Error=<%d>\n", err, GetLastError());
  1014. }
  1015. goto label_exit;
  1016. }
  1017. //
  1018. // The query was accepted, so execute it via the Next call.
  1019. //
  1020. dwLength = WSA_QUERY_BUFFER_LENGTH;
  1021. err = WSALookupServiceNextW (hRnR, 0, &dwLength, pwsaq);
  1022. if (err != NO_ERROR)
  1023. {
  1024. err = GetLastError();
  1025. } else if (pwsaq->dwNumberOfCsAddrs) {
  1026. GetHostNameCopyBack(pIpAddrBuffer, pwsaq);
  1027. /* check if there is any alias available */
  1028. err = WSALookupServiceNextW (hRnR, 0, &dwLength, pwsaq);
  1029. if (err != NO_ERROR) {
  1030. err = GetLastError();
  1031. if (err != WSAEFAULT) {
  1032. err = NO_ERROR; // Ignore this error
  1033. }
  1034. } else if (pwsaq->dwOutputFlags & RESULT_IS_ALIAS) {
  1035. GetHostNameCopyBack(pIpAddrBuffer, pwsaq);
  1036. }
  1037. }
  1038. WSALookupServiceEnd (hRnR);
  1039. if ((WSAEFAULT == err) &&
  1040. (pAllocatedBuffer = malloc(2*dwLength)))
  1041. {
  1042. if (Trace)
  1043. {
  1044. DbgPrint("\tLmhsvc: WSALookupServiceNextW ==> WSAEFAULT: Retrying, BufferLength=<%d>-><2*%d> ...\n",
  1045. WSA_QUERY_BUFFER_LENGTH, dwLength);
  1046. }
  1047. dwLength *= 2;
  1048. pwsaq = (PWSAQUERYSETW) pAllocatedBuffer;
  1049. RtlZeroMemory(pwsaq, sizeof(*pwsaq));
  1050. pwsaq->dwSize = sizeof(*pwsaq);
  1051. pwsaq->lpszServiceInstanceName = szHostnameW;
  1052. pwsaq->lpServiceClassId = &HostnameGuid;
  1053. pwsaq->dwNameSpace = NS_DNS;
  1054. err = WSALookupServiceBeginW(pwsaq, LUP_RETURN_NAME| LUP_RETURN_ADDR| LUP_RETURN_ALIASES, &hRnR);
  1055. if(err == NO_ERROR)
  1056. {
  1057. err = WSALookupServiceNextW (hRnR, 0, &dwLength, pwsaq);
  1058. if (err == NO_ERROR && pwsaq->dwNumberOfCsAddrs) {
  1059. GetHostNameCopyBack(pIpAddrBuffer, pwsaq);
  1060. if (WSALookupServiceNextW (hRnR, 0, &dwLength, pwsaq) == NO_ERROR) {
  1061. if (pwsaq->dwOutputFlags & RESULT_IS_ALIAS) {
  1062. GetHostNameCopyBack(pIpAddrBuffer, pwsaq);
  1063. }
  1064. }
  1065. }
  1066. WSALookupServiceEnd (hRnR);
  1067. }
  1068. }
  1069. if (err != NO_ERROR)
  1070. {
  1071. if (Trace)
  1072. {
  1073. DbgPrint("LmhSvc: WSALookupServiceNextW returned <%x>, NumAddrs=<%d>, Error=<%d>, dwLength=<%d>\n",
  1074. err, pwsaq->dwNumberOfCsAddrs, GetLastError(), dwLength);
  1075. }
  1076. }
  1077. label_exit:
  1078. if (pAllocatedBuffer) {
  1079. free(pAllocatedBuffer);
  1080. }
  1081. status = PostForGetHostByName(fd);
  1082. return(status);
  1083. }
  1084. #include <ipexport.h>
  1085. #include <icmpapi.h>
  1086. #define DEFAULT_BUFFER_SIZE (0x2000 - 8)
  1087. #define DEFAULT_SEND_SIZE 32
  1088. #define DEFAULT_COUNT 2
  1089. #define DEFAULT_TTL 32
  1090. #define DEFAULT_TOS 0
  1091. #define DEFAULT_TIMEOUT 2000L // default timeout set to 2 secs.
  1092. LONG
  1093. CheckIPAddresses(
  1094. IN tIPADDR_BUFFER_DNS *pIpAddrBuffer,
  1095. IN ULONG *IpAddr,
  1096. IN BOOLEAN fOrdered
  1097. )
  1098. /*++
  1099. Routine Description:
  1100. This function checks a list of IP addrs for reachability by pinging each in turn
  1101. until a successful one is found. This function assumes that the list of addresses
  1102. is terminated by a 0 address.
  1103. Arguments:
  1104. Return Value:
  1105. 0 if successful, -1 otherwise.
  1106. --*/
  1107. {
  1108. ULONG i;
  1109. ULONG *pIpAddrs;
  1110. HANDLE IcmpHandle;
  1111. PUCHAR pSendBuffer;
  1112. PUCHAR pRcvBuffer;
  1113. ULONG address = 0;
  1114. ULONG result;
  1115. ULONG status;
  1116. ULONG numberOfReplies;
  1117. IP_OPTION_INFORMATION SendOpts;
  1118. if (!(pSendBuffer = malloc(DEFAULT_SEND_SIZE)) ||
  1119. (!(pRcvBuffer = malloc(DEFAULT_BUFFER_SIZE))))
  1120. {
  1121. if (Trace)
  1122. {
  1123. DbgPrint("LmhSvc.CheckIPAddresses: ERROR -- malloc failed for %s\n",
  1124. (pSendBuffer ? "pRcvBuffer" : "pSendBuffer"));
  1125. }
  1126. if (pSendBuffer)
  1127. {
  1128. free (pSendBuffer);
  1129. }
  1130. return -1;
  1131. }
  1132. //
  1133. // Open channel
  1134. //
  1135. IcmpHandle = IcmpCreateFile();
  1136. if (IcmpHandle == INVALID_HANDLE_VALUE)
  1137. {
  1138. DBG_PRINT ( "Unable to contact IP driver, error code %d.\n", GetLastError() );
  1139. free (pSendBuffer);
  1140. free (pRcvBuffer);
  1141. return -1;
  1142. }
  1143. //
  1144. // init to the first address.
  1145. //
  1146. pIpAddrs = pIpAddrBuffer->IpAddrsList;
  1147. *IpAddr = (fOrdered) ? *pIpAddrs : htonl(*pIpAddrs);
  1148. //
  1149. // Initialize the send buffer pattern.
  1150. //
  1151. for (i = 0; i < DEFAULT_SEND_SIZE; i++)
  1152. {
  1153. pSendBuffer[i] = (UCHAR)('A' + (i % 23));
  1154. }
  1155. //
  1156. // Initialize the send options
  1157. //
  1158. SendOpts.OptionsData = NULL;
  1159. SendOpts.OptionsSize = 0;
  1160. SendOpts.Ttl = DEFAULT_TTL;
  1161. SendOpts.Tos = DEFAULT_TOS;
  1162. SendOpts.Flags = 0;
  1163. //
  1164. // For each IP address in the list
  1165. //
  1166. while (*pIpAddrs)
  1167. {
  1168. struct in_addr addr;
  1169. address = (fOrdered) ? *pIpAddrs : htonl(*pIpAddrs);
  1170. addr.s_addr = address;
  1171. if (address == INADDR_BROADCAST)
  1172. {
  1173. if (Trace)
  1174. {
  1175. DbgPrint("LmhSvc: Cannot ping a Broadcast address = <%s>\n", inet_ntoa(addr));
  1176. }
  1177. pIpAddrs++;
  1178. continue;
  1179. }
  1180. for (i=0; i < DEFAULT_COUNT; i++)
  1181. {
  1182. if (Trace)
  1183. {
  1184. DbgPrint("LmhSvc: Pinging <%s>\n", inet_ntoa(addr));
  1185. }
  1186. numberOfReplies = IcmpSendEcho (IcmpHandle,
  1187. address,
  1188. pSendBuffer,
  1189. (unsigned short) DEFAULT_SEND_SIZE,
  1190. &SendOpts,
  1191. pRcvBuffer,
  1192. DEFAULT_BUFFER_SIZE, // pRcvBuffer size!
  1193. DEFAULT_TIMEOUT);
  1194. //
  1195. // If ping successful, return the IP address
  1196. //
  1197. if (numberOfReplies != 0)
  1198. {
  1199. PICMP_ECHO_REPLY reply;
  1200. reply = (PICMP_ECHO_REPLY) pRcvBuffer;
  1201. if (reply->Status == IP_SUCCESS)
  1202. {
  1203. if (Trace)
  1204. {
  1205. DbgPrint("LmhSvc: SUCCESS: Received <%d> replies after Pinging <%s>\n",
  1206. numberOfReplies, inet_ntoa(addr));
  1207. }
  1208. result = IcmpCloseHandle(IcmpHandle);
  1209. *IpAddr = address;
  1210. free (pSendBuffer);
  1211. free (pRcvBuffer);
  1212. return 0;
  1213. }
  1214. }
  1215. }
  1216. if (Trace)
  1217. {
  1218. DbgPrint("LmhSvc: FAILed: Pinging <%s>\n", inet_ntoa(addr));
  1219. }
  1220. pIpAddrs++;
  1221. }
  1222. result = IcmpCloseHandle(IcmpHandle);
  1223. //
  1224. // Return the first addr if none matched in the hope that TCP session setup might succeed even though
  1225. // the pings failed.
  1226. //
  1227. free (pSendBuffer);
  1228. free (pRcvBuffer);
  1229. return NO_ERROR;
  1230. }
  1231. ULONG
  1232. VerifyIPAddresses(
  1233. IN HANDLE fd,
  1234. IN tIPADDR_BUFFER_DNS *pIpAddrBuffer
  1235. )
  1236. /*++
  1237. Routine Description:
  1238. This function finds out the reachable IP addr and returns the Irp to Netbt
  1239. Arguments:
  1240. Return Value:
  1241. NONE
  1242. --*/
  1243. {
  1244. DWORD Status;
  1245. ULONG GoodAddr;
  1246. pIpAddrBuffer->Resolved = FALSE;
  1247. Status = CheckIPAddresses(pIpAddrBuffer, &GoodAddr, TRUE);
  1248. if (Status == NO_ERROR) {
  1249. pIpAddrBuffer->IpAddrsList[0] = ntohl(GoodAddr);
  1250. //
  1251. // NULL terminate
  1252. //
  1253. pIpAddrBuffer->IpAddrsList[1] = 0;
  1254. pIpAddrBuffer->Resolved = TRUE;
  1255. } else {
  1256. pIpAddrBuffer->IpAddrsList[0] = 0;
  1257. }
  1258. Status = PostForCheckIPAddr(fd);
  1259. return Status;
  1260. }
  1261. VOID
  1262. CheckIPAddrWorkerRtn(
  1263. IN LPVOID lpParam
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. This function submits IP address check Irps into Netbt, on completion of the Irp, it submits the IP address
  1268. list to CheckIPAddresses.
  1269. Arguments:
  1270. Return Value:
  1271. NONE
  1272. --*/
  1273. {
  1274. HANDLE EventList[2];
  1275. DWORD status;
  1276. HANDLE hNbt;
  1277. ULONG EventCount;
  1278. LONG err;
  1279. LONG Value;
  1280. LARGE_INTEGER Timeout = RtlEnlargedIntegerMultiply (-10 * 60, 1000 * 1000 * 10); // 10 minutes
  1281. assert(**lpParam == 1);
  1282. //
  1283. // ignore the return code from resyncNbt().
  1284. //
  1285. // In most cases (no domains spanning an ip router), it is not a
  1286. // catastrophe if nbt.sys couldn't successfully process the NBT_RESYNC
  1287. // ioctl command. Since I'm ignoring the return, I announce I'm running
  1288. // before I call it to allow other dependent services to start.
  1289. //
  1290. //
  1291. status = PrimeCacheNbt(&hNbt, 1);
  1292. if (Trace)
  1293. {
  1294. DbgPrint("LMHSVC: Entered CheckIPAddrWorkerRtn, hNbt %lx.\n", hNbt);
  1295. }
  1296. if (hNbt != (HANDLE)-1)
  1297. {
  1298. status = PostForCheckIPAddr(hNbt);
  1299. if (status == NO_ERROR)
  1300. {
  1301. EventCount = 2;
  1302. }
  1303. else
  1304. {
  1305. if (Trace)
  1306. {
  1307. DbgPrint("Lmhsvc:Error posting Irp for get host by name\n");
  1308. }
  1309. EventCount = 1;
  1310. }
  1311. }
  1312. else
  1313. {
  1314. EventCount = 1;
  1315. }
  1316. //
  1317. // "A SERVICE_MAIN_FUNCTION does not return until the service is ready
  1318. // to terminate."
  1319. //
  1320. // (ref: api32wh.hlp, SERVICE_MAIN_FUNCTION)
  1321. //
  1322. //
  1323. assert(Poison[1]);
  1324. EventList[0] = Poison[1];
  1325. EventList[1] = NbtEvent[1];
  1326. while (TRUE)
  1327. {
  1328. status = NtWaitForMultipleObjects(
  1329. EventCount,
  1330. EventList,
  1331. WaitAny, // wait for any event
  1332. FALSE,
  1333. (EventCount == 1)? &Timeout: NULL);
  1334. if (status == WAIT_TIMEOUT)
  1335. {
  1336. if (hNbt == (HANDLE)-1)
  1337. {
  1338. PrimeCacheNbt(&hNbt, 1);
  1339. if (hNbt == (HANDLE)-1)
  1340. {
  1341. continue; // to wait
  1342. }
  1343. }
  1344. status = PostForCheckIPAddr(hNbt); // try again
  1345. if (status == NO_ERROR)
  1346. {
  1347. EventCount = 2;
  1348. }
  1349. }
  1350. else if (status == 1)
  1351. {
  1352. if (Trace)
  1353. {
  1354. DbgPrint("LMHSVC: Doing VerifyAddr\n");
  1355. }
  1356. // the irp used for gethostby name has returned
  1357. status = VerifyIPAddresses(hNbt, pIpAddrBufferChkIP);
  1358. //
  1359. // disable the get host by name stuff if we have an error
  1360. // posting a buffer to the transport
  1361. //
  1362. if (status != NO_ERROR)
  1363. {
  1364. EventCount = 1;
  1365. }
  1366. }
  1367. else
  1368. {
  1369. // it must have been a the Poison event signalling the end of the
  1370. // the service, so exit after getting the Irp back from the
  1371. // transport. This system will look after canceling the IO and
  1372. // getting the Irp back.
  1373. NtClose(Poison[1]);
  1374. NtClose(NbtEvent[1]);
  1375. NtClose(hNbt);
  1376. break;
  1377. }
  1378. }
  1379. if (Trace)
  1380. {
  1381. DBG_PRINT ("LMHSVC: Exiting [CheckIPAddrWorkerRtn] now!\n");
  1382. }
  1383. ExitThread(NO_ERROR);
  1384. return;
  1385. }