////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000 Microsoft Corporation // // Module: ConnMgr.cpp // // Author: Dan Elliott // // Abstract: // // Environment: // Neptune // // Revision History: // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Include files // #include #include #include #include #include #include #include #include #include #include #include #include #include "connmgr.h" #include "msobcomm.h" #define STRSAFE_NO_DEPRECATE #include const static int MAX_NUM_NET_COMPONENTS = 128; const static int MAX_GUID_LEN = 40; const DWORD CConnectionManager::RAS_AUTODIAL_ENABLED = 0; const DWORD CConnectionManager::RAS_AUTODIAL_DISABLED = 1; const DWORD CConnectionManager::RAS_AUTODIAL_DONT_KNOW = 2; //////////////////////////////// // Wininet/URL Helpers //////////////////////////////// STDAPI InternetOpenWrap( LPCTSTR pszAgent, DWORD dwAccessType, LPCTSTR pszProxy, LPCTSTR pszProxyBypass, DWORD dwFlags, HINTERNET * phFileHandle ); STDAPI InternetOpenUrlWrap( HINTERNET hInternet, LPCTSTR pszUrl, LPCTSTR pszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext, HINTERNET * phFileHandle ); STDAPI HttpQueryInfoWrap( HINTERNET hRequest, DWORD dwInfoLevel, LPVOID lpvBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex ); BOOL IsGlobalOffline( VOID ); VOID SetOffline( IN BOOL fOffline ); STDAPI PingWebServer( HINTERNET hInternet, LPCTSTR pszUrl, BOOL* pfConnected ); static NLA_BLOB* _NLABlobNext( IN NLA_BLOB* pnlaBlob ); static int _AllocWSALookupServiceNext( IN HANDLE hQuery, IN DWORD dwControlFlags, OUT LPWSAQUERYSET* ppResults ); static int StringCmpGUID( IN LPCWSTR szGuid, IN const GUID* pguid ); ////////////////////////////////////////////////////////////////////////////// // // CConnectionManager // // Default constructor // // parameters: // None. // // returns: // Nothing. // ////////////////////////////////////////////////////////////////////////////// CConnectionManager::CConnectionManager() : m_dwConnectionCapabilities(CONNECTIONTYPE_INVALID), m_dwPreferredConnection(CONNECTIONTYPE_INVALID), m_pPreferredConnection(NULL), m_cLanConnections(0), m_cPhoneConnections(0), m_hInternetPing(NULL), m_bProxySaved(FALSE), m_bProxyApplied(FALSE), m_bUseProxy(FALSE), m_dwRasAutodialDisable(RAS_AUTODIAL_DONT_KNOW), m_bForceOnline(FALSE), m_bExclude1394(FALSE) { ZeroMemory(&m_CurrentProxySettings, sizeof(m_CurrentProxySettings)); } // CConnectionManager::CConnectionManager ////////////////////////////////////////////////////////////////////////////// // // ~CConnectionManager // // Destructor. // // parameters: // None. // // returns: // Nothing. // ////////////////////////////////////////////////////////////////////////////// CConnectionManager::~CConnectionManager() { if (m_hInternetPing) { InternetCloseHandle(m_hInternetPing); } if (m_bProxySaved) { RestoreProxySettings(); FreeProxyOptionList(&m_CurrentProxySettings); } if (m_bForceOnline) { SetOffline(TRUE); TRACE(L"Set wininet back to offline"); } if (m_pPreferredConnection) { m_pPreferredConnection->Release(); } } // CConnectionManager::~CConnectionManager ////////////////////////////////////////////////////////////////////////////// // // GetCapabilities // // Queries the system for network connection capabilities. In addition, the // number of phone and LAN connections are counted and a preferred connection // type is determined. // // parameters: // None. // // returns: // A bitmask indicating the capabilities that are present. // ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CConnectionManager::GetCapabilities( DWORD* pdwCapabilities ) { TRACE(L"CConnectionManager::GetCapabilities\n"); HRESULT hr = S_OK; if (NULL == pdwCapabilities) { MYASSERT(NULL != pdwCapabilities); return E_POINTER; } #ifndef CONNMGR_INITFROMREGISTRY // The #else part of this directive contains test code that retrieves // connection capabilities and preference settings from the registry // DWORD m_cLanConnections = 0; DWORD m_cPhoneConnections = 0; // Initialize the net connection enumeration. For each interface // retrieved, SetProxyBlanket must be called to set the authentication for // the interface proxy handle because the Network Connection Manager lives // in a remote process with a different security context. // INetConnectionManager* pmgr = NULL; if ( SUCCEEDED(hr = CoCreateInstance( CLSID_ConnectionManager, NULL, CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD, IID_PPV_ARG(INetConnectionManager, &pmgr) ) ) && SUCCEEDED(hr = SetProxyBlanket(pmgr)) ) { TRACE(L"INetConnectionManager\n"); IEnumNetConnection* penum = NULL; if ( SUCCEEDED(hr = pmgr->EnumConnections(NCME_DEFAULT, &penum)) && SUCCEEDED(hr = SetProxyBlanket(penum)) ) { TRACE(L"IEnumNetConnection\n"); hr = penum->Reset(); while (S_OK == hr) { INetConnection* pnc = NULL; ULONG ulRetrieved; if ( S_OK == (hr = penum->Next(1, &pnc, &ulRetrieved)) && SUCCEEDED(hr = SetProxyBlanket(pnc)) ) { NETCON_PROPERTIES* pprops = NULL; hr = pnc->GetProperties(&pprops); if (SUCCEEDED(hr)) { // Log the network connectivity detected TRACE4(L"INetConnection: %s--%s--%d--%d\n", pprops->pszwName, pprops->pszwDeviceName, pprops->MediaType, pprops->Status); if (IsEnabledConnection(pprops)) { switch(pprops->MediaType) { case NCM_LAN: m_cLanConnections++; if (! (HasConnection( CONNECTIONTYPE_LAN_INDETERMINATE ) ) ) { if (HasBroadband()) { AddConnectionCapability( CONNECTIONTYPE_LAN_INDETERMINATE ); ClearConnectionCapability( CONNECTIONTYPE_LAN_BROADBAND ); } else { AddConnectionCapability( CONNECTIONTYPE_LAN_BROADBAND ); } } break; case NCM_SHAREDACCESSHOST_LAN: case NCM_SHAREDACCESSHOST_RAS: // Do not increment LAN connection count here. // This media type is in addition to the NCM_LAN // for the NIC. // AddConnectionCapability(CONNECTIONTYPE_LAN_ICS); break; case NCM_PHONE: #ifdef BLACKCOMB // For Whistler, determination of modem capability is done via // CObCommunicationManager::CheckDialReady. m_cPhoneConnections++; AddConnectionCapability(CONNECTIONTYPE_MODEM); #endif // BLACKCOMB break; case NCM_ISDN: case NCM_PPPOE: AddConnectionCapability(CONNECTIONTYPE_OTHER); break; } // switch } NcFreeNetconProperties(pprops); } } if (NULL != pnc) { pnc->Release(); } } if (S_FALSE == hr) { // IEnumNetConnection::Next returned S_FALSE to indicate // that no more elements were available. hr = S_OK; } } if (NULL != penum) { penum->Release(); } } if (NULL != pmgr) { pmgr->Release(); } DeterminePreferredConnection(); #else HKEY hKey = NULL; DWORD dwSize; if(ERROR_SUCCESS == (lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OOBE_MAIN_REG_KEY, 0, KEY_QUERY_VALUE, &hKey) ) ) { dwSize = sizeof(DWORD); if (ERROR_SUCCESS != (lResult = RegQueryValueEx(hKey, L"ConnectionCapabilities", 0, NULL, (LPBYTE)&m_dwConnectionCapabilities, &dwSize) ) ) { m_dwConnectionCapabilities = CONNECTIONTYPE_INVALID; } if (ERROR_SUCCESS != (lResult = RegQueryValueEx(hKey, L"PreferredConnection", 0, NULL, (LPBYTE)&m_dwPreferredConnection, &dwSize ) ) ) { m_dwPreferredConnection = CONNECTIONTYPE_INVALID; } RegCloseKey(hKey); } else { m_dwConnectionCapabilities = CONNECTIONTYPE_INVALID; m_dwPreferredConnection = CONNECTIONTYPE_INVALID; } #endif // CONNMGR_INITFROMREGISTRY TRACE(L"Exiting CConnectionManager::GetCapabilities\n"); *pdwCapabilities = m_dwConnectionCapabilities; return hr; } // CConnectionManager::GetCapabilities ////////////////////////////////////////////////////////////////////////////// // // SetPreferredConnection // // Set the preferred connection type. This allows an override of the // internally determined preference. // // parameters: // dwType one of the CONNECTIONTYPE_* values from obcomm.h. // // returns: // Boolean indicating whether the preferred connection was set. // ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CConnectionManager::SetPreferredConnection( const DWORD dwType, BOOL* pfSupportedType ) { BOOL fSupportedType = FALSE; switch (dwType) { case CONNECTIONTYPE_NONE: fSupportedType = TRUE; break; case CONNECTIONTYPE_MODEM: #ifdef BLACKCOMB // Modem capability for Whistler is handled via // CObCommunicationManager::CheckDialReady. However, CONNECTIONTYPE_MODEM is a // valid enum value to pass to this function so we don't want to hit the // default and assert. Hence, the case and break aren't ifdef'd. if (HasModem()) { fSupportedType = TRUE; } #endif // BLACKCOMB break; case CONNECTIONTYPE_LAN_ICS: if (HasIcs()) { fSupportedType = TRUE; } break; case CONNECTIONTYPE_LAN_BROADBAND: if (HasBroadband()) { fSupportedType = TRUE; } break; default: // Unsupported connection type or multiple connection types MYASSERT(FALSE); } // switch if (fSupportedType) { TRACE1(L"SetPreferredConnection %d", dwType); m_dwPreferredConnection = dwType; GetPreferredConnection(); } else { TRACE1(L"Unsupported Connection type %d", dwType); } if (NULL != pfSupportedType) { *pfSupportedType = fSupportedType; } return fSupportedType; } // CConnectionManager::SetPreferredConnection ////////////////////////////////////////////////////////////////////////////// // // ConnectedToInternet // // Determines whether the system is currently connected to the Internet. // // parameters: // pfConnected pointer to a buffer that will receive the boolean // indicating whether the connection exists. // // returns: // TRUE if system is connected to the internet via LAN or // dial-up or can be connected via dial-up // FALSE otherwise // ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CConnectionManager::ConnectedToInternet( BOOL* pfConnected ) { DWORD dwFlags; if (NULL == pfConnected) { MYASSERT(NULL != pfConnected); return E_POINTER; } *pfConnected = InternetGetConnectedState(&dwFlags, 0); // Log the network connectivity detected TRACE2(L"InternetGetConnectedState %d, 0x%08lx", *pfConnected, dwFlags); return S_OK; } // CConnectionManager::ConnectedToInternet /////////////////////////////////////////////////////////// // // SetPreferredConnectionTcpipProperties // STDMETHODIMP CConnectionManager::SetPreferredConnectionTcpipProperties( BOOL fAutoIpAddress, DWORD StaticIp_A, DWORD StaticIp_B, DWORD StaticIp_C, DWORD StaticIp_D, DWORD SubnetMask_A, DWORD SubnetMask_B, DWORD SubnetMask_C, DWORD SubnetMask_D, DWORD DefGateway_A, DWORD DefGateway_B, DWORD DefGateway_C, DWORD DefGateway_D, BOOL fAutoDns, DWORD DnsPref_A, DWORD DnsPref_B, DWORD DnsPref_C, DWORD DnsPref_D, DWORD DnsAlt_A, DWORD DnsAlt_B, DWORD DnsAlt_C, DWORD DnsAlt_D ) { HRESULT hr; REMOTE_IPINFO ipInfo; struct in_addr inaddr; WCHAR rgchStaticIp[INET_ADDRSTRLEN]; WCHAR rgchSubnetMask[INET_ADDRSTRLEN]; WCHAR rgchDefGateway[2 * INET_ADDRSTRLEN] = L"DefGw="; WCHAR rgchGatewayMetric[2 * INET_ADDRSTRLEN] = L"GwMetric="; WCHAR rgchDnsAddr[3 * INET_ADDRSTRLEN] = L"DNS="; WCHAR* pch = NULL; NETCON_PROPERTIES* pncProps = NULL; memset(&ipInfo, 0, sizeof(REMOTE_IPINFO)); hr = m_pPreferredConnection->GetProperties(&pncProps); if (FAILED(hr)) { TRACE1(L"Failed to retrieve preferred connection properties (0x%08X)\n", hr); goto SetPreferredConnectionTcpipPropertiesExit; } ipInfo.dwEnableDhcp = fAutoIpAddress; if (! fAutoIpAddress) { // if a static ip address was specified, convert it to a string and add // it to the REMOTE_IPINFO structure // memset(&inaddr, 0, sizeof(struct in_addr)); inaddr.S_un.S_un_b.s_b1 = (BYTE)StaticIp_A; inaddr.S_un.S_un_b.s_b2 = (BYTE)StaticIp_B; inaddr.S_un.S_un_b.s_b3 = (BYTE)StaticIp_C; inaddr.S_un.S_un_b.s_b4 = (BYTE)StaticIp_D; if (! INetNToW(inaddr, rgchStaticIp)) { hr = E_FAIL; TRACE1(L"Failed to create ip address string (0x%08X)\n", hr); goto SetPreferredConnectionTcpipPropertiesExit; } ipInfo.pszwIpAddrList = rgchStaticIp; memset(&inaddr, 0, sizeof(struct in_addr)); inaddr.S_un.S_un_b.s_b1 = (BYTE)SubnetMask_A; inaddr.S_un.S_un_b.s_b2 = (BYTE)SubnetMask_B; inaddr.S_un.S_un_b.s_b3 = (BYTE)SubnetMask_C; inaddr.S_un.S_un_b.s_b4 = (BYTE)SubnetMask_D; if (! INetNToW(inaddr, rgchSubnetMask)) { hr = E_FAIL; TRACE1(L"Failed to create ip address string (0x%08X)\n", hr); goto SetPreferredConnectionTcpipPropertiesExit; } ipInfo.pszwSubnetMaskList = rgchSubnetMask; pch = rgchDefGateway + lstrlen(rgchDefGateway); memset(&inaddr, 0, sizeof(struct in_addr)); inaddr.S_un.S_un_b.s_b1 = (BYTE)DefGateway_A; inaddr.S_un.S_un_b.s_b2 = (BYTE)DefGateway_B; inaddr.S_un.S_un_b.s_b3 = (BYTE)DefGateway_C; inaddr.S_un.S_un_b.s_b4 = (BYTE)DefGateway_D; if (! INetNToW(inaddr, pch)) { hr = E_FAIL; TRACE1(L"Failed to create ip address string (0x%08X)\n", hr); goto SetPreferredConnectionTcpipPropertiesExit; } lstrcat(rgchGatewayMetric, L"1"); TRACE4(L"Tcpip StaticIp %d.%d.%d.%d", StaticIp_A, StaticIp_B, StaticIp_C, StaticIp_D); TRACE4(L"Tcpip SubnetMask %d.%d.%d.%d", SubnetMask_A, SubnetMask_B, SubnetMask_C, SubnetMask_D); TRACE4(L"Tcpip DefGateway %d.%d.%d.%d", DefGateway_A, DefGateway_B, DefGateway_C, DefGateway_D); //ipInfo.pszwIpAddrList = rgchDefGateway; } if (! fAutoDns) { // if dns addresses were specified, convert them to strings and add // them to the REMOTE_IPINFO structure // pch = rgchDnsAddr + lstrlen(rgchDnsAddr); memset(&inaddr, 0, sizeof(struct in_addr)); inaddr.S_un.S_un_b.s_b1 = (BYTE)DnsPref_A; inaddr.S_un.S_un_b.s_b2 = (BYTE)DnsPref_B; inaddr.S_un.S_un_b.s_b3 = (BYTE)DnsPref_C; inaddr.S_un.S_un_b.s_b4 = (BYTE)DnsPref_D; if (! INetNToW(inaddr, pch)) { hr = E_FAIL; TRACE1(L"Failed to create dns address string (0x%08X)\n", hr); goto SetPreferredConnectionTcpipPropertiesExit; } pch += lstrlen(pch); *pch++ = L','; inaddr.S_un.S_un_b.s_b1 = (BYTE)DnsAlt_A; inaddr.S_un.S_un_b.s_b2 = (BYTE)DnsAlt_B; inaddr.S_un.S_un_b.s_b3 = (BYTE)DnsAlt_C; inaddr.S_un.S_un_b.s_b4 = (BYTE)DnsAlt_D; if (! INetNToW(inaddr, pch)) { hr = E_FAIL; TRACE1(L"Failed to create alternate dns address string (0x%08X)\n", hr); goto SetPreferredConnectionTcpipPropertiesExit; } TRACE4(L"Tcpip DnsPref %d.%d.%d.%d", DnsPref_A, DnsPref_B, DnsPref_C, DnsPref_D); TRACE4(L"Tcpip DnsAlt %d.%d.%d.%d", DnsAlt_A, DnsAlt_B, DnsAlt_C, DnsAlt_D); } // plus 4 for 3 semi-colons and the null-terminator ipInfo.pszwOptionList = (WCHAR*) malloc((lstrlen(rgchDefGateway) + lstrlen(rgchGatewayMetric) + lstrlen(rgchDnsAddr) + 4) * sizeof(WCHAR) ); if (NULL == ipInfo.pszwOptionList) { TRACE(L"Failed to allocate memory for option list\n"); goto SetPreferredConnectionTcpipPropertiesExit; } wsprintf(ipInfo.pszwOptionList, L"%s;%s;%s;", rgchDefGateway, rgchGatewayMetric, rgchDnsAddr ); hr = SetTcpipProperties(pncProps->guidId, &ipInfo); if (FAILED(hr)) { TRACE1(L"Failed to set TCPIP info (0x%08X)\n", hr); } SetPreferredConnectionTcpipPropertiesExit: if (NULL != ipInfo.pszwOptionList) { free(ipInfo.pszwOptionList); ipInfo.pszwOptionList = NULL; } if (NULL != pncProps) { NcFreeNetconProperties(pncProps); pncProps = NULL; } return hr; } // CObCommunicationManager::SetPreferredConnectionTcpipProperties /////////////////////////////////////////////////////////// // // SetTcpipProperties // HRESULT CConnectionManager::SetTcpipProperties( GUID guid, REMOTE_IPINFO* pipInfo ) { HRESULT hr; INetCfg* pNetCfg = NULL; ITcpipProperties* pTcpipProps = NULL; hr = GetNetCfgInterface(TRUE, &pNetCfg); if (SUCCEEDED(hr)) { hr = GetTcpipPrivateInterface(pNetCfg, &pTcpipProps); if (SUCCEEDED(hr)) { hr = pTcpipProps->SetIpInfoForAdapter(&guid, pipInfo); TRACE1(L"SetIpInfoForAdapter 0x%08lx", hr); if (SUCCEEDED(hr)) { hr = pNetCfg->Apply(); TRACE1(L"INetCfg::Apply 0x%08lx", hr); } pTcpipProps->Release(); } ReleaseNetCfgInterface(pNetCfg, TRUE); } return hr; } // CObCommunicationManager::SetTcpipProperties ////////////////////////////////////////////////////////////////////////////// // // LanConnectionReady // // Determines whether the system has a LAN connection that is connected to the // Internet. // // parameters: // None. // // returns: // Boolean indicating whether or not their is a ready connection. // ////////////////////////////////////////////////////////////////////////////// BOOL CConnectionManager::LanConnectionReady() { BOOL fReady = FALSE; #ifndef CONNMGR_INITFROMREGISTRY if (HasBroadband() || HasIcs()) { DWORD dwFlags = 0; if ( InternetGetConnectedState(&dwFlags, 0) && (INTERNET_CONNECTION_LAN & dwFlags) ) { fReady = TRUE; } } #else DWORD dwLanConnectionReady; DWORD dwSize = sizeof(DWORD); if(ERROR_SUCCESS == (lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OOBE_MAIN_REG_KEY, 0, KEY_QUERY_VALUE, &hKey) ) ) { lResult = RegQueryValueEx(hKey, L"LanConnectionReady", 0, NULL, (LPBYTE)&dwLanConnectionReady, &dwSize ); RegCloseKey(hKey); } fReady = (ERROR_SUCCESS == lResult) ? (BOOL)dwLanConnectionReady : FALSE; #endif // CONNMGR_INITFROMREGISTRY return fReady; } // CConnectionManager::LanConnectionReady ////////////////////////////////////////////////////////////////////////////// // // SetProxyBlanket // // Set the authentication settings for the binding handle for the // interface proxy. This is necessary for setting up security for interface // pointers returned by a remote process, such as the Network Connections // Manager (netman.dll). // // parameters: // pUnk pointer to the interface for which the proxy will be // bound. // // returns: // HRESULT returned by CoSetProxyBlanket. // ////////////////////////////////////////////////////////////////////////////// HRESULT CConnectionManager::SetProxyBlanket( IUnknown* pUnk ) { HRESULT hr; hr = CoSetProxyBlanket ( pUnk, RPC_C_AUTHN_WINNT, // use NT default security RPC_C_AUTHZ_NONE, // use NT default authentication NULL, // must be null if default RPC_C_AUTHN_LEVEL_CALL, // call RPC_C_IMP_LEVEL_IMPERSONATE, NULL, // use process token EOAC_NONE); if(SUCCEEDED(hr)) { IUnknown * pUnkSet = NULL; hr = pUnk->QueryInterface(IID_PPV_ARG(IUnknown, &pUnkSet)); if(SUCCEEDED(hr)) { hr = CoSetProxyBlanket ( pUnkSet, RPC_C_AUTHN_WINNT, // use NT default security RPC_C_AUTHZ_NONE, // use NT default authentication NULL, // must be null if default RPC_C_AUTHN_LEVEL_CALL, // call RPC_C_IMP_LEVEL_IMPERSONATE, NULL, // use process token EOAC_NONE); pUnkSet->Release(); } } return hr; } // CConnectionManager::SetProxyBlanket ////////////////////////////////////////////////////////////////////////////// // // DeterminePreferredConnection // // Determine the preferred connection. The order of preference is // * ICS // * Broadband (DSL, cable modem, etc.) // * Modem // // parameters: // None. // // returns: // Nothing. // ////////////////////////////////////////////////////////////////////////////// void CConnectionManager::DeterminePreferredConnection() { // REVIEW: Differences between full-screen and desktop in using default // connectoid. // if (HasIcs()) { m_dwPreferredConnection = CONNECTIONTYPE_LAN_ICS; } else if (HasBroadband()) { m_dwPreferredConnection = CONNECTIONTYPE_LAN_BROADBAND; } #ifdef BLACKCOMB // Modem capability for Whistler is handled via // CObCommunicationManager::CheckDialReady else if (HasModem()) { m_dwPreferredConnection = CONNECTIONTYPE_MODEM; } #endif // BLACKCOMB else // CONNECTIONTYPE_NONE || CONNECTIONTYPE_LAN_INDETERMINATE { m_dwPreferredConnection = CONNECTIONTYPE_NONE; } GetPreferredConnection(); } // CConnectionManager::DeterminePreferredConnection ////////////////////////////////////////////////////////////////////////////// // // GetPreferredConnection // // Determine the name of the connectoid for the preferred connection. // // parameters: // None. // // returns: // Nothing. // ////////////////////////////////////////////////////////////////////////////// void CConnectionManager::GetPreferredConnection() { HRESULT hr; NETCON_MEDIATYPE ncMediaType = NCM_NONE; // assume no connection switch (m_dwPreferredConnection) { case CONNECTIONTYPE_LAN_ICS: ncMediaType = NCM_SHAREDACCESSHOST_LAN; break; case CONNECTIONTYPE_LAN_BROADBAND: ncMediaType = NCM_LAN; break; } // switch(m_dwPreferredConnection) // Free up previous preferred connection properties // if (NULL != m_pPreferredConnection) { m_pPreferredConnection->Release(); m_pPreferredConnection = NULL; } if (NCM_NONE != ncMediaType) { INetConnectionManager* pmgr = NULL; if ( SUCCEEDED(hr = CoCreateInstance( CLSID_ConnectionManager, NULL, CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD, IID_PPV_ARG(INetConnectionManager, &pmgr) ) ) && SUCCEEDED(hr = SetProxyBlanket(pmgr)) ) { TRACE(L"INetConnectionManager\n"); IEnumNetConnection* penum = NULL; if ( SUCCEEDED(hr = pmgr->EnumConnections(NCME_DEFAULT, &penum)) && SUCCEEDED(hr = SetProxyBlanket(penum)) ) { TRACE(L"IEnumNetConnection\n"); MYASSERT(NULL == m_pPreferredConnection); hr = penum->Reset(); // Find the first connection matching the preferred type. This // works because the only types we are concerned with are // broadband and ICS. By definition, we should not be here if // there are more than 1 of these connections. If there are // more than 1 of these we should be deferring to the HomeNet // Wizard. // // ONCE THIS OBJECT SUPPORTS MODEM CONNECTIONS OR MULTIPLE // BROADBAND CONNECTIONS we'll need a more sophisticated method // of determining that we've found the correct connection. // while (S_OK == hr && NULL == m_pPreferredConnection) { INetConnection* pnc = NULL; ULONG ulRetrieved; if ( S_OK == (hr = penum->Next(1, &pnc, &ulRetrieved)) && SUCCEEDED(hr = SetProxyBlanket(pnc)) ) { NETCON_PROPERTIES* pprops = NULL; hr = pnc->GetProperties(&pprops); // Log the network connectivity detected TRACE4(L"INetConnection: %s--%s--%d--%d\n", pprops->pszwName, pprops->pszwDeviceName, pprops->MediaType, pprops->Status); if (SUCCEEDED(hr)) { if (IsEnabledConnection(pprops)) { if (ncMediaType == pprops->MediaType) { m_pPreferredConnection = pnc; pnc = NULL; } } NcFreeNetconProperties(pprops); } } if (NULL != pnc) { pnc->Release(); } } if (S_FALSE == hr) { // IEnumNetConnection::Next returned S_FALSE to indicate // that no more elements were available. hr = S_OK; } } if (NULL != penum) { penum->Release(); } } if (NULL != pmgr) { pmgr->Release(); } } } // CConnectionManager::GetPreferredConnection ////////////////////////////////////////////////////////////////////////////// // // GetPreferredConnectionName // // Fills in a user-allocated buffer with the name of the connectoid for the // preferred connection. // // parameters: // szConnectionName buffer that will recieve the name of the preferred // connectoid // cchConnectionName count of characters that the buffer can hold // // returns: // S_OK if the name is retrieved successfully // S_FALSE if there is no default connectoid // E_INVALIDARG if there is no buffer or if the buffer size is 0 // ////////////////////////////////////////////////////////////////////////////// HRESULT CConnectionManager::GetPreferredConnectionName( LPWSTR szConnectionName, DWORD cchConnectionName ) { HRESULT hr = S_FALSE; if (NULL == szConnectionName || 0 == cchConnectionName) { MYASSERT(NULL != szConnectionName); MYASSERT(0 < cchConnectionName); return E_INVALIDARG; } if (NULL != m_pPreferredConnection) { NETCON_PROPERTIES* pprops = NULL; hr = m_pPreferredConnection->GetProperties(&pprops); if (SUCCEEDED(hr)) { MYASSERT(NULL != pprops); if (NULL == pprops->pszwName) { hr = S_FALSE; } if (S_OK == hr) { lstrcpyn(szConnectionName, pprops->pszwName, cchConnectionName ); } NcFreeNetconProperties(pprops); } } return hr; } // CConnectionManager::GetPreferredConnectionName HRESULT CConnectionManager::GetNetCfgInterface( BOOL fNeedWriteLock, INetCfg** ppNetCfg ) { HRESULT hr; INetCfg* pNetCfg = NULL; if (NULL == ppNetCfg) { ASSERT(NULL != ppNetCfg); return E_INVALIDARG; } *ppNetCfg = NULL; hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_SERVER, IID_INetCfg, (LPVOID*)&pNetCfg ); if (SUCCEEDED(hr)) { INetCfgLock* pNetCfgLock = NULL; if (fNeedWriteLock) { hr = pNetCfg->QueryInterface(IID_INetCfgLock, (VOID**)&pNetCfgLock); if (SUCCEEDED(hr)) { hr = pNetCfgLock->AcquireWriteLock( 5, // millisec timeout L"Out-of-Box Experience", NULL // name of previous holder ); if (S_FALSE == hr) { hr = NETCFG_E_NO_WRITE_LOCK; TRACE(L"AcquireWriteLock failed"); } pNetCfgLock->Release(); } else { TRACE1(L"QueryInterface IID_INetCfgLock 0x%08lx", hr); } } if (SUCCEEDED(hr)) { hr = pNetCfg->Initialize(NULL); if (SUCCEEDED(hr)) { *ppNetCfg = pNetCfg; } else { TRACE1(L"INetCfg Initialize 0x%08lx", hr); } } } else { TRACE1(L"CoCreateInstance CLSID_CNetCfg IID_INetCfg 0x%08lx", hr); } if (FAILED(hr)) { if (pNetCfg != NULL) { pNetCfg->Release(); } } return hr; } // CConnectionManager::GetNetCfgInterface void CConnectionManager::ReleaseNetCfgInterface( INetCfg* pNetCfg, BOOL fHasWriteLock ) { HRESULT hr = S_OK; if (NULL != pNetCfg) { hr = pNetCfg->Uninitialize(); INetCfgLock* pNetCfgLock = NULL; if (fHasWriteLock) { hr = pNetCfg->QueryInterface(IID_INetCfgLock, (VOID**)&pNetCfgLock); if (SUCCEEDED(hr)) { hr = pNetCfgLock->ReleaseWriteLock(); pNetCfgLock->Release(); } } pNetCfg->Release(); } } // CConnectionManager::ReleaseNetCfgInterface HRESULT CConnectionManager::GetTcpipPrivateInterface( INetCfg* pNetCfg, ITcpipProperties** ppTcpipProperties ) { HRESULT hr; if (NULL == ppTcpipProperties) { return E_INVALIDARG; } INetCfgClass* pncclass = NULL; hr = pNetCfg->QueryNetCfgClass(&GUID_DEVCLASS_NETTRANS, IID_INetCfgClass, (void**)&pncclass ); if (SUCCEEDED(hr)) { INetCfgComponent* pnccItem = NULL; hr = pncclass->FindComponent(NETCFG_TRANS_CID_MS_TCPIP, &pnccItem); if (SUCCEEDED(hr)) { INetCfgComponentPrivate* pinccp = NULL; hr = pnccItem->QueryInterface(IID_INetCfgComponentPrivate, (void**) &pinccp ); if (SUCCEEDED(hr)) { hr = pinccp->QueryNotifyObject(IID_ITcpipProperties, (void**) ppTcpipProperties ); if (FAILED(hr)) { TRACE1(L"QueryNotifyObject IID_ITcpipProperties 0x%08lx", hr); } pinccp->Release(); pinccp = NULL; } else { TRACE1(L"QueryInterface IID_INetCfgComponentPrivate 0x%08lx", hr); } pnccItem->Release(); pnccItem = NULL; } else { TRACE1(L"FindComponent NETCFG_TRANS_CID_MS_TCPIP 0x%08lx", hr); } pncclass->Release(); pncclass = NULL; } else { TRACE1(L"QueryNetCfgClass IID_INetCfgClass 0x%08lx", hr); } return hr; } // CConnectionManager::GetTcpipPrivateInterface STDAPI InternetOpenWrap( LPCTSTR pszAgent, DWORD dwAccessType, LPCTSTR pszProxy, LPCTSTR pszProxyBypass, DWORD dwFlags, HINTERNET * phFileHandle ) { HRESULT hr = S_OK; DWORD dwError = 0; *phFileHandle = InternetOpen(pszAgent, dwAccessType, pszProxy, pszProxyBypass, dwFlags); if (!*phFileHandle) { dwError = GetLastError(); TRACE1(L"InternetOpen failed (WININET Error %d)", dwError); hr = HRESULT_FROM_WIN32(dwError); } return hr; } STDAPI InternetOpenUrlWrap( HINTERNET hInternet, LPCTSTR pszUrl, LPCTSTR pszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext, HINTERNET * phFileHandle ) { HRESULT hr = S_OK; DWORD dwError = 0; *phFileHandle = InternetOpenUrl(hInternet, pszUrl, pszHeaders, dwHeadersLength, dwFlags, dwContext); if (!*phFileHandle) { dwError = GetLastError(); TRACE1(L"InternetOpenUrl failed (WININET Error %d)", dwError); hr = HRESULT_FROM_WIN32(dwError); } return hr; } STDAPI HttpQueryInfoWrap( HINTERNET hRequest, DWORD dwInfoLevel, LPVOID lpvBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex ) { HRESULT hr = S_OK; if (!HttpQueryInfo(hRequest, dwInfoLevel, lpvBuffer, lpdwBufferLength, lpdwIndex)) { DWORD dwError; dwError = GetLastError(); TRACE1(L"HttpQueryInfo failed (WININET Error %d)", dwError); hr = HRESULT_FROM_WIN32(dwError); } return hr; } BOOL IsGlobalOffline( VOID ) /*++ Routine Description: Determines whether wininet is in global offline mode Arguments: None Return Value: BOOL TRUE - offline FALSE - online --*/ { DWORD dwState = 0; DWORD dwSize = sizeof(DWORD); BOOL fRet = FALSE; if(InternetQueryOption( NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize )) { if (dwState & INTERNET_STATE_DISCONNECTED_BY_USER) { fRet = TRUE; } } return fRet; } VOID SetOffline( IN BOOL fOffline ) /*++ Routine Description: Sets wininet's offline mode Arguments: fOffline - online or offline Return Value: None. --*/ { INTERNET_CONNECTED_INFO ci; memset(&ci, 0, sizeof(ci)); if (fOffline) { ci.dwConnectedState = INTERNET_STATE_DISCONNECTED_BY_USER; ci.dwFlags = ISO_FORCE_DISCONNECTED; } else { ci.dwConnectedState = INTERNET_STATE_CONNECTED; } InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci)); } STDAPI PingWebServer( HINTERNET hInternet, LPCTSTR pszUrl, BOOL* pfConnected ) { HRESULT hr = E_FAIL; HINTERNET hOpenUrlSession; *pfConnected = FALSE; hr = InternetOpenUrlWrap( hInternet, pszUrl, NULL, 0, INTERNET_FLAG_NO_UI | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD, NULL, &hOpenUrlSession); if (SUCCEEDED(hr)) { DWORD dwSize = sizeof(DWORD); DWORD dwStatusCode; hr = HttpQueryInfoWrap( hOpenUrlSession, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE, (LPVOID) &dwStatusCode, &dwSize, NULL); if (SUCCEEDED(hr)) { // HTTP status code greater than or equal to 500 means server // or network problem occur *pfConnected = (dwStatusCode < 500); TRACE1(L"HTTP status code from WPA HTTP server %d", dwStatusCode); } InternetCloseHandle(hOpenUrlSession); } return hr; } BOOL CConnectionManager::GetInternetHandleForPinging( HINTERNET* phInternet ) { static const WCHAR OOBE_HTTP_AGENT_NAME[] = L"Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.1)"; static const int TIMEOUT_IN_MILLISEC = 30000; if (m_hInternetPing == NULL) { HINTERNET hInternet; if (SUCCEEDED(InternetOpenWrap( OOBE_HTTP_AGENT_NAME, PRE_CONFIG_INTERNET_ACCESS, NULL, NULL, 0, &hInternet ))) { DWORD dwValue; dwValue = TIMEOUT_IN_MILLISEC; InternetSetOption( hInternet, INTERNET_OPTION_CONNECT_TIMEOUT, &dwValue, sizeof(DWORD)); m_hInternetPing = hInternet; } } *phInternet = m_hInternetPing; return (m_hInternetPing != NULL); } ////////////////////////////////////////////////////////////////////////////// // // ConnectedToInternetEx // // Determines whether the system is currently connected to the Internet. // // parameters: // pfConnected pointer to a buffer that will receive the boolean // indicating whether the connection exists. // // returns: // TRUE if the system is connected to the internet. Note it may // trigger autodial if it is enabled and no connection is // available when this is called // FALSE otherwise // ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CConnectionManager::ConnectedToInternetEx( BOOL* pfConnected ) { const WCHAR MS_URL[] = L"http://WPA.one.microsoft.com"; HINTERNET hInternet; HRESULT hr = E_FAIL; *pfConnected = FALSE; TRACE(L"tries to connect to the WPA HTTP server"); if (IsGlobalOffline()) { SetOffline(FALSE); m_bForceOnline = TRUE; TRACE(L"Force wininet to go online"); } DisableRasAutodial(); // // Try to use the proxy settings from winnt32.exe first because it is // quite likely a proper configuration. If the settings // is not available or if we failed to connect to the web server // using these settings, use the original settings and check the web // server connectivity once more. // if (GetInternetHandleForPinging(&hInternet)) { DWORD dwDisable = 0; DWORD dwSize = sizeof(DWORD); DWORD dwOrigDisable; if (!InternetQueryOption( hInternet, INTERNET_OPTION_DISABLE_AUTODIAL, (LPVOID) &dwOrigDisable, &dwSize)) { // Assume the orginal state is autodial-enabled. dwOrigDisable = 0; } // InternetSetOption for INTERNET_OPTION_DISABLE_AUTODIAL affects the // behavior of an application, e.g. it cause InternetAutodial // elsewhere to fail. It does not affect other applications, however. dwDisable = 1; InternetSetOption( hInternet, INTERNET_OPTION_DISABLE_AUTODIAL, &dwDisable, sizeof(DWORD)); if (m_bUseProxy) { // // If we have already applied or we can successfully apply the // proxy settings // if (ApplyWinntProxySettings()) { // User or we may have update the proxy and other settings in // registry InternetSetOption( hInternet, INTERNET_OPTION_REFRESH, NULL, 0); hr = PingWebServer(hInternet, MS_URL, pfConnected); } } if (*pfConnected == FALSE) { // // Restore proxy setting if it is already applied // if (m_bUseProxy) { // Don't revert the change by SetProxySettings call. RestoreProxySettings(); } // User or we may have update the proxy and other settings in // registry InternetSetOption( hInternet, INTERNET_OPTION_REFRESH, NULL, 0); hr = PingWebServer(hInternet, MS_URL, pfConnected); } InternetSetOption( hInternet, INTERNET_OPTION_DISABLE_AUTODIAL, &dwOrigDisable, sizeof(DWORD)); } RestoreRasAutoDial(); TRACE1(L"%s connect to WPA HTTP server", (*pfConnected) ? L"could" : L"could not"); return hr; } // CConnectionManager::ConnectedToInternetEx typedef struct tagConnmgrPARAM { HWND hwnd; CConnectionManager *pConnmgr; } CONNMGRPARAM, *PCONNMGRPARAM; DWORD WINAPI ConnectedToInternetExThread(LPVOID vpParam) { BOOL fConnected = FALSE; PCONNMGRPARAM pParam = (PCONNMGRPARAM) vpParam; HRESULT hr = S_OK; hr = pParam->pConnmgr->ConnectedToInternetEx(&fConnected); PostMessage(pParam->hwnd, WM_OBCOMM_NETCHECK_DONE, fConnected, hr); GlobalFree(pParam); return 0; } ////////////////////////////////////////////////////////////////////////////// // // AsyncConnectedToInternetEx // // Determines whether the system is currently connected to the Internet. // // parameters: // pfConnected pointer to a buffer that will receive the boolean // indicating whether the connection exists. // // returns: // TRUE if the system is connected to the internet. Note it may // trigger autodial if it is enabled and no connection is // available when this is called // FALSE otherwise // // note: // Deprecated. // ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CConnectionManager::AsyncConnectedToInternetEx( const HWND hwnd ) { DWORD threadId; HANDLE hThread; PCONNMGRPARAM pParam = NULL; HRESULT hr = S_OK; DWORD dwError; pParam = (PCONNMGRPARAM) GlobalAlloc(GPTR, sizeof(CONNMGRPARAM)); if (pParam) { pParam->hwnd = hwnd; pParam->pConnmgr = this; hThread = CreateThread(NULL, 0, ConnectedToInternetExThread, pParam, 0, &threadId); if (hThread == NULL) { dwError = GetLastError(); hr = HRESULT_FROM_WIN32(dwError); } } else { hr = E_OUTOFMEMORY; } if (FAILED(hr)) { // Notify the script so that it won't hang PostMessage(hwnd, WM_OBCOMM_NETCHECK_DONE, FALSE, hr); } return hr; } // CConnectionManager::AsyncConnectedToInternetEx ////////////////////////////////////////////////////////////////////////////// // // IsEnabledConnection // // Determines whether a connection should be considered as having Internet // capability or not, based on its media type and current status. // // parameters: // ncMedia The media type of the connection // ncStatus The current status of the connection // // returns: // TRUE We should not considered it as having Internet capability // FALSE otherwise // ////////////////////////////////////////////////////////////////////////////// BOOL CConnectionManager::IsEnabledConnection( NETCON_PROPERTIES* pprops ) { BOOL bRet; switch (pprops->MediaType) { case NCM_LAN: bRet = (pprops->Status != NCS_DISCONNECTED); if (bRet && m_bExclude1394 && Is1394Adapter(&(pprops->guidId))) { TRACE1(L"%s not considered as LAN", pprops->pszwName); bRet = FALSE; } break; case NCM_SHAREDACCESSHOST_LAN: case NCM_SHAREDACCESSHOST_RAS: bRet = (pprops->Status != NCS_DISCONNECTED); break; default: bRet = TRUE; } return bRet; } ////////////////////////////////////////////////////////////////////////////// // // SaveProxySettings // // Save existing proxy settings for current user. // // returns: // TRUE The value is successfully saved // FALSE otherwise // ////////////////////////////////////////////////////////////////////////////// BOOL CConnectionManager::SaveProxySettings() { if (!m_bProxySaved) { TRACE(TEXT("try to save the existing proxy settings")); if (AllocProxyOptionList(&m_CurrentProxySettings)) { DWORD dwBufferLength = sizeof(m_CurrentProxySettings); if (InternetQueryOption( NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &m_CurrentProxySettings, &dwBufferLength )) { m_bProxySaved = TRUE; TRACE(TEXT("successfully save the proxy settings")); } else { FreeProxyOptionList(&m_CurrentProxySettings); } } if (!m_bProxySaved) { TRACE1( TEXT("fail to save the proxy settings (Error %d)"), GetLastError() ); } } return m_bProxySaved; } ////////////////////////////////////////////////////////////////////////////// // // RestoreProxySettings // // Restore the setting captured by SaveProxySettings. // ////////////////////////////////////////////////////////////////////////////// void CConnectionManager::RestoreProxySettings() { BOOL bRestored = FALSE; if (m_bProxyApplied) { TRACE(TEXT("try to restore the original proxy settings")); bRestored = InternetSetOption( NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &m_CurrentProxySettings, sizeof(m_CurrentProxySettings) ); if (bRestored) { m_bProxyApplied = FALSE; TRACE(TEXT("successfully restored the proxy settings")); } else { TRACE1( TEXT("failed to restore the proxy settings (WININET Error %d)"), GetLastError() ); } } } static LPTSTR pDuplicateString( LPCTSTR szText ) { int cchText; LPTSTR szOutText; if (szText == NULL) { return NULL; } cchText = lstrlen(szText); szOutText = (LPTSTR) GlobalAlloc(GPTR, sizeof(TCHAR) * (cchText + 1)); if (szOutText) { lstrcpyn(szOutText, szText, cchText + 1); } return szOutText; } ////////////////////////////////////////////////////////////////////////////// // // ApplyWinntProxySettings // // Apply the proxy settings for NIC saved during winnt32.exe to the current user. // Before the values is applied, it makes sure that existing settings is saved. // // returns: // TRUE the proxy settings was successfully applied // FALSE otherwise // ////////////////////////////////////////////////////////////////////////////// BOOL CConnectionManager::ApplyWinntProxySettings() { #define MAX_URL_LENGTH 2048 DWORD dwProxyFlags = 0; LPTSTR szProxyList = NULL; TCHAR szWinntPath[MAX_PATH]; // // Save proxy settings if it has not been saved. // SaveProxySettings(); // // Apply proxy settings if it has not been applied. // if (m_bProxySaved && !m_bProxyApplied) { TRACE1(TEXT("tries to apply proxy settings, saved in %s"), WINNT_INF_FILENAME); if (GetCanonicalizedPath(szWinntPath, WINNT_INF_FILENAME)) { DWORD dwEnableOobeProxy; dwEnableOobeProxy = GetPrivateProfileInt( OOBE_PROXY_SECTION, OOBE_ENABLE_OOBY_PROXY, 0, szWinntPath ); if (dwEnableOobeProxy) { INTERNET_PER_CONN_OPTION_LIST PrevProxySettings; if (AllocProxyOptionList(&PrevProxySettings)) { INTERNET_PER_CONN_OPTION* pOption = PrevProxySettings.pOptions; DWORD dwBufferLength = sizeof(PrevProxySettings); TCHAR szBuffer[MAX_URL_LENGTH]; pOption[0].Value.dwValue = GetPrivateProfileInt( OOBE_PROXY_SECTION, OOBE_FLAGS, 0, szWinntPath ); if (GetPrivateProfileString( OOBE_PROXY_SECTION, OOBE_PROXY_SERVER, TEXT(""), szBuffer, MAX_URL_LENGTH, szWinntPath )) { pOption[1].Value.pszValue = pDuplicateString(szBuffer); } if (GetPrivateProfileString( OOBE_PROXY_SECTION, OOBE_PROXY_BYPASS, TEXT(""), szBuffer, MAX_URL_LENGTH, szWinntPath )) { pOption[2].Value.pszValue = pDuplicateString(szBuffer); } if (GetPrivateProfileString( OOBE_PROXY_SECTION, OOBE_AUTOCONFIG_URL, TEXT(""), szBuffer, MAX_URL_LENGTH, szWinntPath )) { pOption[3].Value.pszValue = pDuplicateString(szBuffer); } pOption[4].Value.dwValue = GetPrivateProfileInt( OOBE_PROXY_SECTION, OOBE_AUTODISCOVERY_FLAGS, 0, szWinntPath ); if (GetPrivateProfileString( OOBE_PROXY_SECTION, OOBE_AUTOCONFIG_SECONDARY_URL, TEXT(""), szBuffer, MAX_URL_LENGTH, szWinntPath )) { pOption[5].Value.pszValue = pDuplicateString(szBuffer); } m_bProxyApplied = InternetSetOption( NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &PrevProxySettings, sizeof(PrevProxySettings) ); FreeProxyOptionList(&PrevProxySettings); } } } if (m_bProxyApplied) { TRACE(TEXT("successfully load the proxy settings")); } else { TRACE1(TEXT("could not load the proxy settings (WIN32 Error %d)"), GetLastError()); } } return m_bProxyApplied; } void CConnectionManager::UseWinntProxySettings() { m_bUseProxy = TRUE; } void CConnectionManager::DisableWinntProxySettings() { TCHAR szWinntPath[MAX_PATH]; if (GetCanonicalizedPath(szWinntPath, WINNT_INF_FILENAME)) { WritePrivateProfileString( OOBE_PROXY_SECTION, OOBE_ENABLE_OOBY_PROXY, TEXT("0"), szWinntPath ); TRACE1(TEXT("disabled the proxy settings in %s"), WINNT_INF_FILENAME); } } BOOL CConnectionManager::AllocProxyOptionList( INTERNET_PER_CONN_OPTION_LIST *pList ) { INTERNET_PER_CONN_OPTION* pOption; pOption = (INTERNET_PER_CONN_OPTION*) GlobalAlloc( GPTR, sizeof(INTERNET_PER_CONN_OPTION) * NUM_PROXY_OPTIONS); if (pOption) { pList->dwSize = sizeof(*pList); pList->pszConnection = NULL; pList->dwOptionCount = NUM_PROXY_OPTIONS; pList->pOptions = pOption; pOption[0].dwOption = INTERNET_PER_CONN_FLAGS; pOption[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER; pOption[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS; pOption[3].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; pOption[4].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS; pOption[5].dwOption = INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL; } else { pList->pOptions = NULL; } return (pOption != NULL); } void CConnectionManager::FreeProxyOptionList( INTERNET_PER_CONN_OPTION_LIST *pList ) { INTERNET_PER_CONN_OPTION* pOption = pList->pOptions; if (pOption) { if (pOption[1].Value.pszValue) { GlobalFree(pOption[1].Value.pszValue); } if (pOption[2].Value.pszValue) { GlobalFree(pOption[2].Value.pszValue); } if (pOption[3].Value.pszValue) { GlobalFree(pOption[3].Value.pszValue); } if (pOption[5].Value.pszValue) { GlobalFree(pOption[5].Value.pszValue); } GlobalFree(pOption); pList->pOptions = NULL; } } void CConnectionManager::DisableRasAutodial() { DWORD dwValue = RAS_AUTODIAL_DISABLED; if (m_dwRasAutodialDisable == RAS_AUTODIAL_DONT_KNOW) { DWORD dwSize = sizeof(m_dwRasAutodialDisable); if (RasGetAutodialParam( RASADP_LoginSessionDisable, &m_dwRasAutodialDisable, &dwSize ) != ERROR_SUCCESS) { m_dwRasAutodialDisable = RAS_AUTODIAL_ENABLED; } else { TRACE1( L"Save value of RASADP_LoginSessionDisable %d", m_dwRasAutodialDisable ); } } if (RasSetAutodialParam( RASADP_LoginSessionDisable, &dwValue, sizeof(dwValue) ) == ERROR_SUCCESS) { TRACE(L"Disabled RAS Autodial for current logon session"); } } void CConnectionManager::RestoreRasAutoDial() { if (m_dwRasAutodialDisable != RAS_AUTODIAL_DONT_KNOW) { if (RasSetAutodialParam( RASADP_LoginSessionDisable, &m_dwRasAutodialDisable, sizeof(m_dwRasAutodialDisable) ) == ERROR_SUCCESS) { TRACE(L"Restore value of RAS Autodial for current logon session"); } } } HRESULT CConnectionManager::GetProxySettings( BOOL* pbUseAuto, BOOL* pbUseScript, BSTR* pszScriptUrl, BOOL* pbUseProxy, BSTR* pszProxy ) { HRESULT hr = E_FAIL; // // Save proxy settings if it has not been saved. // SaveProxySettings(); if (m_bProxySaved) { INTERNET_PER_CONN_OPTION* pOption = m_CurrentProxySettings.pOptions; *pbUseAuto = pOption[0].Value.dwValue & PROXY_TYPE_AUTO_DETECT; *pbUseScript = pOption[0].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL; *pbUseProxy = pOption[0].Value.dwValue & PROXY_TYPE_PROXY; if (pOption[1].Value.pszValue) { *pszProxy = SysAllocString(pOption[1].Value.pszValue); } else { *pszProxy = NULL; } if (pOption[3].Value.pszValue) { *pszScriptUrl = SysAllocString(pOption[3].Value.pszValue); } else { *pszScriptUrl = NULL; } hr = S_OK; } return hr; } HRESULT CConnectionManager::SetProxySettings( BOOL bUseAuto, BOOL bUseScript, BSTR szScriptUrl, BOOL bUseProxy, BSTR szProxy ) { HRESULT hr = E_FAIL; // // We don't behavior correctly in this->ConnectedToInternetEx if we // also use proxy settings saved in winnt32. // MYASSERT(!m_bUseProxy); // // Save proxy settings if it has not been saved. // SaveProxySettings(); if (m_bProxySaved) { INTERNET_PER_CONN_OPTION_LIST ProxySettings; if (AllocProxyOptionList(&ProxySettings)) { INTERNET_PER_CONN_OPTION* pOption = ProxySettings.pOptions; pOption[0].Value.dwValue = PROXY_TYPE_DIRECT; if (bUseAuto) { pOption[0].Value.dwValue |= PROXY_TYPE_AUTO_DETECT; } if (bUseScript) { pOption[0].Value.dwValue |= PROXY_TYPE_AUTO_PROXY_URL; } if (bUseProxy) { pOption[0].Value.dwValue |= PROXY_TYPE_PROXY; } pOption[1].Value.pszValue = szProxy; pOption[2].Value.pszValue = NULL; pOption[3].Value.pszValue = szScriptUrl; pOption[4].Value.dwValue = m_CurrentProxySettings.pOptions[4].Value.dwValue; if (bUseAuto) { pOption[4].Value.dwValue |= AUTO_PROXY_FLAG_USER_SET; } pOption[5].Value.pszValue = m_CurrentProxySettings.pOptions[5].Value.pszValue; TRACE5(TEXT("tries to set LAN proxy: %d, %s, %s, %d"), pOption[0].Value.dwValue, pOption[1].Value.pszValue, pOption[3].Value.pszValue, pOption[4].Value.dwValue, pOption[5].Value.pszValue ); if (InternetSetOption( NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &ProxySettings, sizeof(ProxySettings) )) { m_bProxyApplied = TRUE; hr = S_OK; } // so that we don't free the memory from the caller in // FreeProxyOptionList pOption[1].Value.pszValue = NULL; pOption[3].Value.pszValue = NULL; pOption[5].Value.pszValue = NULL; FreeProxyOptionList(&ProxySettings); } } if (SUCCEEDED(hr)) { TRACE(TEXT("successfully set the proxy settings")); } else { TRACE1(TEXT("could not set the proxy settings (WIN32 Error %d)"), GetLastError()); } return hr; } STDMETHODIMP CConnectionManager::GetPublicLanCount(int* pcPublicLan) { PSTRINGLIST PubList = NULL; HRESULT hr = S_OK; EnumPublicAdapters(&PubList); int i = 0; for (PSTRINGLIST p = PubList; p; p = p->Next) { i++; } *pcPublicLan = i; if (PubList) { DestroyList(PubList); } return hr; } HRESULT CConnectionManager::Enum1394Adapters( OUT PSTRINGLIST* pList ) { UINT i; INetCfgComponent* arrayComp[MAX_NUM_NET_COMPONENTS]; IEnumNetCfgComponent* pEnum = NULL; INetCfgClass* pNetCfgClass = NULL; INetCfgComponent* pNetCfgComp = NULL; LPWSTR szPnpId = NULL; HRESULT hr = S_OK; DWORD dwCharacteristics = 0; ULONG iCount = 0; PSTRINGLIST List = NULL; PSTRINGLIST Cell = NULL; GUID guidInstance; WCHAR szInstanceGuid[MAX_GUID_LEN + 1] = L""; INetCfg* pNetCfg = NULL; ZeroMemory(arrayComp, sizeof(arrayComp)); hr = GetNetCfgInterface(FALSE, &pNetCfg); if (FAILED(hr)) { goto cleanup; } // // Obtain the INetCfgClass interface pointer // hr = pNetCfg->QueryNetCfgClass( &GUID_DEVCLASS_NET, IID_INetCfgClass, (void**)&pNetCfgClass ); if( FAILED( hr ) ) { goto cleanup; } // // Retrieve the enumerator interface // hr = pNetCfgClass->EnumComponents( &pEnum ); if( FAILED( hr ) ) { goto cleanup; } hr = pEnum->Next( MAX_NUM_NET_COMPONENTS, &arrayComp[0], &iCount ); if( FAILED( hr ) ) { goto cleanup; } MYASSERT( iCount <= MAX_NUM_NET_COMPONENTS ); if ( iCount > MAX_NUM_NET_COMPONENTS ) { hr = E_UNEXPECTED; goto cleanup; } for( i = 0; i < iCount; i++ ) { pNetCfgComp = arrayComp[i]; hr = pNetCfgComp->GetCharacteristics( &dwCharacteristics ); if( FAILED( hr ) ) { goto cleanup; } // // If this is a physical adapter // if( dwCharacteristics & NCF_PHYSICAL ) { hr = pNetCfgComp->GetId( &szPnpId ); if (FAILED(hr)) { goto cleanup; } // // If this is a 1394 network adapter // if (!lstrcmpi(szPnpId, L"v1394\\nic1394")) { hr = pNetCfgComp->GetInstanceGuid(&guidInstance); if (FAILED(hr)) { goto cleanup; } if (!StringFromGUID2(guidInstance, szInstanceGuid, MAX_GUID_LEN)) { goto cleanup; } Cell = CreateStringCell(szInstanceGuid); if (!Cell) { goto cleanup; } InsertList(&List, Cell); Cell = NULL; } CoTaskMemFree( szPnpId ); szPnpId = NULL; } } *pList = List; List = NULL; cleanup: if (List) { DestroyList(List); } if (Cell) { DeleteStringCell(Cell); } if (szPnpId) { CoTaskMemFree(szPnpId); } for (i = 0; i < iCount; i++) { if (arrayComp[i]) { arrayComp[i]->Release(); } } if (pNetCfgClass) { pNetCfgClass->Release(); } if (pEnum) { pEnum->Release(); } if (pNetCfg) { ReleaseNetCfgInterface(pNetCfg, FALSE); } return hr; } BOOL CConnectionManager::Is1394Adapter( GUID* pguid ) { PSTRINGLIST List = NULL; PSTRINGLIST p; BOOL bRet = FALSE; Enum1394Adapters(&List); if (List) { for (p = List; p; p = p->Next) { if (!StringCmpGUID(p->String, pguid)) { bRet = TRUE; break; } } DestroyList(List); } return bRet; } HRESULT CConnectionManager::EnumPublicConnections( OUT PSTRINGLIST* pList ) { HRESULT hr = S_OK; PSTRINGLIST PubList = NULL; TRACE(L"Begin EnumPublicConnections ..."); EnumPublicAdapters(&PubList); if (!PubList) { *pList = NULL; return hr; } // Initialize the net connection enumeration. For each interface // retrieved, SetProxyBlanket must be called to set the authentication for // the interface proxy handle because the Network Connection Manager lives // in a remote process with a different security context. // INetConnectionManager* pmgr = NULL; IEnumNetConnection* penum = NULL; NETCON_PROPERTIES* pprops = NULL; INetConnection* pnc = NULL; PSTRINGLIST List = NULL; PSTRINGLIST p = NULL; PSTRINGLIST Cell = NULL; ULONG ulRetrieved; hr = CoCreateInstance( CLSID_ConnectionManager, NULL, CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD, IID_INetConnectionManager, (VOID**) &pmgr ); if (FAILED(hr)) { goto cleanup; } hr = SetProxyBlanket(pmgr); if (FAILED(hr)) { goto cleanup; } hr = pmgr->EnumConnections(NCME_DEFAULT, &penum); if (FAILED(hr)) { goto cleanup; } hr = SetProxyBlanket(penum); if (FAILED(hr)) { goto cleanup; } hr = penum->Reset(); if (FAILED(hr)) { goto cleanup; } hr = penum->Next(1, &pnc, &ulRetrieved); while (S_OK == hr) { hr = SetProxyBlanket(pnc); if (FAILED(hr)) { goto cleanup; } hr = pnc->GetProperties(&pprops); if (FAILED(hr)) { goto cleanup; } if (pprops->MediaType == NCM_LAN && pprops->Status != NCS_DISCONNECTED) { for (p = PubList; p; p = p->Next) { if (!StringCmpGUID(p->String, &(pprops->guidId))) { Cell = CreateStringCell(pprops->pszwName); if (Cell) { TRACE1(L" + %s", pprops->pszwName); InsertList(&List, Cell); } } } } NcFreeNetconProperties(pprops); pprops = NULL; pnc->Release(); pnc = NULL; hr = penum->Next(1, &pnc, &ulRetrieved); } if (hr != S_FALSE) { goto cleanup; } // IEnumNetConnection::Next returned S_FALSE to indicate // that no more elements were available. hr = S_OK; *pList = List; List = NULL; cleanup: if (List) { DestroyList(List); } if (NULL != pprops) { NcFreeNetconProperties(pprops); } if (NULL != pnc) { pnc->Release(); } if (NULL != penum) { penum->Release(); } if (NULL != pmgr) { pmgr->Release(); } TRACE1(L"End EnumPublicConnections (0x%08lx)", hr); return hr; } HRESULT CConnectionManager::EnumPublicAdapters( OUT PSTRINGLIST* pList ) { static GUID g_guidNLAServiceClass = NLA_SERVICE_CLASS_GUID; static const int MAX_ADAPTER_NAME_LEN = 256; WSADATA wsaData; int error; PSTRINGLIST AdapterList = NULL; PSTRINGLIST ExcludeList = NULL; TRACE(L"Begin EnumPublicAdapters ..."); if (m_bExclude1394) { Enum1394Adapters(&ExcludeList); } if (0 == (error = WSAStartup(MAKEWORD(2, 2), &wsaData))) { // Init query for network names WSAQUERYSET restrictions = {0}; restrictions.dwSize = sizeof(restrictions); restrictions.lpServiceClassId = &g_guidNLAServiceClass; restrictions.dwNameSpace = NS_NLA; HANDLE hQuery; // Make sure we do not ask for the (chicken) blobs that take a long time to get if (0 == (error = WSALookupServiceBegin(&restrictions, LUP_NOCONTAINERS | LUP_DEEP, &hQuery))) { PWSAQUERYSET pqsResults = NULL; while (0 == _AllocWSALookupServiceNext(hQuery, 0, &pqsResults)) { if (NULL != pqsResults->lpBlob) { NLA_BLOB* pnlaBlob = (NLA_BLOB*) pqsResults->lpBlob->pBlobData; WCHAR szAdapterWide[MAX_ADAPTER_NAME_LEN] = L""; NLA_INTERNET nlaInternet = NLA_INTERNET_UNKNOWN; while (NULL != pnlaBlob) { switch (pnlaBlob->header.type) { case NLA_INTERFACE: MultiByteToWideChar( CP_ACP, 0, pnlaBlob->data.interfaceData.adapterName, -1, szAdapterWide, ARRAYSIZE(szAdapterWide) ); break; case NLA_CONNECTIVITY: nlaInternet = pnlaBlob->data.connectivity.internet; break; } pnlaBlob = _NLABlobNext(pnlaBlob); } if (nlaInternet == NLA_INTERNET_YES && szAdapterWide[0]) { PSTRINGLIST p = NULL; for (p = ExcludeList; p; p = p->Next) { if (!lstrcmpi(p->String, szAdapterWide)) { break; } } // // Check if the adapter is excluded. // if (!p) { PSTRINGLIST Cell = CreateStringCell(szAdapterWide); if (Cell) { TRACE1(L" + %s", szAdapterWide); InsertList(&AdapterList, Cell); } } } } LocalFree(pqsResults); } WSALookupServiceEnd(pqsResults); } WSACleanup(); if (error == 0) { *pList = AdapterList; } else { if (AdapterList) { DestroyList(AdapterList); } } } TRACE1(L"End EnumPublicAdapters (%d)", error); return HRESULT_FROM_WIN32(error); } NLA_BLOB* _NLABlobNext( IN NLA_BLOB* pnlaBlob ) { NLA_BLOB* pNext = NULL; if (pnlaBlob->header.nextOffset) { pNext = (NLA_BLOB*) (((BYTE*) pnlaBlob) + pnlaBlob->header.nextOffset); } return pNext; } int _AllocWSALookupServiceNext( IN HANDLE hQuery, IN DWORD dwControlFlags, OUT LPWSAQUERYSET* ppResults ) { *ppResults = NULL; DWORD cb = 0; int error = 0; if (SOCKET_ERROR == WSALookupServiceNext(hQuery, dwControlFlags, &cb, NULL)) { error = WSAGetLastError(); if (WSAEFAULT == error) { assert(cb); *ppResults = (LPWSAQUERYSET) LocalAlloc(LPTR, cb); if (NULL != *ppResults) { error = 0; if (SOCKET_ERROR == WSALookupServiceNext(hQuery, dwControlFlags, &cb, *ppResults)) { error = WSAGetLastError(); } } else { error = WSA_NOT_ENOUGH_MEMORY; } } } // May as well map outdated error code while we're here. if (WSAENOMORE == error) { error = WSA_E_NO_MORE; } if (error && (*ppResults)) { LocalFree(*ppResults); *ppResults = NULL; } return error; } static int StringCmpGUID( IN LPCWSTR szGuid, IN const GUID* pguid ) { WCHAR szGuid1[MAX_GUID_LEN + 1]; if (!StringFromGUID2(*pguid, szGuid1, MAX_GUID_LEN)) { // consider it as szGuid is greater than pguid return 1; } return lstrcmpi(szGuid, szGuid1); }