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.

1772 lines
41 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. rmapi.c
  5. Abstract:
  6. This module contains code for the part of the router-manager interface
  7. which is common to all the protocols in this component.
  8. Author:
  9. Abolade Gbadegesin (aboladeg) 4-Mar-1998
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <ras.h>
  15. #include <rasuip.h>
  16. #include <raserror.h>
  17. #include <ipinfo.h>
  18. #include "beacon.h"
  19. #include <atlbase.h>
  20. CComModule _Module;
  21. #include <atlcom.h>
  22. #include "nathlp_i.c"
  23. BEGIN_OBJECT_MAP(ObjectMap)
  24. OBJECT_ENTRY(CLSID_SAUpdate, CSharedAccessUpdate)
  25. END_OBJECT_MAP()
  26. extern "C" {
  27. #include <iphlpstk.h>
  28. }
  29. HANDLE NhpComponentEvent = NULL;
  30. NH_COMPONENT_MODE NhComponentMode = NhUninitializedMode;
  31. const WCHAR NhpDhcpDomainString[] = L"DhcpDomain";
  32. const WCHAR NhpDomainString[] = L"Domain";
  33. BOOLEAN NhpDllProcessAttachSucceeded;
  34. const WCHAR NhpEnableProxy[] = L"EnableProxy";
  35. const WCHAR NhpICSDomainString[] = L"ICSDomain";
  36. LONG NhpIsWinsProxyEnabled = -1;
  37. CRITICAL_SECTION NhLock;
  38. HMODULE NhpRtrmgrDll = NULL;
  39. LIST_ENTRY NhApplicationSettingsList;
  40. LIST_ENTRY NhDhcpReservationList;
  41. DWORD NhDhcpScopeAddress = 0;
  42. DWORD NhDhcpScopeMask = 0;
  43. HANDLE NhFileHandle = INVALID_HANDLE_VALUE;
  44. const WCHAR NhTcpipParametersString[] =
  45. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"
  46. L"\\Tcpip\\Parameters";
  47. //
  48. // EXTERNAL DECLARATIONS
  49. //
  50. BOOL
  51. APIENTRY
  52. DllMain(
  53. HINSTANCE Instance,
  54. ULONG Reason,
  55. PVOID Unused
  56. )
  57. /*++
  58. Routine Description:
  59. Standard DLL entry/exit routine.
  60. Initializes/shuts-down the modules implemented in the DLL.
  61. The initialization performed is sufficient that all the modules'
  62. interface lists can be searched, whether or not the protocols are
  63. installed or operational.
  64. Arguments:
  65. Instance - the instance of this DLL in this process
  66. Reason - the reason for invocation
  67. Unused - unused.
  68. Return Value:
  69. BOOL - indicates success or failure.
  70. --*/
  71. {
  72. switch (Reason) {
  73. case DLL_PROCESS_ATTACH: {
  74. WSADATA wd;
  75. NhpDllProcessAttachSucceeded = FALSE;
  76. DisableThreadLibraryCalls(Instance);
  77. __try {
  78. InitializeCriticalSection(&NhLock);
  79. } __except(EXCEPTION_EXECUTE_HANDLER) {
  80. return FALSE;
  81. }
  82. WSAStartup(MAKEWORD(2,2), &wd);
  83. NhInitializeTraceManagement();
  84. if (!NhInitializeEventLogManagement()) {return FALSE; }
  85. InitializeListHead(&NhApplicationSettingsList);
  86. InitializeListHead(&NhDhcpReservationList);
  87. if (NhInitializeBufferManagement()) { return FALSE; }
  88. if (NhInitializeTimerManagement()) { return FALSE; }
  89. if (!NatInitializeModule()) { return FALSE; }
  90. if (!DhcpInitializeModule()) { return FALSE; }
  91. if (!DnsInitializeModule()) { return FALSE; }
  92. if (!AlgInitializeModule()) { return FALSE; }
  93. if (!H323InitializeModule()) { return FALSE; }
  94. if(FAILED(InitializeBeaconSvr())) { return FALSE; }
  95. _Module.Init(ObjectMap, Instance, &LIBID_IPNATHelperLib);
  96. _Module.RegisterTypeLib();
  97. NhpDllProcessAttachSucceeded = TRUE;
  98. break;
  99. }
  100. case DLL_PROCESS_DETACH: {
  101. if (TRUE == NhpDllProcessAttachSucceeded) {
  102. NhResetComponentMode();
  103. TerminateBeaconSvr();
  104. H323CleanupModule();
  105. AlgCleanupModule();
  106. DnsCleanupModule();
  107. DhcpCleanupModule();
  108. NatCleanupModule();
  109. NhShutdownTimerManagement();
  110. NhShutdownBufferManagement();
  111. NhShutdownEventLogManagement();
  112. NhShutdownTraceManagement();
  113. WSACleanup();
  114. if (NhpRtrmgrDll) {
  115. FreeLibrary(NhpRtrmgrDll); NhpRtrmgrDll = NULL;
  116. }
  117. DeleteCriticalSection(&NhLock);
  118. _Module.Term();
  119. }
  120. break;
  121. }
  122. }
  123. return TRUE;
  124. } // DllMain
  125. VOID
  126. NhBuildDhcpReservations(
  127. VOID
  128. )
  129. /*++
  130. Routine Description:
  131. Builds the list of DHCP reservations
  132. Arguments:
  133. none.
  134. Return Value:
  135. None.
  136. Environment:
  137. Invoked with NhLock held on a COM-initialized thread.
  138. --*/
  139. {
  140. HRESULT hr;
  141. IHNetCfgMgr *pCfgMgr = NULL;
  142. IEnumHNetPortMappingBindings *pEnumBindings;
  143. IHNetIcsSettings *pIcsSettings;
  144. PNAT_DHCP_RESERVATION pReservation;
  145. ULONG ulCount;
  146. hr = NhGetHNetCfgMgr(&pCfgMgr);
  147. if (SUCCEEDED(hr))
  148. {
  149. //
  150. // Get the ICS settings interface
  151. //
  152. hr = pCfgMgr->QueryInterface(
  153. IID_PPV_ARG(IHNetIcsSettings, &pIcsSettings)
  154. );
  155. }
  156. if (SUCCEEDED(hr))
  157. {
  158. //
  159. // Get DHCP scope information
  160. //
  161. hr = pIcsSettings->GetDhcpScopeSettings(
  162. &NhDhcpScopeAddress,
  163. &NhDhcpScopeMask
  164. );
  165. //
  166. // Get enumeration of DHCP reservered addresses
  167. //
  168. if (SUCCEEDED(hr))
  169. {
  170. hr = pIcsSettings->EnumDhcpReservedAddresses(&pEnumBindings);
  171. }
  172. pIcsSettings->Release();
  173. }
  174. if (SUCCEEDED(hr))
  175. {
  176. //
  177. // Process the items in the enum
  178. //
  179. do
  180. {
  181. IHNetPortMappingBinding *pBinding;
  182. hr = pEnumBindings->Next(1, &pBinding, &ulCount);
  183. if (SUCCEEDED(hr) && 1 == ulCount)
  184. {
  185. //
  186. // Allocate a new reservation entry
  187. //
  188. pReservation = reinterpret_cast<PNAT_DHCP_RESERVATION>(
  189. NH_ALLOCATE(sizeof(*pReservation))
  190. );
  191. if (NULL != pReservation)
  192. {
  193. ZeroMemory(pReservation, sizeof(*pReservation));
  194. //
  195. // Get computer name
  196. //
  197. hr = pBinding->GetTargetComputerName(
  198. &pReservation->Name
  199. );
  200. if (SUCCEEDED(hr))
  201. {
  202. //
  203. // Get reserved address
  204. //
  205. hr = pBinding->GetTargetComputerAddress(
  206. &pReservation->Address
  207. );
  208. }
  209. if (SUCCEEDED(hr))
  210. {
  211. //
  212. // Add entry to list
  213. //
  214. InsertTailList(
  215. &NhDhcpReservationList,
  216. &pReservation->Link)
  217. ;
  218. }
  219. else
  220. {
  221. //
  222. // Free entry
  223. //
  224. NH_FREE(pReservation);
  225. }
  226. }
  227. else
  228. {
  229. hr = E_OUTOFMEMORY;
  230. }
  231. pBinding->Release();
  232. }
  233. } while (SUCCEEDED(hr) && 1 == ulCount);
  234. pEnumBindings->Release();
  235. }
  236. if (NULL != pCfgMgr)
  237. {
  238. pCfgMgr->Release();
  239. }
  240. } // NhBuildDhcpReservations
  241. ULONG
  242. NhDialSharedConnection(
  243. VOID
  244. )
  245. /*++
  246. Routine Description:
  247. This routine is invoked to connect a home-router interface.
  248. The connection is established by invoking the RAS autodial process
  249. with the appropriate phonebook and entry-name in the security context
  250. of the logged-on user.
  251. Arguments:
  252. none.
  253. Return Value:
  254. ULONG - Win32 status code.
  255. --*/
  256. {
  257. return RasAutoDialSharedConnection();
  258. } // NhDialSharedConnection
  259. VOID
  260. NhFreeApplicationSettings(
  261. VOID
  262. )
  263. /*++
  264. Routine Description:
  265. Frees the list of application settings
  266. Arguments:
  267. none.
  268. Return Value:
  269. None.
  270. Environment:
  271. Invoked with NhLock held.
  272. --*/
  273. {
  274. PLIST_ENTRY Link;
  275. PNAT_APP_ENTRY pAppEntry;
  276. PROFILE("NhFreeApplicationSettings");
  277. while (!IsListEmpty(&NhApplicationSettingsList))
  278. {
  279. Link = RemoveHeadList(&NhApplicationSettingsList);
  280. pAppEntry = CONTAINING_RECORD(Link, NAT_APP_ENTRY, Link);
  281. CoTaskMemFree(pAppEntry->ResponseArray);
  282. NH_FREE(pAppEntry);
  283. }
  284. } // NhFreeApplicationSettings
  285. VOID
  286. NhFreeDhcpReservations(
  287. VOID
  288. )
  289. /*++
  290. Routine Description:
  291. Frees the list of DHCP reservations
  292. Arguments:
  293. none.
  294. Return Value:
  295. None.
  296. Environment:
  297. Invoked with NhLock held.
  298. --*/
  299. {
  300. PLIST_ENTRY Link;
  301. PNAT_DHCP_RESERVATION pReservation;
  302. PROFILE("NhFreeDhcpReservations");
  303. while (!IsListEmpty(&NhDhcpReservationList))
  304. {
  305. Link = RemoveHeadList(&NhDhcpReservationList);
  306. pReservation = CONTAINING_RECORD(Link, NAT_DHCP_RESERVATION, Link);
  307. CoTaskMemFree(pReservation->Name);
  308. NH_FREE(pReservation);
  309. }
  310. } // NhFreeDhcpReservations
  311. BOOLEAN
  312. NhIsDnsProxyEnabled(
  313. VOID
  314. )
  315. /*++
  316. Routine Description:
  317. This routine is invoked to discover whether the DNS proxy is enabled.
  318. Arguments:
  319. none.
  320. Return Value:
  321. BOOLEAN - TRUE if DNS proxy is enabled, FALSE otherwise
  322. Environment:
  323. Invoked from an arbitrary context.
  324. --*/
  325. {
  326. PROFILE("NhIsDnsProxyEnabled");
  327. return DnsIsDnsEnabled();
  328. } // NhIsDnsProxyEnabled
  329. BOOLEAN
  330. NhIsLocalAddress(
  331. ULONG Address
  332. )
  333. /*++
  334. Routine Description:
  335. This routine is invoked to determine whether the given IP address
  336. is for a local interface.
  337. Arguments:
  338. Address - the IP address to find
  339. Return Value:
  340. BOOLEAN - TRUE if the address is found, FALSE otherwise
  341. --*/
  342. {
  343. ULONG Error;
  344. ULONG i;
  345. PMIB_IPADDRTABLE Table;
  346. Error =
  347. AllocateAndGetIpAddrTableFromStack(
  348. &Table, FALSE, GetProcessHeap(), 0
  349. );
  350. if (Error) {
  351. NhTrace(
  352. TRACE_FLAG_IF,
  353. "NhIsLocalAddress: GetIpAddrTableFromStack=%d", Error
  354. );
  355. return FALSE;
  356. }
  357. for (i = 0; i < Table->dwNumEntries; i++) {
  358. if (Table->table[i].dwAddr == Address) {
  359. HeapFree(GetProcessHeap(), 0, Table);
  360. return TRUE;
  361. }
  362. }
  363. HeapFree(GetProcessHeap(), 0, Table);
  364. return FALSE;
  365. } // NhIsLocalAddress
  366. BOOLEAN
  367. NhIsWinsProxyEnabled(
  368. VOID
  369. )
  370. /*++
  371. Routine Description:
  372. This routine is invoked to discover whether the WINS proxy is enabled.
  373. Arguments:
  374. none.
  375. Return Value:
  376. BOOLEAN - TRUE if WINS proxy is enabled, FALSE otherwise
  377. Environment:
  378. Invoked from an arbitrary context.
  379. --*/
  380. {
  381. PROFILE("NhIsWinsProxyEnabled");
  382. return DnsIsWinsEnabled();
  383. } // NhIsWinsProxyEnabled
  384. PIP_ADAPTER_BINDING_INFO
  385. NhQueryBindingInformation(
  386. ULONG AdapterIndex
  387. )
  388. /*++
  389. Routine Description:
  390. This routine is called to obtain the binding information
  391. for the adapter with the given index.
  392. It does this by obtaining a table of IP addresses from the stack,
  393. and determining which addresses correspond to the given index.
  394. Arguments:
  395. AdapterIndex - the adapter for which binding information is required
  396. Return Value:
  397. PIP_ADAPTER_BINDING_INFO - the allocated binding information
  398. --*/
  399. {
  400. PIP_ADAPTER_BINDING_INFO BindingInfo = NULL;
  401. ULONG Count = 0;
  402. ULONG i;
  403. PMIB_IPADDRTABLE Table;
  404. if (AllocateAndGetIpAddrTableFromStack(
  405. &Table, FALSE, GetProcessHeap(), 0
  406. ) == NO_ERROR) {
  407. //
  408. // Count the adapter's addresses
  409. //
  410. for (i = 0; i < Table->dwNumEntries; i++) {
  411. if (Table->table[i].dwIndex == AdapterIndex) { ++Count; }
  412. }
  413. //
  414. // Allocate space for the binding info
  415. //
  416. BindingInfo = reinterpret_cast<PIP_ADAPTER_BINDING_INFO>(
  417. NH_ALLOCATE(SIZEOF_IP_BINDING(Count))
  418. );
  419. if (BindingInfo) {
  420. //
  421. // Fill in the binding info
  422. //
  423. BindingInfo->AddressCount = Count;
  424. BindingInfo->RemoteAddress = 0;
  425. Count = 0;
  426. for (i = 0; i < Table->dwNumEntries; i++) {
  427. if (Table->table[i].dwIndex != AdapterIndex) { continue; }
  428. BindingInfo->Address[Count].Address = Table->table[i].dwAddr;
  429. BindingInfo->Address[Count].Mask = Table->table[i].dwMask;
  430. ++Count;
  431. }
  432. }
  433. HeapFree(GetProcessHeap(), 0, Table);
  434. }
  435. return BindingInfo;
  436. } // NhQueryBindingInformation
  437. NTSTATUS
  438. NhQueryDomainName(
  439. PCHAR* DomainName
  440. )
  441. /*++
  442. Routine Description:
  443. This routine is invoked to obtain the local domain name.
  444. Arguments:
  445. DomainName - receives the allocated string containing the domain name
  446. Return Value:
  447. NTSTATUS - NT status code.
  448. Environment:
  449. Invoked from an arbitrary context.
  450. --*/
  451. {
  452. PKEY_VALUE_PARTIAL_INFORMATION Information;
  453. IO_STATUS_BLOCK IoStatus;
  454. HANDLE Key;
  455. ULONG Length;
  456. OBJECT_ATTRIBUTES ObjectAttributes;
  457. NTSTATUS status;
  458. UNICODE_STRING UnicodeString;
  459. PROFILE("NhQueryDomainName");
  460. *DomainName = NULL;
  461. RtlInitUnicodeString(&UnicodeString, NhTcpipParametersString);
  462. InitializeObjectAttributes(
  463. &ObjectAttributes,
  464. &UnicodeString,
  465. OBJ_CASE_INSENSITIVE,
  466. NULL,
  467. NULL
  468. );
  469. //
  470. // Open the 'Tcpip' registry key
  471. //
  472. status =
  473. NtOpenKey(
  474. &Key,
  475. KEY_ALL_ACCESS,
  476. &ObjectAttributes
  477. );
  478. if (!NT_SUCCESS(status)) {
  479. NhTrace(
  480. TRACE_FLAG_REG,
  481. "NhQueryDomainName: error %x opening registry key",
  482. status
  483. );
  484. return status;
  485. }
  486. //
  487. // Read the 'Domain' value
  488. //
  489. status =
  490. NhQueryValueKey(
  491. Key,
  492. NhpDomainString,
  493. &Information
  494. );
  495. if (!NT_SUCCESS(status)) {
  496. status =
  497. NhQueryValueKey(
  498. Key,
  499. NhpDhcpDomainString,
  500. &Information
  501. );
  502. }
  503. NtClose(Key);
  504. if (!NT_SUCCESS(status)) {
  505. NhTrace(
  506. TRACE_FLAG_REG,
  507. "NhQueryDomainName: error %x querying domain name",
  508. status
  509. );
  510. return status;
  511. }
  512. if (REG_SZ != Information->Type
  513. || L'\0' != *(PWCHAR) (Information->Data +
  514. (Information->DataLength - sizeof(WCHAR)))) {
  515. NH_FREE(Information);
  516. NhTrace(
  517. TRACE_FLAG_REG,
  518. "NhQueryDomainName: Registry contains invalid data"
  519. );
  520. return STATUS_UNSUCCESSFUL;
  521. }
  522. //
  523. // Copy the domain name
  524. //
  525. Length = lstrlenW((PWCHAR)Information->Data) + 1;
  526. *DomainName = reinterpret_cast<PCHAR>(NH_ALLOCATE(Length));
  527. if (!*DomainName) {
  528. NH_FREE(Information);
  529. NhTrace(
  530. TRACE_FLAG_REG,
  531. "NhQueryDomainName: error allocating domain name"
  532. );
  533. return STATUS_NO_MEMORY;
  534. }
  535. status =
  536. RtlUnicodeToMultiByteN(
  537. *DomainName,
  538. Length,
  539. NULL,
  540. (PWCHAR)Information->Data,
  541. Length * sizeof(WCHAR)
  542. );
  543. NH_FREE(Information);
  544. return status;
  545. } // NhQueryDomainName
  546. ULONG
  547. NhQueryHostByName(
  548. PWCHAR pszHostName,
  549. PWCHAR pszDomainName,
  550. ULONG ScopeNetwork,
  551. ULONG ScopeMask
  552. )
  553. /*++
  554. Routine Description:
  555. This is a helper routine. It queries the local DNS Client (resident resolver)
  556. to see if it already knows the IP address of the desired hostname. This
  557. may have happened by our DHCP module adding it to the hosts.ics file.
  558. Arguments:
  559. Pointer to the host name and domain suffix name. Scope net and mask.
  560. Return Value:
  561. IP address of the host; if we dont find it we return 0.
  562. Environment:
  563. Invoked from an arbitrary context.
  564. --*/
  565. {
  566. ULONG retIP = 0;
  567. PWCHAR pszFQDN = NULL;
  568. DNS_STATUS dnsStatus;
  569. PDNS_RECORD pQueryResultsSet = NULL;
  570. DWORD dwQueryOptions, dwSize;
  571. if (!pszHostName ||
  572. !pszDomainName ||
  573. !*pszHostName ||
  574. !*pszDomainName)
  575. {
  576. return 0;
  577. }
  578. //
  579. // create a FQDN hostname
  580. // total length = hostname length + dot length + domainname length + null
  581. //
  582. dwSize = wcslen(pszHostName) + 1 + wcslen(pszDomainName) + 1;
  583. pszFQDN = reinterpret_cast<PWCHAR>(NH_ALLOCATE(sizeof(WCHAR) * dwSize));
  584. if (!pszFQDN)
  585. {
  586. NhTrace(
  587. TRACE_FLAG_DNS,
  588. "NhQueryHostByName: allocation failed for client name"
  589. );
  590. return 0;
  591. }
  592. ZeroMemory(pszFQDN, (sizeof(WCHAR) * dwSize));
  593. wcscpy(pszFQDN, pszHostName); // copy the hostname
  594. wcscat(pszFQDN, L"."); // add the dot
  595. wcscat(pszFQDN, pszDomainName); // add the suffix
  596. dwQueryOptions =
  597. (
  598. DNS_QUERY_STANDARD |
  599. DNS_QUERY_CACHE_ONLY |
  600. DNS_QUERY_TREAT_AS_FQDN
  601. );
  602. dnsStatus = DnsQuery_W(
  603. (PWSTR) pszFQDN,
  604. DNS_TYPE_A,
  605. dwQueryOptions,
  606. NULL,
  607. &pQueryResultsSet,
  608. NULL
  609. );
  610. if ((NO_ERROR == dnsStatus) && (pQueryResultsSet))
  611. {
  612. PDNS_RECORD pRR = pQueryResultsSet;
  613. while (pRR)
  614. {
  615. if (pRR->Flags.S.Section == DNSREC_ANSWER &&
  616. pRR->wType == DNS_TYPE_A)
  617. {
  618. if (((pRR->Data.A.IpAddress & ~ScopeMask) != 0) &&
  619. ((pRR->Data.A.IpAddress & ~ScopeMask) != ~ScopeMask) &&
  620. ((pRR->Data.A.IpAddress & ScopeMask) == ScopeNetwork))
  621. {
  622. retIP = pRR->Data.A.IpAddress;
  623. break;
  624. }
  625. }
  626. pRR = pRR->pNext;
  627. }
  628. }
  629. if (pQueryResultsSet)
  630. {
  631. DnsRecordListFree(
  632. pQueryResultsSet,
  633. DnsFreeRecordListDeep
  634. );
  635. }
  636. if (pszFQDN)
  637. {
  638. NH_FREE(pszFQDN);
  639. }
  640. return retIP;
  641. } // NhQueryHostByName
  642. NTSTATUS
  643. NhQueryICSDomainSuffix(
  644. PWCHAR *ppszDomain
  645. )
  646. /*++
  647. Routine Description:
  648. This is a helper routine. It queries the registry to see if there
  649. is a setting for the ICSDomain string - if not, it returns the default
  650. suffix used for ICS.
  651. Arguments:
  652. Pointer to a suffix string. Caller MUST release using NH_FREE.
  653. Return Value:
  654. NTSTATUS - NT status code.
  655. Environment:
  656. Invoked from an arbitrary context.
  657. --*/
  658. {
  659. NTSTATUS status;
  660. PKEY_VALUE_PARTIAL_INFORMATION Information;
  661. IO_STATUS_BLOCK IoStatus;
  662. HANDLE Key;
  663. ULONG Length;
  664. OBJECT_ATTRIBUTES ObjectAttributes;
  665. UNICODE_STRING UnicodeString;
  666. if (!ppszDomain)
  667. {
  668. NhTrace(
  669. TRACE_FLAG_REG,
  670. "NhQueryICSDomainSuffix: invalid (null pointer) parameter"
  671. );
  672. return STATUS_INVALID_PARAMETER;
  673. }
  674. *ppszDomain = NULL;
  675. //
  676. // retrieve current suffix string (if any)
  677. //
  678. RtlInitUnicodeString(&UnicodeString, NhTcpipParametersString);
  679. InitializeObjectAttributes(
  680. &ObjectAttributes,
  681. &UnicodeString,
  682. OBJ_CASE_INSENSITIVE,
  683. NULL,
  684. NULL
  685. );
  686. //
  687. // Open the 'Tcpip' registry key
  688. //
  689. status =
  690. NtOpenKey(
  691. &Key,
  692. KEY_READ,
  693. &ObjectAttributes
  694. );
  695. if (!NT_SUCCESS(status)) {
  696. NhTrace(
  697. TRACE_FLAG_REG,
  698. "NhQueryICSDomainSuffix: error %x opening registry key",
  699. status
  700. );
  701. return status;
  702. }
  703. //
  704. // Read the 'Domain' value
  705. //
  706. status =
  707. NhQueryValueKey(
  708. Key,
  709. NhpICSDomainString,
  710. &Information
  711. );
  712. NtClose(Key);
  713. if (!NT_SUCCESS(status) || !Information) {
  714. NhTrace(
  715. TRACE_FLAG_REG,
  716. "NhQueryICSDomainSuffix: error %x querying ICSDomain name - "
  717. "using default instead",
  718. status
  719. );
  720. //
  721. // Copy default domain name instead
  722. //
  723. Length = wcslen(DNS_HOMENET_SUFFIX) + 1;
  724. *ppszDomain = reinterpret_cast<PWCHAR>(
  725. NH_ALLOCATE(sizeof(WCHAR) * Length)
  726. );
  727. if (!*ppszDomain) {
  728. NhTrace(
  729. TRACE_FLAG_REG,
  730. "NhQueryICSDomainSuffix: error allocating domain name"
  731. );
  732. return STATUS_NO_MEMORY;
  733. }
  734. wcscpy(*ppszDomain, DNS_HOMENET_SUFFIX);
  735. }
  736. else
  737. {
  738. if (REG_SZ != Information->Type
  739. || L'\0' != *(PWCHAR) (Information->Data +
  740. (Information->DataLength - sizeof(WCHAR)))) {
  741. NH_FREE(Information);
  742. NhTrace(
  743. TRACE_FLAG_REG,
  744. "NhQueryICSDomainSuffix: Registry contains invalid data"
  745. );
  746. return STATUS_UNSUCCESSFUL;
  747. }
  748. //
  749. // Copy the domain name
  750. //
  751. Length = wcslen((PWCHAR)Information->Data) + 1;
  752. *ppszDomain = reinterpret_cast<PWCHAR>(
  753. NH_ALLOCATE(sizeof(WCHAR) * Length)
  754. );
  755. if (!*ppszDomain) {
  756. NH_FREE(Information);
  757. NhTrace(
  758. TRACE_FLAG_REG,
  759. "NhQueryICSDomainSuffix: error allocating domain name"
  760. );
  761. return STATUS_NO_MEMORY;
  762. }
  763. wcscpy(*ppszDomain, (PWCHAR)Information->Data);
  764. NH_FREE(Information);
  765. }
  766. return STATUS_SUCCESS;
  767. } // NhQueryICSDomainSuffix
  768. NTSTATUS
  769. NhQueryValueKey(
  770. HANDLE Key,
  771. const WCHAR ValueName[],
  772. PKEY_VALUE_PARTIAL_INFORMATION* Information
  773. )
  774. /*++
  775. Routine Description:
  776. This routine is called to obtain the value of a registry key.
  777. Arguments:
  778. Key - the key to be queried
  779. ValueName - the value to be queried
  780. Information - receives a pointer to the information read
  781. Return Value:
  782. NTSTATUS - NT status code.
  783. --*/
  784. {
  785. UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
  786. ULONG InformationLength;
  787. NTSTATUS status;
  788. UNICODE_STRING UnicodeString;
  789. PROFILE("NhQueryValueKey");
  790. RtlInitUnicodeString(&UnicodeString, ValueName);
  791. *Information = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
  792. InformationLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  793. //
  794. // Read the value's size
  795. //
  796. status =
  797. NtQueryValueKey(
  798. Key,
  799. &UnicodeString,
  800. KeyValuePartialInformation,
  801. *Information,
  802. InformationLength,
  803. &InformationLength
  804. );
  805. if (!NT_SUCCESS(status) &&
  806. status != STATUS_BUFFER_OVERFLOW &&
  807. status != STATUS_BUFFER_TOO_SMALL
  808. ) {
  809. NhTrace(
  810. TRACE_FLAG_REG,
  811. "NhQueryValueKey: status %08x obtaining value size",
  812. status
  813. );
  814. *Information = NULL;
  815. return status;
  816. }
  817. //
  818. // Allocate space for the value's size
  819. //
  820. *Information =
  821. (PKEY_VALUE_PARTIAL_INFORMATION)NH_ALLOCATE(InformationLength + 2);
  822. if (!*Information) {
  823. NhTrace(
  824. TRACE_FLAG_REG,
  825. "NhQueryValueKey: error allocating %d bytes",
  826. InformationLength + 2
  827. );
  828. return STATUS_NO_MEMORY;
  829. }
  830. //
  831. // Read the value's data
  832. //
  833. status =
  834. NtQueryValueKey(
  835. Key,
  836. &UnicodeString,
  837. KeyValuePartialInformation,
  838. *Information,
  839. InformationLength,
  840. &InformationLength
  841. );
  842. if (!NT_SUCCESS(status)) {
  843. NhTrace(
  844. TRACE_FLAG_REG,
  845. "NhQueryValueKey: status %08x obtaining value data",
  846. status
  847. );
  848. NH_FREE(*Information);
  849. *Information = NULL;
  850. }
  851. return status;
  852. } // NhQueryValueKey
  853. ULONG
  854. NhMapAddressToAdapter(
  855. ULONG Address
  856. )
  857. /*++
  858. Routine Description:
  859. This routine is invoked to map an IP address to an adapter index.
  860. It does so by obtaining the stack's address-table, which contains
  861. valid adapter-indices rather than IP router-manager indices.
  862. This table is then used to obtain the IP address's adapter-index.
  863. Arguments:
  864. Address - the local address for which an adapter-index is required
  865. Return Value:
  866. ULONG - adapter index.
  867. --*/
  868. {
  869. ULONG AdapterIndex = (ULONG)-1;
  870. ULONG i;
  871. PMIB_IPADDRTABLE Table;
  872. PROFILE("NhMapAddressToAdapter");
  873. if (AllocateAndGetIpAddrTableFromStack(
  874. &Table, FALSE, GetProcessHeap(), 0
  875. ) == NO_ERROR) {
  876. for (i = 0; i < Table->dwNumEntries; i++) {
  877. if (Table->table[i].dwAddr != Address) { continue; }
  878. AdapterIndex = Table->table[i].dwIndex;
  879. break;
  880. }
  881. HeapFree(GetProcessHeap(), 0, Table);
  882. }
  883. return AdapterIndex;
  884. } // NhMapAddressToAdapter
  885. ULONG
  886. NhMapInterfaceToAdapter(
  887. ULONG Index
  888. )
  889. /*++
  890. Routine Description:
  891. This routine is invoked to map an interface to an adapter index.
  892. It does so by invoking the appropriate IP router-manager entry-point.
  893. Arguments:
  894. Index - the index of the interface to be mapped
  895. Return Value:
  896. ULONG - adapter index.
  897. --*/
  898. {
  899. MAPINTERFACETOADAPTER FarProc;
  900. PROFILE("NhMapInterfaceToAdapter");
  901. EnterCriticalSection(&NhLock);
  902. if (!NhpRtrmgrDll) { NhpRtrmgrDll = LoadLibraryA("IPRTRMGR.DLL"); }
  903. LeaveCriticalSection(&NhLock);
  904. if (!NhpRtrmgrDll) { return (ULONG)-1; }
  905. FarProc = (MAPINTERFACETOADAPTER)GetProcAddress(NhpRtrmgrDll, "MapInterfaceToAdapter");
  906. return (ULONG)(FarProc ? (*FarProc)(Index) : -1);
  907. } // NhMapInterfaceToAdapter
  908. VOID
  909. NhResetComponentMode(
  910. VOID
  911. )
  912. /*++
  913. Routine Description:
  914. This routine relinquishes control of the kernel-mode translation module,
  915. and returns this module to an uninitialized state.
  916. Arguments:
  917. none.
  918. Return Value:
  919. none.
  920. --*/
  921. {
  922. EnterCriticalSection(&NhLock);
  923. if (NhpComponentEvent) {
  924. CloseHandle(NhpComponentEvent); NhpComponentEvent = NULL;
  925. }
  926. if (INVALID_HANDLE_VALUE != NhFileHandle) {
  927. NatUnloadDriver(NhFileHandle); NhFileHandle = INVALID_HANDLE_VALUE;
  928. }
  929. NhComponentMode = NhUninitializedMode;
  930. LeaveCriticalSection(&NhLock);
  931. } // NhResetComponentMode
  932. BOOLEAN
  933. NhSetComponentMode(
  934. NH_COMPONENT_MODE ComponentMode
  935. )
  936. /*++
  937. Routine Description:
  938. This routine is invoked to atomically set the module into a particular mode
  939. in order to prevent conflict between shared-access and connection-sharing,
  940. both of which are implemented in this module, and both of which run
  941. in the 'netsvcs' instance of SVCHOST.EXE.
  942. In setting either mode, the routine first determines whether it is already
  943. executing in the alternate mode, in which case it fails.
  944. Otherwise, it attempts to open a handle to ipnat.sys to claim exclusive
  945. control of the kernel-mode translation module. The kernel-mode translation
  946. module enforces exclusive ownership -- it will fail the open w/
  947. ERROR_ACCESS_DENIED if another process has claimed control of the driver.
  948. Otherwise, the kernel-mode translation module is claimed for this module
  949. and the module is set into the required mode.
  950. This routine will also attempt to create a named event. This event
  951. was previously used to enforce exclusive ownership in the past, when
  952. the driver was unable to do so. We will not fail if the event already
  953. exists (or if we are unable to create it). We still create the event,
  954. though, so that other modules that choose to use this mechanism will
  955. still be able to correctly report the cause of the error.
  956. Arguments:
  957. ComponentMode - the mode into which the module is to be set.
  958. Return Value:
  959. BOOLEAN - TRUE if successful, FALSE if the module could not be set
  960. or if the kernel-mode translation module has already been claimed.
  961. --*/
  962. {
  963. EnterCriticalSection(&NhLock);
  964. if (NhUninitializedMode != NhComponentMode
  965. && NhComponentMode != ComponentMode) {
  966. //
  967. // The module has been set to a different mode.
  968. //
  969. LeaveCriticalSection(&NhLock);
  970. NhStartEventLog();
  971. NhErrorLog(
  972. (ComponentMode == NhRoutingProtocolMode)
  973. ? IP_NAT_LOG_ROUTING_PROTOCOL_CONFLICT
  974. : IP_NAT_LOG_SHARED_ACCESS_CONFLICT,
  975. 0,
  976. ""
  977. );
  978. NhStopEventLog();
  979. return FALSE;
  980. }
  981. //
  982. // Attempt to load and open a handle to the NAT driver, if we have not
  983. // already done so. This is needed to detect if another process has already
  984. // taken control of the driver.
  985. //
  986. if (INVALID_HANDLE_VALUE == NhFileHandle) {
  987. ULONG Error;
  988. IP_NAT_GLOBAL_INFO GlobalInfo;
  989. ZeroMemory(&GlobalInfo, sizeof(GlobalInfo));
  990. GlobalInfo.Header.Version = IP_NAT_VERSION;
  991. GlobalInfo.Header.Size = FIELD_OFFSET(RTR_INFO_BLOCK_HEADER, TocEntry);
  992. Error = NatLoadDriver(&NhFileHandle, &GlobalInfo);
  993. if (ERROR_ACCESS_DENIED == Error) {
  994. //
  995. // An access denied error signifies a conflict.
  996. //
  997. NhFileHandle = INVALID_HANDLE_VALUE;
  998. LeaveCriticalSection(&NhLock);
  999. NhStartEventLog();
  1000. NhErrorLog(
  1001. (ComponentMode == NhRoutingProtocolMode)
  1002. ? IP_NAT_LOG_ROUTING_PROTOCOL_CONFLICT
  1003. : IP_NAT_LOG_SHARED_ACCESS_CONFLICT,
  1004. 0,
  1005. ""
  1006. );
  1007. NhStopEventLog();
  1008. return FALSE;
  1009. } else if (NO_ERROR != Error) {
  1010. //
  1011. // We weren't able to load the driver for some other reason.
  1012. //
  1013. NhFileHandle = INVALID_HANDLE_VALUE;
  1014. LeaveCriticalSection(&NhLock);
  1015. NhStartEventLog();
  1016. NhErrorLog(
  1017. IP_NAT_LOG_LOAD_DRIVER_FAILED,
  1018. Error,
  1019. ""
  1020. );
  1021. NhStopEventLog();
  1022. return FALSE;
  1023. }
  1024. }
  1025. if (NULL == NhpComponentEvent) {
  1026. NhpComponentEvent =
  1027. CreateEventA(NULL, FALSE, FALSE, IP_NAT_SERVICE_NAME);
  1028. //
  1029. // We will continue executing even if we are not able to create
  1030. // the named event, or if the event already exists. This is mainly
  1031. // for other users of the NAT who follow the old access control
  1032. // system, instead of letting the driver enforce single-ownership
  1033. // requirements.
  1034. //
  1035. }
  1036. NhComponentMode = ComponentMode;
  1037. LeaveCriticalSection(&NhLock);
  1038. return TRUE;
  1039. } // NhSetComponentMode
  1040. VOID
  1041. NhSignalNatInterface(
  1042. ULONG Index,
  1043. BOOLEAN Boundary
  1044. )
  1045. /*++
  1046. Routine Description:
  1047. This routine is invoked upon reconfiguration of a NAT interface.
  1048. It invokes the reconfiguration for the DHCP allocator and DNS proxy,
  1049. neither of which are expected to operate on a NAT boundary interface.
  1050. This notification gives either (or both) an opportunity to deactivate
  1051. itself on NAT interfaces or reactivate itself on non-NAT interfaces.
  1052. Arguments:
  1053. Index - the interface whose configuration has changed
  1054. Boundary - indicates whether the interface is now a boundary interface
  1055. Return Value:
  1056. none.
  1057. Environment:
  1058. Invoked from an arbitrary context.
  1059. --*/
  1060. {
  1061. PROFILE("NhSignalNatInterface");
  1062. //
  1063. // Attempt to obtain the corresponding DHCP and DNS interfaces.
  1064. // It is important that this works regardless of whether DHCP allocation,
  1065. // DNS proxying or DirectPlay transparent proxying is enabled;
  1066. // the interface lists are initialized minimally in 'DllMain' above.
  1067. //
  1068. DhcpSignalNatInterface(Index, Boundary);
  1069. DnsSignalNatInterface(Index, Boundary);
  1070. AlgSignalNatInterface(Index, Boundary);
  1071. H323SignalNatInterface(Index, Boundary);
  1072. } // NhSignalNatInterface
  1073. VOID
  1074. NhUpdateApplicationSettings(
  1075. VOID
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. This routine is invoked to (re)load the advanced application settings.
  1080. Arguments:
  1081. none.
  1082. Return Value:
  1083. none.
  1084. --*/
  1085. {
  1086. HRESULT hr;
  1087. PNAT_APP_ENTRY pAppEntry;
  1088. IHNetCfgMgr *pCfgMgr = NULL;
  1089. IHNetProtocolSettings *pProtocolSettings;
  1090. IEnumHNetApplicationProtocols *pEnumApps;
  1091. BOOLEAN ComInitialized = FALSE;
  1092. ULONG ulCount;
  1093. PROFILE("NhUpdateApplicationSettings");
  1094. EnterCriticalSection(&NhLock);
  1095. //
  1096. // Free old settings list
  1097. //
  1098. NhFreeApplicationSettings();
  1099. //
  1100. // Free DHCP reservation list
  1101. //
  1102. NhFreeDhcpReservations();
  1103. //
  1104. // Make sure COM is initialized on this thread
  1105. //
  1106. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE );
  1107. if (SUCCEEDED(hr))
  1108. {
  1109. ComInitialized = TRUE;
  1110. }
  1111. else if (RPC_E_CHANGED_MODE == hr)
  1112. {
  1113. hr = S_OK;
  1114. }
  1115. if (SUCCEEDED(hr))
  1116. {
  1117. //
  1118. // Get the IHNetCfgMgr pointer out of the GIT
  1119. //
  1120. hr = NhGetHNetCfgMgr(&pCfgMgr);
  1121. }
  1122. if (SUCCEEDED(hr))
  1123. {
  1124. //
  1125. // Get the IHNetProtocolSettings interface
  1126. //
  1127. hr = pCfgMgr->QueryInterface(
  1128. IID_PPV_ARG(IHNetProtocolSettings, &pProtocolSettings)
  1129. );
  1130. }
  1131. if (SUCCEEDED(hr))
  1132. {
  1133. //
  1134. // Get the enumeration of enabled application protocols
  1135. //
  1136. hr = pProtocolSettings->EnumApplicationProtocols(TRUE, &pEnumApps);
  1137. pProtocolSettings->Release();
  1138. }
  1139. if (SUCCEEDED(hr))
  1140. {
  1141. //
  1142. // Process the items in the enum
  1143. //
  1144. do
  1145. {
  1146. IHNetApplicationProtocol *pAppProtocol;
  1147. hr = pEnumApps->Next(1, &pAppProtocol, &ulCount);
  1148. if (SUCCEEDED(hr) && 1 == ulCount)
  1149. {
  1150. //
  1151. // Allocate a new app entry
  1152. //
  1153. pAppEntry = reinterpret_cast<PNAT_APP_ENTRY>(
  1154. NH_ALLOCATE(sizeof(*pAppEntry))
  1155. );
  1156. if (NULL != pAppEntry)
  1157. {
  1158. ZeroMemory(pAppEntry, sizeof(*pAppEntry));
  1159. //
  1160. // Get protocol
  1161. //
  1162. hr = pAppProtocol->GetOutgoingIPProtocol(
  1163. &pAppEntry->Protocol
  1164. );
  1165. if (SUCCEEDED(hr))
  1166. {
  1167. //
  1168. // Get port
  1169. //
  1170. hr = pAppProtocol->GetOutgoingPort(
  1171. &pAppEntry->Port
  1172. );
  1173. }
  1174. if (SUCCEEDED(hr))
  1175. {
  1176. //
  1177. // Get responses
  1178. //
  1179. hr = pAppProtocol->GetResponseRanges(
  1180. &pAppEntry->ResponseCount,
  1181. &pAppEntry->ResponseArray
  1182. );
  1183. }
  1184. if (SUCCEEDED(hr))
  1185. {
  1186. //
  1187. // Add entry to list
  1188. //
  1189. InsertTailList(&NhApplicationSettingsList, &pAppEntry->Link);
  1190. }
  1191. else
  1192. {
  1193. //
  1194. // Free entry
  1195. //
  1196. NH_FREE(pAppEntry);
  1197. }
  1198. }
  1199. else
  1200. {
  1201. hr = E_OUTOFMEMORY;
  1202. }
  1203. pAppProtocol->Release();
  1204. }
  1205. } while (SUCCEEDED(hr) && 1 == ulCount);
  1206. pEnumApps->Release();
  1207. }
  1208. //
  1209. // Build the DHCP reservation list
  1210. //
  1211. NhBuildDhcpReservations();
  1212. LeaveCriticalSection(&NhLock);
  1213. //
  1214. // Free config manager
  1215. //
  1216. if (NULL != pCfgMgr)
  1217. {
  1218. pCfgMgr->Release();
  1219. }
  1220. //
  1221. // Uninitialize COM
  1222. //
  1223. if (TRUE == ComInitialized)
  1224. {
  1225. CoUninitialize();
  1226. }
  1227. } // NhUpdateApplicationSettings
  1228. ULONG
  1229. APIENTRY
  1230. RegisterProtocol(
  1231. IN OUT PMPR_ROUTING_CHARACTERISTICS RoutingCharacteristics,
  1232. IN OUT PMPR_SERVICE_CHARACTERISTICS ServiceCharacteristics
  1233. )
  1234. /*++
  1235. Routine Description:
  1236. This routine is invoked once for each protocol implemented in this module.
  1237. On each invocation, the supplied 'RoutingCharacteristics' indicates
  1238. the protocol to be registered in its 'dwProtocolId' field.
  1239. Arguments:
  1240. RoutingCharacteristics - on input, the protocol to be registered
  1241. and the router-manager's supported functionality.
  1242. ServiceCharacteristics - unused.
  1243. Return Value:
  1244. ULONG - status code.
  1245. --*/
  1246. {
  1247. if (RoutingCharacteristics->dwVersion < MS_ROUTER_VERSION) {
  1248. return ERROR_NOT_SUPPORTED;
  1249. }
  1250. if ((RoutingCharacteristics->fSupportedFunctionality &
  1251. (RF_ROUTING|RF_ADD_ALL_INTERFACES)) !=
  1252. (RF_ROUTING|RF_ADD_ALL_INTERFACES)) {
  1253. return ERROR_NOT_SUPPORTED;
  1254. }
  1255. switch (RoutingCharacteristics->dwProtocolId) {
  1256. case MS_IP_NAT: {
  1257. //
  1258. // Attempt to set the component into 'Connection Sharing' mode.
  1259. // This module implements both shared-access and connection-sharing
  1260. // which are mutually exclusive, so we need to ensure that
  1261. // shared-access is not operational before proceeding.
  1262. //
  1263. if (!NhSetComponentMode(NhRoutingProtocolMode)) {
  1264. return ERROR_CAN_NOT_COMPLETE;
  1265. }
  1266. CopyMemory(
  1267. RoutingCharacteristics,
  1268. &NatRoutingCharacteristics,
  1269. sizeof(NatRoutingCharacteristics)
  1270. );
  1271. RoutingCharacteristics->fSupportedFunctionality = RF_ROUTING;
  1272. break;
  1273. }
  1274. case MS_IP_DNS_PROXY: {
  1275. CopyMemory(
  1276. RoutingCharacteristics,
  1277. &DnsRoutingCharacteristics,
  1278. sizeof(DnsRoutingCharacteristics)
  1279. );
  1280. RoutingCharacteristics->fSupportedFunctionality =
  1281. (RF_ROUTING|RF_ADD_ALL_INTERFACES);
  1282. break;
  1283. }
  1284. case MS_IP_DHCP_ALLOCATOR: {
  1285. CopyMemory(
  1286. RoutingCharacteristics,
  1287. &DhcpRoutingCharacteristics,
  1288. sizeof(DhcpRoutingCharacteristics)
  1289. );
  1290. RoutingCharacteristics->fSupportedFunctionality =
  1291. (RF_ROUTING|RF_ADD_ALL_INTERFACES);
  1292. break;
  1293. }
  1294. case MS_IP_ALG: {
  1295. CopyMemory(
  1296. RoutingCharacteristics,
  1297. &AlgRoutingCharacteristics,
  1298. sizeof(AlgRoutingCharacteristics)
  1299. );
  1300. RoutingCharacteristics->fSupportedFunctionality =
  1301. (RF_ROUTING|RF_ADD_ALL_INTERFACES);
  1302. break;
  1303. }
  1304. case MS_IP_H323: {
  1305. CopyMemory(
  1306. RoutingCharacteristics,
  1307. &H323RoutingCharacteristics,
  1308. sizeof(H323RoutingCharacteristics)
  1309. );
  1310. RoutingCharacteristics->fSupportedFunctionality =
  1311. (RF_ROUTING|RF_ADD_ALL_INTERFACES);
  1312. break;
  1313. }
  1314. default: {
  1315. return ERROR_NOT_SUPPORTED;
  1316. }
  1317. }
  1318. ServiceCharacteristics->mscMpr40ServiceChars.fSupportedFunctionality = 0;
  1319. return NO_ERROR;
  1320. } // RegisterProtocol