/*++ Copyright (c) 1998, Microsoft Corporation Module Name: svcmain.c Abstract: This module contains code for the module's shared-access mode, in which the module runs as a service rather than as a routing component. Author: Abolade Gbadegesin (aboladeg) 31-Aug-1998 Revision History: --*/ #include "precomp.h" #pragma hdrstop #include #include #include #include #include "beacon.h" HANDLE NhpAddressChangeEvent = NULL; OVERLAPPED NhpAddressChangeOverlapped; HANDLE NhpAddressChangeWaitHandle = NULL; SERVICE_STATUS NhpServiceStatus; SERVICE_STATUS_HANDLE NhpServiceStatusHandle = 0; PIP_ADAPTER_BINDING_INFO NhpSharedPrivateLanBindingInfo = NULL; GUID NhpSharedPrivateLanGuid; ULONG NhpSharedPrivateLanIndex = (ULONG)-1; HANDLE NhpStopDhcpEvent = NULL; HANDLE NhpStopDnsEvent = NULL; HANDLE NhpStopAlgEvent = NULL; HANDLE NhpStopH323Event = NULL; HANDLE NhpStopNatEvent = NULL; BOOLEAN NhpRasmanReferenced = FALSE; BOOLEAN NhpFwLoggingInitialized = FALSE; BOOL NhPolicyAllowsFirewall = TRUE; BOOL NhPolicyAllowsSharing = TRUE; BOOLEAN NoLocalDns = TRUE; //whether DNS server is running or going to run on local host BOOLEAN NhpNoLocalDhcp = TRUE; //whether DHCP server is running or goint to run on local host BOOLEAN NhpQoSEnabled = FALSE; IUdpBroadcastMapper *NhpUdpBroadcastMapper = NULL; BOOLEAN NhpClassObjectsRegistered = FALSE; // // Pointer to the GlobalInterfaceTable for the process // IGlobalInterfaceTable *NhGITp = NULL; // // GIT cookie for the IHNetCfgMgr instance // DWORD NhCfgMgrCookie = 0; const TCHAR c_szDnsServiceName[] = TEXT("DNS"); const TCHAR c_szDhcpServiceName[] = TEXT("DHCPServer"); ULONG NhpEnableQoSWindowSizeAdjustment( BOOLEAN fEnable ); VOID NhpStartAddressChangeNotification( VOID ); VOID NhpStopAddressChangeNotification( VOID ); VOID NhpUpdateConnectionsFolder( VOID ); BOOL NhpUpdatePolicySettings( VOID ); HRESULT NhGetHNetCfgMgr( IHNetCfgMgr **ppCfgMgr ) /*++ Routine Description: This routine obtains a pointer to the home networking configuration manager. Arguments: ppCfgMgr - receives the IHNetCfgMgr pointer. The caller must release this pointer. Return Value: standard HRESULT Environment: COM must be initialized on the calling thread --*/ { HRESULT hr = S_OK; if (NULL == NhGITp) { EnterCriticalSection(&NhLock); if (NULL == NhGITp) { IHNetCfgMgr *pCfgMgr; // // Create the global interface table // hr = CoCreateInstance( CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IGlobalInterfaceTable, &NhGITp) ); if (SUCCEEDED(hr)) { // // Create the homenet configuration manager // hr = CoCreateInstance( CLSID_HNetCfgMgr, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IHNetCfgMgr, &pCfgMgr) ); if (FAILED(hr)) { NhTrace( TRACE_FLAG_INIT, "NhGetHNetCfgMgr: Unable to create HNetCfgMgr (0x%08x)", hr ); } } else { NhTrace( TRACE_FLAG_INIT, "NhGetHNetCfgMgr: Unable to create GIT (0x%08x)", hr ); } if (SUCCEEDED(hr)) { // // Store the CfgMgr pointer in the GIT // hr = NhGITp->RegisterInterfaceInGlobal( pCfgMgr, IID_IHNetCfgMgr, &NhCfgMgrCookie ); pCfgMgr->Release(); if (FAILED(hr)) { NhTrace( TRACE_FLAG_INIT, "NhGetHNetCfgMgr: Unable to register HNetCfgMgr (0x%08x)", hr ); } } } LeaveCriticalSection(&NhLock); } if (SUCCEEDED(hr)) { hr = NhGITp->GetInterfaceFromGlobal( NhCfgMgrCookie, IID_PPV_ARG(IHNetCfgMgr, ppCfgMgr) ); } return hr; } // NhGetHNetCfgMgr ULONG NhMapGuidToAdapter( PWCHAR Guid ) /*++ Routine Description: This routine is invoked to map a GUID to an adapter index. It does so by querying 'GetInterfaceInfo' for the array of interfaces, which contains the GUID and adapter index for each interface. Arguments: Guid - the GUID to be mapped to an adapter index. Return Value: ULONG - the required adapter index --*/ { ULONG AdapterIndex = (ULONG)-1; ULONG i; ULONG GuidLength; PIP_INTERFACE_INFO Info; PWCHAR Name; ULONG NameLength; ULONG Size; PROFILE("NhMapGuidToAdapter"); Size = 0; GuidLength = lstrlenW(Guid); if (GetInterfaceInfo(NULL, &Size) == ERROR_INSUFFICIENT_BUFFER) { Info = reinterpret_cast( HeapAlloc(GetProcessHeap(), 0, Size) ); if (Info) { if (GetInterfaceInfo(Info, &Size) == NO_ERROR) { for (i = 0; i < (ULONG)Info->NumAdapters; i++) { NameLength = lstrlenW(Info->Adapter[i].Name); if (NameLength < GuidLength) { continue; } Name = Info->Adapter[i].Name + (NameLength - GuidLength); if (lstrcmpiW(Guid, Name) == 0) { AdapterIndex = Info->Adapter[i].Index; break; } } } HeapFree(GetProcessHeap(), 0, Info); } } return AdapterIndex; } // NhMapGuidToAdapter VOID NTAPI NhpAddressChangeCallbackRoutine( PVOID Context, BOOLEAN TimedOut ) /*++ Routine Description: This routine is invoked when a change to a local address is signalled. It is responsible for updating the bindings of the private and public interfaces, and re-requesting change notification. Arguments: none used. Return Value: none. --*/ { PROFILE("NhpAddressChangeCallbackRoutine"); NtSetEvent(NatConnectionNotifyEvent, NULL); NhpStartAddressChangeNotification(); } // NhpAddressChangeCallbackRoutine VOID NhpDeletePrivateInterface( VOID ) /*++ Routine Description: This routine is invoked to remove the private interface from each shared-access component. Arguments: none. Return Value: none. --*/ { PROFILE("NhpDeletePrivateInterface"); if (NhpStopDnsEvent) { DnsRmDeleteInterface(0); } if (NhpStopDhcpEvent) { DhcpRmDeleteInterface(0); } if (NhpStopAlgEvent) { AlgRmDeleteInterface(0); } if (NhpStopH323Event) { H323RmDeleteInterface(0); } if (NhpStopNatEvent) { NatRmDeleteInterface(0); } RtlZeroMemory(&NhpSharedPrivateLanGuid, sizeof(NhpSharedPrivateLanGuid)); } // NhpDeletePrivateInterface ULONG NhpEnableQoSWindowSizeAdjustment( BOOLEAN fEnable ) /*++ Routine Description: Instructs PSCHED to enable or disable window size adjustment. Arguments: fEnable -- TRUE if adjustments are to be enabled; FALSE, to be disabled Return Value: ULONG -- Win32 error --*/ { ULONG ulError = ERROR_SUCCESS; DWORD dwValue; WMIHANDLE hDataBlock = NULL; GUID qosGuid; PROFILE("NhpEnableQoSWindowSizeAdjustment"); do { // // WmiOpenBlock doesn't take a const guid, se we need to // copy the defind value // CopyMemory(&qosGuid, &GUID_QOS_ENABLE_WINDOW_ADJUSTMENT, sizeof(GUID)); // // Obtain a handle to the data block // ulError = WmiOpenBlock( &qosGuid, GENERIC_WRITE, &hDataBlock ); if (ERROR_SUCCESS != ulError) { NhTrace( TRACE_FLAG_INIT, "NhpEnableQoSWindowSizeAdjustment: WmiOpenBlock = %u", ulError ); break; } // // Set the value for the data block // dwValue = (fEnable ? 1 : 0); ulError = WmiSetSingleInstanceW( hDataBlock, L"PSCHED", 0, sizeof(dwValue), &dwValue ); if (ERROR_SUCCESS != ulError) { NhTrace( TRACE_FLAG_INIT, "NhpEnableQoSWindowSizeAdjustment: WmiSetSingleInstanceW = %u", ulError ); break; } } while (FALSE); if (NULL != hDataBlock) { WmiCloseBlock(hDataBlock); } return ulError; } // NhpEnableQoSWindowSizeAdjustment VOID NhpStartAddressChangeNotification( VOID ) /*++ Routine Description: This routine is invoked to request notifications of changes to local IP addresses. The notifications are signalled on an event which is created in this routine, and are acted on in a callback routine which is registered in this routine. Arguments: none. Return Value: none. --*/ { ULONG Error; NTSTATUS status; HANDLE TcpipHandle; PROFILE("NhpStartAddressChangeNotification"); // // Create an event on which to receive notifications // and register a callback routine to be invoked if the event is signalled. // Then request notification of address changes on the event. // do { EnterCriticalSection(&NhLock); if (!NhpAddressChangeEvent) { status = NtCreateEvent( &NhpAddressChangeEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE ); if (!NT_SUCCESS(status)) { break; } status = RtlRegisterWait( &NhpAddressChangeWaitHandle, NhpAddressChangeEvent, NhpAddressChangeCallbackRoutine, NULL, INFINITE, 0 ); if (!NT_SUCCESS(status)) { break; } } ZeroMemory(&NhpAddressChangeOverlapped, sizeof(OVERLAPPED)); NhpAddressChangeOverlapped.hEvent = NhpAddressChangeEvent; Error = NotifyAddrChange(&TcpipHandle, &NhpAddressChangeOverlapped); if (Error != ERROR_IO_PENDING) { break; } LeaveCriticalSection(&NhLock); return; } while(FALSE); // // A failure has occurred, so cleanup and quit. // We proceed in this case without notification of address changes. // NhpStopAddressChangeNotification(); LeaveCriticalSection(&NhLock); } // NhpStartAddressChangeNotification VOID NhpStopAddressChangeNotification( VOID ) /*++ Routine Description: This routine is called to stop notification of local IP address changes, and to clean up resources used for handling notifications. Arguments: none. Return Value: none. --*/ { EnterCriticalSection(&NhLock); if (NhpAddressChangeWaitHandle) { RtlDeregisterWait(NhpAddressChangeWaitHandle); NhpAddressChangeWaitHandle = NULL; } if (NhpAddressChangeEvent) { NtClose(NhpAddressChangeEvent); NhpAddressChangeEvent = NULL; } LeaveCriticalSection(&NhLock); } // NhpStopAddressChangeNotification VOID NhpUpdateConnectionsFolder( VOID ) /*++ Routine Description: This routine is called to refresh the connections folder UI. Arguments: None. Return Value: None. Environment: COM must be initialized on the calling thread. --*/ { HRESULT hr; INetConnectionRefresh *pNetConnectionRefresh; hr = CoCreateInstance( CLSID_ConnectionManager, NULL, CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD, IID_PPV_ARG(INetConnectionRefresh, &pNetConnectionRefresh) ); if (SUCCEEDED(hr)) { pNetConnectionRefresh->RefreshAll(); pNetConnectionRefresh->Release(); } } // NhpUpdateConnectionsFolder BOOL NhpUpdatePolicySettings( VOID ) /*++ Routine Description: This routine is called to update the group policy settings. Arguments: None. Return Value: BOOL -- returns TRUE if the policy settings have changed since the previous call. Environment: COM must be initialized on the calling thread. --*/ { INetConnectionUiUtilities *pNetConnUiUtil; HRESULT hr; BOOL fOldPolicyAllowsFirewall; BOOL fOldPolicyAllowsSharing; BOOL fPolicyAllowsFirewall; BOOL fPolicyAllowsSharing; hr = CoCreateInstance( CLSID_NetConnectionUiUtilities, NULL, CLSCTX_ALL, IID_PPV_ARG(INetConnectionUiUtilities, &pNetConnUiUtil) ); if (SUCCEEDED(hr)) { fPolicyAllowsFirewall = pNetConnUiUtil->UserHasPermission(NCPERM_PersonalFirewallConfig); fPolicyAllowsSharing = pNetConnUiUtil->UserHasPermission(NCPERM_ShowSharedAccessUi); pNetConnUiUtil->Release(); } else { // // On failure assume that policy permits everything. // fPolicyAllowsFirewall = TRUE; fPolicyAllowsSharing = TRUE; NhTrace( TRACE_FLAG_INIT, "NhpUpdatePolicySettings: Unable to create INetConnectionUiUtilities (0x%08x)", hr ); } // // Update global variables w/ new settings // fOldPolicyAllowsFirewall = InterlockedExchange( reinterpret_cast(&NhPolicyAllowsFirewall), static_cast(fPolicyAllowsFirewall) ); fOldPolicyAllowsSharing = InterlockedExchange( reinterpret_cast(&NhPolicyAllowsSharing), static_cast(fPolicyAllowsSharing) ); NhTrace( TRACE_FLAG_INIT, "NhpUpdatePolicySettings: NhPolicyAllowsFirewall=%i, NhPolicyAllowsSharing=%i", NhPolicyAllowsFirewall, NhPolicyAllowsSharing ); return (fOldPolicyAllowsFirewall != fPolicyAllowsFirewall || fOldPolicyAllowsSharing != fPolicyAllowsSharing); } // NhpUpdatePolicySettings BOOLEAN NhQueryScopeInformation( PULONG Address, PULONG Mask ) /*++ Routine Description: This routine is called to retrieve information about the current scope for automatic addressing. Arguments: Address - receives the address of the scope Mask - receives the network mask of the scope Return Value: BOOLEAN - TRUE if successful, FALSE otherwise. --*/ { EnterCriticalSection(&NhLock); if (0 == NhDhcpScopeAddress) { LeaveCriticalSection(&NhLock); return FALSE; } *Address = NhDhcpScopeAddress; *Mask = NhDhcpScopeMask; LeaveCriticalSection(&NhLock); return TRUE; } // NhQueryScopeInformation ULONG NhpQueryServiceStartType(SC_HANDLE hService, DWORD * pdwStartType) { ASSERT(hService); ASSERT(pdwStartType); ULONG Error = ERROR_SUCCESS; DWORD cbBuf = sizeof (QUERY_SERVICE_CONFIG) + 5 * (32 * sizeof(WCHAR)); LPQUERY_SERVICE_CONFIG pConfig = NULL; pConfig = (LPQUERY_SERVICE_CONFIG) NH_ALLOCATE(cbBuf); if (!pConfig) return ERROR_NOT_ENOUGH_MEMORY; do { if (!QueryServiceConfig(hService, pConfig, cbBuf, &cbBuf)) { Error = GetLastError(); if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { NH_FREE(pConfig); pConfig = (LPQUERY_SERVICE_CONFIG) NH_ALLOCATE(cbBuf); if (NULL == pConfig) { Error = ERROR_NOT_ENOUGH_MEMORY; break; } if (!QueryServiceConfig(hService, pConfig, cbBuf, &cbBuf)) { Error = GetLastError(); break; } } else { break; } } Error = ERROR_SUCCESS; *pdwStartType = pConfig->dwStartType; } while(FALSE); if (pConfig) NH_FREE(pConfig); return Error; } BOOL NhpIsServiceRunningOrGoingToRun(SC_HANDLE hScm, LPCTSTR pSvcName) { BOOL bRet = FALSE; SC_HANDLE hService = NULL; DWORD dwStartType = 0; hService = OpenService(hScm, pSvcName, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG); if (hService) { SERVICE_STATUS Status; ZeroMemory(&Status, sizeof(Status)); if (ERROR_SUCCESS == NhpQueryServiceStartType(hService, &dwStartType) && SERVICE_AUTO_START == dwStartType) { bRet = TRUE; } else if (QueryServiceStatus(hService, &Status) && (SERVICE_RUNNING == Status.dwCurrentState || SERVICE_START_PENDING == Status.dwCurrentState)) { bRet = TRUE; } CloseServiceHandle(hService); } return bRet; } ULONG NhpEnableICSDNS( VOID ) /*++ Routine Description: This routine enables "ICS DNS". Arguments: none. Return Value: Win32 error. --*/ { ULONG Error = NO_ERROR; do { Error = DnsRmEnableInterface(0); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhpEnableICSDNS: DnsRmEnableInterface=%d", Error ); break; } Error = DnsEnableSuffixQuery(); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhpEnableICSDNS: DnsEnableSuffixQuery=%d", Error ); break; } } while (FALSE); return Error; } ULONG NhpDisableICSDNS( VOID ) /*++ Routine Description: This routine disables "ICS DNS". Arguments: none. Return Value: Win32 error. --*/ { ULONG Error = NO_ERROR; do { Error = DnsRmDisableInterface(0); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhpDisableICSDNS: DnsRmDisableInterface=%d", Error ); break; } Error = DnsDisableSuffixQuery(); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhpDisableICSDNS: DnsDisableSuffixQuery=%d", Error ); break; } } while (FALSE); return Error; } ULONG NhStartICSProtocols( VOID ) /*++ Routine Description: This routine starts the DNS and DHCP modules. Arguments: Argument* - count and array of arguments specified to the service Return Value: none. --*/ { ULONG Error = NO_ERROR; IP_AUTO_DHCP_GLOBAL_INFO DhcpInfo = { IPNATHLP_LOGGING_ERROR, 0, 7 * 24 * 60, DEFAULT_SCOPE_ADDRESS, DEFAULT_SCOPE_MASK, 0 }; IP_DNS_PROXY_GLOBAL_INFO DnsInfo = { IPNATHLP_LOGGING_ERROR, IP_DNS_PROXY_FLAG_ENABLE_DNS, 3 }; // // Get ICS settings to see if these should be started... // do { SC_HANDLE hScm = OpenSCManager(NULL, NULL, GENERIC_READ); //dont start the DNS module if DNS server is running on local host if (hScm) { NoLocalDns = !NhpIsServiceRunningOrGoingToRun(hScm, c_szDnsServiceName); } if (NoLocalDns) { if (!(NhpStopDnsEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { Error = GetLastError(); break; } else { Error = DnsRmStartProtocol( NhpStopDnsEvent, NULL, &DnsInfo, IP_NAT_VERSION, sizeof(IP_DNS_PROXY_GLOBAL_INFO), 1 ); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhStartICSProtocols: NhpStartICSDNS=%d", Error ); CloseHandle(NhpStopDnsEvent); NhpStopDnsEvent = NULL; break; } } } //dont start the DHCP module if DNS server is running on local host if (hScm) { NhpNoLocalDhcp = !NhpIsServiceRunningOrGoingToRun(hScm, c_szDhcpServiceName); } if (NhpNoLocalDhcp) { if (!(NhpStopDhcpEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { break; } else { NhQueryScopeInformation( &DhcpInfo.ScopeNetwork, &DhcpInfo.ScopeMask ); DhcpInfo.ScopeNetwork &= DhcpInfo.ScopeMask; Error = DhcpRmStartProtocol( NhpStopDhcpEvent, NULL, &DhcpInfo, IP_NAT_VERSION, sizeof(DhcpInfo), 1 ); if (Error) { NhTrace( TRACE_FLAG_INIT, "ServiceMain: DhcpRmStartProtocol=%d", Error ); CloseHandle(NhpStopDhcpEvent); NhpStopDhcpEvent = NULL; break; } } } if (hScm) CloseServiceHandle(hScm); // // Instruct QoS to enable window size adjustments. Any error that // occurs here is not propagated, as ICS will still work correctly // if this fails. // ULONG Error2 = NhpEnableQoSWindowSizeAdjustment(TRUE); if (ERROR_SUCCESS == Error2) { NhpQoSEnabled = TRUE; } // // Create the UDP broadcast mapper // HRESULT hr; CComObject *pUdpBroadcast; hr = CComObject::CreateInstance(&pUdpBroadcast); if (SUCCEEDED(hr)) { pUdpBroadcast->AddRef(); hr = pUdpBroadcast->Initialize(&NatComponentReference); if (SUCCEEDED(hr)) { hr = pUdpBroadcast->QueryInterface( IID_PPV_ARG(IUdpBroadcastMapper, &NhpUdpBroadcastMapper) ); } pUdpBroadcast->Release(); } if (FAILED(hr)) { Error = ERROR_CAN_NOT_COMPLETE; break; } // // Start the Beaconing Service // StartBeaconSvr(); return NO_ERROR; } while (FALSE); return Error; } ULONG NhStopICSProtocols( VOID ) /*++ Routine Description: This routine stops the "ICS" modules (DNS, DHCP, QoSWindow, Beacon etc.) Arguments: none. Return Value: none. --*/ { ULONG Error = NO_ERROR; // // Stop the Beaconing Service // StopBeaconSvr(); // // Cleanup the UDP broadcast mapper // if (NULL != NhpUdpBroadcastMapper) { NhpUdpBroadcastMapper->Shutdown(); NhpUdpBroadcastMapper->Release(); NhpUdpBroadcastMapper = NULL; } // // Instruct QoS to disable window size adjustments // if (NhpQoSEnabled) { NhpEnableQoSWindowSizeAdjustment(FALSE); NhpQoSEnabled = FALSE; } // // Remove the private interface from each shared-access component // NhpDeletePrivateInterface(); // // Stop DHCP followed by DNS // if (NhpStopDhcpEvent) { DhcpRmStopProtocol(); WaitForSingleObject(NhpStopDhcpEvent, INFINITE); CloseHandle(NhpStopDhcpEvent); NhpStopDhcpEvent = NULL; } if (NhpStopDnsEvent) { DnsRmStopProtocol(); WaitForSingleObject(NhpStopDnsEvent, INFINITE); CloseHandle(NhpStopDnsEvent); NhpStopDnsEvent = NULL; } return Error; } ULONG NhUpdatePrivateInterface( VOID ) /*++ Routine Description: This routine is invoked to add the private interface to each shared-access component. It is also invoked when the private interface is already added, but some change has occurred which requires that it be updated (e.g. IP address change). Arguments: none. Return Value: Win32 error. --*/ { ULONG AdapterIndex; PIP_ADAPTER_BINDING_INFO BindingInfo; ULONG Error; ULONG Count; GUID *pLanGuid; HRESULT hr; IHNetCfgMgr *pCfgMgr; IHNetIcsSettings *pIcsSettings; IEnumHNetIcsPrivateConnections *pEnum; IHNetIcsPrivateConnection *pIcsConn; IHNetConnection *pConn; IP_NAT_INTERFACE_INFO NatInfo = { 0, 0, { IP_NAT_VERSION, sizeof(RTR_INFO_BLOCK_HEADER), 0, { 0, 0, 0, 0 }} }; UNICODE_STRING UnicodeString; PROFILE("NhUpdatePrivateInterface"); // // We begin by reading the GUID from the configuration store, // and we then map that GUID to an adapter index. // Using that adapter index, we obtain the binding information // for the private interface. // We can then determine whether a change has occurred // by comparing the previous and new GUID and binding information. // // // Get the CfgMgr pointer out of the GIT // hr = NhGetHNetCfgMgr(&pCfgMgr); if (FAILED(hr)) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: GetInterfaceFromGlobal=0x%08x", hr ); return ERROR_CAN_NOT_COMPLETE; } // // Get the ICS settings interface // hr = pCfgMgr->QueryInterface(IID_PPV_ARG(IHNetIcsSettings, &pIcsSettings)); pCfgMgr->Release(); if (FAILED(hr)) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: QI for IHNetIcsSettings=0x%08x", hr ); return ERROR_CAN_NOT_COMPLETE; } // // Get the enumeration of the ICS private interfaces // hr = pIcsSettings->EnumIcsPrivateConnections(&pEnum); pIcsSettings->Release(); if (FAILED(hr)) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: EnumIcsPrivateConnections=0x%08x", hr ); return ERROR_CAN_NOT_COMPLETE; } // // Get the private connection // hr = pEnum->Next(1, &pIcsConn, &Count); pEnum->Release(); if (FAILED(hr) || 1 != Count) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: pEnum->Next=0x%08x, Count=%d", hr, Count ); return ERROR_CAN_NOT_COMPLETE; } // // QI for the IHNetConnection // hr = pIcsConn->QueryInterface(IID_PPV_ARG(IHNetConnection, &pConn)); pIcsConn->Release(); if (FAILED(hr)) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: QI for IHNetConnection=0x%08x", hr ); return ERROR_CAN_NOT_COMPLETE; } // // Get the GUID for the connection // hr = pConn->GetGuid(&pLanGuid); pConn->Release(); if (FAILED(hr)) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: GetGuid=0x%08x", hr ); return ERROR_CAN_NOT_COMPLETE; } // // Determine the adapter-index corresponding to the GUID // RtlStringFromGUID(*pLanGuid, &UnicodeString); AdapterIndex = NhMapGuidToAdapter(UnicodeString.Buffer); RtlFreeUnicodeString(&UnicodeString); if (AdapterIndex == (ULONG)-1) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: MapGuidToAdapter" ); CoTaskMemFree(pLanGuid); return ERROR_CAN_NOT_COMPLETE; } // // Retrieve the binding information for the adapter // BindingInfo = NhQueryBindingInformation(AdapterIndex); if (!BindingInfo) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: QueryBindingInformation failed(2)\n" ); CoTaskMemFree(pLanGuid); return ERROR_NO_SUCH_INTERFACE; } // // See if any change has occurred which requires an update. // if (RtlEqualMemory(pLanGuid, &NhpSharedPrivateLanGuid, sizeof(GUID)) && AdapterIndex == NhpSharedPrivateLanIndex && NhpSharedPrivateLanBindingInfo && BindingInfo->AddressCount == NhpSharedPrivateLanBindingInfo->AddressCount && BindingInfo->AddressCount && RtlEqualMemory( &BindingInfo->Address[0], &NhpSharedPrivateLanBindingInfo->Address[0], sizeof(IP_LOCAL_BINDING) )) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: no changes detected" ); NH_FREE(BindingInfo); CoTaskMemFree(pLanGuid); return NO_ERROR; } // // A change has occurred which requires an update. // First we get rid of any existing private LAN interface, // then we add the new interface to each component (NAT, DHCP, DNS proxy) // and bind and enable the new interface. // NhpDeletePrivateInterface(); do { Error = NatRmAddInterface( NULL, 0, PERMANENT, IF_TYPE_OTHER, IF_ACCESS_BROADCAST, IF_CONNECTION_DEDICATED, &NatInfo, IP_NAT_VERSION, sizeof(NatInfo), 1 ); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: NatRmAddInterface=%d", Error ); break; } if (NhpNoLocalDhcp) { Error = DhcpRmAddInterface( NULL, 0, PERMANENT, IF_TYPE_OTHER, IF_ACCESS_BROADCAST, IF_CONNECTION_DEDICATED, NULL, IP_NAT_VERSION, 0, 0 ); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: DhcpRmAddInterface=%d", Error ); break; } } if (NoLocalDns) { Error = DnsRmAddInterface( NULL, 0, PERMANENT, IF_TYPE_OTHER, IF_ACCESS_BROADCAST, IF_CONNECTION_DEDICATED, NULL, IP_NAT_VERSION, 0, 0 ); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: DnsRmAddInterface=%d", Error ); break; } } Error = AlgRmAddInterface( NULL, 0, PERMANENT, IF_TYPE_OTHER, IF_ACCESS_BROADCAST, IF_CONNECTION_DEDICATED, NULL, IP_NAT_VERSION, 0, 0 ); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: AlgRmAddInterface=%d", Error ); break; } Error = H323RmAddInterface( NULL, 0, PERMANENT, IF_TYPE_OTHER, IF_ACCESS_BROADCAST, IF_CONNECTION_DEDICATED, NULL, IP_NAT_VERSION, 0, 0 ); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: H323RmAddInterface=%d", Error ); break; } // // Bind the private interface of each component // Error = NatBindInterface(0, NULL, BindingInfo, AdapterIndex); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: NatRmBindInterface=%d", Error ); break; } if (NhpNoLocalDhcp) { Error = DhcpRmBindInterface(0, BindingInfo); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: DhcpRmBindInterface=%d", Error ); break; } } if (NoLocalDns) { Error = DnsRmBindInterface(0, BindingInfo); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: DnsRmBindInterface=%d", Error ); break; } } Error = AlgRmBindInterface(0, BindingInfo); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: AlgRmBindInterface=%d", Error ); break; } Error = H323RmBindInterface(0, BindingInfo); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: H323RmBindInterface=%d", Error ); break; } // // Enable the private interface for the components. // The NAT private interface is always enabled, and therefore // requires no additional call. // if (NhpNoLocalDhcp) { Error = DhcpRmEnableInterface(0); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: DhcpRmEnableInterface=%d", Error ); break; } } if (NoLocalDns) { Error = DnsRmEnableInterface(0); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: DnsRmEnableInterface=%d", Error ); break; } } Error = AlgRmEnableInterface(0); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: AlgRmEnableInterface=%d", Error ); break; } Error = H323RmEnableInterface(0); if (Error) { NhTrace( TRACE_FLAG_INIT, "NhUpdatePrivateInterface: H323RmEnableInterface=%d", Error ); break; } // // The interface was activated successfully. // RtlCopyMemory(&NhpSharedPrivateLanGuid, pLanGuid, sizeof(GUID)); NhpSharedPrivateLanIndex = AdapterIndex; CoTaskMemFree(pLanGuid); if (NhpSharedPrivateLanBindingInfo) { NH_FREE(NhpSharedPrivateLanBindingInfo); } NhpSharedPrivateLanBindingInfo = BindingInfo; return NO_ERROR; } while(FALSE); NH_FREE(BindingInfo); CoTaskMemFree(pLanGuid); return Error; } // NhUpdatePrivateInterface VOID ServiceHandler( ULONG ControlCode ) /*++ Routine Description: This routine is called to control the 'SharedAccess' service. Arguments: ControlCode - indicates the requested operation Return Value: none. --*/ { BOOLEAN ComInitialized = FALSE; HRESULT hr; PROFILE("ServiceHandler"); if (ControlCode == IPNATHLP_CONTROL_UPDATE_CONNECTION) { // // Update our policy settings // NhpUpdatePolicySettings(); // // Signal the configuration-changed event // NtSetEvent(NatConfigurationChangedEvent, NULL); SignalBeaconSvr(); } else if (ControlCode == IPNATHLP_CONTROL_UPDATE_SETTINGS) { // // Update all state which depends on shared access settings // NatRemoveApplicationSettings(); NhUpdateApplicationSettings(); NatInstallApplicationSettings(); } else if (ControlCode == IPNATHLP_CONTROL_UPDATE_FWLOGGER) { FwUpdateLoggingSettings(); } else if (ControlCode == IPNATHLP_CONTROL_UPDATE_AUTODIAL) { NtSetEvent(NatConnectionNotifyEvent, NULL); } else if (ControlCode == IPNATHLP_CONTROL_UPDATE_DNS_DISABLE) { NhpDisableICSDNS(); } else if (ControlCode == IPNATHLP_CONTROL_UPDATE_DNS_ENABLE) { NhpEnableICSDNS(); } else if (ControlCode == IPNATHLP_CONTROL_UPDATE_POLICY) { if (NhpUpdatePolicySettings()) { NtSetEvent(NatConfigurationChangedEvent, NULL); } } else if (ControlCode == SERVICE_CONTROL_STOP && NhpServiceStatus.dwCurrentState != SERVICE_STOPPED && NhpServiceStatus.dwCurrentState != SERVICE_STOP_PENDING) { NhpServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; if (NhpServiceStatusHandle) { SetServiceStatus(NhpServiceStatusHandle, &NhpServiceStatus); } if (NhpClassObjectsRegistered) { _Module.RevokeClassObjects(); NhpClassObjectsRegistered = FALSE; } NhpStopAddressChangeNotification(); if (NhpStopNatEvent) { NatRmStopProtocol(); WaitForSingleObject(NhpStopNatEvent, INFINITE); CloseHandle(NhpStopNatEvent); NhpStopNatEvent = NULL; } if (NhpStopAlgEvent) { AlgRmStopProtocol(); WaitForSingleObject(NhpStopAlgEvent, INFINITE); CloseHandle(NhpStopAlgEvent); NhpStopAlgEvent = NULL; } if (NhpStopH323Event) { H323RmStopProtocol(); WaitForSingleObject(NhpStopH323Event, INFINITE); CloseHandle(NhpStopH323Event); NhpStopH323Event = NULL; } EnterCriticalSection(&NhLock); NhFreeApplicationSettings(); if (NhpSharedPrivateLanBindingInfo) { NH_FREE(NhpSharedPrivateLanBindingInfo); NhpSharedPrivateLanBindingInfo = NULL; } LeaveCriticalSection(&NhLock); NhpServiceStatus.dwCurrentState = SERVICE_STOPPED; NhResetComponentMode(); // // Shutdown the firewall logging subsystem // if (NhpFwLoggingInitialized) { FwCleanupLogger(); NhpFwLoggingInitialized = FALSE; } // // Release our reference to RasMan // if (NhpRasmanReferenced) { RasReferenceRasman(FALSE); NhpRasmanReferenced = FALSE; } // // Update the network connections folder (so that the firewall icons // will disappear as necessary). // hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE ); if (SUCCEEDED(hr)) { ComInitialized = TRUE; } else if (RPC_E_CHANGED_MODE == hr) { hr = S_OK; } if (SUCCEEDED(hr)) { NhpUpdateConnectionsFolder(); } if (TRUE == ComInitialized) { CoUninitialize(); } NhStopEventLog(); } if (NhpServiceStatusHandle) { SetServiceStatus(NhpServiceStatusHandle, &NhpServiceStatus); } } // ServiceHandler VOID ServiceMain( ULONG ArgumentCount, PWCHAR ArgumentArray[] ) /*++ Routine Description: This routine is the entrypoint for the connection-sharing service. It is responsible for initializing the module and starting operation. Arguments: Argument* - count and array of arguments specified to the service Return Value: none. --*/ { HRESULT hr; ULONG Error; BOOLEAN ComInitialized = FALSE; IP_ALG_GLOBAL_INFO AlgInfo = { IPNATHLP_LOGGING_ERROR, 0 }; IP_H323_GLOBAL_INFO H323Info = { IPNATHLP_LOGGING_ERROR, 0 }; IP_NAT_GLOBAL_INFO NatInfo = { IPNATHLP_LOGGING_ERROR, 0, { IP_NAT_VERSION, FIELD_OFFSET(RTR_INFO_BLOCK_HEADER, TocEntry), 0, { 0, 0, 0, 0 }} }; PROFILE("ServiceMain"); do { NhStartEventLog(); // // Initialize service status, register a service control handler, // and indicate that the service is starting // ZeroMemory(&NhpServiceStatus, sizeof(NhpServiceStatus)); NhpServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; NhpServiceStatus.dwCurrentState = SERVICE_START_PENDING; NhpServiceStatusHandle = RegisterServiceCtrlHandler( TEXT("SharedAccess"), ServiceHandler ); if (!NhpServiceStatusHandle) { break; } // // Attempt to set the component into 'Shared Access' mode. // This module implements both shared-access and connection-sharing // which are mutually exclusive, so we need to ensure that // connection-sharing is not operational before proceeding. // if (!NhSetComponentMode(NhSharedAccessMode)) { NhTrace( TRACE_FLAG_INIT, "ServiceMain: cannot enable Shared Access mode" ); break; } // // Make sure COM is initialized on this thread // hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE ); if (SUCCEEDED(hr)) { ComInitialized = TRUE; } else { if (RPC_E_CHANGED_MODE != hr) { NhTrace( TRACE_FLAG_INIT, "ServiceMain: Unable to initialize COM (0x%08x)", hr ); break; } else { ASSERT(FALSE); NhTrace( TRACE_FLAG_INIT, "ServiceMain: Unexpectedly in STA!" ); } } // // Obtain the current policy settings. // NhpServiceStatus.dwCheckPoint++; SetServiceStatus(NhpServiceStatusHandle, &NhpServiceStatus); NhpUpdatePolicySettings(); // // Reference RasMan. As we live in the same process as rasman, the // normal SC dependency mechanism won't necessarily keep the rasman // service alive (119042) // NhpServiceStatus.dwCheckPoint++; SetServiceStatus(NhpServiceStatusHandle, &NhpServiceStatus); if (ERROR_SUCCESS != (Error = RasReferenceRasman(TRUE))) { NhTrace( TRACE_FLAG_INIT, "ServiceMain: Unable to reference RasMan (0x%08x)", Error ); break; } NhpRasmanReferenced = TRUE; // // Initialize the firewall logging subsystem // Error = FwInitializeLogger(); if (ERROR_SUCCESS != Error) { NhTrace( TRACE_FLAG_INIT, "ServiceMain: FwInitializeLogger=%d", Error ); break; } NhpFwLoggingInitialized = TRUE; // // Register the class object for our notification sink // hr = _Module.RegisterClassObjects( CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE ); if (FAILED(hr)) { NhTrace( TRACE_FLAG_INIT, "ServiceMain: _Module.RegisterClassObjects=0x%08x", hr ); break; } NhpClassObjectsRegistered = TRUE; // // Start operations by loading the NAT, Ftp, ALG, and H.323 modules // NhpServiceStatus.dwWaitHint = 30000; SetServiceStatus(NhpServiceStatusHandle, &NhpServiceStatus); if (!(NhpStopNatEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { break; } else { Error = NatRmStartProtocol( NhpStopNatEvent, NULL, &NatInfo, IP_NAT_VERSION, sizeof(NatInfo), 1 ); if (Error) { NhTrace( TRACE_FLAG_INIT, "ServiceMain: NatRmStartProtocol=%d", Error ); CloseHandle(NhpStopNatEvent); NhpStopNatEvent = NULL; break; } } NhpServiceStatus.dwCheckPoint++; SetServiceStatus(NhpServiceStatusHandle, &NhpServiceStatus); if (!(NhpStopAlgEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) { break; } else { Error = AlgRmStartProtocol( NhpStopAlgEvent, NULL, &AlgInfo, IP_NAT_VERSION, sizeof(AlgInfo), 1 ); if (Error) { NhTrace( TRACE_FLAG_INIT, "ServiceMain: AlgRmStartProtocol=%d", Error ); CloseHandle(NhpStopAlgEvent); NhpStopAlgEvent = NULL; break; } } NhpServiceStatus.dwCheckPoint++; SetServiceStatus(NhpServiceStatusHandle, &NhpServiceStatus); if (!(NhpStopH323Event = CreateEvent(NULL, FALSE, FALSE, NULL))) { break; } else { Error = H323RmStartProtocol( NhpStopH323Event, NULL, &H323Info, IP_NAT_VERSION, sizeof(H323Info), 1 ); if (Error) { NhTrace( TRACE_FLAG_INIT, "ServiceMain: H323RmStartProtocol=%d", Error ); CloseHandle(NhpStopH323Event); NhpStopH323Event = NULL; break; } } // // Start connection management. If needed, this will load the DNS and // DHCP modules. The Beacon Service is also started. // NhpServiceStatus.dwCheckPoint++; SetServiceStatus(NhpServiceStatusHandle, &NhpServiceStatus); Error = NatStartConnectionManagement(); if (Error) { NhTrace( TRACE_FLAG_INIT, "ServiceMain: NatStartConnectionManagement=%d", Error ); break; } NhpServiceStatus.dwCheckPoint++; SetServiceStatus(NhpServiceStatusHandle, &NhpServiceStatus); NhpStartAddressChangeNotification(); // // Indicate that the service is now up and running. // NhpServiceStatus.dwCurrentState = SERVICE_RUNNING; NhpServiceStatus.dwWaitHint = 0; NhpServiceStatus.dwCheckPoint = 0; NhpServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_PARAMCHANGE; SetServiceStatus(NhpServiceStatusHandle, &NhpServiceStatus); NhTrace(TRACE_FLAG_INIT, "ServiceMain: service started successfully"); // // Ask the connections folder to update itself. // NhpUpdateConnectionsFolder(); // // Uninitialize COM // if (TRUE == ComInitialized) { CoUninitialize(); } return; } while(FALSE); // // A failure occurred; do cleanup // NhpServiceStatus.dwWaitHint = 0; NhpServiceStatus.dwCheckPoint = 0; NhTrace(TRACE_FLAG_INIT, "ServiceMain: service could not start"); StopBeaconSvr(); // // Uninitialize COM // if (TRUE == ComInitialized) { CoUninitialize(); } ServiceHandler(SERVICE_CONTROL_STOP); } // ServiceMain