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.

3129 lines
80 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. sharing.c
  5. Abstract:
  6. This module contains code for routines which support connection sharing
  7. configuration.
  8. Connection sharing involves a public (internet) interface, ordinarily
  9. a dialup interface identified by phonebook/entry-name, as well as
  10. a private (home) interface, required to be a lan interface.
  11. On setting up connection sharing, the service is enabled if necessary,
  12. and the private lan interface is configured with static address 169.254.0.1
  13. via the TCP/IP 'SetAdapterIpAddress' API routine.
  14. The name of the shared connection is stored in the registry along with
  15. the GUID of the shared private LAN connection, under the registry key
  16. HKLM\Software\Microsoft\SharedAccess\Parameters.
  17. N.B. NT registry routines are used, to avoid the hit incurred by
  18. going through the Win32 server.
  19. Author:
  20. Abolade Gbadegesin (aboladeg) 22-Apr-1998
  21. Revision History:
  22. --*/
  23. #include "precomp.h"
  24. #pragma hdrstop
  25. #define _PNP_POWER_
  26. #include <ndispnp.h>
  27. #include <ntddip.h>
  28. #include <winsock2.h>
  29. #include <dhcpcapi.h>
  30. #include <netconp.h>
  31. #if 0
  32. //
  33. // Structure: CS_ADDRESS_INFORMATION
  34. //
  35. typedef struct _CS_ADDRESS_INFORMATION {
  36. PKEY_VALUE_PARTIAL_INFORMATION IPAddress;
  37. PKEY_VALUE_PARTIAL_INFORMATION SubnetMask;
  38. PKEY_VALUE_PARTIAL_INFORMATION DefaultGateway;
  39. PKEY_VALUE_PARTIAL_INFORMATION EnableDHCP;
  40. } CS_ADDRESS_INFORMATION, *PCS_ADDRESS_INFORMATION;
  41. //
  42. // DHCPCSVC.DLL import prototype
  43. //
  44. typedef DWORD
  45. (APIENTRY* PDHCPNOTIFYCONFIGCHANGE)(
  46. LPWSTR,
  47. LPWSTR,
  48. BOOL,
  49. DWORD,
  50. DWORD,
  51. DWORD,
  52. SERVICE_ENABLE
  53. );
  54. #endif
  55. //
  56. // OLE entrypoints loaded dynamically
  57. //
  58. PCOINITIALIZEEX g_pCoInitializeEx;
  59. PCOUNINITIALIZE g_pCoUninitialize;
  60. PCOCREATEINSTANCE g_pCoCreateInstance;
  61. PCOSETPROXYBLANKET g_pCoSetProxyBlanket;
  62. PCOTASKMEMFREE g_pCoTaskMemFree;
  63. //
  64. // CONSTANT DEFINITIONS
  65. //
  66. #if 0
  67. const CHAR c_szAllocateAndGetIpAddrTableFromStack[] =
  68. "AllocateAndGetIpAddrTableFromStack";
  69. #endif
  70. const CHAR c_szCoInitializeEx[] = "CoInitializeEx";
  71. const CHAR c_szCoUninitialize[] = "CoUninitialize";
  72. const CHAR c_szCoCreateInstance[] = "CoCreateInstance";
  73. const CHAR c_szCoSetProxyBlanket[] = "CoSetProxyBlanket";
  74. const CHAR c_szCoTaskMemFree[] = "CoTaskMemFree";
  75. #if 0
  76. const CHAR c_szDhcpNotifyConfigChange[] = "DhcpNotifyConfigChange";
  77. const CHAR c_szGetInterfaceInfo[] = "GetInterfaceInfo";
  78. #endif
  79. const CHAR c_szMprConfigBufferFree[] = "MprConfigBufferFree";
  80. const CHAR c_szMprConfigServerConnect[] = "MprConfigServerConnect";
  81. const CHAR c_szMprConfigServerDisconnect[] = "MprConfigServerDisconnect";
  82. const CHAR c_szMprConfigTransportGetHandle[] = "MprConfigTransportGetHandle";
  83. const CHAR c_szMprConfigTransportGetInfo[] = "MprConfigTransportGetInfo";
  84. const CHAR c_szMprInfoBlockFind[] = "MprInfoBlockFind";
  85. #if 0
  86. const CHAR c_szSetAdapterIpAddress[] = "SetAdapterIpAddress";
  87. #endif
  88. const TCHAR c_szSharedAccess[] = TEXT("SharedAccess");
  89. #if 0
  90. const WCHAR c_szBackupDefaultGateway[] = L"BackupDefaultGateway";
  91. const WCHAR c_szBackupEnableDHCP[] = L"BackupEnableDHCP";
  92. const WCHAR c_szBackupIPAddress[] = L"BackupIPAddress";
  93. const WCHAR c_szBackupSubnetMask[] = L"BackupSubnetMask";
  94. const WCHAR c_szDefaultGateway[] = L"DefaultGateway";
  95. const WCHAR c_szDevice[] = L"\\Device\\";
  96. const WCHAR c_szDhcpcsvcDll[] = L"DHCPCSVC.DLL";
  97. const WCHAR c_szEmpty[] = L"";
  98. const WCHAR c_szEnableDHCP[] = L"EnableDHCP";
  99. const WCHAR c_szInterfaces[] = L"Interfaces";
  100. const WCHAR c_szIPAddress[] = L"IPAddress";
  101. const WCHAR c_szIphlpapiDll[] = L"IPHLPAPI.DLL";
  102. #endif
  103. const WCHAR c_szMprapiDll[] = L"MPRAPI.DLL";
  104. const WCHAR c_szMsTcpip[] = L"MS_TCPIP";
  105. const WCHAR c_szOle32Dll[] = L"OLE32.DLL";
  106. #if 0
  107. const WCHAR c_szScopeAddress[] = L"ScopeAddress";
  108. const WCHAR c_szScopeMask[] = L"ScopeMask";
  109. #endif
  110. const WCHAR c_szSharedAccessParametersKey[] =
  111. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\SharedAccess"
  112. L"\\Parameters";
  113. #if 0
  114. const WCHAR c_szSharedConnection[] = L"SharedConnection";
  115. const WCHAR c_szSharedPrivateLan[] = L"SharedPrivateLan";
  116. const WCHAR c_szSubnetMask[] = L"SubnetMask";
  117. const WCHAR c_szTcpip[] = L"Tcpip";
  118. const WCHAR c_szTcpipParametersKey[] =
  119. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip"
  120. L"\\Parameters";
  121. const WCHAR c_szFirewallConnection[] = L"FirewallConnection";
  122. const WCHAR c_szFirewallConnectionCount[] = L"FirewallConnectionCount";
  123. #endif
  124. //
  125. // LOCAL VARIABLE DEFINITIONS
  126. //
  127. static BOOLEAN CsInitialized = FALSE;
  128. static CRITICAL_SECTION CsCriticalSection;
  129. static BOOLEAN CsDllMainCalled = FALSE;
  130. static HINSTANCE CsOle32Dll = NULL;
  131. //
  132. // FUNCTION PROTOTYPES
  133. //
  134. #if 0
  135. VOID
  136. CspBackupAddressInformation(
  137. HANDLE Key,
  138. PCS_ADDRESS_INFORMATION AddressInformation
  139. );
  140. NTSTATUS
  141. CspCaptureAddressInformation(
  142. PWCHAR AdapterGuid,
  143. PCS_ADDRESS_INFORMATION Information
  144. );
  145. VOID
  146. CspCleanupAddressInformation(
  147. PCS_ADDRESS_INFORMATION AddressInformation
  148. );
  149. NTSTATUS
  150. CspRestoreAddressInformation(
  151. HANDLE Key,
  152. PWCHAR AdapterGuid
  153. );
  154. BOOLEAN
  155. CspIsConnectionFwWorker(
  156. LPRASSHARECONN ConnectionArray,
  157. ULONG Count,
  158. LPRASSHARECONN Connection,
  159. ULONG *ConnNumber OUT OPTIONAL
  160. );
  161. ULONG
  162. CspAddFirewallConnection(
  163. LPRASSHARECONN Connection,
  164. ULONG Number
  165. );
  166. ULONG
  167. CspRemoveFirewallConnection(
  168. LPRASSHARECONN Connection,
  169. ULONG Position,
  170. LPRASSHARECONN ConnectionArray,
  171. ULONG Count
  172. );
  173. #endif
  174. BOOL
  175. CsDllMain(
  176. ULONG Reason
  177. )
  178. /*++
  179. Routine Description:
  180. This pseudo-entrypoint is invoked by RASAPI32.DLL's DllMain,
  181. to initialize and shutdown the connection-sharing module.
  182. Initialization is minimal to keep down the performance hit incurred
  183. on systems which make no use of the shared-access functionality.
  184. Arguments:
  185. Reason - indicates whether to initialize or shutdown.
  186. Return Value:
  187. BOOL - indicates success (TRUE) or failure (FALSE).
  188. --*/
  189. {
  190. if (Reason == DLL_PROCESS_ATTACH) {
  191. __try {
  192. InitializeCriticalSection(&CsCriticalSection);
  193. } __except(EXCEPTION_EXECUTE_HANDLER) {
  194. return FALSE;
  195. }
  196. CsDllMainCalled = TRUE;
  197. } else if (Reason == DLL_PROCESS_DETACH) {
  198. if (!CsDllMainCalled) { return TRUE; }
  199. __try {
  200. EnterCriticalSection(&CsCriticalSection);
  201. } __except(EXCEPTION_EXECUTE_HANDLER) {
  202. return TRUE;
  203. }
  204. CsShutdownModule();
  205. LeaveCriticalSection(&CsCriticalSection);
  206. DeleteCriticalSection(&CsCriticalSection);
  207. }
  208. return TRUE;
  209. } // DllMain
  210. VOID
  211. CsControlService(
  212. ULONG ControlCode
  213. )
  214. /*++
  215. Routine Description:
  216. This routine is called to send a control-code to the Shared Access service
  217. if it is active. Control-codes are used to indicate changes to the settings
  218. for the service; see IPNATHLP.H for a list of private control-codes used
  219. to indicate configuration changes.
  220. Arguments:
  221. ControlCode - the control to be sent.
  222. Return Value:
  223. none.
  224. --*/
  225. {
  226. SC_HANDLE ScmHandle;
  227. SC_HANDLE ServiceHandle;
  228. SERVICE_STATUS ServiceStatus;
  229. ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  230. if (ScmHandle) {
  231. ServiceHandle =
  232. OpenService(ScmHandle, c_szSharedAccess, SERVICE_ALL_ACCESS);
  233. if (ServiceHandle) {
  234. ControlService(ServiceHandle, ControlCode, &ServiceStatus);
  235. CloseServiceHandle(ServiceHandle);
  236. }
  237. CloseServiceHandle(ScmHandle);
  238. }
  239. } // CsControlService
  240. #if 0
  241. ULONG
  242. CsFirewallConnection(
  243. LPRASSHARECONN Connection,
  244. BOOLEAN Enable
  245. )
  246. /*++
  247. Routine Description:
  248. This routine is invoked to enable or disable the firewall on a connection.
  249. Arguments:
  250. Connection - the connection to [un]firewall
  251. Enable - true if the firewall is to be enabled for this connection,
  252. false if the firewall is to be disabled
  253. Return Value:
  254. Win32 Error code
  255. --*/
  256. {
  257. ULONG Count = 0;
  258. ULONG Position;
  259. LPRASSHARECONN ConnectionArray;
  260. DWORD Error;
  261. BOOLEAN IsFirewalled = FALSE;
  262. //
  263. // Query the number of currently firewalled connections, and
  264. // retrieve the connection array if any exists.
  265. //
  266. Error = CsQueryFirewallConnections(NULL, &Count);
  267. if (Error && Error != ERROR_INSUFFICIENT_BUFFER) {
  268. return Error;
  269. }
  270. if (Count) {
  271. ConnectionArray =
  272. (LPRASSHARECONN) Malloc(Count * sizeof(RASSHARECONN));
  273. if (!ConnectionArray) {
  274. return ERROR_NOT_ENOUGH_MEMORY;
  275. }
  276. Error = CsQueryFirewallConnections(ConnectionArray, &Count);
  277. if (Error) {
  278. Free(ConnectionArray);
  279. return Error;
  280. }
  281. } else {
  282. ConnectionArray = NULL;
  283. }
  284. //
  285. // If there are firewalled connections, check to see if the connection
  286. // passed in is one of them.
  287. //
  288. if (Count) {
  289. IsFirewalled = CspIsConnectionFwWorker(
  290. ConnectionArray,
  291. Count,
  292. Connection,
  293. &Position
  294. );
  295. }
  296. if (Enable) {
  297. if (!IsFirewalled) {
  298. Error = CspAddFirewallConnection(
  299. Connection,
  300. Count
  301. );
  302. if(ERROR_SUCCESS == Error) {
  303. //
  304. // Start (if needed) and update service. If the service
  305. // is already running, CsStartService returns ERROR_SUCCESS.
  306. //
  307. if (0 == Count) {
  308. Error = CsStartService();
  309. }
  310. CsControlService(IPNATHLP_CONTROL_UPDATE_CONNECTION);
  311. }
  312. } else {
  313. //
  314. // Define ALREADY_ENABLED error?
  315. //
  316. Error = ERROR_CAN_NOT_COMPLETE;
  317. }
  318. } else {
  319. if (IsFirewalled) {
  320. Error = CspRemoveFirewallConnection(
  321. Connection,
  322. Position,
  323. ConnectionArray,
  324. Count
  325. );
  326. if (ERROR_SUCCESS == Error) {
  327. //
  328. // Stop or update service. We only stop the service if
  329. // there is no shared connection, and this was the last
  330. // firewalled connection (i.e., count was 10
  331. //
  332. RASSHARECONN SharedConn;
  333. Error = CsQuerySharedConnection(&SharedConn);
  334. if (ERROR_SUCCESS != Error && 1 == Count) {
  335. CsStopService();
  336. } else {
  337. CsControlService(IPNATHLP_CONTROL_UPDATE_CONNECTION);
  338. }
  339. Error = ERROR_SUCCESS;
  340. }
  341. } else {
  342. //
  343. // Define NOT_FIREWALLED error?
  344. //
  345. Error = ERROR_CAN_NOT_COMPLETE;
  346. }
  347. }
  348. if (ConnectionArray) {
  349. Free(ConnectionArray);
  350. }
  351. return Error;
  352. } // CsFirewallConnection
  353. #endif
  354. ULONG
  355. CsInitializeModule(
  356. VOID
  357. )
  358. /*++
  359. Routine Description:
  360. This routine is called to initialize the connection-sharing configuration
  361. module. Initialization consists of loading the entrypoints which we have
  362. deferred loading up till now, in both MPRAPI.DLL and OLE32.DLL.
  363. Arguments:
  364. Instance - handle to the module-instance
  365. Return Value:
  366. ULONG - Win32 status code.
  367. --*/
  368. {
  369. ULONG Error;
  370. HINSTANCE Hinstance;
  371. EnterCriticalSection(&CsCriticalSection);
  372. if (CsInitialized) {
  373. Error = NO_ERROR;
  374. } else {
  375. if (!(CsOle32Dll = LoadLibraryW(c_szOle32Dll)) ||
  376. !(g_pCoInitializeEx =
  377. (PCOINITIALIZEEX)GetProcAddress(
  378. CsOle32Dll, c_szCoInitializeEx
  379. )) ||
  380. !(g_pCoUninitialize =
  381. (PCOUNINITIALIZE)GetProcAddress(
  382. CsOle32Dll, c_szCoUninitialize
  383. )) ||
  384. !(g_pCoCreateInstance =
  385. (PCOCREATEINSTANCE)GetProcAddress(
  386. CsOle32Dll, c_szCoCreateInstance
  387. )) ||
  388. !(g_pCoSetProxyBlanket =
  389. (PCOSETPROXYBLANKET)GetProcAddress(
  390. CsOle32Dll, c_szCoSetProxyBlanket
  391. )) ||
  392. !(g_pCoTaskMemFree =
  393. (PCOTASKMEMFREE)GetProcAddress(
  394. CsOle32Dll, c_szCoTaskMemFree
  395. ))) {
  396. if (CsOle32Dll) { FreeLibrary(CsOle32Dll); CsOle32Dll = NULL; }
  397. TRACE1("CsInitializeModule: %d", GetLastError());
  398. Error = ERROR_PROC_NOT_FOUND;
  399. } else {
  400. CsInitialized = TRUE;
  401. Error = NO_ERROR;
  402. }
  403. }
  404. LeaveCriticalSection(&CsCriticalSection);
  405. return Error;
  406. } // CsInitializeModule
  407. #if 0
  408. ULONG
  409. CsIsFirewalledConnection(
  410. LPRASSHARECONN Connection,
  411. PBOOLEAN Firewalled
  412. )
  413. /*++
  414. Routine Description:
  415. This routine is invoked to determine if a connection is firewalled
  416. Arguments:
  417. Connection - the connection to check
  418. Firewalled - receives the return value
  419. Return Value:
  420. ULONG - win32 error
  421. --*/
  422. {
  423. ULONG Count = 0;
  424. LPRASSHARECONN ConnectionArray;
  425. ULONG Error;
  426. if (!Firewalled) {
  427. return ERROR_INVALID_PARAMETER;
  428. }
  429. *Firewalled = FALSE;
  430. Error = CsQueryFirewallConnections(NULL, &Count);
  431. if (Error && Error != ERROR_INSUFFICIENT_BUFFER) {
  432. return Error;
  433. }
  434. ConnectionArray =
  435. (LPRASSHARECONN) Malloc(Count * sizeof(RASSHARECONN));
  436. if (!ConnectionArray) {
  437. return ERROR_NOT_ENOUGH_MEMORY;
  438. }
  439. Error = CsQueryFirewallConnections(ConnectionArray, &Count);
  440. if (Error) {
  441. Free(ConnectionArray);
  442. return Error;
  443. }
  444. *Firewalled = CspIsConnectionFwWorker(ConnectionArray, Count, Connection, NULL);
  445. Free(ConnectionArray);
  446. return NO_ERROR;
  447. } // CsIsConnectionFirewalled
  448. BOOLEAN
  449. CsIsRoutingProtocolInstalled(
  450. ULONG ProtocolId
  451. )
  452. /*++
  453. Routine Description:
  454. This routine is invoked to determine whether the routing protocol
  455. with the given protocol-ID is installed for Routing and Remote Access.
  456. This is determined by examining the configuration for the service.
  457. Arguments:
  458. ProtocolId - identifies the protocol to be found
  459. Return Value:
  460. TRUE if the protocol is installed, FALSE otherwise.
  461. --*/
  462. {
  463. PUCHAR Buffer;
  464. ULONG BufferLength;
  465. HINSTANCE Hinstance;
  466. PMPRCONFIGBUFFERFREE MprConfigBufferFree;
  467. PMPRCONFIGSERVERCONNECT MprConfigServerConnect;
  468. PMPRCONFIGSERVERDISCONNECT MprConfigServerDisconnect;
  469. PMPRCONFIGTRANSPORTGETHANDLE MprConfigTransportGetHandle;
  470. PMPRCONFIGTRANSPORTGETINFO MprConfigTransportGetInfo;
  471. PMPRINFOBLOCKFIND MprInfoBlockFind;
  472. HANDLE ServerHandle;
  473. HANDLE TransportHandle;
  474. //
  475. // Load the MPRAPI.DLL module and retrieve the entrypoints
  476. // to be used for examining the RRAS configuration.
  477. //
  478. if (!(Hinstance = LoadLibraryW(c_szMprapiDll)) ||
  479. !(MprConfigBufferFree =
  480. (PMPRCONFIGBUFFERFREE)
  481. GetProcAddress(Hinstance, c_szMprConfigBufferFree)) ||
  482. !(MprConfigServerConnect =
  483. (PMPRCONFIGSERVERCONNECT)
  484. GetProcAddress(Hinstance, c_szMprConfigServerConnect)) ||
  485. !(MprConfigServerDisconnect =
  486. (PMPRCONFIGSERVERDISCONNECT)
  487. GetProcAddress(Hinstance, c_szMprConfigServerDisconnect)) ||
  488. !(MprConfigTransportGetHandle =
  489. (PMPRCONFIGTRANSPORTGETHANDLE)
  490. GetProcAddress(Hinstance, c_szMprConfigTransportGetHandle)) ||
  491. !(MprConfigTransportGetInfo =
  492. (PMPRCONFIGTRANSPORTGETINFO)
  493. GetProcAddress(Hinstance, c_szMprConfigTransportGetInfo)) ||
  494. !(MprInfoBlockFind =
  495. (PMPRINFOBLOCKFIND)
  496. GetProcAddress(Hinstance, c_szMprInfoBlockFind))) {
  497. if (Hinstance) { FreeLibrary(Hinstance); }
  498. return FALSE;
  499. }
  500. //
  501. // Connect to the RRAS configuration, and retrieve the configuration
  502. // for the IP transport-layer routing protocols. This should include
  503. // the configuration for the routing-protocol in 'ProtocolId',
  504. // if installed.
  505. //
  506. ServerHandle = NULL;
  507. if (MprConfigServerConnect(NULL, &ServerHandle) != NO_ERROR ||
  508. MprConfigTransportGetHandle(ServerHandle, PID_IP, &TransportHandle)
  509. != NO_ERROR ||
  510. MprConfigTransportGetInfo(
  511. ServerHandle,
  512. TransportHandle,
  513. &Buffer,
  514. &BufferLength,
  515. NULL,
  516. NULL,
  517. NULL
  518. ) != NO_ERROR) {
  519. if (ServerHandle) { MprConfigServerDisconnect(ServerHandle); }
  520. FreeLibrary(Hinstance);
  521. return FALSE;
  522. }
  523. MprConfigServerDisconnect(ServerHandle);
  524. //
  525. // Look for the requested protocol's configuration,
  526. // and return TRUE if it is found; otherwise, return FALSE.
  527. //
  528. if (MprInfoBlockFind(Buffer, ProtocolId, NULL, NULL, NULL) == NO_ERROR) {
  529. MprConfigBufferFree(Buffer);
  530. FreeLibrary(Hinstance);
  531. return TRUE;
  532. }
  533. MprConfigBufferFree(Buffer);
  534. FreeLibrary(Hinstance);
  535. return FALSE;
  536. } // CsIsRoutingProtocolInstalled
  537. #endif
  538. ULONG
  539. CsIsSharedConnection(
  540. LPRASSHARECONN Connection,
  541. PBOOLEAN Shared
  542. )
  543. /*++
  544. Routine Description:
  545. This routine is invoked to determine whether the given connection
  546. is the currently-shared connection.
  547. For added performance, this may be changed to cache the shared-connection
  548. and use registry change-notification to detect updates.
  549. Arguments:
  550. Connection - the connection in question
  551. Shared - receives 'TRUE' if the 'Name' is the shared connection,
  552. and 'FALSE' otherwise
  553. Return Value:
  554. ULONG - Win32 status code.
  555. Environment:
  556. This routine is called *without* initializing the module
  557. (i.e. loading mprapi.dll and ole32.dll), for performance reasons.
  558. Hence, it may not invoke any mprapi.dll routines.
  559. --*/
  560. {
  561. ULONG Error;
  562. RASSHARECONN SharedConnection;
  563. if (Shared) {
  564. Error = CsQuerySharedConnection(&SharedConnection);
  565. if (Error) {
  566. *Shared = FALSE;
  567. } else {
  568. *Shared = RasIsEqualSharedConnection(Connection, &SharedConnection);
  569. }
  570. }
  571. return NO_ERROR;
  572. } // CsIsSharedConnection
  573. #if 0
  574. ULONG
  575. CsMapGuidToAdapterIndex(
  576. PWCHAR Guid,
  577. PGETINTERFACEINFO GetInterfaceInfo
  578. )
  579. /*++
  580. Routine Description:
  581. This routine is called to match the GUID in the given string to
  582. an adapter in the list returned by calling the given entrypoint.
  583. Arguments:
  584. Guid - identifies the GUID of the adapter to be found
  585. GetInterfaceInfo - supplies GUID information for each adapter
  586. Return Value:
  587. ULONG - the index of the adapter, if found; otherwise, -1.
  588. --*/
  589. {
  590. ULONG AdapterIndex = (ULONG)-1;
  591. ULONG i;
  592. ULONG GuidLength;
  593. PIP_INTERFACE_INFO Info;
  594. PWCHAR Name;
  595. ULONG NameLength;
  596. ULONG Size;
  597. Size = 0;
  598. GuidLength = lstrlenW(Guid);
  599. if (GetInterfaceInfo(NULL, &Size) == ERROR_INSUFFICIENT_BUFFER) {
  600. Info = Malloc(Size);
  601. if (Info) {
  602. if (GetInterfaceInfo(Info, &Size) == NO_ERROR) {
  603. for (i = 0; i < (ULONG)Info->NumAdapters; i++) {
  604. NameLength = lstrlenW(Info->Adapter[i].Name);
  605. if (NameLength < GuidLength) { continue; }
  606. Name = Info->Adapter[i].Name + (NameLength - GuidLength);
  607. if (lstrcmpiW(Guid, Name) == 0) {
  608. AdapterIndex = Info->Adapter[i].Index;
  609. break;
  610. }
  611. }
  612. }
  613. Free(Info);
  614. }
  615. }
  616. return AdapterIndex;
  617. } // CsMapGuidToAdapter
  618. #endif
  619. NTSTATUS
  620. CsOpenKey(
  621. PHANDLE Key,
  622. ACCESS_MASK DesiredAccess,
  623. PCWSTR Name
  624. )
  625. /*++
  626. Routine Description:
  627. This routine is invoked to open a given registry key.
  628. Arguments:
  629. Key - receives the opened key
  630. DesiredAccess - specifies the requested access
  631. Name - specifies the key to be opened
  632. Return Value:
  633. NTSTATUS - NT status code.
  634. --*/
  635. {
  636. OBJECT_ATTRIBUTES ObjectAttributes;
  637. UNICODE_STRING UnicodeString;
  638. RtlInitUnicodeString(&UnicodeString, Name);
  639. InitializeObjectAttributes(
  640. &ObjectAttributes,
  641. &UnicodeString,
  642. OBJ_CASE_INSENSITIVE,
  643. NULL,
  644. NULL
  645. );
  646. return NtOpenKey(Key, DesiredAccess, &ObjectAttributes);
  647. } // CsOpenKey
  648. #if 0
  649. ULONG
  650. CspAddFirewallConnection(
  651. LPRASSHARECONN Connection,
  652. ULONG Number
  653. )
  654. /*++
  655. Routine Description:
  656. This routine is invoked to add a connection to the registry set.
  657. Arguments:
  658. Connection - the connection to add
  659. Number - the number of this connection
  660. Return Value:
  661. Win32 error code
  662. --*/
  663. {
  664. HANDLE Key;
  665. UNICODE_STRING ValueName;
  666. ULONG Count;
  667. NTSTATUS Status;
  668. //
  669. // +11 is enough room to hold the digits of a number >4,000,000,000, so
  670. // buffer overflow won't be an issue below.
  671. //
  672. WCHAR wsz[sizeof(c_szFirewallConnection)/sizeof(WCHAR) + 11];
  673. //
  674. // Open the key to SharedAccess/Parameters
  675. //
  676. Status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
  677. if (!NT_SUCCESS(Status)) {
  678. return RtlNtStatusToDosError(Status);
  679. }
  680. //
  681. // Generate the string for the connection value
  682. //
  683. swprintf(wsz, L"%s%u", c_szFirewallConnection, Number);
  684. RtlInitUnicodeString(&ValueName, wsz);
  685. //
  686. // Write the connection to the registry
  687. //
  688. Status = NtSetValueKey(
  689. Key,
  690. &ValueName,
  691. 0,
  692. REG_BINARY,
  693. Connection,
  694. Connection->dwSize
  695. );
  696. if(!NT_SUCCESS(Status)) {
  697. NtClose(Key);
  698. return RtlNtStatusToDosError(Status);
  699. }
  700. //
  701. // Write the updated count to the registry
  702. //
  703. RtlInitUnicodeString(&ValueName, c_szFirewallConnectionCount);
  704. Count = Number + 1; // number is 0 indexed
  705. Status = NtSetValueKey(
  706. Key,
  707. &ValueName,
  708. 0,
  709. REG_DWORD,
  710. &Count,
  711. sizeof(DWORD)
  712. );
  713. NtClose(Key);
  714. return RtlNtStatusToDosError(Status);
  715. } // CspAddFirewallConnection
  716. VOID
  717. CspBackupAddressInformation(
  718. HANDLE Key,
  719. PCS_ADDRESS_INFORMATION Information
  720. )
  721. {
  722. NTSTATUS status;
  723. UNICODE_STRING UnicodeString;
  724. do {
  725. RtlInitUnicodeString(&UnicodeString, c_szBackupIPAddress);
  726. status =
  727. NtSetValueKey(
  728. Key,
  729. &UnicodeString,
  730. 0,
  731. Information->IPAddress->Type,
  732. Information->IPAddress->Data,
  733. Information->IPAddress->DataLength
  734. );
  735. if (!NT_SUCCESS(status)) { break; }
  736. RtlInitUnicodeString(&UnicodeString, c_szBackupSubnetMask);
  737. status =
  738. NtSetValueKey(
  739. Key,
  740. &UnicodeString,
  741. 0,
  742. Information->SubnetMask->Type,
  743. Information->SubnetMask->Data,
  744. Information->SubnetMask->DataLength
  745. );
  746. if (!NT_SUCCESS(status)) { break; }
  747. RtlInitUnicodeString(&UnicodeString, c_szBackupDefaultGateway);
  748. status =
  749. NtSetValueKey(
  750. Key,
  751. &UnicodeString,
  752. 0,
  753. Information->DefaultGateway->Type,
  754. Information->DefaultGateway->Data,
  755. Information->DefaultGateway->DataLength
  756. );
  757. if (!NT_SUCCESS(status)) { break; }
  758. RtlInitUnicodeString(&UnicodeString, c_szBackupEnableDHCP);
  759. status =
  760. NtSetValueKey(
  761. Key,
  762. &UnicodeString,
  763. 0,
  764. Information->EnableDHCP->Type,
  765. Information->EnableDHCP->Data,
  766. Information->EnableDHCP->DataLength
  767. );
  768. if (!NT_SUCCESS(status)) { break; }
  769. return;
  770. } while(FALSE);
  771. RtlInitUnicodeString(&UnicodeString, c_szBackupIPAddress);
  772. NtDeleteValueKey(Key, &UnicodeString);
  773. RtlInitUnicodeString(&UnicodeString, c_szBackupSubnetMask);
  774. NtDeleteValueKey(Key, &UnicodeString);
  775. RtlInitUnicodeString(&UnicodeString, c_szBackupDefaultGateway);
  776. NtDeleteValueKey(Key, &UnicodeString);
  777. RtlInitUnicodeString(&UnicodeString, c_szBackupEnableDHCP);
  778. NtDeleteValueKey(Key, &UnicodeString);
  779. } // CspBackupAddressInformation
  780. NTSTATUS
  781. CspCaptureAddressInformation(
  782. PWCHAR AdapterGuid,
  783. PCS_ADDRESS_INFORMATION Information
  784. )
  785. {
  786. HANDLE Key;
  787. PWCHAR KeyName;
  788. ULONG KeyNameLength;
  789. NTSTATUS status;
  790. KeyNameLength =
  791. sizeof(WCHAR) *
  792. (lstrlenW(c_szTcpipParametersKey) + 1 +
  793. lstrlenW(c_szInterfaces) + 1 +
  794. lstrlenW(AdapterGuid) + 2);
  795. if (!(KeyName = Malloc(KeyNameLength))) { return STATUS_NO_MEMORY; }
  796. wsprintfW(
  797. KeyName, L"%ls\\%ls\\%ls", c_szTcpipParametersKey, c_szInterfaces,
  798. AdapterGuid
  799. );
  800. status = CsOpenKey(&Key, KEY_READ, KeyName);
  801. Free(KeyName);
  802. if (!NT_SUCCESS(status)) { return status; }
  803. do {
  804. status =
  805. CsQueryValueKey(
  806. Key, c_szIPAddress, &Information->IPAddress
  807. );
  808. if (!NT_SUCCESS(status)) { break; }
  809. status =
  810. CsQueryValueKey(
  811. Key, c_szSubnetMask, &Information->SubnetMask
  812. );
  813. if (!NT_SUCCESS(status)) { break; }
  814. status =
  815. CsQueryValueKey(
  816. Key, c_szDefaultGateway, &Information->DefaultGateway
  817. );
  818. if (!NT_SUCCESS(status)) { break; }
  819. status =
  820. CsQueryValueKey(
  821. Key, c_szEnableDHCP, &Information->EnableDHCP
  822. );
  823. if (!NT_SUCCESS(status)) { break; }
  824. } while(FALSE);
  825. NtClose(Key);
  826. return status;
  827. } // CspCaptureAddressInformation
  828. VOID
  829. CspCleanupAddressInformation(
  830. PCS_ADDRESS_INFORMATION Information
  831. )
  832. {
  833. Free0(Information->IPAddress);
  834. Free0(Information->SubnetMask);
  835. Free0(Information->DefaultGateway);
  836. Free0(Information->EnableDHCP);
  837. } // CspCleanupAddressInformation
  838. ULONG
  839. CspRemoveFirewallConnection(
  840. LPRASSHARECONN Connection,
  841. ULONG Position,
  842. LPRASSHARECONN ConnectionArray,
  843. ULONG Count
  844. )
  845. /*++
  846. Routine Description:
  847. This routine is invoked to remove a connection to the registry set.
  848. Arguments:
  849. Connection - the connection to remove
  850. Number - its index in ConnectionArray
  851. ConnectionArray - currently firewalled connections
  852. Count - the number of entries in ConnectionArray
  853. Return Value:
  854. Win32 error code
  855. --*/
  856. {
  857. HANDLE Key;
  858. UNICODE_STRING ValueName;
  859. ULONG i;
  860. NTSTATUS Status;
  861. //
  862. // +11 is enough room to hold the digits of a number >4,000,000,000, so
  863. // buffer overflow won't be an issue below.
  864. //
  865. WCHAR wsz[sizeof(c_szFirewallConnection)/sizeof(WCHAR) + 11];
  866. //
  867. // Open the key to IPFirewall/Parameters
  868. //
  869. Status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
  870. if (!NT_SUCCESS(Status)) {
  871. return RtlNtStatusToDosError(Status);
  872. }
  873. //
  874. // Shift entries above the connection we're removing down one
  875. // (overwriting the entry we want to remove)
  876. //
  877. for (i = Position + 1; i < Count; i++) {
  878. //
  879. // Generate key name for previous entry
  880. //
  881. swprintf(wsz, L"%s%u", c_szFirewallConnection, i - 1);
  882. RtlInitUnicodeString(&ValueName, wsz);
  883. //
  884. // Write current entry into previous slot
  885. //
  886. Status = NtSetValueKey(
  887. Key,
  888. &ValueName,
  889. 0,
  890. REG_BINARY,
  891. &ConnectionArray[i],
  892. ConnectionArray[i].dwSize
  893. );
  894. if(!NT_SUCCESS(Status)) {
  895. NtClose(Key);
  896. return RtlNtStatusToDosError(Status);
  897. }
  898. }
  899. //
  900. // Delete the last entry. This is either the entry we want to
  901. // remove (if it was the last entry to begin with), or an entry
  902. // that has already been duplicated into the previous position.
  903. //
  904. swprintf(wsz, L"%s%u", c_szFirewallConnection, Count - 1);
  905. RtlInitUnicodeString(&ValueName, wsz);
  906. Status = NtDeleteValueKey(Key, &ValueName);
  907. if(!NT_SUCCESS(Status)) {
  908. NtClose(Key);
  909. return RtlNtStatusToDosError(Status);
  910. }
  911. //
  912. // Store the decremented count in the registry
  913. //
  914. RtlInitUnicodeString(&ValueName, c_szFirewallConnectionCount);
  915. i = Count - 1;
  916. Status = NtSetValueKey(
  917. Key,
  918. &ValueName,
  919. 0,
  920. REG_DWORD,
  921. &i,
  922. sizeof(DWORD)
  923. );
  924. NtClose(Key);
  925. return RtlNtStatusToDosError(Status);
  926. } // CspRemoveFirewallConnection
  927. ULONG
  928. CsQueryFirewallConnections(
  929. LPRASSHARECONN ConnectionArray,
  930. ULONG *ConnectionCount
  931. )
  932. /*++
  933. Routine Description:
  934. This routine is invoked to retrieve the firewalled connections, if any.
  935. Arguments:
  936. ConnectionArray - receives the retrieved connections.
  937. ConnectionCount - in: how many entries the array can hold
  938. out: number of entries returned, or the needed
  939. size of the array (for ERROR_INSUFFICIENT_BUFFER)
  940. Return Value:
  941. ULONG - Win32 status code.
  942. --*/
  943. {
  944. HANDLE Key;
  945. PKEY_VALUE_PARTIAL_INFORMATION Information;
  946. NTSTATUS Status;
  947. ULONG Count;
  948. ULONG i;
  949. if (!ConnectionCount) { return ERROR_INVALID_PARAMETER; }
  950. if (*ConnectionCount && !ConnectionArray) {
  951. //
  952. // It's OK to pass in NULL for the array if just trying
  953. // to determine what size buffer to use
  954. //
  955. return ERROR_INVALID_PARAMETER;
  956. }
  957. //
  958. // Open the 'SharedAccess\Parameters' key,
  959. // and read the 'FirewallConnectionCount' value
  960. //
  961. Status = CsOpenKey(&Key, KEY_READ, c_szSharedAccessParametersKey);
  962. if (!NT_SUCCESS(Status)) {
  963. TRACE1(
  964. "CsQueryFirewallConnections: CsOpenKey=%x", Status
  965. );
  966. return RtlNtStatusToDosError(Status);
  967. }
  968. Status = CsQueryValueKey(Key, c_szFirewallConnectionCount, &Information);
  969. if (NT_SUCCESS(Status)) {
  970. //
  971. // Validate the information, and check to see if the passed in array
  972. // is sufficient in size.
  973. //
  974. if (Information->DataLength != sizeof(DWORD) ||
  975. Information->Type != REG_DWORD) {
  976. TRACE(
  977. "CsQueryFirewallConnections: invalid data in registry for count"
  978. );
  979. NtClose(Key);
  980. Free(Information);
  981. return ERROR_INVALID_DATA;
  982. }
  983. Count = (ULONG) *Information->Data;
  984. Free(Information);
  985. } else {
  986. Count = 0;
  987. }
  988. if (*ConnectionCount < Count) {
  989. //
  990. // Too many entries for the passed in buffer
  991. //
  992. NtClose(Key);
  993. *ConnectionCount = Count;
  994. return ERROR_INSUFFICIENT_BUFFER;
  995. }
  996. *ConnectionCount = Count;
  997. //
  998. // Read all of the connection entries from the registry.
  999. //
  1000. for(i = 0; i < Count; i++) {
  1001. WCHAR wsz[sizeof(c_szFirewallConnection)/sizeof(WCHAR) + 11];
  1002. swprintf(wsz, L"%s%u", c_szFirewallConnection, i);
  1003. Status = CsQueryValueKey(Key, wsz, &Information);
  1004. if (!NT_SUCCESS(Status)) {
  1005. NtClose(Key);
  1006. return RtlNtStatusToDosError(Status);
  1007. }
  1008. //
  1009. // Validate the retrieved information,
  1010. // and copy it to the given buffer
  1011. //
  1012. if (Information->DataLength != sizeof(RASSHARECONN) ||
  1013. ((LPRASSHARECONN)Information->Data)->dwSize != sizeof(RASSHARECONN)) {
  1014. TRACE2(
  1015. "CsQueryFirewallConnections: invalid length %d (size=%d) in registry",
  1016. Information->DataLength,
  1017. ((LPRASSHARECONN)Information->Data)->dwSize
  1018. );
  1019. Free(Information);
  1020. NtClose(Key);
  1021. return ERROR_INVALID_DATA;
  1022. }
  1023. CopyMemory(&ConnectionArray[i], Information->Data, sizeof(RASSHARECONN));
  1024. Free(Information);
  1025. }
  1026. return NO_ERROR;
  1027. } // CsQueryFirewallConnections
  1028. BOOLEAN
  1029. CspIsConnectionFwWorker(
  1030. LPRASSHARECONN ConnectionArray,
  1031. ULONG Count,
  1032. LPRASSHARECONN Connection,
  1033. ULONG *Position OUT OPTIONAL
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. This routine is invoked to determine if a connection is firewalled
  1038. Arguments:
  1039. ConnectionArray - Buffer containing currently FWd connections
  1040. Count - number of connections in the array
  1041. Connection - the connection to check
  1042. Position - receives the number of the connection, if found (undefined otherwise)
  1043. Return Value:
  1044. BOOLEAN -- true if the passed in connection is currently firewalled
  1045. --*/
  1046. {
  1047. ULONG i;
  1048. for (i = 0; i < Count; i++) {
  1049. if (RasIsEqualSharedConnection(Connection, &ConnectionArray[i])) {
  1050. if (Position) *Position = i;
  1051. return TRUE;
  1052. }
  1053. }
  1054. return FALSE;
  1055. } // FwpIsConnectionFwWorker
  1056. NTSTATUS
  1057. CspRestoreAddressInformation(
  1058. HANDLE Key,
  1059. PWCHAR AdapterGuid
  1060. )
  1061. {
  1062. HANDLE AdapterKey = NULL;
  1063. PWCHAR AdapterKeyName = NULL;
  1064. PDHCPNOTIFYCONFIGCHANGE DhcpNotifyConfigChange;
  1065. ULONG Error;
  1066. HINSTANCE Hinstance;
  1067. CS_ADDRESS_INFORMATION Information;
  1068. ULONG Length;
  1069. NTSTATUS status;
  1070. UNICODE_STRING UnicodeString;
  1071. if (!(Hinstance = LoadLibraryW(c_szDhcpcsvcDll)) ||
  1072. !(DhcpNotifyConfigChange =
  1073. (PDHCPNOTIFYCONFIGCHANGE)
  1074. GetProcAddress(
  1075. Hinstance, c_szDhcpNotifyConfigChange
  1076. ))) {
  1077. if (Hinstance) { FreeLibrary(Hinstance); }
  1078. return ERROR_PROC_NOT_FOUND;
  1079. }
  1080. do {
  1081. ZeroMemory(&Information, sizeof(Information));
  1082. status =
  1083. CsQueryValueKey(
  1084. Key, c_szBackupIPAddress, &Information.IPAddress
  1085. );
  1086. if (!NT_SUCCESS(status)) { break; }
  1087. status =
  1088. CsQueryValueKey(
  1089. Key, c_szBackupSubnetMask, &Information.SubnetMask
  1090. );
  1091. if (!NT_SUCCESS(status)) { break; }
  1092. status =
  1093. CsQueryValueKey(
  1094. Key, c_szBackupDefaultGateway, &Information.DefaultGateway
  1095. );
  1096. if (!NT_SUCCESS(status)) { break; }
  1097. status =
  1098. CsQueryValueKey(
  1099. Key, c_szBackupEnableDHCP, &Information.EnableDHCP
  1100. );
  1101. if (!NT_SUCCESS(status)) { break; }
  1102. Length =
  1103. sizeof(WCHAR) *
  1104. (lstrlenW(c_szTcpipParametersKey) + 1 +
  1105. lstrlenW(c_szInterfaces) + 1 +
  1106. lstrlenW(AdapterGuid) + 2);
  1107. if (!(AdapterKeyName = Malloc(Length))) {
  1108. status = STATUS_NO_MEMORY;
  1109. break;
  1110. }
  1111. wsprintfW(
  1112. AdapterKeyName, L"%ls\\%ls\\%ls", c_szTcpipParametersKey,
  1113. c_szInterfaces, AdapterGuid
  1114. );
  1115. status = CsOpenKey(&AdapterKey, KEY_ALL_ACCESS, AdapterKeyName);
  1116. if (!NT_SUCCESS(status)) { break; }
  1117. RtlInitUnicodeString(&UnicodeString, c_szIPAddress);
  1118. status =
  1119. NtSetValueKey(
  1120. AdapterKey,
  1121. &UnicodeString,
  1122. 0,
  1123. Information.IPAddress->Type,
  1124. Information.IPAddress->Data,
  1125. Information.IPAddress->DataLength
  1126. );
  1127. RtlInitUnicodeString(&UnicodeString, c_szSubnetMask);
  1128. status =
  1129. NtSetValueKey(
  1130. AdapterKey,
  1131. &UnicodeString,
  1132. 0,
  1133. Information.SubnetMask->Type,
  1134. Information.SubnetMask->Data,
  1135. Information.SubnetMask->DataLength
  1136. );
  1137. RtlInitUnicodeString(&UnicodeString, c_szDefaultGateway);
  1138. status =
  1139. NtSetValueKey(
  1140. AdapterKey,
  1141. &UnicodeString,
  1142. 0,
  1143. Information.DefaultGateway->Type,
  1144. Information.DefaultGateway->Data,
  1145. Information.DefaultGateway->DataLength
  1146. );
  1147. RtlInitUnicodeString(&UnicodeString, c_szEnableDHCP);
  1148. status =
  1149. NtSetValueKey(
  1150. AdapterKey,
  1151. &UnicodeString,
  1152. 0,
  1153. Information.EnableDHCP->Type,
  1154. Information.EnableDHCP->Data,
  1155. Information.EnableDHCP->DataLength
  1156. );
  1157. if (!NT_SUCCESS(status)) { break; }
  1158. RtlInitUnicodeString(&UnicodeString, c_szBackupIPAddress);
  1159. NtDeleteValueKey(Key, &UnicodeString);
  1160. RtlInitUnicodeString(&UnicodeString, c_szBackupSubnetMask);
  1161. NtDeleteValueKey(Key, &UnicodeString);
  1162. RtlInitUnicodeString(&UnicodeString, c_szBackupDefaultGateway);
  1163. NtDeleteValueKey(Key, &UnicodeString);
  1164. RtlInitUnicodeString(&UnicodeString, c_szBackupEnableDHCP);
  1165. NtDeleteValueKey(Key, &UnicodeString);
  1166. if (*(PULONG)Information.EnableDHCP->Data) {
  1167. Error =
  1168. DhcpNotifyConfigChange(
  1169. NULL,
  1170. AdapterGuid,
  1171. FALSE,
  1172. 0,
  1173. 0,
  1174. 0,
  1175. DhcpEnable
  1176. );
  1177. } else {
  1178. ULONG Address;
  1179. UNICODE_STRING BindList;
  1180. UNICODE_STRING LowerComponent;
  1181. ULONG Mask;
  1182. IP_PNP_RECONFIG_REQUEST Request;
  1183. UNICODE_STRING UpperComponent;
  1184. Address = IpPszToHostAddr((PWCHAR)Information.IPAddress->Data);
  1185. if (Address) {
  1186. Address = RtlUlongByteSwap(Address);
  1187. Mask = IpPszToHostAddr((PWCHAR)Information.SubnetMask->Data);
  1188. if (Mask) {
  1189. Mask = RtlUlongByteSwap(Mask);
  1190. Error =
  1191. DhcpNotifyConfigChange(
  1192. NULL,
  1193. AdapterGuid,
  1194. TRUE,
  1195. 0,
  1196. Address,
  1197. Mask,
  1198. DhcpDisable
  1199. );
  1200. }
  1201. }
  1202. RtlInitUnicodeString(&BindList, c_szEmpty);
  1203. RtlInitUnicodeString(&LowerComponent, c_szEmpty);
  1204. RtlInitUnicodeString(&UpperComponent, c_szTcpip);
  1205. ZeroMemory(&Request, sizeof(Request));
  1206. Request.version = IP_PNP_RECONFIG_VERSION;
  1207. Request.gatewayListUpdate = TRUE;
  1208. Request.Flags = IP_PNP_FLAG_GATEWAY_LIST_UPDATE;
  1209. status =
  1210. NdisHandlePnPEvent(
  1211. NDIS,
  1212. RECONFIGURE,
  1213. &LowerComponent,
  1214. &UpperComponent,
  1215. &BindList,
  1216. &Request,
  1217. sizeof(Request)
  1218. );
  1219. }
  1220. } while(FALSE);
  1221. if (AdapterKey) { NtClose(AdapterKey); }
  1222. Free0(AdapterKeyName);
  1223. CspCleanupAddressInformation(&Information);
  1224. FreeLibrary(Hinstance);
  1225. return status;
  1226. } // CspRestoreAddressInformation
  1227. ULONG
  1228. CsQueryLanConnTable(
  1229. LPRASSHARECONN ExcludedConnection,
  1230. NETCON_PROPERTIES** LanConnTable,
  1231. LPDWORD LanConnCount
  1232. )
  1233. /*++
  1234. Routine Description:
  1235. This routine is invoked to retrieve an array of LAN connections,
  1236. discounting 'ExcludeConnection', which will typically be the name
  1237. of the public interface.
  1238. Arguments:
  1239. ExcludeConnection - a connection not allowed to be the private connection
  1240. LanConnTable - optionally receives a table of possible private networks.
  1241. LanConnCount - receives a count of the possible private networks.
  1242. Return Value:
  1243. ULONG - Win32 status code.
  1244. --*/
  1245. {
  1246. BOOLEAN CleanupOle = TRUE;
  1247. INetConnection* ConArray[32];
  1248. ULONG ConCount;
  1249. INetConnectionManager* ConMan = NULL;
  1250. IEnumNetConnection* EnumCon = NULL;
  1251. ULONG Error;
  1252. HRESULT hr;
  1253. ULONG i;
  1254. ULONG j;
  1255. ULONG LanCount = 0;
  1256. NETCON_PROPERTIES* LanProps = NULL;
  1257. NETCON_PROPERTIES* LanTable = NULL;
  1258. BSTR Name;
  1259. NETCON_STATUS ncs;
  1260. NTSTATUS status;
  1261. ULONG Size;
  1262. NETCON_MEDIATYPE MediaType;
  1263. UNICODE_STRING UnicodeString;
  1264. *LanConnCount = 0;
  1265. if (LanConnTable) { *LanConnTable = NULL; }
  1266. hr = g_pCoInitializeEx(NULL, COINIT_MULTITHREADED|COINIT_DISABLE_OLE1DDE);
  1267. if (!SUCCEEDED(hr)) {
  1268. if (hr == RPC_E_CHANGED_MODE) {
  1269. CleanupOle = FALSE;
  1270. } else {
  1271. TRACE1("CsQueryLanConnTable: CoInitializeEx=%x", hr);
  1272. return ERROR_CAN_NOT_COMPLETE;
  1273. }
  1274. }
  1275. i = 0;
  1276. Error = NO_ERROR;
  1277. do {
  1278. //
  1279. // Instantiate the connection manager
  1280. //
  1281. hr =
  1282. g_pCoCreateInstance(
  1283. &CLSID_ConnectionManager,
  1284. NULL,
  1285. CLSCTX_SERVER,
  1286. &IID_INetConnectionManager,
  1287. (PVOID*)&ConMan
  1288. );
  1289. if (!SUCCEEDED(hr)) {
  1290. TRACE1("CsQueryLanConnTable: CoCreateInstance=%x", hr);
  1291. ConMan = NULL; break;
  1292. }
  1293. //
  1294. // Instantiate a connection-enumerator
  1295. //
  1296. hr =
  1297. INetConnectionManager_EnumConnections(
  1298. ConMan,
  1299. NCME_DEFAULT,
  1300. &EnumCon
  1301. );
  1302. if (!SUCCEEDED(hr)) {
  1303. TRACE1("CsQueryLanConnTable: EnumConnections=%x", hr);
  1304. EnumCon = NULL; break;
  1305. }
  1306. hr =
  1307. g_pCoSetProxyBlanket(
  1308. (IUnknown*)EnumCon,
  1309. RPC_C_AUTHN_WINNT,
  1310. RPC_C_AUTHN_NONE,
  1311. NULL,
  1312. RPC_C_AUTHN_LEVEL_CALL,
  1313. RPC_C_IMP_LEVEL_IMPERSONATE,
  1314. NULL,
  1315. EOAC_NONE
  1316. );
  1317. //
  1318. // Enumerate the items
  1319. //
  1320. for ( ; ; ) {
  1321. hr =
  1322. IEnumNetConnection_Next(
  1323. EnumCon,
  1324. Dimension(ConArray),
  1325. ConArray,
  1326. &ConCount
  1327. );
  1328. if (!SUCCEEDED(hr) || !ConCount) { hr = S_OK; break; }
  1329. if (LanConnTable) {
  1330. //
  1331. // Allocate or reallocate the memory for storing
  1332. // connections which we will return to the caller.
  1333. //
  1334. if (!LanTable) {
  1335. LanTable =
  1336. (NETCON_PROPERTIES*)
  1337. GlobalAlloc(
  1338. 0,
  1339. ConCount * sizeof(NETCON_PROPERTIES)
  1340. );
  1341. } else {
  1342. PVOID Temp =
  1343. GlobalAlloc(
  1344. 0,
  1345. (LanCount + ConCount) * sizeof(NETCON_PROPERTIES)
  1346. );
  1347. if (Temp) {
  1348. CopyMemory(
  1349. Temp,
  1350. LanTable,
  1351. LanCount * sizeof(NETCON_PROPERTIES)
  1352. );
  1353. }
  1354. GlobalFree(LanTable);
  1355. LanTable = Temp;
  1356. }
  1357. if (!LanTable) { Error = ERROR_NOT_ENOUGH_MEMORY; break; }
  1358. }
  1359. LanCount += ConCount;
  1360. //
  1361. // Examine the properties for the connections retrieved
  1362. //
  1363. for (j = 0; j < ConCount; j++) {
  1364. hr = INetConnection_GetProperties(ConArray[j], &LanProps);
  1365. INetConnection_Release(ConArray[j]);
  1366. if (SUCCEEDED(hr) &&
  1367. LanProps->MediaType == NCM_LAN &&
  1368. (!ExcludedConnection->fIsLanConnection ||
  1369. !IsEqualGUID(
  1370. &ExcludedConnection->guid, &LanProps->guidId))) {
  1371. //
  1372. // This connection qualifies to be private; copy it.
  1373. //
  1374. if (!LanConnTable) {
  1375. ++i;
  1376. } else {
  1377. LanTable[i] = *LanProps;
  1378. LanTable[i].pszwName = StrDupW(LanProps->pszwName);
  1379. LanTable[i].pszwDeviceName =
  1380. StrDupW(LanProps->pszwDeviceName);
  1381. if (LanTable[i].pszwName &&
  1382. LanTable[i].pszwDeviceName
  1383. ) {
  1384. ++i;
  1385. } else {
  1386. Free0(LanTable[i].pszwName);
  1387. Free0(LanTable[i].pszwDeviceName);
  1388. }
  1389. }
  1390. }
  1391. if (LanProps) {
  1392. g_pCoTaskMemFree(LanProps->pszwName);
  1393. g_pCoTaskMemFree(LanProps->pszwDeviceName);
  1394. g_pCoTaskMemFree(LanProps);
  1395. LanProps = NULL;
  1396. }
  1397. }
  1398. }
  1399. } while (FALSE);
  1400. if (EnumCon) { IEnumNetConnection_Release(EnumCon); }
  1401. if (ConMan) { INetConnectionManager_Release(ConMan); }
  1402. if (CleanupOle) { g_pCoUninitialize(); }
  1403. if (LanConnTable) { *LanConnTable = LanTable; }
  1404. *LanConnCount = i;
  1405. return Error;
  1406. } // CsQueryLanConnTable
  1407. VOID
  1408. CsQueryScopeInformation(
  1409. IN OUT PHANDLE Key,
  1410. PULONG Address,
  1411. PULONG Mask
  1412. )
  1413. /*++
  1414. Routine Description:
  1415. This routine is called to retrieve the private network address and mask
  1416. to be used for shared access. If no value is found, the default
  1417. is supplied.
  1418. Arguments:
  1419. Key - optionally supplies an open handle to the SharedAccess\Parameters
  1420. registry key
  1421. Address - receives the address for the private network,
  1422. in network byte order
  1423. Mask - receives the mask for the private network, in network byte order
  1424. Return Value:
  1425. none.
  1426. --*/
  1427. {
  1428. PKEY_VALUE_PARTIAL_INFORMATION Information;
  1429. HANDLE LocalKey = NULL;
  1430. NTSTATUS status;
  1431. if (!Key) { Key = &LocalKey; }
  1432. if (*Key) {
  1433. status = STATUS_SUCCESS;
  1434. } else {
  1435. status = CsOpenKey(Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
  1436. }
  1437. if (NT_SUCCESS(status)) {
  1438. status = CsQueryValueKey(*Key, c_szScopeAddress, &Information);
  1439. if (NT_SUCCESS(status)) {
  1440. if (!(*Address = IpPszToHostAddr((PWCHAR)Information->Data))) {
  1441. Free(Information);
  1442. } else {
  1443. Free(Information);
  1444. status = CsQueryValueKey(*Key, c_szScopeMask, &Information);
  1445. if (NT_SUCCESS(status)) {
  1446. if (!(*Mask = IpPszToHostAddr((PWCHAR)Information->Data))) {
  1447. Free(Information);
  1448. } else {
  1449. Free(Information);
  1450. *Address = RtlUlongByteSwap(*Address);
  1451. *Mask = RtlUlongByteSwap(*Mask);
  1452. if (LocalKey) { NtClose(LocalKey); }
  1453. return;
  1454. }
  1455. }
  1456. }
  1457. }
  1458. }
  1459. *Address = DEFAULT_SCOPE_ADDRESS;
  1460. *Mask = DEFAULT_SCOPE_MASK;
  1461. if (LocalKey) { NtClose(LocalKey); }
  1462. } // CsQueryScopeInformation
  1463. #endif
  1464. ULONG
  1465. CsQuerySharedConnection(
  1466. LPRASSHARECONN Connection
  1467. )
  1468. /*++
  1469. Routine Description:
  1470. This routine is invoked to retrieve the shared connection, if any.
  1471. Arguments:
  1472. Connection - receives the retrieved connection.
  1473. Return Value:
  1474. ULONG - Win32 status code.
  1475. --*/
  1476. {
  1477. BOOL fUninitializeCOM = TRUE;
  1478. IHNetIcsSettings *pIcsSettings;
  1479. IEnumHNetIcsPublicConnections *pEnumIcsPub;
  1480. IHNetIcsPublicConnection *pIcsPub;
  1481. IHNetConnection *pConn;
  1482. ULONG ulCount;
  1483. HRESULT hr;
  1484. ASSERT(NULL != g_pCoInitializeEx);
  1485. ASSERT(NULL != g_pCoCreateInstance);
  1486. ASSERT(NULL != g_pCoUninitialize);
  1487. if (!Connection) { return ERROR_INVALID_PARAMETER; }
  1488. hr = g_pCoInitializeEx(
  1489. NULL,
  1490. COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE
  1491. );
  1492. if (FAILED(hr))
  1493. {
  1494. fUninitializeCOM = FALSE;
  1495. if(RPC_E_CHANGED_MODE == hr)
  1496. {
  1497. hr = S_OK;
  1498. }
  1499. }
  1500. if (SUCCEEDED(hr))
  1501. {
  1502. hr = g_pCoCreateInstance(
  1503. &CLSID_HNetCfgMgr,
  1504. NULL,
  1505. CLSCTX_ALL,
  1506. &IID_IHNetIcsSettings,
  1507. (VOID**)&pIcsSettings
  1508. );
  1509. }
  1510. if (SUCCEEDED(hr))
  1511. {
  1512. hr = IHNetIcsSettings_EnumIcsPublicConnections(
  1513. pIcsSettings,
  1514. &pEnumIcsPub
  1515. );
  1516. IHNetIcsSettings_Release(pIcsSettings);
  1517. }
  1518. if (SUCCEEDED(hr))
  1519. {
  1520. hr = IEnumHNetIcsPublicConnections_Next(
  1521. pEnumIcsPub,
  1522. 1,
  1523. &pIcsPub,
  1524. &ulCount
  1525. );
  1526. IEnumHNetIcsPublicConnections_Release(pEnumIcsPub);
  1527. }
  1528. if (SUCCEEDED(hr) && 1 == ulCount)
  1529. {
  1530. hr = IHNetIcsPublicConnection_QueryInterface(
  1531. pIcsPub,
  1532. &IID_IHNetConnection,
  1533. (VOID**)&pConn
  1534. );
  1535. IHNetIcsPublicConnection_Release(pIcsPub);
  1536. }
  1537. else
  1538. {
  1539. hr = E_FAIL;
  1540. }
  1541. if (SUCCEEDED(hr))
  1542. {
  1543. HNET_CONN_PROPERTIES *pProps;
  1544. //
  1545. // Convert the IHNetConnection to a RASSHARECONN
  1546. //
  1547. hr = IHNetConnection_GetProperties(pConn, &pProps);
  1548. if (SUCCEEDED(hr) && pProps->fLanConnection)
  1549. {
  1550. GUID *pGuid;
  1551. g_pCoTaskMemFree(pProps);
  1552. hr = IHNetConnection_GetGuid(pConn, &pGuid);
  1553. if (SUCCEEDED(hr))
  1554. {
  1555. RasGuidToSharedConnection(pGuid, Connection);
  1556. g_pCoTaskMemFree(pGuid);
  1557. }
  1558. }
  1559. else if (SUCCEEDED(hr))
  1560. {
  1561. LPWSTR pszwName;
  1562. LPWSTR pszwPath;
  1563. g_pCoTaskMemFree(pProps);
  1564. hr = IHNetConnection_GetName(pConn, &pszwName);
  1565. if (SUCCEEDED(hr))
  1566. {
  1567. hr = IHNetConnection_GetRasPhonebookPath(pConn, &pszwPath);
  1568. if (SUCCEEDED(hr))
  1569. {
  1570. RasEntryToSharedConnection(pszwPath, pszwName, Connection);
  1571. g_pCoTaskMemFree(pszwPath);
  1572. }
  1573. g_pCoTaskMemFree(pszwName);
  1574. }
  1575. }
  1576. IHNetConnection_Release(pConn);
  1577. }
  1578. if (fUninitializeCOM)
  1579. {
  1580. g_pCoUninitialize();
  1581. }
  1582. return SUCCEEDED(hr) ? NO_ERROR : ERROR_CAN_NOT_COMPLETE;
  1583. } // CsQuerySharedConnection
  1584. #if 0
  1585. ULONG
  1586. CsQuerySharedPrivateLan(
  1587. GUID* LanGuid
  1588. )
  1589. /*++
  1590. Routine Description:
  1591. This routine is invoked to retrieve the private LAN connection, if any.
  1592. Arguments:
  1593. LanGuid - receives the retrieved GUID.
  1594. Return Value:
  1595. ULONG - Win32 status code.
  1596. --*/
  1597. {
  1598. ULONG Error;
  1599. HANDLE Key;
  1600. PKEY_VALUE_PARTIAL_INFORMATION Information;
  1601. NTSTATUS status;
  1602. UNICODE_STRING UnicodeString;
  1603. //
  1604. // Open the 'SharedAccess\Parameters' key, read the 'SharedPrivateLan'
  1605. // value, and convert it to a GUID
  1606. //
  1607. status = CsOpenKey(&Key, KEY_READ, c_szSharedAccessParametersKey);
  1608. if (!NT_SUCCESS(status)) {
  1609. TRACE1("CsQuerySharedPrivateLan: NtOpenKey=%x", status);
  1610. return RtlNtStatusToDosError(status);
  1611. }
  1612. status = CsQueryValueKey(Key, c_szSharedPrivateLan, &Information);
  1613. NtClose(Key);
  1614. if (!NT_SUCCESS(status)) { return NO_ERROR; }
  1615. RtlInitUnicodeString(&UnicodeString, (PWCHAR)Information->Data);
  1616. status = RtlGUIDFromString(&UnicodeString, LanGuid);
  1617. Free(Information);
  1618. return NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
  1619. } // CsQuerySharedPrivateLan
  1620. ULONG
  1621. CsQuerySharedPrivateLanAddress(
  1622. PULONG Address
  1623. )
  1624. /*++
  1625. Routine Description:
  1626. This routine is invoked to retrieve the IP address assigned
  1627. to the shared private LAN interface.
  1628. Arguments:
  1629. Address - on output, receives the IP address of the shared private LAN
  1630. interface.
  1631. Return Value:
  1632. ULONG - Win32 status code.
  1633. --*/
  1634. {
  1635. ULONG AdapterIndex;
  1636. PALLOCATEANDGETIPADDRTABLEFROMSTACK AllocateAndGetIpAddrTableFromStack;
  1637. ULONG Error;
  1638. PGETINTERFACEINFO GetInterfaceInfo;
  1639. HINSTANCE Hinstance;
  1640. ULONG i;
  1641. PKEY_VALUE_PARTIAL_INFORMATION Information;
  1642. HANDLE Key = NULL;
  1643. NTSTATUS status;
  1644. PMIB_IPADDRTABLE Table;
  1645. if (!Address) { return ERROR_INVALID_PARAMETER; }
  1646. //
  1647. // Open the service's Parameters key and attempt to retrieve
  1648. // the GUID for the shared private LAN interface.
  1649. //
  1650. status = CsOpenKey(&Key, KEY_READ, c_szSharedAccessParametersKey);
  1651. if (!NT_SUCCESS(status)) {
  1652. TRACE1("CsQuerySharedPrivateLanAddress: NtOpenKey=%x", status);
  1653. return RtlNtStatusToDosError(status);
  1654. }
  1655. status = CsQueryValueKey(Key, c_szSharedPrivateLan, &Information);
  1656. NtClose(Key);
  1657. if (!NT_SUCCESS(status)) { return ERROR_SHARING_NO_PRIVATE_LAN; }
  1658. //
  1659. // Load IPHLPAPI, which contains the 'GetInterfaceInfo' entrypoint
  1660. // that we will use to map this GUID to an adapter-index,
  1661. // as well as the 'AllocateAndGetIpAddrTableFromStack' entrypoint
  1662. // that we will use to map the adapter-index to an IP address list.
  1663. //
  1664. if (!(Hinstance = LoadLibraryW(c_szIphlpapiDll)) ||
  1665. !(AllocateAndGetIpAddrTableFromStack =
  1666. (PALLOCATEANDGETIPADDRTABLEFROMSTACK)
  1667. GetProcAddress(
  1668. Hinstance, c_szAllocateAndGetIpAddrTableFromStack
  1669. )) ||
  1670. !(GetInterfaceInfo =
  1671. (PGETINTERFACEINFO)
  1672. GetProcAddress(
  1673. Hinstance, c_szGetInterfaceInfo
  1674. ))) {
  1675. if (Hinstance) { FreeLibrary(Hinstance); }
  1676. Free(Information);
  1677. return ERROR_PROC_NOT_FOUND;
  1678. }
  1679. //
  1680. // Map the GUID to an adapter index.
  1681. //
  1682. AdapterIndex =
  1683. CsMapGuidToAdapterIndex((PWCHAR)Information->Data, GetInterfaceInfo);
  1684. Free(Information);
  1685. if (AdapterIndex == (ULONG)-1) {
  1686. FreeLibrary(Hinstance);
  1687. return ERROR_SHARING_NO_PRIVATE_LAN;
  1688. }
  1689. //
  1690. // Map the adapter index to an IP address
  1691. //
  1692. Error =
  1693. AllocateAndGetIpAddrTableFromStack(
  1694. &Table,
  1695. FALSE,
  1696. GetProcessHeap(),
  1697. 0
  1698. );
  1699. FreeLibrary(Hinstance);
  1700. if (Error) { return Error; }
  1701. for (i = 0; i < Table->dwNumEntries; i++) {
  1702. if (AdapterIndex == Table->table[i].dwIndex) {
  1703. break;
  1704. }
  1705. }
  1706. if (i >= Table->dwNumEntries) {
  1707. Error = ERROR_SHARING_NO_PRIVATE_LAN;
  1708. } else {
  1709. *Address = Table->table[i].dwAddr;
  1710. }
  1711. HeapFree(GetProcessHeap(), 0, Table);
  1712. return Error;
  1713. } // CsQuerySharedPrivateLanAddress
  1714. #endif
  1715. NTSTATUS
  1716. CsQueryValueKey(
  1717. HANDLE Key,
  1718. const WCHAR ValueName[],
  1719. PKEY_VALUE_PARTIAL_INFORMATION* Information
  1720. )
  1721. /*++
  1722. Routine Description:
  1723. This routine is called to obtain the value of a registry key.
  1724. Arguments:
  1725. Key - the key to be queried
  1726. ValueName - the value to be queried
  1727. Information - receives a pointer to the information read
  1728. Return Value:
  1729. NTSTATUS - NT status code.
  1730. --*/
  1731. {
  1732. UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
  1733. ULONG InformationLength;
  1734. NTSTATUS status;
  1735. UNICODE_STRING UnicodeString;
  1736. RtlInitUnicodeString(&UnicodeString, ValueName);
  1737. *Information = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
  1738. InformationLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  1739. //
  1740. // Read the value's size
  1741. //
  1742. status =
  1743. NtQueryValueKey(
  1744. Key,
  1745. &UnicodeString,
  1746. KeyValuePartialInformation,
  1747. *Information,
  1748. InformationLength,
  1749. &InformationLength
  1750. );
  1751. if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW &&
  1752. status != STATUS_BUFFER_TOO_SMALL) {
  1753. *Information = NULL;
  1754. return status;
  1755. }
  1756. //
  1757. // Allocate space for the value's size
  1758. //
  1759. *Information = (PKEY_VALUE_PARTIAL_INFORMATION)Malloc(InformationLength+2);
  1760. if (!*Information) { return STATUS_NO_MEMORY; }
  1761. //
  1762. // Read the value's data
  1763. //
  1764. status =
  1765. NtQueryValueKey(
  1766. Key,
  1767. &UnicodeString,
  1768. KeyValuePartialInformation,
  1769. *Information,
  1770. InformationLength,
  1771. &InformationLength
  1772. );
  1773. if (!NT_SUCCESS(status)) { Free(*Information); *Information = NULL; }
  1774. return status;
  1775. } // CsQueryValueKey
  1776. #if 0
  1777. ULONG
  1778. CsRenameSharedConnection(
  1779. LPRASSHARECONN NewConnection
  1780. )
  1781. /*++
  1782. Routine Description:
  1783. This routine is invoked to change the name of the currently-shared
  1784. connection, if any. It is assumed that the private LAN will remain
  1785. unchanged, and that the connection which is currently shared is a dialup
  1786. connection.
  1787. Arguments:
  1788. NewConnection - the new name for the shared connection
  1789. Return Value:
  1790. ULONG - Win32 status code.
  1791. --*/
  1792. {
  1793. HANDLE AdminHandle;
  1794. PUCHAR Buffer;
  1795. LPRASSHARECONN OldConnection;
  1796. ULONG Error;
  1797. PUCHAR Header;
  1798. HANDLE Key;
  1799. PKEY_VALUE_PARTIAL_INFORMATION Information;
  1800. HANDLE InterfaceHandle;
  1801. ULONG Length;
  1802. OBJECT_ATTRIBUTES ObjectAttributes;
  1803. HANDLE ServerHandle;
  1804. NTSTATUS status;
  1805. UNICODE_STRING UnicodeString;
  1806. //
  1807. // Open the 'SharedAccess\Parameters' key,
  1808. // and read the 'SharedConnection' value
  1809. //
  1810. status = CsOpenKey(&Key, KEY_READ, c_szSharedAccessParametersKey);
  1811. if (!NT_SUCCESS(status)) {
  1812. TRACE1("CsRenameSharedConnection: NtOpenKey=%x", status);
  1813. return RtlNtStatusToDosError(status);
  1814. }
  1815. status = CsQueryValueKey(Key, c_szSharedConnection, &Information);
  1816. NtClose(Key);
  1817. if (!NT_SUCCESS(status)) { return NO_ERROR; }
  1818. //
  1819. // Validate the data retrieved
  1820. //
  1821. if (Information->DataLength != sizeof(RASSHARECONN) ||
  1822. ((LPRASSHARECONN)Information->Data)->dwSize != sizeof(RASSHARECONN)
  1823. ) {
  1824. TRACE2(
  1825. "CsRenameSharedConnection: invalid length %d (size=%d) in registry",
  1826. Information->DataLength, ((LPRASSHARECONN)Information->Data)->dwSize
  1827. );
  1828. Free(Information); return NO_ERROR;
  1829. }
  1830. //
  1831. // Ensure that the connection which was shared is not a LAN connection,
  1832. // and if so proceed to share the new connection instead.
  1833. //
  1834. OldConnection = (LPRASSHARECONN)Information->Data;
  1835. if (OldConnection->fIsLanConnection) {
  1836. TRACE("CsRenameSharedConnection: cannot rename shared LAN connection");
  1837. Free(Information); return ERROR_INVALID_PARAMETER;
  1838. }
  1839. //
  1840. // Clear any cached credentials for the old connection,
  1841. // and share the new connection.
  1842. //
  1843. RasSetSharedConnectionCredentials(OldConnection, NULL);
  1844. Free(Information);
  1845. return CsShareConnection(NewConnection);
  1846. } // CsRenameSharedConnection
  1847. ULONG
  1848. CsSetupSharedPrivateLan(
  1849. REFGUID LanGuid,
  1850. BOOLEAN EnableSharing
  1851. )
  1852. /*++
  1853. Routine Description:
  1854. This routine is invoked to configure the designated private connection.
  1855. Arguments:
  1856. LanGuid - identifies the LAN connection to be configured
  1857. EnableSharing - if TRUE, sharing is enabled and the static address is set;
  1858. otherwise, sharing is disabled.
  1859. Return Value:
  1860. ULONG - Win32 status code.
  1861. --*/
  1862. {
  1863. CS_ADDRESS_INFORMATION AddressInformation;
  1864. PALLOCATEANDGETIPADDRTABLEFROMSTACK AllocateAndGetIpAddrTableFromStack;
  1865. ANSI_STRING AnsiString;
  1866. ULONG Error;
  1867. PGETINTERFACEINFO GetInterfaceInfo;
  1868. HINSTANCE Hinstance;
  1869. ULONG i;
  1870. HANDLE Key = NULL;
  1871. UNICODE_STRING LanGuidString;
  1872. ULONG ScopeAddress;
  1873. ULONG ScopeMask;
  1874. PSETADAPTERIPADDRESS SetAdapterIpAddress;
  1875. ULONG Size;
  1876. NTSTATUS status;
  1877. PMIB_IPADDRTABLE Table;
  1878. UNICODE_STRING UnicodeString;
  1879. //
  1880. // To install or remove the static private IP address,
  1881. // we make use of several entrypoints in IPHLPAPI.DLL,
  1882. // which we now load dynamically.
  1883. //
  1884. RtlStringFromGUID(LanGuid, &UnicodeString);
  1885. RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
  1886. if (!(Hinstance = LoadLibraryW(c_szIphlpapiDll)) ||
  1887. !(AllocateAndGetIpAddrTableFromStack =
  1888. (PALLOCATEANDGETIPADDRTABLEFROMSTACK)
  1889. GetProcAddress(
  1890. Hinstance, c_szAllocateAndGetIpAddrTableFromStack
  1891. )) ||
  1892. !(GetInterfaceInfo =
  1893. (PGETINTERFACEINFO)
  1894. GetProcAddress(
  1895. Hinstance, c_szGetInterfaceInfo
  1896. )) ||
  1897. !(SetAdapterIpAddress =
  1898. (PSETADAPTERIPADDRESS)
  1899. GetProcAddress(
  1900. Hinstance, c_szSetAdapterIpAddress
  1901. ))) {
  1902. if (Hinstance) { FreeLibrary(Hinstance); }
  1903. RtlFreeUnicodeString(&UnicodeString);
  1904. RtlFreeAnsiString(&AnsiString);
  1905. return ERROR_PROC_NOT_FOUND;
  1906. }
  1907. //
  1908. // Determine whether some LAN adapter other than the private LAN
  1909. // is already using a 169.254.0.0 address.
  1910. // In the process, make sure that the private LAN has only one
  1911. // IP address (otherwise, 'SetAdapterIpAddress' fails.)
  1912. //
  1913. CsQueryScopeInformation(&Key, &ScopeAddress, &ScopeMask);
  1914. if (!Key) {
  1915. FreeLibrary(Hinstance);
  1916. RtlFreeUnicodeString(&UnicodeString);
  1917. RtlFreeAnsiString(&AnsiString);
  1918. return ERROR_CAN_NOT_COMPLETE;
  1919. }
  1920. Error =
  1921. AllocateAndGetIpAddrTableFromStack(
  1922. &Table,
  1923. FALSE,
  1924. GetProcessHeap(),
  1925. 0
  1926. );
  1927. if (!Error) {
  1928. ULONG Index;
  1929. ULONG Count;
  1930. Index = CsMapGuidToAdapterIndex(UnicodeString.Buffer, GetInterfaceInfo);
  1931. for (i = 0, Count = 0; i < Table->dwNumEntries; i++) {
  1932. if (Index == Table->table[i].dwIndex) {
  1933. ++Count;
  1934. } else if ((Table->table[i].dwAddr & ScopeMask) ==
  1935. (ScopeAddress & ScopeMask)) {
  1936. //
  1937. // It appears that some other LAN adapter has an address in
  1938. // the proposed scope.
  1939. // This may happen when multiple netcards go into autonet mode
  1940. // or when the RAS server is handing out autonet addresses.
  1941. // Therefore, as long as we're using the autonet scope,
  1942. // allow this behavior; otherwise prohibit it.
  1943. //
  1944. if ((ScopeAddress & ScopeMask) != 0x0000fea9) {
  1945. break;
  1946. }
  1947. }
  1948. }
  1949. if (i < Table->dwNumEntries) {
  1950. Error = ERROR_SHARING_ADDRESS_EXISTS;
  1951. } else if (Count > 1) {
  1952. Error = ERROR_SHARING_MULTIPLE_ADDRESSES;
  1953. }
  1954. HeapFree(GetProcessHeap(), 0, Table);
  1955. }
  1956. if (Error) {
  1957. FreeLibrary(Hinstance);
  1958. RtlFreeUnicodeString(&UnicodeString);
  1959. RtlFreeAnsiString(&AnsiString);
  1960. NtClose(Key);
  1961. return Error;
  1962. }
  1963. //
  1964. // Set the predefined static IP address for the private LAN,
  1965. // which we now read either from the registry or from the internal default.
  1966. //
  1967. // Before actually making the change, we capture the original IP address
  1968. // so that it can be restored when the user turns off shared access.
  1969. // Once the IP address is changed, we backup the original IP address
  1970. // in the shared access parameters key.
  1971. //
  1972. status =
  1973. CspCaptureAddressInformation(
  1974. UnicodeString.Buffer, &AddressInformation
  1975. );
  1976. Error =
  1977. SetAdapterIpAddress(
  1978. AnsiString.Buffer,
  1979. FALSE,
  1980. ScopeAddress,
  1981. ScopeMask,
  1982. 0
  1983. );
  1984. if (!Error) {
  1985. if (NT_SUCCESS(status)) {
  1986. CspBackupAddressInformation(Key, &AddressInformation);
  1987. }
  1988. } else {
  1989. TRACE1("CsSetupSharedPrivateLan: SetAdapterIpAddress=%d", Error);
  1990. if (Error == ERROR_TOO_MANY_NAMES) {
  1991. Error = ERROR_SHARING_MULTIPLE_ADDRESSES;
  1992. } else {
  1993. //
  1994. // Query the state of the connection.
  1995. // If it is disconnected, convert the error code
  1996. // to something more informative.
  1997. //
  1998. UNICODE_STRING DeviceString;
  1999. NIC_STATISTICS NdisStatistics;
  2000. RtlInitUnicodeString(&DeviceString, c_szDevice);
  2001. RtlAppendUnicodeStringToString(&DeviceString, &UnicodeString);
  2002. NdisStatistics.Size = sizeof(NdisStatistics);
  2003. NdisQueryStatistics(&DeviceString, &NdisStatistics);
  2004. RtlFreeUnicodeString(&DeviceString);
  2005. if (NdisStatistics.MediaState == MEDIA_STATE_UNKNOWN) {
  2006. Error = ERROR_SHARING_HOST_ADDRESS_CONFLICT;
  2007. } else if (NdisStatistics.DeviceState != DEVICE_STATE_CONNECTED ||
  2008. NdisStatistics.MediaState != MEDIA_STATE_CONNECTED) {
  2009. Error = ERROR_SHARING_NO_PRIVATE_LAN;
  2010. }
  2011. }
  2012. }
  2013. CspCleanupAddressInformation(&AddressInformation);
  2014. FreeLibrary(Hinstance);
  2015. RtlFreeUnicodeString(&UnicodeString);
  2016. RtlFreeAnsiString(&AnsiString);
  2017. if (Error) { NtClose(Key); return Error; }
  2018. //
  2019. // All went well above; now we save the name of the private LAN connection
  2020. // under the 'SharedAccess\\Parameters' registry key.
  2021. //
  2022. RtlStringFromGUID(LanGuid, &LanGuidString);
  2023. RtlInitUnicodeString(&UnicodeString, c_szSharedPrivateLan);
  2024. status =
  2025. NtSetValueKey(
  2026. Key,
  2027. &UnicodeString,
  2028. 0,
  2029. REG_SZ,
  2030. LanGuidString.Buffer,
  2031. LanGuidString.Length + sizeof(WCHAR)
  2032. );
  2033. NtClose(Key);
  2034. RtlFreeUnicodeString(&LanGuidString);
  2035. if (!NT_SUCCESS(status)) { return RtlNtStatusToDosError(status); }
  2036. return NO_ERROR;
  2037. } // CsSetupSharedPrivateLan
  2038. ULONG
  2039. CsSetSharedPrivateLan(
  2040. REFGUID LanGuid
  2041. )
  2042. /*++
  2043. Routine Description:
  2044. This routine is invoked to (re)configure the designated private connection
  2045. Arguments:
  2046. LanGuid - identifies the new LAN connection to be configured
  2047. Return Value:
  2048. ULONG - Win32 status code.
  2049. --*/
  2050. {
  2051. HANDLE Key;
  2052. ULONG Error;
  2053. NTSTATUS status;
  2054. PKEY_VALUE_PARTIAL_INFORMATION Information;
  2055. UNICODE_STRING UnicodeString;
  2056. status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
  2057. if (!NT_SUCCESS(status)) {
  2058. TRACE1("CsSetSharedPrivateLan: CsOpenKey=%x", status);
  2059. return RtlNtStatusToDosError(status);
  2060. }
  2061. //
  2062. // Remove old information (and reset old interface) in registry if present
  2063. //
  2064. status = CsQueryValueKey(Key, c_szSharedPrivateLan, &Information);
  2065. RtlInitUnicodeString(&UnicodeString, c_szSharedPrivateLan);
  2066. NtDeleteValueKey(Key, &UnicodeString);
  2067. if (NT_SUCCESS(status)) {
  2068. CspRestoreAddressInformation(Key, (PWCHAR)Information->Data);
  2069. Free(Information);
  2070. }
  2071. //
  2072. // Setup the private network with a private address
  2073. //
  2074. Error = CsSetupSharedPrivateLan(LanGuid, TRUE);
  2075. if (Error) {
  2076. TRACE1("CsSetSharedPrivateLan: CsSetupSharedPrivateLan=%d",Error);
  2077. return Error;
  2078. }
  2079. return NO_ERROR;
  2080. } // CsSetSharedPrivateLan
  2081. ULONG
  2082. CsShareConnection(
  2083. LPRASSHARECONN Connection
  2084. )
  2085. /*++
  2086. Routine Description:
  2087. This routine enables sharing on the connection with the given name.
  2088. Arguments:
  2089. Connection - the connection to be shared
  2090. Return Value:
  2091. ULONG - Win32 status code.
  2092. --*/
  2093. {
  2094. UNICODE_STRING BindList;
  2095. HANDLE Key;
  2096. UNICODE_STRING LowerComponent;
  2097. IP_PNP_RECONFIG_REQUEST Request;
  2098. NTSTATUS status;
  2099. UNICODE_STRING UpperComponent;
  2100. ULONG Value;
  2101. UNICODE_STRING ValueString;
  2102. //
  2103. // Set the 'SharedConnection' value in the registry,
  2104. // under the 'SharedAccess\Parameters' key.
  2105. //
  2106. status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
  2107. if (!NT_SUCCESS(status)) {
  2108. TRACE1("CsShareConnection: CsOpenKey=%x", status);
  2109. return RtlNtStatusToDosError(status);
  2110. }
  2111. RtlInitUnicodeString(&ValueString, c_szSharedConnection);
  2112. status =
  2113. NtSetValueKey(
  2114. Key,
  2115. &ValueString,
  2116. 0,
  2117. REG_BINARY,
  2118. Connection,
  2119. Connection->dwSize
  2120. );
  2121. NtClose(Key);
  2122. if (!NT_SUCCESS(status)) {
  2123. TRACE1("CsShareConnection: NtSetValueKey=%x", status);
  2124. return RtlNtStatusToDosError(status);
  2125. }
  2126. return NO_ERROR;
  2127. } // CsShareConnection
  2128. #endif
  2129. VOID
  2130. CsShutdownModule(
  2131. VOID
  2132. )
  2133. /*++
  2134. Routine Description:
  2135. This routine is invoked to clean up state for the module.
  2136. Arguments:
  2137. none.
  2138. Return Value:
  2139. none.
  2140. Environment:
  2141. Invoked with 'CsCriticalSection' held by the caller.
  2142. --*/
  2143. {
  2144. if (CsInitialized) {
  2145. if (CsOle32Dll) { FreeLibrary(CsOle32Dll); CsOle32Dll = NULL; }
  2146. }
  2147. } // CsShutdownModule
  2148. #if 0
  2149. ULONG
  2150. CsStartService(
  2151. VOID
  2152. )
  2153. /*++
  2154. Routine Description:
  2155. This routine is invoked to start the routing and remote access service.
  2156. Arguments:
  2157. none.
  2158. Return Value:
  2159. ULONG - Win32 status code.
  2160. Revision History:
  2161. Loosely based on CService::HrMoveOutOfState by KennT.
  2162. --*/
  2163. {
  2164. ULONG Error;
  2165. SC_HANDLE ScmHandle;
  2166. SC_HANDLE ServiceHandle;
  2167. SERVICE_STATUS ServiceStatus;
  2168. ULONG Timeout;
  2169. //
  2170. // Connect to the service control manager
  2171. //
  2172. ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  2173. if (!ScmHandle) { return GetLastError(); }
  2174. do {
  2175. //
  2176. // Open the shared access service
  2177. //
  2178. ServiceHandle =
  2179. OpenService(ScmHandle, c_szSharedAccess, SERVICE_ALL_ACCESS);
  2180. if (!ServiceHandle) { Error = GetLastError(); break; }
  2181. //
  2182. // Mark it as auto-start
  2183. //
  2184. ChangeServiceConfig(
  2185. ServiceHandle,
  2186. SERVICE_NO_CHANGE,
  2187. SERVICE_AUTO_START,
  2188. SERVICE_NO_CHANGE,
  2189. NULL,
  2190. NULL,
  2191. NULL,
  2192. NULL,
  2193. NULL,
  2194. NULL,
  2195. NULL
  2196. );
  2197. //
  2198. // Attempt to start the service
  2199. //
  2200. if (!StartService(ServiceHandle, 0, NULL)) {
  2201. Error = GetLastError();
  2202. if (Error == ERROR_SERVICE_ALREADY_RUNNING) { Error = NO_ERROR; }
  2203. break;
  2204. }
  2205. //
  2206. // Wait for the service to start
  2207. //
  2208. Timeout = 30;
  2209. Error = ERROR_CAN_NOT_COMPLETE;
  2210. do {
  2211. //
  2212. // Query the service's state
  2213. //
  2214. if (!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  2215. Error = GetLastError(); break;
  2216. }
  2217. //
  2218. // See if the service has started
  2219. //
  2220. if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
  2221. Error = NO_ERROR; break;
  2222. } else if (ServiceStatus.dwCurrentState == SERVICE_STOPPED ||
  2223. ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) {
  2224. break;
  2225. }
  2226. //
  2227. // Wait a little longer
  2228. //
  2229. Sleep(1000);
  2230. } while(Timeout--);
  2231. } while(FALSE);
  2232. if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
  2233. CloseServiceHandle(ScmHandle);
  2234. return Error;
  2235. } // CsStartService
  2236. VOID
  2237. CsStopService(
  2238. VOID
  2239. )
  2240. /*++
  2241. Routine Description:
  2242. This routine is invoked to uninstall the service.
  2243. The routine, however, does not uninstall the service at all,
  2244. which just goes to show you...
  2245. Instead, it marks the service as demand-start.
  2246. Arguments:
  2247. none.
  2248. Return Value:
  2249. none.
  2250. --*/
  2251. {
  2252. ULONG Error;
  2253. SC_HANDLE ScmHandle;
  2254. SC_HANDLE ServiceHandle;
  2255. SERVICE_STATUS ServiceStatus;
  2256. //
  2257. // Connect to the service control manager
  2258. //
  2259. ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  2260. if (!ScmHandle) { return; }
  2261. do {
  2262. //
  2263. // Open the shared access service
  2264. //
  2265. ServiceHandle =
  2266. OpenService(ScmHandle, c_szSharedAccess, SERVICE_ALL_ACCESS);
  2267. if (!ServiceHandle) { Error = GetLastError(); break; }
  2268. //
  2269. // Mark it as demand-start
  2270. //
  2271. ChangeServiceConfig(
  2272. ServiceHandle,
  2273. SERVICE_NO_CHANGE,
  2274. SERVICE_DEMAND_START,
  2275. SERVICE_NO_CHANGE,
  2276. NULL,
  2277. NULL,
  2278. NULL,
  2279. NULL,
  2280. NULL,
  2281. NULL,
  2282. NULL
  2283. );
  2284. //
  2285. // Attempt to stop the service
  2286. //
  2287. ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
  2288. } while(FALSE);
  2289. if (ServiceHandle) { CloseServiceHandle(ServiceHandle); }
  2290. CloseServiceHandle(ScmHandle);
  2291. return;
  2292. } // CsStopService
  2293. ULONG
  2294. CsUnshareConnection(
  2295. BOOLEAN RemovePrivateLan,
  2296. PBOOLEAN Shared
  2297. )
  2298. /*++
  2299. Routine Description:
  2300. This routine is invoked to unshare a shared connection.
  2301. This is accomplished by removing the settings from the registry.
  2302. Arguments:
  2303. RemovePrivateLan - if TRUE, the private LAN connection is reset
  2304. to use DHCP rather than the NAT private address.
  2305. Shared - receives 'TRUE' if a shared connection was found, FALSE otherwise.
  2306. Return Value:
  2307. ULONG - Win32 status code.
  2308. --*/
  2309. {
  2310. LPRASSHARECONN Connection;
  2311. HANDLE Key;
  2312. PKEY_VALUE_PARTIAL_INFORMATION Information;
  2313. PIP_NAT_INTERFACE_INFO Info;
  2314. GUID LanGuid;
  2315. ULONG Length;
  2316. ULONG Size;
  2317. NTSTATUS status;
  2318. UNICODE_STRING UnicodeString;
  2319. if (Shared) { *Shared = FALSE; }
  2320. //
  2321. // Open the 'SharedAccess\Parameters' key, read the 'SharedConnection'
  2322. // value, and validate the information retrieved.
  2323. //
  2324. status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
  2325. if (!NT_SUCCESS(status)) {
  2326. TRACE1("CsUnshareConnection: NtOpenKey=%x", status);
  2327. return RtlNtStatusToDosError(status);
  2328. }
  2329. //
  2330. // Read the 'SharedConnection' value
  2331. //
  2332. status = CsQueryValueKey(Key, c_szSharedConnection, &Information);
  2333. if (!NT_SUCCESS(status)) { return NO_ERROR; }
  2334. if (Information->DataLength != sizeof(RASSHARECONN) ||
  2335. ((LPRASSHARECONN)Information->Data)->dwSize != sizeof(RASSHARECONN)) {
  2336. TRACE2(
  2337. "CsUnshareConnection: invalid length %d (size=%d) in registry",
  2338. Information->DataLength, ((LPRASSHARECONN)Information->Data)->dwSize
  2339. );
  2340. NtClose(Key); Free(Information); return NO_ERROR;
  2341. }
  2342. //
  2343. // Inform the caller that a connection was indeed originally shared,
  2344. // clear any credentials cached for that connection, free the buffer
  2345. // containing the shared connection's information, and delete the
  2346. // 'SharedConnection' value from the registry.
  2347. //
  2348. if (Shared) { *Shared = TRUE; }
  2349. Connection = (LPRASSHARECONN)Information->Data;
  2350. RasSetSharedConnectionCredentials(Connection, NULL);
  2351. Free(Information);
  2352. RtlInitUnicodeString(&UnicodeString, c_szSharedConnection);
  2353. NtDeleteValueKey(Key, &UnicodeString);
  2354. //
  2355. // See if we're resetting the private LAN connection,
  2356. // and if so, read (and delete) the 'SharedPrivateLan' value.
  2357. // In the process, restore the original address-information
  2358. // for the connection.
  2359. //
  2360. if (RemovePrivateLan) {
  2361. status = CsQueryValueKey(Key, c_szSharedPrivateLan, &Information);
  2362. RtlInitUnicodeString(&UnicodeString, c_szSharedPrivateLan);
  2363. NtDeleteValueKey(Key, &UnicodeString);
  2364. if (NT_SUCCESS(status)) {
  2365. CspRestoreAddressInformation(Key, (PWCHAR)Information->Data);
  2366. Free(Information);
  2367. }
  2368. }
  2369. NtClose(Key);
  2370. return NO_ERROR;
  2371. } // CsUnshareConnection
  2372. WCHAR*
  2373. StrDupW(
  2374. LPCWSTR psz
  2375. )
  2376. {
  2377. WCHAR* psz2 = Malloc((lstrlenW(psz) + 1) * sizeof(WCHAR));
  2378. if (psz2) { lstrcpyW(psz2, psz); }
  2379. return psz2;
  2380. }
  2381. VOID
  2382. TestBackupAddress(
  2383. PWCHAR Guid
  2384. )
  2385. {
  2386. HANDLE Key;
  2387. CS_ADDRESS_INFORMATION Information;
  2388. NTSTATUS status;
  2389. status = CspCaptureAddressInformation(Guid, &Information);
  2390. if (NT_SUCCESS(status)) {
  2391. status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
  2392. if (NT_SUCCESS(status)) {
  2393. CspBackupAddressInformation(Key, &Information);
  2394. NtClose(Key);
  2395. }
  2396. CspCleanupAddressInformation(&Information);
  2397. }
  2398. }
  2399. VOID
  2400. TestRestoreAddress(
  2401. PWCHAR Guid
  2402. )
  2403. {
  2404. HANDLE Key;
  2405. NTSTATUS status;
  2406. status = CsOpenKey(&Key, KEY_ALL_ACCESS, c_szSharedAccessParametersKey);
  2407. if (NT_SUCCESS(status)) {
  2408. status = CspRestoreAddressInformation(Key, Guid);
  2409. }
  2410. }
  2411. VOID CsRefreshNetConnections(
  2412. VOID
  2413. )
  2414. {
  2415. BOOL bUninitializeCOM = TRUE;
  2416. HRESULT hResult;
  2417. ASSERT(NULL != g_pCoInitializeEx);
  2418. ASSERT(NULL != g_pCoCreateInstance);
  2419. ASSERT(NULL != g_pCoUninitialize);
  2420. hResult = g_pCoInitializeEx(NULL, COINIT_MULTITHREADED|COINIT_DISABLE_OLE1DDE); // we don't know if the thread is COM or not
  2421. if(RPC_E_CHANGED_MODE == hResult)
  2422. {
  2423. hResult = S_OK;
  2424. bUninitializeCOM = FALSE;
  2425. }
  2426. if (SUCCEEDED(hResult))
  2427. {
  2428. INetConnectionRefresh * pRefresh = NULL;
  2429. hResult = g_pCoCreateInstance(&CLSID_ConnectionManager, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD, &IID_INetConnectionRefresh, (void**) &pRefresh);
  2430. if(SUCCEEDED(hResult))
  2431. {
  2432. g_pCoSetProxyBlanket((IUnknown*) pRefresh, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
  2433. // ignore error as the interface is not invalidated by error
  2434. hResult = INetConnectionRefresh_RefreshAll(pRefresh);
  2435. INetConnectionRefresh_Release(pRefresh);
  2436. }
  2437. if(TRUE == bUninitializeCOM)
  2438. {
  2439. g_pCoUninitialize();
  2440. }
  2441. }
  2442. }
  2443. #endif