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.

1098 lines
29 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. smbsvc.c
  5. Abstract:
  6. This the user-mode proxy for the kernel mode DNS resolver.
  7. features:
  8. 1. Multi-threaded
  9. NBT4 use a single-threaded design. The DNS name resolution is a performance blocker.
  10. When a connection request is being served by LmhSvc, all the other requests requiring
  11. DNS resolution will be blocked.
  12. 2. IPv6 and IPv4 compatiable
  13. 3. can be run either as a service or standalone executable (for debug purpose)
  14. When started as service, debug spew is sent to debugger.
  15. When started as a standalong executable, the debug spew is sent to either
  16. the console or debugger. smbhelper.c contain the _main for the standardalone
  17. executable.
  18. Author:
  19. Jiandong Ruan
  20. Revision History:
  21. --*/
  22. #include "precomp.h"
  23. #include "smbtrace.h"
  24. #include <nt.h>
  25. #include <ntrtl.h>
  26. #include <nturtl.h>
  27. #include <windows.h>
  28. #include <shellapi.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <locale.h>
  32. #include <tdi.h>
  33. #include <winsock2.h>
  34. #include <ws2tcpip.h>
  35. #include <mstcpip.h>
  36. #include <ipexport.h>
  37. #include <winsock2.h>
  38. #include <icmpapi.h>
  39. #include "svclib.h"
  40. #include "ping6.h"
  41. #include "smbsvc.tmh"
  42. #if DBG
  43. //
  44. // In order to disable the compiler optimization,
  45. // don't use static on SmbDebug.
  46. // (When static is used, compiler may find that
  47. // SmbDebug isn't changed in this module, it will
  48. // remove the "if (SmbDebug)" )
  49. //
  50. static int (*SmbDbgPrint)(char *fmt,...) = NULL;
  51. # define KDPRINT(y) \
  52. do { \
  53. int (*MyDbgPrint)(char *fmt,...) = SmbDbgPrint; \
  54. if (NULL != MyDbgPrint) { \
  55. MyDbgPrint y; \
  56. MyDbgPrint(": %d of %s\n", __LINE__, __FILE__); \
  57. } \
  58. } while(0)
  59. #else
  60. # define KDPRINT(y)
  61. #endif
  62. static HANDLE OpenSmb(LPWSTR Name);
  63. #define DEFAULT_RECV_SIZE (0x2000) // Icmp recv buffer size
  64. #define DEFAULT_TTL 32
  65. #define DEFAULT_TOS 0
  66. #define DEFAULT_TIMEOUT 2000L // default timeout set to 2 secs.
  67. static HANDLE hTerminateEvent;
  68. static BYTE SendBuffer[] = "SMBEcho";
  69. static IP_OPTION_INFORMATION SendOpts = {
  70. DEFAULT_TTL, DEFAULT_TOS, 0, 0, NULL
  71. };
  72. #ifdef __USE_GETADDRINFO__
  73. //
  74. // Please use getaddrinfo whenever it has a UNICODE version
  75. //
  76. VOID
  77. ReturnAllIPAddress(
  78. PSMB_DNS_BUFFER dns,
  79. struct addrinfo *res
  80. )
  81. {
  82. SOCKET_ADDRESS SelectedAddr;
  83. struct addrinfo *p = res;
  84. BOOL bFoundIPv4 = FALSE;
  85. for (p = res; p; p = p->ai_next) {
  86. if (p->ai_family == PF_INET6) {
  87. //
  88. // Save the last slot for IPv4 address
  89. //
  90. if (!bFoundIPv4 && dns->IpAddrsNum == SMB_MAX_IPADDRS_PER_HOST - 1) {
  91. continue;
  92. }
  93. //
  94. // Skip all the multicast address
  95. //
  96. if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)p->ai_addr)->sin6_addr)) {
  97. continue;
  98. }
  99. //
  100. // Only allow supported addresses in
  101. //
  102. if (!(dns->RequestType & SMB_DNS_AAAA_GLOBAL) &&
  103. !SMB_IS_ADDRESS_ALLOWED(((struct sockaddr_in6*)p->ai_addr)->sin6_addr.u.Byte)) {
  104. continue;
  105. }
  106. SelectedAddr.lpSockdddr = p->ai_addr;
  107. SelectedAddr.iSockaddrLength = sizeof (sockaddr_in6);
  108. } else if (p->ai_family == PF_INET) {
  109. SelectedAddr.lpSockdddr = p->ai_addr;
  110. SelectedAddr.iSockaddrLength = sizeof (sockaddr_in);
  111. bFoundIPv4 = TRUE;
  112. } else {
  113. ASSERT (0);
  114. continue;
  115. }
  116. SmbReturnIPAddress (dns, &SelectedAddr);
  117. }
  118. return p;
  119. }
  120. VOID
  121. SmbGetHostByName(
  122. PSMB_DNS_BUFFER dns
  123. )
  124. {
  125. struct addrinfo hints = {0};
  126. struct addrinfo *res;
  127. CHAR nodename[DNS_NAME_BUFFER_LENGTH];
  128. KDPRINT(("Resolving %ws", dns->Name));
  129. dns->Resolved = FALSE;
  130. dns->IpAddrsNum = 0;
  131. if (WideCharToMultiByte(
  132. CP_THREAD_ACP,
  133. WC_NO_BEST_FIT_CHARS,
  134. dns->Name,
  135. dns->NameLen,
  136. nodename,
  137. DNS_NAME_BUFFER_LENGTH,
  138. NULL,
  139. NULL
  140. ) == 0) {
  141. KDPRINT(("WideCharToMultiByte return %d", GetLastError()));
  142. return;
  143. }
  144. hints.ai_family = 0;
  145. hints.ai_flags = AI_CANONNAME;
  146. hints.ai_socktype = SOCK_STREAM;
  147. if (getaddrinfo(nodename, NULL, &hints, &res)) {
  148. KDPRINT(("getaddrinfo return %d", GetLastError()));
  149. return;
  150. }
  151. if (NULL == res) {
  152. //
  153. // This should not happen since getaddrinfo returns success above
  154. //
  155. ASSERT(0);
  156. return;
  157. }
  158. dns->NameLen = MultiByteToWideChar(
  159. CP_THREAD_ACP,
  160. MB_ERR_INVALID_CHARS,
  161. res->ai_canonname,
  162. -1,
  163. dns->Name,
  164. DNS_NAME_BUFFER_LENGTH
  165. );
  166. if (0 == dns->NameLen) {
  167. KDPRINT(("MultiByteToWideChar return %d", GetLastError()));
  168. }
  169. dns->Resolved = TRUE;
  170. ReturnAllIPAddress(dns, res);
  171. freeaddrinfo(res);
  172. }
  173. #else
  174. VOID
  175. SmbCopyDnsName(
  176. IN OUT PSMB_DNS_BUFFER dns,
  177. IN WCHAR *name
  178. )
  179. /*++
  180. Routine Description:
  181. This routine update the Name and NameLen field of dns.
  182. If the input name is too long, nothing will happen
  183. Arguments:
  184. Return Value:
  185. --*/
  186. {
  187. int len;
  188. if (NULL == name) {
  189. return;
  190. }
  191. len = wcslen(name) + 1;
  192. if ( len > DNS_NAME_BUFFER_LENGTH ) {
  193. return;
  194. }
  195. memcpy (dns->Name, name, len * sizeof(WCHAR));
  196. dns->NameLen = len - 1;
  197. KDPRINT(("DNS name is updated with %ws", dns->Name));
  198. SmbTrace(SMB_TRACE_DNS, ("\tFQDN %ws", dns->Name));
  199. }
  200. VOID
  201. SmbReturnIPAddress (
  202. IN OUT PSMB_DNS_BUFFER dns,
  203. IN PSOCKET_ADDRESS pSelectedAddr
  204. )
  205. {
  206. struct sockaddr_in *pv4addr = NULL;
  207. struct sockaddr_in6 *pv6addr = NULL;
  208. PSMB_IP_ADDRESS pSmbIpAddress = NULL;
  209. #ifdef DBG
  210. CHAR name_buffer[48];
  211. #endif
  212. //
  213. // Update the return buffer (returned to the kernel mode driver)
  214. //
  215. dns->Resolved = TRUE;
  216. if (dns->IpAddrsNum >= SMB_MAX_IPADDRS_PER_HOST) {
  217. return;
  218. }
  219. pSmbIpAddress = &dns->IpAddrsList[dns->IpAddrsNum];
  220. dns->IpAddrsNum++;
  221. if (pSelectedAddr->lpSockaddr->sa_family == AF_INET) {
  222. pSmbIpAddress->sin_family = SMB_AF_INET;
  223. pv4addr = (struct sockaddr_in*)(pSelectedAddr->lpSockaddr);
  224. RtlCopyMemory(&pSmbIpAddress->ip4.sin4_addr, &pv4addr->sin_addr, sizeof(pv4addr->sin_addr));
  225. SmbTrace(SMB_TRACE_DNS, ("\treturn %!ipaddr!", pv4addr->sin_addr.S_un.S_addr));
  226. } else {
  227. pSmbIpAddress->sin_family = SMB_AF_INET6;
  228. pv6addr = (struct sockaddr_in6*)(pSelectedAddr->lpSockaddr);
  229. RtlCopyMemory(pSmbIpAddress->ip6.sin6_addr, &pv6addr->sin6_addr, sizeof(pv6addr->sin6_addr));
  230. pSmbIpAddress->ip6.sin6_scope_id = pv6addr->sin6_scope_id;
  231. SmbTrace(SMB_TRACE_DNS, ("\treturn %!IPV6ADDR!", &pv6addr->sin6_addr));
  232. }
  233. }
  234. int
  235. SortIPAddrs(
  236. IN int af,
  237. OUT LPVOID Addrs,
  238. IN u_int NumAddrs,
  239. IN u_int width,
  240. OUT SOCKET_ADDRESS_LIST ** pAddrlist
  241. )
  242. /*++
  243. Routine Description:
  244. Lifted from %SDXROOT%\net\sockets\winsock2\ws2_32\src\addrinfo.cpp
  245. Sort addresses of the same family.
  246. A wrapper around a sort Ioctl.
  247. If the Ioctl isn't implemented, the sort is a no-op.
  248. Arguments:
  249. Return Value:
  250. --*/
  251. {
  252. DWORD status = NO_ERROR;
  253. DWORD bytesReturned = 0;
  254. DWORD size = 0;
  255. DWORD i = 0;
  256. PSOCKADDR paddr = NULL;
  257. UINT countAddrs = NumAddrs;
  258. LPSOCKET_ADDRESS_LIST paddrlist = NULL;
  259. //
  260. // build SOCKET_ADDRESS_LIST
  261. // - allocate
  262. // - fill in with pointers into SOCKADDR array
  263. //
  264. size = FIELD_OFFSET( SOCKET_ADDRESS_LIST, Address[countAddrs] );
  265. paddrlist = (SOCKET_ADDRESS_LIST *)LocalAlloc(LMEM_FIXED, size);
  266. if ( !paddrlist ) {
  267. status = WSA_NOT_ENOUGH_MEMORY;
  268. goto Done;
  269. }
  270. for ( i=0; i<countAddrs; i++ ) {
  271. paddr = (PSOCKADDR) (((PBYTE)Addrs) + i * width);
  272. paddrlist->Address[i].lpSockaddr = paddr;
  273. paddrlist->Address[i].iSockaddrLength = width;
  274. }
  275. paddrlist->iAddressCount = countAddrs;
  276. //
  277. // sort if multiple addresses and able to open socket
  278. // - open socket of desired type for sort
  279. // - sort, if sort fails just return unsorted
  280. //
  281. if ( countAddrs > 1 ) {
  282. SOCKET s = INVALID_SOCKET;
  283. s = socket( af, SOCK_DGRAM, 0 );
  284. if ( s == INVALID_SOCKET ) {
  285. goto Done;
  286. }
  287. status = WSAIoctl(
  288. s,
  289. SIO_ADDRESS_LIST_SORT,
  290. (LPVOID)paddrlist,
  291. size,
  292. (LPVOID)paddrlist,
  293. size,
  294. & bytesReturned,
  295. NULL,
  296. NULL );
  297. closesocket(s);
  298. status = NO_ERROR;
  299. }
  300. Done:
  301. if ( status == NO_ERROR ) {
  302. *pAddrlist = paddrlist;
  303. }
  304. return status;
  305. }
  306. typedef enum {
  307. SMB_DNS_UNRESOLVED = 0,
  308. SMB_DNS_BUFFER_TOO_SMALL,
  309. SMB_DNS_RESOLVED,
  310. SMB_DNS_REACHABLE
  311. } SMB_DNS_STATUS;
  312. typedef struct {
  313. union {
  314. SOCKADDR_IN *pV4Addrs;
  315. SOCKADDR_IN6 *pV6Addrs;
  316. PVOID pAddrs;
  317. };
  318. u_int NumSlots;
  319. u_int NumAddrs;
  320. } SMB_ADDR_LIST, *PSMB_ADDR_LIST;
  321. int
  322. SaveV6Address(
  323. IN struct in6_addr * NewAddr,
  324. IN OUT PSMB_ADDR_LIST pSmbAddrList
  325. )
  326. /*++
  327. Routine Description:
  328. Save an address into our array of addresses,
  329. possibly growing the array.
  330. Arguments:
  331. Return Value:
  332. Returns FALSE on failure. (Couldn't grow array.)
  333. --*/
  334. {
  335. SOCKADDR_IN6 *addr6 = NULL;
  336. DWORD dwSize = 0;
  337. DWORD dwNewSlots = 0;
  338. SOCKADDR_IN6 *NewAddrs = NULL;
  339. USHORT ServicePort = 0;
  340. //
  341. // add another sockaddr to array if not enough space
  342. //
  343. if (pSmbAddrList->NumSlots == pSmbAddrList->NumAddrs) {
  344. if (pSmbAddrList->pV6Addrs) {
  345. ASSERT (pSmbAddrList->NumSlots);
  346. dwNewSlots = 2 * pSmbAddrList->NumSlots;
  347. dwSize = dwNewSlots * sizeof (SOCKADDR_IN6);
  348. NewAddrs = (SOCKADDR_IN6 *) LocalReAlloc(pSmbAddrList->pV6Addrs, dwSize, LMEM_ZEROINIT);
  349. } else {
  350. dwNewSlots = SMB_MAX_IPADDRS_PER_HOST;
  351. dwSize = dwNewSlots * sizeof (SOCKADDR_IN6);
  352. NewAddrs = (SOCKADDR_IN6 *) LocalAlloc(LPTR, dwSize);
  353. }
  354. if (NewAddrs == NULL)
  355. return FALSE;
  356. pSmbAddrList->pV6Addrs = NewAddrs;
  357. pSmbAddrList->NumSlots = dwNewSlots;
  358. }
  359. // fill in IP6 sockaddr
  360. addr6 = pSmbAddrList->pV6Addrs + (pSmbAddrList->NumAddrs++);
  361. addr6->sin6_family = AF_INET6;
  362. addr6->sin6_port = ServicePort;
  363. memcpy(&addr6->sin6_addr, NewAddr, sizeof(*NewAddr));
  364. return TRUE;
  365. }
  366. int
  367. SaveV4Address(
  368. IN struct in_addr * NewAddr,
  369. IN OUT PSMB_ADDR_LIST pSmbAddrList
  370. )
  371. /*++
  372. Routine Description:
  373. Save an address into our array of addresses,
  374. possibly growing the array.
  375. Arguments:
  376. Return Value:
  377. Returns FALSE on failure. (Couldn't grow array.)
  378. --*/
  379. {
  380. SOCKADDR_IN *addr = NULL;
  381. DWORD dwSize = 0;
  382. DWORD dwNewSlots = 0;
  383. SOCKADDR_IN *NewAddrs = NULL;
  384. USHORT ServicePort = 0;
  385. //
  386. // add another sockaddr to array if not enough space
  387. //
  388. if (pSmbAddrList->NumSlots == pSmbAddrList->NumAddrs) {
  389. if (pSmbAddrList->pV4Addrs) {
  390. ASSERT (pSmbAddrList->NumSlots);
  391. dwNewSlots = 2 * pSmbAddrList->NumSlots;
  392. dwSize = dwNewSlots * sizeof (SOCKADDR_IN);
  393. NewAddrs = (SOCKADDR_IN *) LocalReAlloc(pSmbAddrList->pV4Addrs, dwSize, LMEM_ZEROINIT);
  394. } else {
  395. dwNewSlots = SMB_MAX_IPADDRS_PER_HOST;
  396. dwSize = dwNewSlots * sizeof (SOCKADDR_IN);
  397. NewAddrs = (SOCKADDR_IN *) LocalAlloc(LPTR, dwSize);
  398. }
  399. if (NewAddrs == NULL)
  400. return FALSE;
  401. pSmbAddrList->pV4Addrs = NewAddrs;
  402. pSmbAddrList->NumSlots = dwNewSlots;
  403. }
  404. // fill in IP sockaddr
  405. addr = pSmbAddrList->pV4Addrs + (pSmbAddrList->NumAddrs++);
  406. addr->sin_family = AF_INET;
  407. addr->sin_port = ServicePort;
  408. memcpy(&addr->sin_addr, NewAddr, sizeof(*NewAddr));
  409. return TRUE;
  410. }
  411. VOID
  412. CleanupAddrList (
  413. IN OUT PSMB_ADDR_LIST pSmbAddrList
  414. )
  415. {
  416. if (pSmbAddrList->pAddrs) {
  417. LocalFree (pSmbAddrList->pAddrs);
  418. pSmbAddrList->pAddrs = NULL;
  419. }
  420. RtlZeroMemory (pSmbAddrList, sizeof(SMB_ADDR_LIST));
  421. }
  422. typedef struct {
  423. SMB_ADDR_LIST V4AddrList;
  424. SMB_ADDR_LIST V6AddrList;
  425. LPSOCKET_ADDRESS_LIST pSortedV4AddrList;
  426. LPSOCKET_ADDRESS_LIST pSortedV6AddrList;
  427. } SMB_DNS_RESULT, *PSMB_DNS_RESULT;
  428. VOID
  429. CleanupDnsResult (
  430. IN OUT PSMB_DNS_RESULT pSmbDnsResult
  431. )
  432. {
  433. CleanupAddrList (&pSmbDnsResult->V4AddrList);
  434. CleanupAddrList (&pSmbDnsResult->V6AddrList);
  435. if (pSmbDnsResult->pSortedV4AddrList) {
  436. LocalFree (pSmbDnsResult->pSortedV4AddrList);
  437. pSmbDnsResult->pSortedV4AddrList = NULL;
  438. }
  439. if (pSmbDnsResult->pSortedV6AddrList) {
  440. LocalFree (pSmbDnsResult->pSortedV6AddrList);
  441. pSmbDnsResult->pSortedV6AddrList = NULL;
  442. }
  443. }
  444. #define SMB_INIT_WSA_SIZE (sizeof(WSAQUERYSETW) + 2048)
  445. //
  446. // use WSALookupXXXX APIs since we don't have a UNICODE version of getaddrinfo
  447. //
  448. DWORD
  449. LookupDns(
  450. IN WCHAR * pwchName,
  451. IN GUID * pgProvider,
  452. IN OUT PSMB_DNS_BUFFER dns,
  453. IN OUT PSMB_DNS_RESULT pSmbDnsResult
  454. )
  455. /*++
  456. Routine Description:
  457. Arguments:
  458. Return Value:
  459. WINERROR
  460. --*/
  461. {
  462. PCSADDR_INFO pcsadr = NULL;
  463. struct sockaddr_in *pv4addr = NULL;
  464. struct sockaddr_in6 *pv6addr = NULL;
  465. DWORD dwError = ERROR_SUCCESS;
  466. HANDLE hRnR = NULL;
  467. DWORD i = 0;
  468. PWSAQUERYSETW pwsaq = NULL;
  469. DWORD dwSize = 0;
  470. DWORD dwCurrentSize = 0;
  471. #ifdef DBG
  472. CHAR name_buffer[48];
  473. #endif
  474. //
  475. // Allocate the memory and setup the request
  476. //
  477. dwSize = dwCurrentSize = SMB_INIT_WSA_SIZE;
  478. pwsaq = (PWSAQUERYSETW)LocalAlloc(LPTR, dwSize);
  479. if (NULL == pwsaq) {
  480. SmbTrace(SMB_TRACE_DNS, ("\tOut of memory"));
  481. goto cleanup;
  482. }
  483. pwsaq->dwSize = sizeof(*pwsaq);
  484. pwsaq->lpszServiceInstanceName = pwchName;
  485. pwsaq->lpServiceClassId = pgProvider;
  486. pwsaq->dwNameSpace = NS_DNS;
  487. //
  488. // Start the lookup
  489. //
  490. dwError = WSALookupServiceBeginW (pwsaq, LUP_RETURN_NAME| LUP_RETURN_ADDR, &hRnR);
  491. if (dwError != NO_ERROR) {
  492. dwError = GetLastError();
  493. SmbTrace(SMB_TRACE_DNS, ("Error: %!winerr!", dwError));
  494. goto cleanup;
  495. }
  496. while(1) {
  497. dwSize = dwCurrentSize;
  498. dwError = WSALookupServiceNextW (hRnR, 0, &dwSize, pwsaq);
  499. if (dwError != NO_ERROR) {
  500. dwError = GetLastError();
  501. SmbTrace(SMB_TRACE_DNS, ("Error: %!winerr!", dwError));
  502. if (dwError != WSAEFAULT) {
  503. break;
  504. }
  505. if (dwSize <= SMB_INIT_WSA_SIZE) {
  506. ASSERT(0);
  507. SmbTrace(SMB_TRACE_DNS, ("\tInvalid buffer size %d returned by DNS", dwSize));
  508. break;
  509. }
  510. //
  511. // Realloc the buffer using the suggested size
  512. //
  513. LocalFree(pwsaq);
  514. pwsaq = NULL;
  515. pwsaq = (PWSAQUERYSETW)LocalAlloc(LPTR, dwSize);
  516. if (NULL == pwsaq) {
  517. SmbTrace(SMB_TRACE_DNS, ("\tOut of memory"));
  518. goto cleanup;
  519. }
  520. dwCurrentSize = dwSize;
  521. continue;
  522. }
  523. //
  524. // Pick up the canonical name
  525. //
  526. SmbCopyDnsName(dns, pwsaq->lpszServiceInstanceName);
  527. for (i = 0, pcsadr = pwsaq->lpcsaBuffer; i < pwsaq->dwNumberOfCsAddrs; i++, pcsadr++) {
  528. switch (pcsadr->RemoteAddr.lpSockaddr->sa_family) {
  529. case AF_INET:
  530. if (pcsadr->RemoteAddr.iSockaddrLength >= sizeof(struct sockaddr_in)) {
  531. pv4addr = (struct sockaddr_in*)(pcsadr->RemoteAddr.lpSockaddr);
  532. SaveV4Address (&pv4addr->sin_addr, &pSmbDnsResult->V4AddrList);
  533. SmbTrace(SMB_TRACE_DNS, ("\t%!ipaddr!", pv4addr->sin_addr.S_un.S_addr));
  534. }
  535. break;
  536. case AF_INET6:
  537. if (pcsadr->RemoteAddr.iSockaddrLength >= sizeof(struct sockaddr_in6)) {
  538. pv6addr = (struct sockaddr_in6*)(pcsadr->RemoteAddr.lpSockaddr);
  539. //
  540. // Skip all the multicast address
  541. //
  542. if (IN6_IS_ADDR_MULTICAST(&pv6addr->sin6_addr)) {
  543. SmbTrace(SMB_TRACE_DNS, ("\tSkip %!IPV6ADDR!", &pv6addr->sin6_addr));
  544. continue;
  545. }
  546. if (!(dns->RequestType & SMB_DNS_AAAA_GLOBAL) &&
  547. !SMB_IS_ADDRESS_ALLOWED(pv6addr->sin6_addr.u.Byte)) {
  548. SmbTrace(SMB_TRACE_DNS, ("\tSkip %!IPV6ADDR!", &pv6addr->sin6_addr));
  549. continue;
  550. }
  551. SaveV6Address (&pv6addr->sin6_addr, &pSmbDnsResult->V6AddrList);
  552. SmbTrace(SMB_TRACE_DNS, ("\t%!IPV6ADDR!", &pv6addr->sin6_addr));
  553. }
  554. break;
  555. default:
  556. KDPRINT(("Skip non-IP address"));
  557. break;
  558. }
  559. }
  560. }
  561. WSALookupServiceEnd(hRnR);
  562. hRnR = NULL;
  563. cleanup:
  564. if (NULL != hRnR) {
  565. WSALookupServiceEnd(hRnR);
  566. hRnR = NULL;
  567. }
  568. LocalFree(pwsaq); // LocalFree can handle NULL case
  569. pwsaq = NULL;
  570. return dwError;
  571. }
  572. static GUID guidHostnameV6 = SVCID_DNS_TYPE_AAAA;
  573. static GUID guidHostnameV4 = SVCID_DNS_TYPE_A;
  574. VOID
  575. SmbGetHostByName(
  576. PSMB_DNS_BUFFER dns
  577. )
  578. /*++
  579. Routine Description:
  580. Resolve the name through DNS.
  581. Arguments:
  582. Return Value:
  583. --*/
  584. {
  585. DWORD dwError = 0;
  586. int i;
  587. SMB_DNS_RESULT SmbDnsResult = { 0 };
  588. dns->Resolved = FALSE;
  589. dns->IpAddrsNum = 0;
  590. if (dns->NameLen > DNS_MAX_NAME_LENGTH) {
  591. SmbTrace(SMB_TRACE_DNS, ("Error: name too long %d", dns->NameLen));
  592. KDPRINT(("Receive invalid request"));
  593. goto cleanup;
  594. }
  595. dns->Name[dns->NameLen] = L'\0';
  596. SmbTrace(SMB_TRACE_DNS, ("Resolving %ws", dns->Name));
  597. if (dns->RequestType & SMB_DNS_AAAA_GLOBAL) {
  598. dns->RequestType |= SMB_DNS_AAAA;
  599. SmbTrace(SMB_TRACE_DNS, ("\tGlobal IPv6 Address is on"));
  600. }
  601. if (dns->RequestType & SMB_DNS_AAAA) {
  602. KDPRINT(("Looking for AAAA record for %ws", dns->Name));
  603. SmbTrace(SMB_TRACE_DNS, ("\tLookup AAAA record"));
  604. dwError = LookupDns(dns->Name, &guidHostnameV6, dns, &SmbDnsResult);
  605. SmbTrace(SMB_TRACE_DNS, ("\tFound %d IPv6 address", SmbDnsResult.V6AddrList.NumAddrs));
  606. if (SmbDnsResult.V6AddrList.NumAddrs > 0) {
  607. SortIPAddrs(
  608. AF_INET6,
  609. (LPVOID)SmbDnsResult.V6AddrList.pAddrs,
  610. SmbDnsResult.V6AddrList.NumAddrs,
  611. sizeof(SOCKADDR_IN6),
  612. &SmbDnsResult.pSortedV6AddrList
  613. );
  614. }
  615. }
  616. if (dns->RequestType & SMB_DNS_A) {
  617. KDPRINT(("Looking for A record for %ws", dns->Name));
  618. SmbTrace(SMB_TRACE_DNS, ("\tLookup A record"));
  619. dwError = LookupDns(dns->Name, &guidHostnameV4, dns, &SmbDnsResult);
  620. SmbTrace(SMB_TRACE_DNS, ("\tFound %d IPv4 address", SmbDnsResult.V4AddrList.NumAddrs));
  621. if (SmbDnsResult.V4AddrList.NumAddrs > 0) {
  622. SortIPAddrs(
  623. AF_INET,
  624. (LPVOID)SmbDnsResult.V4AddrList.pAddrs,
  625. SmbDnsResult.V4AddrList.NumAddrs,
  626. sizeof(SOCKADDR_IN),
  627. &SmbDnsResult.pSortedV4AddrList
  628. );
  629. }
  630. }
  631. cleanup:
  632. if (SmbDnsResult.pSortedV6AddrList) {
  633. for (i = 0; i < SmbDnsResult.pSortedV6AddrList->iAddressCount; i++) {
  634. SmbReturnIPAddress (dns, &SmbDnsResult.pSortedV6AddrList->Address[i]);
  635. }
  636. }
  637. if (SmbDnsResult.pSortedV4AddrList) {
  638. //
  639. // Make sure we have an IPv4 address to failover
  640. //
  641. if (dns->IpAddrsNum >= SMB_MAX_IPADDRS_PER_HOST &&
  642. SmbDnsResult.pSortedV4AddrList->iAddressCount > 0) {
  643. dns->IpAddrsNum = SMB_MAX_IPADDRS_PER_HOST / 2;
  644. SmbTrace(SMB_TRACE_DNS, ("\tTruncate IPv6 address to give room to IPv4"));
  645. }
  646. for (i = 0; i < SmbDnsResult.pSortedV4AddrList->iAddressCount; i++) {
  647. SmbReturnIPAddress (dns, &SmbDnsResult.pSortedV4AddrList->Address[i]);
  648. }
  649. }
  650. SmbTrace(SMB_TRACE_DNS, ("\tNum of IP address returned: %d", dns->IpAddrsNum));
  651. CleanupDnsResult (&SmbDnsResult);
  652. }
  653. #endif // __USE_GETADDRINFO__
  654. DWORD
  655. SmbGetHostThread(
  656. LPVOID ctx
  657. )
  658. {
  659. NTSTATUS status;
  660. DWORD Error;
  661. HANDLE WaitObject[2];
  662. SMB_DNS_BUFFER Dns;
  663. IO_STATUS_BLOCK iosb;
  664. #define TERMINATE_EVENT (WAIT_OBJECT_0)
  665. #define IO_EVENT (WAIT_OBJECT_0+1)
  666. SmbTrace(SMB_TRACE_DNS, ("Thread start: detecting NetbiosSmb driver"));
  667. WaitObject[TERMINATE_EVENT] = hTerminateEvent;
  668. while(1) {
  669. DWORD dwLocalError = ERROR_SUCCESS;
  670. WaitObject[IO_EVENT] = OpenSmb(DD_SMB6_EXPORT_NAME);
  671. if (WaitObject[IO_EVENT] != NULL) {
  672. break;
  673. }
  674. Error = GetLastError();
  675. //
  676. // Wait for 60 seconds and try again
  677. //
  678. dwLocalError = WaitForSingleObject(hTerminateEvent, 60000);
  679. if (dwLocalError != WAIT_TIMEOUT) {
  680. return Error;
  681. }
  682. }
  683. SmbTrace(SMB_TRACE_DNS, ("Thread start: NetbiosSmb driver detected"));
  684. while (1) {
  685. status = NtDeviceIoControlFile(
  686. WaitObject[IO_EVENT], // Handle
  687. NULL, // Wait Event
  688. NULL, // ApcRoutine
  689. NULL, // ApcContext
  690. &iosb, // IoStatusBlock
  691. IOCTL_SMB_DNS, // IoControlCode
  692. &Dns, // InputBuffer
  693. sizeof(Dns), // InputBufferSize
  694. &Dns, // OutputBuffer
  695. sizeof(Dns) // OutputBufferSize
  696. );
  697. if (status == STATUS_PENDING) {
  698. Error = WaitForMultipleObjects(
  699. 2,
  700. WaitObject,
  701. FALSE,
  702. INFINITE
  703. );
  704. if (Error == TERMINATE_EVENT) {
  705. IO_STATUS_BLOCK iosb2;
  706. KDPRINT(("Receive terminate event, cancelling request"));
  707. status = NtCancelIoFile(WaitObject[IO_EVENT], &iosb2);
  708. KDPRINT(("NtCancelIoFile: status 0x%08lx, iosb.Status 0x%08lx", status, iosb.Status));
  709. break;
  710. }
  711. ASSERT(Error == IO_EVENT);
  712. status = iosb.Status;
  713. ASSERT(status != STATUS_PENDING);
  714. }
  715. SmbTrace(SMB_TRACE_DNS, ("%!status!", status));
  716. //
  717. // Bail out immediately if the underlying driver tell us quota exceeded
  718. //
  719. if (status == STATUS_QUOTA_EXCEEDED) {
  720. KDPRINT(("NtDeviceIoControlFile: STATUS_QUOTA_EXCEEDED"));
  721. break;
  722. }
  723. if (status != STATUS_SUCCESS) {
  724. KDPRINT(("NtDeviceIoControlFile: status = 0x%08lx", status));
  725. Error = WaitForSingleObject(hTerminateEvent, 5000);
  726. if (Error == WAIT_OBJECT_0) {
  727. KDPRINT(("Receive terminate event"));
  728. break;
  729. }
  730. ASSERT(Error == WAIT_TIMEOUT);
  731. } else {
  732. ASSERT(iosb.Information == sizeof(Dns));
  733. SmbGetHostByName(&Dns);
  734. }
  735. }
  736. NtClose(WaitObject[IO_EVENT]);
  737. SmbTrace(SMB_TRACE_DNS, ("Thread exit"));
  738. KDPRINT(("Thread exit"));
  739. return ERROR_SUCCESS;
  740. }
  741. LONG ThreadNumber;
  742. HANDLE hThread[DNS_MAX_RESOLVER];
  743. VOID
  744. SmbSetTraceRoutine(
  745. int (*trace)(char *,...)
  746. )
  747. {
  748. #if DBG
  749. SmbDbgPrint = trace;
  750. #endif
  751. }
  752. DWORD
  753. SmbStartService(
  754. LONG NumWorker,
  755. SMBSVC_UPDATE_STATUS HeartBeating
  756. )
  757. {
  758. WSADATA WsaData;
  759. int i;
  760. DWORD Error = ERROR_SUCCESS;
  761. if (NumWorker > DNS_MAX_RESOLVER || NumWorker < 0) {
  762. SmbTrace(SMB_TRACE_DNS, ("Error: %d worker threads", NumWorker));
  763. return ERROR_INVALID_PARAMETER;
  764. }
  765. if (NumWorker == 0) {
  766. NumWorker = DNS_MAX_RESOLVER;
  767. }
  768. SmbTrace(SMB_TRACE_DNS, ("Starting %d worker threads", NumWorker));
  769. if (WSAStartup(MAKEWORD(2, 0), &WsaData) == SOCKET_ERROR) {
  770. Error = WSAGetLastError();
  771. KDPRINT (("Failed to startup Winsock2"));
  772. SmbTrace(SMB_TRACE_DNS, ("Error: %!winerr!", Error));
  773. return Error;
  774. }
  775. hTerminateEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  776. if (NULL == hTerminateEvent) {
  777. Error = GetLastError();
  778. KDPRINT(("Create hTerminateEvent returns %d", Error));
  779. SmbTrace(SMB_TRACE_DNS, ("Error: %!winerr!", Error));
  780. return Error;
  781. }
  782. if (NULL != HeartBeating) {
  783. HeartBeating();
  784. }
  785. Error = ERROR_SUCCESS;
  786. for (i = 0; i < NumWorker; i++) {
  787. hThread[i] = CreateThread(
  788. NULL,
  789. 8192,
  790. (LPTHREAD_START_ROUTINE)SmbGetHostThread,
  791. NULL,
  792. 0,
  793. NULL
  794. );
  795. if (NULL != HeartBeating) {
  796. HeartBeating();
  797. }
  798. if (NULL == hThread[i]) {
  799. Error = GetLastError();
  800. KDPRINT(("CreateThread returns %d", Error));
  801. SmbTrace(SMB_TRACE_DNS, ("Error: %!winerr!", Error));
  802. break;
  803. }
  804. }
  805. ThreadNumber = i;
  806. if (i > 0) {
  807. Error = ERROR_SUCCESS;
  808. }
  809. SmbTrace(SMB_TRACE_DNS, ("Thread Num: %d: %!winerr!", ThreadNumber, Error));
  810. return Error;
  811. }
  812. VOID
  813. SmbStopService(
  814. SMBSVC_UPDATE_STATUS HeartBeating
  815. )
  816. {
  817. DWORD Error;
  818. LONG i;
  819. SmbTrace(SMB_TRACE_DNS, ("Stop request received"));
  820. if (NULL == hTerminateEvent) {
  821. SmbTrace(SMB_TRACE_DNS, ("Already Stopped"));
  822. return;
  823. }
  824. SmbTrace(SMB_TRACE_DNS, ("Stopping"));
  825. KDPRINT(("Send terminate event"));
  826. SetEvent(hTerminateEvent);
  827. do {
  828. Error = WaitForMultipleObjects(
  829. ThreadNumber,
  830. hThread,
  831. TRUE,
  832. 1000
  833. );
  834. if (NULL != HeartBeating) {
  835. HeartBeating();
  836. }
  837. } while(Error == WAIT_TIMEOUT);
  838. for (i = 0; i < ThreadNumber; i++) {
  839. CloseHandle(hThread[i]);
  840. hThread[i] = NULL;
  841. }
  842. ThreadNumber = 0;
  843. CloseHandle(hTerminateEvent);
  844. hTerminateEvent = NULL;
  845. if (NULL != HeartBeating) {
  846. HeartBeating();
  847. }
  848. SmbTrace(SMB_TRACE_DNS, ("Stopped"));
  849. }
  850. HANDLE
  851. OpenSmb(
  852. LPWSTR Name
  853. )
  854. {
  855. UNICODE_STRING ucName;
  856. OBJECT_ATTRIBUTES ObAttr;
  857. HANDLE StreamHandle;
  858. IO_STATUS_BLOCK IoStatusBlock;
  859. NTSTATUS status;
  860. RtlInitUnicodeString(&ucName, Name);
  861. InitializeObjectAttributes(
  862. &ObAttr,
  863. &ucName,
  864. OBJ_CASE_INSENSITIVE,
  865. (HANDLE) NULL,
  866. (PSECURITY_DESCRIPTOR) NULL
  867. );
  868. status = NtCreateFile (
  869. &StreamHandle,
  870. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  871. &ObAttr,
  872. &IoStatusBlock,
  873. NULL,
  874. FILE_ATTRIBUTE_NORMAL,
  875. FILE_SHARE_READ | FILE_SHARE_WRITE,
  876. FILE_OPEN_IF,
  877. 0,
  878. NULL,
  879. 0
  880. );
  881. if (status != STATUS_SUCCESS) {
  882. SetLastError(RtlNtStatusToDosError(status));
  883. KDPRINT(("Open device %ws: status = 0x%08lx", Name, status));
  884. return NULL;
  885. }
  886. SetLastError(ERROR_SUCCESS);
  887. return StreamHandle;
  888. }