| Index: net/network_config.cc
|
| diff --git a/net/network_config.cc b/net/network_config.cc
|
| deleted file mode 100644
|
| index 3b10c338b881262828644d5313fa615450500d6a..0000000000000000000000000000000000000000
|
| --- a/net/network_config.cc
|
| +++ /dev/null
|
| @@ -1,991 +0,0 @@
|
| -// Copyright 2007-2010 Google Inc.
|
| -//
|
| -// Licensed under the Apache License, Version 2.0 (the "License");
|
| -// you may not use this file except in compliance with the License.
|
| -// You may obtain a copy of the License at
|
| -//
|
| -// http://www.apache.org/licenses/LICENSE-2.0
|
| -//
|
| -// Unless required by applicable law or agreed to in writing, software
|
| -// distributed under the License is distributed on an "AS IS" BASIS,
|
| -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -// See the License for the specific language governing permissions and
|
| -// limitations under the License.
|
| -// ========================================================================
|
| -
|
| -#include "omaha/net/network_config.h"
|
| -
|
| -#include <winhttp.h>
|
| -#include <atlconv.h>
|
| -#include <atlsecurity.h>
|
| -#include <algorithm>
|
| -#include <hash_set>
|
| -#include <vector>
|
| -#include "base/error.h"
|
| -#include "base/scoped_ptr.h"
|
| -#include "base/scope_guard.h"
|
| -#include "omaha/base/browser_utils.h"
|
| -#include "omaha/base/const_object_names.h"
|
| -#include "omaha/base/constants.h"
|
| -#include "omaha/base/debug.h"
|
| -#include "omaha/base/error.h"
|
| -#include "omaha/base/encrypt.h"
|
| -#include "omaha/base/logging.h"
|
| -#include "omaha/base/omaha_version.h"
|
| -#include "omaha/base/path.h"
|
| -#include "omaha/base/reg_key.h"
|
| -#include "omaha/base/scoped_ptr_address.h"
|
| -#include "omaha/base/string.h"
|
| -#include "omaha/base/system.h"
|
| -#include "omaha/base/user_info.h"
|
| -#include "omaha/base/utils.h"
|
| -#include "omaha/common/config_manager.h"
|
| -#include "omaha/net/cup_request.h"
|
| -#include "omaha/net/http_client.h"
|
| -
|
| -using omaha::encrypt::EncryptData;
|
| -using omaha::encrypt::DecryptData;
|
| -
|
| -namespace omaha {
|
| -
|
| -// Computes the hash value of a ProxyConfig object. Names in the stdext
|
| -// namespace are not currently part of the ISO C++ standard.
|
| -uint32 hash_value(const ProxyConfig& config) {
|
| - uint32 hash = stdext::hash_value(config.auto_detect) ^
|
| - stdext::hash_value(config.auto_config_url.GetString()) ^
|
| - stdext::hash_value(config.proxy.GetString()) ^
|
| - stdext::hash_value(config.proxy_bypass.GetString());
|
| - return hash;
|
| -}
|
| -
|
| -const TCHAR* const NetworkConfigManager::kNetworkSubkey = _T("network");
|
| -const TCHAR* const NetworkConfigManager::kNetworkCupSubkey = _T("secure");
|
| -const TCHAR* const NetworkConfigManager::kCupClientSecretKey = _T("sk");
|
| -const TCHAR* const NetworkConfigManager::kCupClientCookie = _T("c");
|
| -
|
| -const TCHAR* const NetworkConfig::kUserAgent = _T("Google Update/%s");
|
| -
|
| -const TCHAR* const NetworkConfig::kRegKeyProxy = GOOPDATE_MAIN_KEY _T("proxy");
|
| -const TCHAR* const NetworkConfig::kRegValueSource = _T("source");
|
| -
|
| -const TCHAR* const NetworkConfig::kWPADIdentifier = _T("auto");
|
| -const TCHAR* const NetworkConfig::kDirectConnectionIdentifier = _T("direct");
|
| -
|
| -NetworkConfig::NetworkConfig(bool is_machine)
|
| - : is_machine_(is_machine),
|
| - is_initialized_(false) {}
|
| -
|
| -NetworkConfig::~NetworkConfig() {
|
| - if (session_.session_handle && http_client_.get()) {
|
| - http_client_->Close(session_.session_handle);
|
| - session_.session_handle = NULL;
|
| - }
|
| - Clear();
|
| -}
|
| -
|
| -// Initialize creates or opens a global lock to synchronize access to
|
| -// registry where CUP credentials are stored. Each user including non-elevated
|
| -// admins stores network configuration data, such as the CUP password in
|
| -// its HKCU. The admin users, including the LOCAL_SYSTEM, store data in HKLM.
|
| -// Therefore, the naming of the global lock is different: users have their
|
| -// lock postfixed with their sid, so the serialization only occurs within the
|
| -// same user's programs. Admin users use the same named lock since they store
|
| -// data in a shared HKLM. The data of the admin users is disambiguated by
|
| -// postfixing their registry sub key with sids.
|
| -// In conclusion, users have sid-postfixed locks and their data goes in
|
| -// their respective HKCU. Admin users have the same lock and their data goes
|
| -// under HKLM in sid-postfixed stores.
|
| -//
|
| -// The named lock is created in the global namespace to account for users
|
| -// logging in from different TS sessions.
|
| -//
|
| -// The CUP credentials must be protected with ACLs so non-elevated admins can't
|
| -// read elevated-admins' keys and attack the protocol.
|
| -//
|
| -// Also, an Internet session is created.
|
| -HRESULT NetworkConfig::Initialize() {
|
| - ASSERT1(!is_initialized_);
|
| -
|
| - http_client_.reset(CreateHttpClient());
|
| - ASSERT1(http_client_.get());
|
| - if (!http_client_.get()) {
|
| - NET_LOG(LE, (_T("[CreateHttpClient failed]")));
|
| - return E_UNEXPECTED;
|
| - }
|
| - HRESULT hr = http_client_->Initialize();
|
| - if (FAILED(hr)) {
|
| - // TODO(omaha): This makes an assumption that only WinHttp is
|
| - // supported by the network code.
|
| - NET_LOG(LE, (_T("[http_client_->Initialize() failed][0x%x]"), hr));
|
| - return OMAHA_NET_E_WINHTTP_NOT_AVAILABLE;
|
| - }
|
| -
|
| - // Initializes the WinHttp session and configures WinHttp to work in
|
| - // asynchronous mode. In this mode, the network requests are non-blocking
|
| - // and asynchronous events are generated when a request is complete.
|
| - hr = http_client_->Open(NULL,
|
| - WINHTTP_ACCESS_TYPE_NO_PROXY,
|
| - WINHTTP_NO_PROXY_NAME,
|
| - WINHTTP_NO_PROXY_BYPASS,
|
| - WINHTTP_FLAG_ASYNC,
|
| - &session_.session_handle);
|
| - if (FAILED(hr)) {
|
| - NET_LOG(LE, (_T("[http_client_->Open() failed][0x%x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - Add(new UpdateDevProxyDetector);
|
| - BrowserType browser_type(BROWSER_UNKNOWN);
|
| - GetDefaultBrowserType(&browser_type);
|
| - if (browser_type == BROWSER_FIREFOX) {
|
| - Add(new FirefoxProxyDetector);
|
| - }
|
| - // There is no Chrome detector because it uses the same proxy settings as IE.
|
| - Add(new IEProxyDetector);
|
| - Add(new DefaultProxyDetector);
|
| -
|
| - // Use a global network configuration override if available.
|
| - ConfigManager* config_manager = ConfigManager::Instance();
|
| - CString net_config;
|
| - if (SUCCEEDED(config_manager->GetNetConfig(&net_config))) {
|
| - ProxyConfig config_override = NetworkConfig::ParseNetConfig(net_config);
|
| - SetConfigurationOverride(&config_override);
|
| - }
|
| -
|
| - ConfigureProxyAuth();
|
| -
|
| - is_initialized_ = true;
|
| - return S_OK;
|
| -}
|
| -
|
| -void NetworkConfig::Add(ProxyDetectorInterface* detector) {
|
| - ASSERT1(detector);
|
| - __mutexBlock(lock_) {
|
| - detectors_.push_back(detector);
|
| - }
|
| -}
|
| -
|
| -void NetworkConfig::Clear() {
|
| - __mutexBlock(lock_) {
|
| - for (size_t i = 0; i != detectors_.size(); ++i) {
|
| - delete detectors_[i];
|
| - }
|
| - detectors_.clear();
|
| - configurations_.clear();
|
| - }
|
| -}
|
| -
|
| -HRESULT NetworkConfig::Detect() {
|
| - __mutexBlock(lock_) {
|
| - std::vector<ProxyConfig> configurations;
|
| -
|
| - for (size_t i = 0; i != detectors_.size(); ++i) {
|
| - ProxyConfig config;
|
| - if (SUCCEEDED(detectors_[i]->Detect(&config))) {
|
| - configurations.push_back(config);
|
| - }
|
| - }
|
| - configurations_.swap(configurations);
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -void NetworkConfig::SortProxies(std::vector<ProxyConfig>* configurations) {
|
| - ASSERT1(configurations);
|
| -
|
| - std::stable_sort(configurations->begin(), configurations->end(),
|
| - ProxySortPredicate);
|
| -}
|
| -
|
| -HRESULT NetworkConfig::ConfigFromIdentifier(const CString& id,
|
| - ProxyConfig* config) {
|
| - ASSERT1(config);
|
| -
|
| - *config = ProxyConfig();
|
| - if (id == kWPADIdentifier) {
|
| - config->source = kWPADIdentifier;
|
| - config->auto_detect = true;
|
| - } else if (id == kDirectConnectionIdentifier) {
|
| - config->source = kDirectConnectionIdentifier;
|
| - } else {
|
| - return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -void NetworkConfig::AppendLastKnownGoodProxyConfig(
|
| - std::vector<ProxyConfig>* configurations) const {
|
| - ASSERT1(configurations);
|
| - ProxyConfig last_known_good_config;
|
| - if (SUCCEEDED(LoadProxyConfig(&last_known_good_config))) {
|
| - configurations->push_back(last_known_good_config);
|
| - }
|
| -}
|
| -
|
| -void NetworkConfig::AppendStaticProxyConfigs(
|
| - std::vector<ProxyConfig>* configurations) {
|
| - ASSERT1(configurations);
|
| - ProxyConfig config;
|
| -
|
| - HRESULT hr = ConfigFromIdentifier(kWPADIdentifier, &config);
|
| - if (SUCCEEDED(hr)) {
|
| - configurations->push_back(config);
|
| - }
|
| -
|
| - hr = ConfigFromIdentifier(kDirectConnectionIdentifier, &config);
|
| - if (SUCCEEDED(hr)) {
|
| - configurations->push_back(config);
|
| - }
|
| -}
|
| -
|
| -HRESULT NetworkConfig::Detect(const CString& proxy_source,
|
| - ProxyConfig* config) const {
|
| - ASSERT1(config);
|
| - __mutexBlock(lock_) {
|
| - std::vector<ProxyConfig> configurations;
|
| - for (size_t i = 0; i != detectors_.size(); ++i) {
|
| - if (proxy_source == detectors_[i]->source()) {
|
| - return detectors_[i]->Detect(config);
|
| - }
|
| - }
|
| - }
|
| -
|
| - return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
| -}
|
| -
|
| -std::vector<ProxyConfig> NetworkConfig::GetConfigurations() const {
|
| - std::vector<ProxyConfig> configurations;
|
| - __mutexBlock(lock_) {
|
| - configurations = configurations_;
|
| - }
|
| - return configurations;
|
| -}
|
| -
|
| -HRESULT NetworkConfig::GetConfigurationOverride(ProxyConfig* config) {
|
| - ASSERT1(config);
|
| - __mutexBlock(lock_) {
|
| - if (configuration_override_.get()) {
|
| - *config = *configuration_override_;
|
| - return S_OK;
|
| - }
|
| - }
|
| - return E_FAIL;
|
| -}
|
| -
|
| -void NetworkConfig::SetConfigurationOverride(
|
| - const ProxyConfig* configuration_override) {
|
| - __mutexBlock(lock_) {
|
| - if (configuration_override) {
|
| - configuration_override_.reset(new ProxyConfig);
|
| - *configuration_override_ = *configuration_override;
|
| - configuration_override_->source = _T("updatedev/netconfig");
|
| - } else {
|
| - configuration_override_.reset();
|
| - }
|
| - }
|
| -}
|
| -
|
| -HRESULT NetworkConfig::GetCupCredentials(
|
| - CupCredentials* cup_credentials) const {
|
| - return NetworkConfigManager::Instance().GetCupCredentials(cup_credentials);
|
| -}
|
| -
|
| -HRESULT NetworkConfig::SetCupCredentials(
|
| - const CupCredentials* cup_credentials) const {
|
| - NetworkConfigManager& network_manager = NetworkConfigManager::Instance();
|
| - if (cup_credentials == NULL) {
|
| - network_manager.ClearCupCredentials();
|
| - return S_OK;
|
| - }
|
| -
|
| - return network_manager.SetCupCredentials(*cup_credentials);
|
| -}
|
| -
|
| -// Serializes configurations for debugging purposes.
|
| -CString NetworkConfig::ToString(const ProxyConfig& config) {
|
| - CString result;
|
| - result.AppendFormat(_T("priority=%u, source=%s, "),
|
| - config.priority, config.source);
|
| -
|
| - switch (GetAccessType(config)) {
|
| - case WINHTTP_ACCESS_TYPE_NO_PROXY:
|
| - result.AppendFormat(_T("direct connection"));
|
| - break;
|
| - case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
|
| - result.AppendFormat(_T("named proxy=%s, bypass=%s"),
|
| - config.proxy, config.proxy_bypass);
|
| - break;
|
| - case WINHTTP_ACCESS_TYPE_AUTO_DETECT:
|
| - result.AppendFormat(_T("wpad=%d, script=%s"),
|
| - config.auto_detect, config.auto_config_url);
|
| - break;
|
| - default:
|
| - ASSERT1(false);
|
| - break;
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -CString NetworkConfig::ToString(const std::vector<ProxyConfig>& config) {
|
| - CString result;
|
| - for (size_t i = 0; i != config.size(); ++i) {
|
| - result.Append(NetworkConfig::ToString(config[i]));
|
| - result.Append(_T("\r\n"));
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -int NetworkConfig::GetAccessType(const ProxyConfig& config) {
|
| - if (config.auto_detect || !config.auto_config_url.IsEmpty()) {
|
| - return WINHTTP_ACCESS_TYPE_AUTO_DETECT;
|
| - } else if (!config.proxy.IsEmpty()) {
|
| - return WINHTTP_ACCESS_TYPE_NAMED_PROXY;
|
| - } else {
|
| - return WINHTTP_ACCESS_TYPE_NO_PROXY;
|
| - }
|
| -}
|
| -
|
| -bool NetworkConfig::IsUsingCupTestKeys() {
|
| - DWORD value = 0;
|
| - if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
|
| - kRegValueCupKeys,
|
| - &value))) {
|
| - return value != 0;
|
| - } else {
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -void NetworkConfig::ConfigureProxyAuth() {
|
| - const uint32 kProxyMaxPrompts = 1;
|
| - return proxy_auth_.ConfigureProxyAuth(is_machine_, kProxyMaxPrompts);
|
| -}
|
| -
|
| -bool NetworkConfig::GetProxyCredentials(bool allow_ui,
|
| - bool force_ui,
|
| - const CString& proxy_settings,
|
| - const ProxyAuthConfig& config,
|
| - bool is_https,
|
| - CString* username,
|
| - CString* password,
|
| - uint32* auth_scheme) {
|
| - ASSERT1(username);
|
| - ASSERT1(password);
|
| - ASSERT1(auth_scheme);
|
| -
|
| - const CString& proxy = ProxyAuth::ExtractProxy(proxy_settings, is_https);
|
| - return proxy_auth_.GetProxyCredentials(allow_ui, force_ui, proxy,
|
| - config, username,
|
| - password, auth_scheme);
|
| -}
|
| -
|
| -HRESULT NetworkConfig::SetProxyAuthScheme(const CString& proxy_settings,
|
| - bool is_https,
|
| - uint32 auth_scheme) {
|
| - ASSERT1(auth_scheme != UNKNOWN_AUTH_SCHEME);
|
| - const CString& proxy = ProxyAuth::ExtractProxy(proxy_settings, is_https);
|
| - return proxy_auth_.SetProxyAuthScheme(proxy, auth_scheme);
|
| -}
|
| -
|
| -// TODO(omaha): the code does WPAD auto detect in all cases. It is possible for
|
| -// a configuration to specify no auto detection but provide the proxy script
|
| -// url. The current code does not account for this yet.
|
| -HRESULT NetworkConfig::GetProxyForUrl(const CString& url,
|
| - const CString& auto_config_url,
|
| - HttpClient::ProxyInfo* proxy_info) {
|
| - ASSERT1(proxy_info);
|
| -
|
| - NET_LOG(L3, (_T("[NetworkConfig::GetProxyForUrl][%s]"), url));
|
| -
|
| - HttpClient::AutoProxyOptions auto_proxy_options = {0};
|
| - auto_proxy_options.flags = WINHTTP_AUTOPROXY_AUTO_DETECT;
|
| - auto_proxy_options.auto_detect_flags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
|
| - WINHTTP_AUTO_DETECT_TYPE_DNS_A;
|
| - if (!auto_config_url.IsEmpty()) {
|
| - auto_proxy_options.auto_config_url = auto_config_url;
|
| - auto_proxy_options.flags |= WINHTTP_AUTOPROXY_CONFIG_URL;
|
| - }
|
| - auto_proxy_options.auto_logon_if_challenged = true;
|
| -
|
| - HRESULT hr = http_client_->GetProxyForUrl(session_.session_handle,
|
| - url,
|
| - &auto_proxy_options,
|
| - proxy_info);
|
| -
|
| - if (FAILED(hr) && ::UrlIsFileUrl(auto_config_url)) {
|
| - // Some HttpClient implementations, namely WinHTTP, only support PAC files
|
| - // with http or https schemes. Attempt an alternate resolution scheme using
|
| - // jsproxy.dll if the initial attempt fails.
|
| - ASSERT1(user_info::IsThreadImpersonating());
|
| -
|
| - CString local_file;
|
| - hr = ConvertFileUriToLocalPath(auto_config_url, &local_file);
|
| - if (FAILED(hr)) {
|
| - NET_LOG(LE, (_T("[ConvertFileUriToLocalPath failed][0x%08x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - hr = GetProxyForUrlLocal(url, local_file, proxy_info);
|
| - }
|
| -
|
| - return hr;
|
| -}
|
| -
|
| -CString NetworkConfig::GetUserAgent() {
|
| - CString user_agent;
|
| - user_agent.Format(kUserAgent, GetVersionString());
|
| - return user_agent;
|
| -}
|
| -
|
| -CString NetworkConfig::GetMID() {
|
| - CString mid;
|
| - RegKey::GetValue(MACHINE_REG_UPDATE_DEV, kRegValueMID, &mid);
|
| - return mid;
|
| -}
|
| -
|
| -CString NetworkConfig::JoinStrings(const TCHAR* s1,
|
| - const TCHAR* s2,
|
| - const TCHAR* delim) {
|
| - CString result;
|
| - const TCHAR* components[] = {s1, s2};
|
| - JoinStringsInArray(components, arraysize(components), delim, &result);
|
| - return result;
|
| -}
|
| -
|
| -// Using std::hash_set adds about 2K uncompressed code size. Using a CAtlMap
|
| -// adds about 1.5K. Usually, there are only five detected configurations so
|
| -// an O(n^2) algorithm would work well. The advantage of the current
|
| -// implementation is simplicity. It also does not handle conflicts. Conflicts
|
| -// are not expected, due to how the ProxyConfig structure is being used.
|
| -// TODO(omaha): consider not using the hash_set and save about 1K of code.
|
| -void NetworkConfig::RemoveDuplicates(std::vector<ProxyConfig>* config) {
|
| - ASSERT1(config);
|
| -
|
| - // Iterate over the input configurations, remember the hash of each
|
| - // distinct configuration, and remove the duplicates by skipping the
|
| - // configurations seen before.
|
| - std::vector<ProxyConfig> input(*config);
|
| - config->clear();
|
| -
|
| - typedef stdext::hash_set<uint32> Keys;
|
| - Keys keys;
|
| - for (size_t i = 0; i != input.size(); ++i) {
|
| - std::pair<Keys::iterator, bool> result(keys.insert(hash_value(input[i])));
|
| - if (result.second) {
|
| - config->push_back(input[i]);
|
| - }
|
| - }
|
| -}
|
| -
|
| -HRESULT NetworkConfig::CreateProxyConfigRegKey(RegKey* key) {
|
| - ASSERT1(key);
|
| - CString config_root;
|
| -
|
| - if (!user_info::IsRunningAsSystem()) {
|
| - scoped_hkey user_root_key;
|
| - HRESULT hr = ::RegOpenCurrentUser(KEY_READ | KEY_WRITE,
|
| - address(user_root_key));
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - return key->Create(get(user_root_key), kRegKeyProxy);
|
| - } else {
|
| - return key->Create(HKEY_LOCAL_MACHINE, kRegKeyProxy);
|
| - }
|
| -}
|
| -
|
| -HRESULT NetworkConfig::SaveProxyConfig(const ProxyConfig& config) {
|
| - const CString& new_configuration = config.source;
|
| - NET_LOG(L3, (_T("[NetworkConfig::SaveProxyConfig][%s]"), new_configuration));
|
| -
|
| - RegKey key;
|
| - HRESULT hr = CreateProxyConfigRegKey(&key);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - CString current_configuration;
|
| - if (SUCCEEDED(key.GetValue(kRegValueSource, ¤t_configuration)) &&
|
| - current_configuration != new_configuration) {
|
| - NET_LOG(L3, (_T("[Network configuration changed from %s to %s"),
|
| - current_configuration, new_configuration));
|
| - }
|
| -
|
| - return key.SetValue(kRegValueSource, new_configuration);
|
| -}
|
| -
|
| -HRESULT NetworkConfig::LoadProxyConfig(ProxyConfig* config) const {
|
| - ASSERT1(config);
|
| -
|
| - *config = ProxyConfig();
|
| -
|
| - RegKey key;
|
| - HRESULT hr = CreateProxyConfigRegKey(&key);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - CString source;
|
| - hr = key.GetValue(kRegValueSource, &source);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = NetworkConfig::ConfigFromIdentifier(source, config);
|
| - if (FAILED(hr)) {
|
| - hr = Detect(source, config);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - config->priority = ProxyConfig::PROXY_PRIORITY_LAST_KNOWN_GOOD;
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -ProxyConfig NetworkConfig::ParseNetConfig(const CString& net_config) {
|
| - ProxyConfig config;
|
| - int pos(0);
|
| - CString token = net_config.Tokenize(_T(";"), pos);
|
| - while (pos != -1) {
|
| - CString name, value;
|
| - if (ParseNameValuePair(token, _T('='), &name, &value)) {
|
| - bool auto_detect(false);
|
| - if (name == _T("wpad") &&
|
| - SUCCEEDED(String_StringToBool(value, &auto_detect))) {
|
| - config.auto_detect = auto_detect;
|
| - } else if (name == _T("script")) {
|
| - config.auto_config_url = value;
|
| - } else if (name == _T("proxy")) {
|
| - config.proxy = value;
|
| - }
|
| - }
|
| - token = net_config.Tokenize(_T(";"), pos);
|
| - }
|
| - return config;
|
| -}
|
| -
|
| -// Note: The jsproxy functions are exposed to public users as part of the
|
| -// DOJ consent decree and are not formally supported by Microsoft.
|
| -
|
| -GPA_WRAP(jsproxy.dll,
|
| - InternetInitializeAutoProxyDll,
|
| - (DWORD dwVersion, LPSTR lpszDownloadedTempFile, LPSTR lpszMime, LPCVOID lpAutoProxyCallbacks, LPCVOID lpAutoProxyScriptBuffer), // NOLINT
|
| - (dwVersion, lpszDownloadedTempFile, lpszMime, lpAutoProxyCallbacks, lpAutoProxyScriptBuffer), // NOLINT
|
| - WINAPI,
|
| - BOOL,
|
| - FALSE);
|
| -
|
| -GPA_WRAP(jsproxy.dll,
|
| - InternetGetProxyInfo,
|
| - (LPCSTR lpszUrl, DWORD dwUrlLength, LPSTR lpszUrlHostName, DWORD dwUrlHostNameLength, LPSTR *lplpszProxyHostName, LPDWORD lpdwProxyHostNameLength), // NOLINT
|
| - (lpszUrl, dwUrlLength, lpszUrlHostName, dwUrlHostNameLength, lplpszProxyHostName, lpdwProxyHostNameLength), // NOLINT
|
| - WINAPI,
|
| - BOOL,
|
| - FALSE);
|
| -
|
| -GPA_WRAP(jsproxy.dll,
|
| - InternetDeInitializeAutoProxyDll,
|
| - (LPSTR lpszMime, DWORD dwReserved),
|
| - (lpszMime, dwReserved),
|
| - WINAPI,
|
| - BOOL,
|
| - FALSE);
|
| -
|
| -HRESULT NetworkConfig::GetProxyForUrlLocal(const CString& url,
|
| - const CString& path_to_pac_file,
|
| - HttpClient::ProxyInfo* proxy_info) {
|
| - scoped_library jsproxy_lib(::LoadLibrary(_T("jsproxy.dll")));
|
| - ASSERT1(jsproxy_lib);
|
| - if (!jsproxy_lib) {
|
| - HRESULT hr = HRESULTFromLastError();
|
| - NET_LOG(LE, (_T("[GetProxyForUrlLocal][jsproxy not loaded][0x%08x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - // Convert the inputs to ANSI, and call into JSProxy to execute the PAC
|
| - // script; we should get back out a PAC-format list of proxies to use.
|
| - //
|
| - // TODO(omaha3): The MSDN prototypes specify LPSTR, and I've assumed this
|
| - // implies CP_ACP. However, depending on how this was implemented internally,
|
| - // conversion to UTF8 might work better. Investigate this later and confirm.
|
| - CStringA path_a(path_to_pac_file);
|
| -
|
| - if (FALSE == InternetInitializeAutoProxyDllWrap(0, CStrBufA(path_a, MAX_PATH),
|
| - NULL, NULL, NULL)) {
|
| - HRESULT hr = HRESULTFromLastError();
|
| - NET_LOG(LE, (_T("[GetProxyForUrlLocal][jsproxy init failed][0x%08x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - ON_SCOPE_EXIT(InternetDeInitializeAutoProxyDllWrap, (LPSTR)NULL, 0);
|
| -
|
| - CStringA url_a(url);
|
| - CStringA url_hostname_a(GetUriHostNameHostOnly(url, false));
|
| -
|
| - scoped_hglobal proxy_ptr;
|
| - DWORD proxy_len = 0;
|
| - if (FALSE == InternetGetProxyInfoWrap(
|
| - url_a,
|
| - url_a.GetLength(),
|
| - CStrBufA(url_hostname_a, url_hostname_a.GetLength()),
|
| - url_hostname_a.GetLength(),
|
| - reinterpret_cast<LPSTR*>(address(proxy_ptr)),
|
| - &proxy_len)) {
|
| - HRESULT hr = HRESULTFromLastError();
|
| - NET_LOG(LE, (_T("[GetProxyForUrlLocal][jsproxy failed][0x%08x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - ASSERT1(proxy_ptr && proxy_len > 0);
|
| - CStringA proxy(reinterpret_cast<LPSTR>(get(proxy_ptr)), proxy_len);
|
| - ConvertPacResponseToProxyInfo(proxy, proxy_info);
|
| - return S_OK;
|
| -}
|
| -
|
| -void NetworkConfig::ConvertPacResponseToProxyInfo(
|
| - const CStringA& response,
|
| - HttpClient::ProxyInfo* proxy_info) {
|
| - ASSERT1(proxy_info);
|
| -
|
| - NET_LOG(L4, (_T("[ConvertPacResponseToProxyInfo][%s]"), CString(response)));
|
| -
|
| - // The proxy list response from a PAC file for a file is a string of proxies
|
| - // to attempt in order, delimited by semicolons, with a keyword denoting how
|
| - // to use the proxy. For example:
|
| - //
|
| - // PROXY prx1.samp.com; PROXY prx2.test.com:8080; SOCKS prx3.test.com; DIRECT
|
| - //
|
| - // We convert this to a direct semicolon-separated list of host/ports. We
|
| - // stop parsing if we see DIRECT; we omit any non-PROXY entries.
|
| - CString proxy_list;
|
| - for (int start = 0; start >= 0 && start < response.GetLength();) {
|
| - int semi_pos = response.Find(';', start);
|
| - if (semi_pos < 0) {
|
| - semi_pos = response.GetLength();
|
| - }
|
| -
|
| - CStringA entry = response.Mid(start, semi_pos - start).Trim().MakeLower();
|
| - if (entry == "direct") {
|
| - break;
|
| - }
|
| - if (0 == entry.Find("proxy ")) {
|
| - // This is a valid proxy entry. Strip the leading "PROXY " and add it
|
| - // to our parsed list.
|
| - if (!proxy_list.IsEmpty()) {
|
| - proxy_list.AppendChar(_T(';'));
|
| - }
|
| - proxy_list.Append(CString(entry.Mid(6)));
|
| - }
|
| -
|
| - start = semi_pos + 1;
|
| - }
|
| -
|
| - if (proxy_list.IsEmpty()) {
|
| - proxy_info->access_type = WINHTTP_ACCESS_TYPE_NO_PROXY;
|
| - proxy_info->proxy = NULL;
|
| - proxy_info->proxy_bypass = NULL;
|
| - } else {
|
| - // The convention is that any strings in a WINHTTP_PROXY_INFO are expected
|
| - // to be freed by the caller using GlobalFree(). Convert our intermediary
|
| - // CString to a GlobalAlloc() buffer and write that out.
|
| - size_t list_len = (proxy_list.GetLength() + 1) * sizeof(TCHAR);
|
| - TCHAR* list_hglob = reinterpret_cast<TCHAR*>(::GlobalAlloc(GPTR, list_len));
|
| - memcpy(list_hglob, proxy_list.GetString(), list_len);
|
| - proxy_info->access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
|
| - proxy_info->proxy = list_hglob;
|
| - proxy_info->proxy_bypass = NULL;
|
| - }
|
| -}
|
| -
|
| -const NetworkConfigManager* const NetworkConfigManager::kInvalidInstance =
|
| - reinterpret_cast<const NetworkConfigManager* const>(-1);
|
| -NetworkConfigManager* NetworkConfigManager::instance_ = NULL;
|
| -LLock NetworkConfigManager::instance_lock_;
|
| -bool NetworkConfigManager::is_machine_ = false;
|
| -
|
| -NetworkConfigManager::NetworkConfigManager() {
|
| -}
|
| -
|
| -NetworkConfigManager::~NetworkConfigManager() {
|
| - SaveCupCredentialsToRegistry();
|
| -}
|
| -
|
| -HRESULT NetworkConfigManager::CreateInstance() {
|
| - __mutexScope(instance_lock_);
|
| - ASSERT1(instance_ != kInvalidInstance);
|
| - if (!instance_) {
|
| - NET_LOG(L1, (_T("[NetworkConfigManager::CreateInstance][is_machine: %d]"),
|
| - is_machine_));
|
| - instance_ = new NetworkConfigManager();
|
| - VERIFY1(SUCCEEDED(instance_->InitializeLock()));
|
| - VERIFY1(SUCCEEDED(instance_->InitializeRegistryKey()));
|
| - instance_->LoadCupCredentialsFromRegistry();
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -void NetworkConfigManager::DeleteInstance() {
|
| - ASSERT1(instance_ != kInvalidInstance);
|
| -
|
| - NetworkConfigManager* instance =
|
| - omaha::interlocked_exchange_pointer(&instance_, kInvalidInstance);
|
| -
|
| - if (kInvalidInstance != instance && NULL != instance) {
|
| - instance->DeleteInstanceInternal();
|
| - delete instance;
|
| - }
|
| -}
|
| -
|
| -NetworkConfigManager& NetworkConfigManager::Instance() {
|
| - __mutexScope(instance_lock_);
|
| - if (!instance_) {
|
| - VERIFY1(SUCCEEDED(NetworkConfigManager::CreateInstance()));
|
| - }
|
| - return *instance_;
|
| -}
|
| -
|
| -void NetworkConfigManager::set_is_machine(bool is_machine) {
|
| - __mutexScope(instance_lock_);
|
| - if (instance_) {
|
| - NET_LOG(LE, (_T("set_is_machine called after instance created.")));
|
| - }
|
| -
|
| - is_machine_ = is_machine;
|
| -}
|
| -
|
| -void NetworkConfigManager::DeleteInstanceInternal() {
|
| - __mutexBlock(lock_) {
|
| - std::map<CString, NetworkConfig*>::iterator it;
|
| -
|
| - for (it = user_network_config_map_.begin();
|
| - it != user_network_config_map_.end();
|
| - ++it) {
|
| - if (NULL != it->second) {
|
| - delete it->second;
|
| - }
|
| - }
|
| - user_network_config_map_.clear();
|
| - }
|
| -}
|
| -
|
| -HRESULT NetworkConfigManager::GetUserNetworkConfig(
|
| - NetworkConfig** network_config) {
|
| - CString sid;
|
| - HRESULT hr = user_info::GetEffectiveUserSid(&sid);
|
| - if (FAILED(hr)) {
|
| - NET_LOG(LE, (_T("[GetEffectiveUserSid failed][0x%x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - __mutexBlock(lock_) {
|
| - std::map<CString, NetworkConfig*>::iterator it;
|
| - it = user_network_config_map_.find(sid);
|
| -
|
| - if (user_network_config_map_.end() != it) {
|
| - *network_config = it->second;
|
| - return S_OK;
|
| - }
|
| -
|
| - hr = CreateNetworkConfigInstance(network_config, is_machine_);
|
| - if (SUCCEEDED(hr)) {
|
| - user_network_config_map_.insert(std::make_pair(sid, *network_config));
|
| - }
|
| -
|
| - return hr;
|
| - }
|
| -
|
| - return E_FAIL;
|
| -}
|
| -
|
| -HRESULT NetworkConfigManager::CreateNetworkConfigInstance(
|
| - NetworkConfig** network_config_ptr,
|
| - bool is_machine) {
|
| - ASSERT1(network_config_ptr);
|
| -
|
| - NetworkConfig* network_config(new NetworkConfig(is_machine));
|
| - HRESULT hr = network_config->Initialize();
|
| - if (FAILED(hr)) {
|
| - NET_LOG(LE, (_T("[NetworkConfig::Initialize() failed][0x%x]"), hr));
|
| - delete network_config;
|
| - return hr;
|
| - }
|
| -
|
| - *network_config_ptr = network_config;
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT NetworkConfigManager::InitializeLock() {
|
| - NamedObjectAttributes lock_attr;
|
| - GetNamedObjectAttributes(kNetworkConfigLock, is_machine_, &lock_attr);
|
| - return global_lock_.InitializeWithSecAttr(lock_attr.name, &lock_attr.sa) ?
|
| - S_OK : E_FAIL;
|
| -}
|
| -
|
| -HRESULT NetworkConfigManager::InitializeRegistryKey() {
|
| - // The registry path under which to store persistent network configuration.
|
| - // The "network" subkey is created with default security. Below "network",
|
| - // the "secure" key is created so that only system and administrators have
|
| - // access to it.
|
| - CString reg_path = is_machine_ ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
|
| - reg_path = AppendRegKeyPath(reg_path, kNetworkSubkey);
|
| - RegKey reg_key_network;
|
| - DWORD disposition = 0;
|
| - HRESULT hr = reg_key_network.Create(reg_path,
|
| - NULL, // Class.
|
| - 0, // Options.
|
| - KEY_CREATE_SUB_KEY, // SAM desired.
|
| - NULL, // Security attrs.
|
| - &disposition);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - // When initializing for machine, grant access to administrators and system.
|
| - scoped_ptr<CSecurityAttributes> sa;
|
| - if (is_machine_) {
|
| - sa.reset(new CSecurityAttributes);
|
| - GetAdminDaclSecurityAttributes(sa.get(), GENERIC_ALL);
|
| - }
|
| -
|
| - disposition = 0;
|
| - RegKey reg_key_network_secure;
|
| - hr = reg_key_network_secure.Create(reg_key_network.Key(), // Parent.
|
| - kNetworkCupSubkey, // Subkey name.
|
| - NULL, // Class.
|
| - 0, // Options.
|
| - KEY_READ, // SAM desired.
|
| - sa.get(), // Security attrs.
|
| - &disposition);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT NetworkConfigManager::SetCupCredentials(
|
| - const CupCredentials& cup_credentials) {
|
| - __mutexScope(lock_);
|
| -
|
| - const std::vector<uint8>& sk_in(cup_credentials.sk);
|
| -
|
| - if (sk_in.empty()) {
|
| - return E_INVALIDARG;
|
| - }
|
| -
|
| - std::vector<uint8> sk_out;
|
| - HRESULT hr = EncryptData(NULL, 0, &sk_in.front(), sk_in.size(), &sk_out);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - cup_credentials_.reset(new CupCredentials);
|
| -
|
| - cup_credentials_->sk.swap(sk_out);
|
| - cup_credentials_->c.SetString(cup_credentials.c);
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT NetworkConfigManager::GetCupCredentials(
|
| - CupCredentials* cup_credentials) {
|
| - ASSERT1(cup_credentials);
|
| - __mutexScope(lock_);
|
| - if (cup_credentials_ == NULL || cup_credentials_->sk.empty()) {
|
| - return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
|
| - }
|
| -
|
| - std::vector<uint8> decrypted_sk;
|
| - HRESULT hr = DecryptData(NULL,
|
| - 0,
|
| - &cup_credentials_->sk.front(),
|
| - cup_credentials_->sk.size(),
|
| - &decrypted_sk);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - cup_credentials->sk.swap(decrypted_sk);
|
| - cup_credentials->c.SetString(cup_credentials_->c);
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -// This function should be called in singleton creation stage,
|
| -// thus no lock is needed.
|
| -HRESULT NetworkConfigManager::LoadCupCredentialsFromRegistry() {
|
| - __mutexScope(global_lock_);
|
| -
|
| - CString reg_path = is_machine_ ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
|
| - reg_path = AppendRegKeyPath(reg_path, kNetworkSubkey);
|
| - CString key_name = AppendRegKeyPath(reg_path, kNetworkCupSubkey);
|
| - RegKey reg_key;
|
| - HRESULT hr = reg_key.Open(key_name, KEY_READ);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - scoped_array<byte> buf;
|
| - DWORD buf_length = 0;
|
| - hr = reg_key.GetValue(kCupClientSecretKey, address(buf), &buf_length);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - CString cookie;
|
| - hr = reg_key.GetValue(kCupClientCookie, &cookie);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - if (buf_length == 0) {
|
| - return E_FAIL;
|
| - }
|
| - cup_credentials_.reset(new CupCredentials);
|
| - cup_credentials_->sk.resize(buf_length);
|
| - memcpy(&cup_credentials_->sk.front(), buf.get(), buf_length);
|
| - cup_credentials_->c = CT2A(cookie);
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -// This function is called in the destructor only thus no lock is needed.
|
| -HRESULT NetworkConfigManager::SaveCupCredentialsToRegistry() {
|
| - __mutexScope(global_lock_);
|
| -
|
| - CString reg_path = is_machine_ ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
|
| - reg_path = AppendRegKeyPath(reg_path, kNetworkSubkey);
|
| - CString key_name = AppendRegKeyPath(reg_path, kNetworkCupSubkey);
|
| - RegKey reg_key;
|
| - HRESULT hr = reg_key.Open(key_name, KEY_WRITE);
|
| - if (FAILED(hr)) {
|
| - NET_LOG(L2, (_T("[Registry key open failed][%s][0x%08x]"), key_name, hr));
|
| - return hr;
|
| - }
|
| -
|
| - if (cup_credentials_ == NULL || cup_credentials_->sk.empty()) {
|
| - HRESULT hr1 = reg_key.DeleteValue(kCupClientSecretKey);
|
| - HRESULT hr2 = reg_key.DeleteValue(kCupClientCookie);
|
| - return (SUCCEEDED(hr1) && SUCCEEDED(hr2)) ? S_OK : HRESULTFromLastError();
|
| - }
|
| -
|
| - hr = reg_key.SetValue(kCupClientSecretKey,
|
| - static_cast<const byte*>(&cup_credentials_->sk.front()),
|
| - cup_credentials_->sk.size());
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - hr = reg_key.SetValue(kCupClientCookie, CA2T(cup_credentials_->c));
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - return S_OK;
|
| -}
|
| -
|
| -void NetworkConfigManager::ClearCupCredentials() {
|
| - __mutexScope(lock_);
|
| - cup_credentials_.reset(NULL);
|
| -}
|
| -
|
| -} // namespace omaha
|
| -
|
|
|