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.

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