Commit 1d1e5c2e authored by Maciek Kumorek's avatar Maciek Kumorek Committed by Commit Bot

Add support for auto proxy discovery in WinHttp network request.

Bug: 1060701
Change-Id: I7e0a2dff71b20a2ebf36139fa1bc180508cb0bca
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2134943
Commit-Queue: Maciek Kumorek <makumo@microsoft.com>
Reviewed-by: default avatarSorin Jianu <sorin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#791550}
parent 810b81ed
......@@ -77,8 +77,15 @@ source_set("lib") {
"net/network_fetcher.h",
"net/network_winhttp.cc",
"net/network_winhttp.h",
"net/proxy_configuration.cc",
"net/proxy_configuration.h",
"net/proxy_info.cc",
"net/proxy_info.h",
"net/scoped_hinternet.h",
"net/scoped_winttp_proxy_info.h",
"scoped_handle.h",
"scoped_impersonation.cc",
"scoped_impersonation.h",
"setup/setup.cc",
"setup/setup.h",
"setup/setup_util.cc",
......@@ -161,6 +168,8 @@ source_set("updater_tests") {
sources = [
"group_policy_manager_unittest.cc",
"net/network_unittest.cc",
"net/proxy_configuration_unittest.cc",
"net/proxy_info_unittest.cc",
"tag_extractor_unittest.cc",
"util_unittest.cc",
]
......@@ -172,6 +181,7 @@ source_set("updater_tests") {
":tag_extractor",
"//base/test:test_support",
"//testing/gtest",
"//url:url",
]
data_deps = [
......
......@@ -7,12 +7,15 @@
#include <memory>
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "chrome/updater/win/net/scoped_hinternet.h"
#include "components/update_client/network.h"
namespace updater {
class ProxyConfiguration;
// Network fetcher factory for WinHTTP.
class NetworkFetcherFactory : public update_client::NetworkFetcherFactory {
public:
......@@ -26,9 +29,12 @@ class NetworkFetcherFactory : public update_client::NetworkFetcherFactory {
~NetworkFetcherFactory() override;
private:
static scoped_hinternet CreateSessionHandle();
static scoped_hinternet CreateSessionHandle(int proxy_access_type);
SEQUENCE_CHECKER(sequence_checker_);
// Proxy configuration for WinHTTP should be initialized before
// the session handle.
scoped_refptr<ProxyConfiguration> proxy_configuration_;
scoped_hinternet session_handle_;
};
......
......@@ -16,12 +16,15 @@
#include "base/win/windows_version.h"
#include "chrome/updater/win/net/network.h"
#include "chrome/updater/win/net/network_winhttp.h"
#include "chrome/updater/win/net/proxy_configuration.h"
namespace updater {
NetworkFetcher::NetworkFetcher(const HINTERNET& session_handle)
NetworkFetcher::NetworkFetcher(const HINTERNET& session_handle,
scoped_refptr<ProxyConfiguration> proxy_config)
: network_fetcher_(
base::MakeRefCounted<NetworkFetcherWinHTTP>(session_handle)),
base::MakeRefCounted<NetworkFetcherWinHTTP>(session_handle,
proxy_config)),
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
NetworkFetcher::~NetworkFetcher() {
......@@ -77,16 +80,16 @@ void NetworkFetcher::DownloadToFileComplete() {
}
NetworkFetcherFactory::NetworkFetcherFactory()
: session_handle_(CreateSessionHandle()) {}
: proxy_configuration_(GetProxyConfiguration()),
session_handle_(
CreateSessionHandle(proxy_configuration_->access_type())) {}
NetworkFetcherFactory::~NetworkFetcherFactory() = default;
scoped_hinternet NetworkFetcherFactory::CreateSessionHandle() {
const auto* os_info = base::win::OSInfo::GetInstance();
const uint32_t access_type = os_info->version() >= base::win::Version::WIN8_1
? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
: WINHTTP_ACCESS_TYPE_NO_PROXY;
scoped_hinternet NetworkFetcherFactory::CreateSessionHandle(
int proxy_access_type) {
scoped_hinternet session_handle(
::WinHttpOpen(L"Chrome Updater", access_type, WINHTTP_NO_PROXY_NAME,
::WinHttpOpen(L"Chrome Updater", proxy_access_type, WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC));
// Allow TLS1.2 on Windows 7 and Windows 8. See KB3140245. TLS 1.2 is enabled
......@@ -106,7 +109,8 @@ std::unique_ptr<update_client::NetworkFetcher> NetworkFetcherFactory::Create()
const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return session_handle_.get()
? std::make_unique<NetworkFetcher>(session_handle_.get())
? std::make_unique<NetworkFetcher>(session_handle_.get(),
proxy_configuration_)
: nullptr;
}
......
......@@ -26,6 +26,7 @@ class SingleThreadTaskRunner;
namespace updater {
class NetworkFetcherWinHTTP;
class ProxyConfiguration;
class NetworkFetcher : public update_client::NetworkFetcher {
public:
......@@ -37,7 +38,8 @@ class NetworkFetcher : public update_client::NetworkFetcher {
using DownloadToFileCompleteCallback =
update_client::NetworkFetcher::DownloadToFileCompleteCallback;
explicit NetworkFetcher(const HINTERNET& session_handle_);
NetworkFetcher(const HINTERNET& session_handle,
scoped_refptr<ProxyConfiguration> proxy_config);
~NetworkFetcher() override;
NetworkFetcher(const NetworkFetcher&) = delete;
NetworkFetcher& operator=(const NetworkFetcher&) = delete;
......
......@@ -12,6 +12,7 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/numerics/safe_math.h"
#include "base/strings/strcat.h"
#include "base/strings/string16.h"
......@@ -22,9 +23,12 @@
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/win/windows_version.h"
#include "chrome/updater/win/net/net_util.h"
#include "chrome/updater/win/net/network.h"
#include "chrome/updater/win/net/proxy_info.h"
#include "chrome/updater/win/net/scoped_hinternet.h"
#include "chrome/updater/win/net/scoped_winttp_proxy_info.h"
#include "chrome/updater/win/util.h"
#include "url/url_constants.h"
......@@ -53,9 +57,12 @@ void CrackUrl(const GURL& url,
} // namespace
NetworkFetcherWinHTTP::NetworkFetcherWinHTTP(const HINTERNET& session_handle)
NetworkFetcherWinHTTP::NetworkFetcherWinHTTP(
const HINTERNET& session_handle,
scoped_refptr<ProxyConfiguration> proxy_configuration)
: main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
session_handle_(session_handle) {}
session_handle_(session_handle),
proxy_configuration_(proxy_configuration) {}
NetworkFetcherWinHTTP::~NetworkFetcherWinHTTP() {
DVLOG(3) << "~NetworkFetcherWinHTTP";
......@@ -130,8 +137,8 @@ void NetworkFetcherWinHTTP::PostRequest(
fetch_progress_callback_ = std::move(fetch_progress_callback);
fetch_complete_callback_ = std::move(fetch_complete_callback);
DCHECK(url.SchemeIsHTTPOrHTTPS());
CrackUrl(url, &is_https_, &host_, &port_, &path_for_request_);
DCHECK(url_.SchemeIsHTTPOrHTTPS());
CrackUrl(url_, &is_https_, &host_, &port_, &path_for_request_);
verb_ = L"POST";
content_type_ = content_type;
......@@ -139,6 +146,7 @@ void NetworkFetcherWinHTTP::PostRequest(
base::BindRepeating(&NetworkFetcherWinHTTP::WriteDataToMemory, this);
net_error_ = BeginFetch(post_data, post_additional_headers);
if (FAILED(net_error_))
CompleteFetch();
}
......@@ -165,6 +173,7 @@ void NetworkFetcherWinHTTP::DownloadToFile(
base::BindRepeating(&NetworkFetcherWinHTTP::WriteDataToFile, this);
net_error_ = BeginFetch({}, {});
if (FAILED(net_error_))
CompleteFetch();
}
......@@ -173,14 +182,20 @@ HRESULT NetworkFetcherWinHTTP::BeginFetch(
const std::string& data,
base::flat_map<std::string, std::string> additional_headers) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
connect_handle_ = Connect();
if (!connect_handle_.get())
return HRESULTFromLastError();
base::Optional<ScopedWinHttpProxyInfo> winhttp_proxy_info =
proxy_configuration_->GetProxyForUrl(session_handle_, url_);
request_handle_ = OpenRequest();
if (!request_handle_.get())
return HRESULTFromLastError();
SetProxyForRequest(request_handle_.get(), winhttp_proxy_info);
const auto winhttp_callback = ::WinHttpSetStatusCallback(
request_handle_.get(), &NetworkFetcherWinHTTP::WinHttpStatusCallback,
WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0);
......
......@@ -19,6 +19,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/strings/string_piece_forward.h"
#include "chrome/updater/win/net/proxy_configuration.h"
#include "chrome/updater/win/net/scoped_hinternet.h"
#include "components/update_client/network.h"
#include "url/gurl.h"
......@@ -39,7 +40,8 @@ class NetworkFetcherWinHTTP
update_client::NetworkFetcher::ResponseStartedCallback;
using FetchProgressCallback = update_client::NetworkFetcher::ProgressCallback;
explicit NetworkFetcherWinHTTP(const HINTERNET& session_handle_);
NetworkFetcherWinHTTP(const HINTERNET& session_handle,
scoped_refptr<ProxyConfiguration> proxy_configuration);
NetworkFetcherWinHTTP(const NetworkFetcherWinHTTP&) = delete;
NetworkFetcherWinHTTP& operator=(const NetworkFetcherWinHTTP&) = delete;
......@@ -116,6 +118,7 @@ class NetworkFetcherWinHTTP
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
const HINTERNET& session_handle_; // Owned by NetworkFetcherWinHTTPFactory.
scoped_refptr<ProxyConfiguration> proxy_configuration_;
scoped_hinternet connect_handle_;
scoped_hinternet request_handle_;
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/updater/win/net/proxy_configuration.h"
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/policy_manager.h"
#include "chrome/updater/win/net/net_util.h"
#include "chrome/updater/win/net/proxy_info.h"
#include "chrome/updater/win/net/scoped_winttp_proxy_info.h"
#include "chrome/updater/win/scoped_impersonation.h"
#include "chrome/updater/win/user_info.h"
#include "url/gurl.h"
namespace updater {
namespace {
base::string16 FromCharOrEmpty(const base::char16* str) {
return str ? base::string16(str) : L"";
}
// Wrapper for WINHTTP_CURRENT_USER_IE_PROXY_CONFIG structure.
// According to MSDN, callers must free strings with GlobalFree.
class ScopedIeProxyConfig {
public:
ScopedIeProxyConfig();
ScopedIeProxyConfig(const ScopedIeProxyConfig&) = delete;
ScopedIeProxyConfig& operator=(const ScopedIeProxyConfig&) = delete;
~ScopedIeProxyConfig();
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* receive() { return &ie_proxy_config_; }
bool auto_detect() const { return ie_proxy_config_.fAutoDetect; }
base::string16 auto_config_url() const {
return FromCharOrEmpty(ie_proxy_config_.lpszAutoConfigUrl);
}
base::string16 proxy() const {
return FromCharOrEmpty(ie_proxy_config_.lpszProxy);
}
base::string16 proxy_bypass() const {
return FromCharOrEmpty(ie_proxy_config_.lpszProxyBypass);
}
private:
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_proxy_config_ = {};
};
ScopedIeProxyConfig::ScopedIeProxyConfig() {
ie_proxy_config_.fAutoDetect = false;
ie_proxy_config_.lpszAutoConfigUrl = nullptr;
ie_proxy_config_.lpszProxy = nullptr;
ie_proxy_config_.lpszProxyBypass = nullptr;
}
ScopedIeProxyConfig::~ScopedIeProxyConfig() {
if (ie_proxy_config_.lpszAutoConfigUrl)
::GlobalFree(ie_proxy_config_.lpszAutoConfigUrl);
if (ie_proxy_config_.lpszProxy)
::GlobalFree(ie_proxy_config_.lpszProxy);
if (ie_proxy_config_.lpszProxyBypass)
::GlobalFree(ie_proxy_config_.lpszProxyBypass);
}
} // namespace
ProxyConfiguration::ProxyConfiguration(const ProxyInfo& proxy_info)
: proxy_info_(proxy_info) {}
int ProxyConfiguration::access_type() const {
return DoGetAccessType();
}
int ProxyConfiguration::DoGetAccessType() const {
const bool is_using_named_proxy = !proxy_info_.auto_detect &&
proxy_info_.auto_config_url.empty() &&
!proxy_info_.proxy.empty();
return is_using_named_proxy ? WINHTTP_ACCESS_TYPE_NAMED_PROXY
: WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
}
base::Optional<ScopedWinHttpProxyInfo> ProxyConfiguration::GetProxyForUrl(
HINTERNET session_handle,
const GURL& url) const {
return DoGetProxyForUrl(session_handle, url);
}
base::Optional<ScopedWinHttpProxyInfo> ProxyConfiguration::DoGetProxyForUrl(
HINTERNET session_handle,
const GURL& url) const {
// Detect proxy settings using Web Proxy Auto Detection (WPAD).
WINHTTP_AUTOPROXY_OPTIONS auto_proxy_options = {0};
// Per MSDN, setting fAutoLogonIfChallenged to false first may work
// if Windows cached the proxy config.
auto_proxy_options.fAutoLogonIfChallenged = false;
bool try_auto_proxy = false;
if (proxy_info_.auto_detect) {
auto_proxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
auto_proxy_options.dwAutoDetectFlags =
WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
try_auto_proxy = true;
}
// PAC Url was specified, let system auto detect given the PAC url.
if (!proxy_info_.auto_config_url.empty()) {
auto_proxy_options.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
auto_proxy_options.lpszAutoConfigUrl = proxy_info_.auto_config_url.c_str();
try_auto_proxy = true;
}
// Find the proxy server for the url.
ScopedWinHttpProxyInfo winhttp_proxy_info = {};
if (try_auto_proxy) {
const base::string16 url_str = base::SysUTF8ToWide(url.spec());
bool success = ::WinHttpGetProxyForUrl(session_handle, url_str.c_str(),
&auto_proxy_options,
winhttp_proxy_info.receive());
if (!success && ::GetLastError() == ERROR_WINHTTP_LOGIN_FAILURE) {
auto_proxy_options.fAutoLogonIfChallenged = true;
success = ::WinHttpGetProxyForUrl(session_handle, url_str.c_str(),
&auto_proxy_options,
winhttp_proxy_info.receive());
}
if (!success) {
PLOG(ERROR) << "Failed to get proxy for url";
return {};
}
} else {
winhttp_proxy_info.set_proxy(proxy_info_.proxy);
winhttp_proxy_info.set_proxy_bypass(proxy_info_.proxy_bypass);
}
if (!winhttp_proxy_info.IsValid())
return {};
return winhttp_proxy_info;
}
void SetProxyForRequest(
const HINTERNET request_handle,
const base::Optional<ScopedWinHttpProxyInfo>& winhttp_proxy_info) {
// Set the proxy option on the request handle.
if (winhttp_proxy_info.has_value() && winhttp_proxy_info.value().IsValid()) {
const ScopedWinHttpProxyInfo& proxy_info = winhttp_proxy_info.value();
VLOG(1) << "Setting proxy " << proxy_info.proxy();
auto hr = SetOption(request_handle, WINHTTP_OPTION_PROXY,
const_cast<WINHTTP_PROXY_INFO*>(proxy_info.get()));
if (FAILED(hr)) {
PLOG(ERROR) << "Failed to set WINHTTP_OPTION_PROXY: 0x" << std::hex << hr;
}
}
}
scoped_refptr<ProxyConfiguration> GetProxyConfiguration() {
std::unique_ptr<PolicyManagerInterface> policy_manager = GetPolicyManager();
std::string policy_proxy_mode;
if (policy_manager->GetProxyMode(&policy_proxy_mode) &&
policy_proxy_mode.compare(kProxyModeSystem) != 0) {
DVLOG(3) << "Using policy proxy " << policy_proxy_mode;
bool auto_detect = false;
base::string16 pac_url;
base::string16 proxy_url;
bool is_policy_config_valid = true;
if (policy_proxy_mode.compare(kProxyModeFixedServers) == 0) {
std::string policy_proxy_url;
if (!policy_manager->GetProxyServer(&policy_proxy_url)) {
VLOG(1) << "Fixed server mode proxy has no URL specified.";
is_policy_config_valid = false;
} else {
proxy_url = base::SysUTF8ToWide(policy_proxy_url);
}
} else if (policy_proxy_mode.compare(kProxyModePacScript) == 0) {
std::string policy_pac_url;
if (!policy_manager->GetProxyServer(&policy_pac_url)) {
VLOG(1) << "PAC proxy policy has no PAC URL specified.";
is_policy_config_valid = false;
} else {
pac_url = base::SysUTF8ToWide(policy_pac_url);
}
} else if (policy_proxy_mode.compare(kProxyModeAutoDetect)) {
auto_detect = true;
}
if (is_policy_config_valid) {
return base::MakeRefCounted<ProxyConfiguration>(
ProxyInfo{auto_detect, pac_url, proxy_url, L""});
} else {
VLOG(1) << "Configuration set by policy was invalid."
<< "Proceding with system configuration";
}
}
const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
const bool supports_automatic_proxy =
os_info->version() >= base::win::Version::WIN8_1;
if (supports_automatic_proxy)
return base::MakeRefCounted<AutoProxyConfiguration>();
ScopedImpersonation impersonate_user;
if (IsLocalSystemUser()) {
DVLOG(3) << "Running as SYSTEM, impersonate the current user.";
base::win::ScopedHandle user_token = GetUserTokenFromCurrentSessionId();
if (user_token.IsValid()) {
impersonate_user.Impersonate(user_token.Get());
}
}
ScopedIeProxyConfig ie_proxy_config;
if (::WinHttpGetIEProxyConfigForCurrentUser(ie_proxy_config.receive())) {
return base::MakeRefCounted<ProxyConfiguration>(ProxyInfo{
ie_proxy_config.auto_detect(), ie_proxy_config.auto_config_url(),
ie_proxy_config.proxy(), ie_proxy_config.proxy_bypass()});
} else {
DPLOG(ERROR) << "Failed to get proxy for current user";
}
return base::MakeRefCounted<ProxyConfiguration>();
}
int AutoProxyConfiguration::DoGetAccessType() const {
return WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY;
}
base::Optional<ScopedWinHttpProxyInfo> AutoProxyConfiguration::DoGetProxyForUrl(
HINTERNET,
const GURL&) const {
// When using automatic proxy settings, Windows will resolve the proxy
// for us.
DVLOG(3) << "Auto-proxy: skip getting proxy for a url";
return {};
}
} // namespace updater
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_UPDATER_WIN_NET_PROXY_CONFIGURATION_H_
#define CHROME_UPDATER_WIN_NET_PROXY_CONFIGURATION_H_
#include <windows.h>
#include <winhttp.h>
#include <memory>
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "chrome/updater/win/net/proxy_info.h"
#include "chrome/updater/win/net/scoped_winttp_proxy_info.h"
class GURL;
namespace updater {
// Classes in this module represent sources of system proxy configuration.
// On Windows 8.1 and above, we can use Auto Proxy mode in WinHTTP and let
// the OS configure the proxy.
// This is represented by the AutoProxyConfiguration class.
// When a proxy related policy is set or when using Windows 8 or below,
// we'd set proxy manually using ProxyConfiguration class.
//
// Default WinHTTP proxy strategy - provide proxy server info to WinHTTP.
// Used when policy is set or on Windows 8 and below.
// This class can use either provided proxy information from the
// IE Config or a policy policy setting or query per request proxy info
// with WPAD (Web Proxy Auto Discovery).
class ProxyConfiguration : public base::RefCounted<ProxyConfiguration> {
public:
ProxyConfiguration() = default;
explicit ProxyConfiguration(const ProxyInfo& proxy_info);
ProxyConfiguration(const ProxyConfiguration&) = delete;
ProxyConfiguration& operator=(const ProxyConfiguration&) = delete;
int access_type() const;
base::Optional<ScopedWinHttpProxyInfo> GetProxyForUrl(
HINTERNET session_handle,
const GURL& url) const;
protected:
virtual ~ProxyConfiguration() = default;
private:
friend class base::RefCounted<ProxyConfiguration>;
virtual int DoGetAccessType() const;
virtual base::Optional<ScopedWinHttpProxyInfo> DoGetProxyForUrl(
HINTERNET session_handle,
const GURL& url) const;
ProxyInfo proxy_info_;
};
// Auto proxy strategy - let WinHTTP detect proxy settings.
// This is only available on Windows 8.1 and above.
class AutoProxyConfiguration final : public ProxyConfiguration {
protected:
~AutoProxyConfiguration() override = default;
private:
// Overrides for ProxyConfiguration.
int DoGetAccessType() const override;
base::Optional<ScopedWinHttpProxyInfo> DoGetProxyForUrl(
HINTERNET session_handle,
const GURL& url) const override;
};
// Sets proxy info on a request handle, if WINHTTP_PROXY_INFO is provided.
void SetProxyForRequest(
const HINTERNET request_handle,
const base::Optional<ScopedWinHttpProxyInfo>& winhttp_proxy_info);
// Factory method for the proxy configuration strategy.
scoped_refptr<ProxyConfiguration> GetProxyConfiguration();
} // namespace updater
#endif // CHROME_UPDATER_WIN_NET_PROXY_CONFIGURATION_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/updater/win/net/proxy_configuration.h"
#include "base/memory/scoped_refptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace updater {
TEST(ProxyConfiguration, DirectProxy) {
auto proxy_configuration = base::MakeRefCounted<ProxyConfiguration>();
EXPECT_EQ(proxy_configuration->access_type(),
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY);
}
TEST(ProxyConfiguration, AutoProxy) {
auto proxy_configuration = base::MakeRefCounted<AutoProxyConfiguration>();
EXPECT_EQ(proxy_configuration->access_type(),
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY);
base::Optional<ScopedWinHttpProxyInfo> winhttp_proxy_info =
proxy_configuration->GetProxyForUrl(nullptr, GURL(L"http://example.com"));
EXPECT_FALSE(winhttp_proxy_info.has_value());
}
TEST(ProxyConfiguration, NamedProxy) {
auto proxy_configuration = base::MakeRefCounted<ProxyConfiguration>(
ProxyInfo(false, L"", L"http://192.168.0.1", L""));
EXPECT_EQ(proxy_configuration->access_type(),
WINHTTP_ACCESS_TYPE_NAMED_PROXY);
}
TEST(ProxyConfiguration, WPADProxyGetProxyForUrl) {
auto proxy_configuration =
base::MakeRefCounted<ProxyConfiguration>(ProxyInfo(true, L"", L"", L""));
EXPECT_EQ(proxy_configuration->access_type(),
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY);
base::Optional<ScopedWinHttpProxyInfo> winhttp_proxy_info =
proxy_configuration->GetProxyForUrl(nullptr, GURL(L"http://example.com"));
EXPECT_FALSE(winhttp_proxy_info.has_value());
}
} // namespace updater
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/updater/win/net/proxy_info.h"
namespace updater {
ProxyInfo::ProxyInfo() = default;
ProxyInfo::~ProxyInfo() = default;
ProxyInfo::ProxyInfo(bool auto_detect,
const base::string16& auto_config_url,
const base::string16& proxy,
const base::string16& proxy_bypass)
: auto_detect(auto_detect),
auto_config_url(auto_config_url),
proxy(proxy),
proxy_bypass(proxy_bypass) {}
ProxyInfo::ProxyInfo(const ProxyInfo& proxy_info) = default;
ProxyInfo& ProxyInfo::operator=(const ProxyInfo& proxy_info) = default;
ProxyInfo::ProxyInfo(ProxyInfo&& proxy_info) = default;
ProxyInfo& ProxyInfo::operator=(ProxyInfo&& proxy_info) = default;
} // namespace updater
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_UPDATER_WIN_NET_PROXY_INFO_H_
#define CHROME_UPDATER_WIN_NET_PROXY_INFO_H_
#include "base/strings/string16.h"
namespace updater {
struct ProxyInfo {
ProxyInfo();
ProxyInfo(bool auto_detect,
const base::string16& auto_config_url,
const base::string16& proxy,
const base::string16& proxy_bypass);
~ProxyInfo();
ProxyInfo(const ProxyInfo& proxy_info);
ProxyInfo& operator=(const ProxyInfo& proxy_info);
ProxyInfo(ProxyInfo&& proxy_info);
ProxyInfo& operator=(ProxyInfo&& proxy_info);
// Specifies the configuration is Web Proxy Auto Discovery (WPAD).
bool auto_detect = false;
// The url of the proxy auto configuration (PAC) script, if known.
base::string16 auto_config_url;
// Named proxy information.
// The proxy string is usually something as "http=foo:80;https=bar:8080".
// According to the documentation for WINHTTP_PROXY_INFO, multiple proxies
// are separated by semicolons or whitespace.
base::string16 proxy;
base::string16 proxy_bypass;
};
} // namespace updater
#endif // CHROME_UPDATER_WIN_NET_PROXY_INFO_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/updater/win/net/proxy_info.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace updater {
TEST(ProxyInfoTest, DefaultIsDirectConnection) {
ProxyInfo proxy_info;
EXPECT_FALSE(proxy_info.auto_detect);
EXPECT_TRUE(proxy_info.auto_config_url.empty());
EXPECT_TRUE(proxy_info.proxy.empty());
EXPECT_TRUE(proxy_info.proxy_bypass.empty());
}
TEST(ProxyInfoTest, CanCopy) {
ProxyInfo proxy_info(true, L"Foo", L"Bar", L"Baz");
ProxyInfo proxy_info2(proxy_info);
EXPECT_TRUE(proxy_info.auto_detect);
EXPECT_EQ(proxy_info.auto_detect, proxy_info2.auto_detect);
EXPECT_STREQ(L"Foo", proxy_info.auto_config_url.c_str());
EXPECT_STREQ(L"Foo", proxy_info2.auto_config_url.c_str());
EXPECT_STREQ(L"Bar", proxy_info.proxy.c_str());
EXPECT_STREQ(L"Bar", proxy_info2.proxy.c_str());
EXPECT_STREQ(L"Baz", proxy_info.proxy_bypass.c_str());
EXPECT_STREQ(L"Baz", proxy_info2.proxy_bypass.c_str());
}
TEST(ProxyInfoTest, CanMove) {
ProxyInfo proxy_info{true, L"Foo", L"Bar", L"Baz"};
ProxyInfo proxy_info2 = std::move(proxy_info);
EXPECT_TRUE(proxy_info2.auto_detect);
EXPECT_STREQ(L"Foo", proxy_info2.auto_config_url.c_str());
EXPECT_STREQ(L"Bar", proxy_info2.proxy.c_str());
EXPECT_STREQ(L"Baz", proxy_info2.proxy_bypass.c_str());
EXPECT_TRUE(proxy_info.auto_config_url.empty());
EXPECT_TRUE(proxy_info.proxy.empty());
EXPECT_TRUE(proxy_info.proxy_bypass.empty());
}
} // namespace updater
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_UPDATER_WIN_NET_SCOPED_WINTTP_PROXY_INFO_H_
#define CHROME_UPDATER_WIN_NET_SCOPED_WINTTP_PROXY_INFO_H_
#include <windows.h>
#include <winhttp.h>
#include "base/logging.h"
#include "base/strings/string16.h"
namespace updater {
// Wrapper class for the WINHTTP_PROXY_INFO structure.
// Note that certain Win32 APIs expected the strings to be allocated with
// with GlobalAlloc.
class ScopedWinHttpProxyInfo {
public:
ScopedWinHttpProxyInfo() {}
ScopedWinHttpProxyInfo(const ScopedWinHttpProxyInfo& other) = delete;
ScopedWinHttpProxyInfo& operator=(const ScopedWinHttpProxyInfo& other) =
delete;
ScopedWinHttpProxyInfo(ScopedWinHttpProxyInfo&& other) {
proxy_info_.lpszProxy = other.proxy_info_.lpszProxy;
other.proxy_info_.lpszProxy = nullptr;
proxy_info_.lpszProxyBypass = other.proxy_info_.lpszProxyBypass;
other.proxy_info_.lpszProxyBypass = nullptr;
}
ScopedWinHttpProxyInfo& operator=(ScopedWinHttpProxyInfo&& other) {
proxy_info_.lpszProxy = other.proxy_info_.lpszProxy;
other.proxy_info_.lpszProxy = nullptr;
proxy_info_.lpszProxyBypass = other.proxy_info_.lpszProxyBypass;
other.proxy_info_.lpszProxyBypass = nullptr;
return *this;
}
~ScopedWinHttpProxyInfo() {
if (proxy_info_.lpszProxy)
::GlobalFree(proxy_info_.lpszProxy);
if (proxy_info_.lpszProxyBypass)
::GlobalFree(proxy_info_.lpszProxyBypass);
}
bool IsValid() const { return proxy_info_.lpszProxy; }
void set_access_type(DWORD access_type) {
proxy_info_.dwAccessType = access_type;
}
base::char16* proxy() const { return proxy_info_.lpszProxy; }
void set_proxy(const base::string16& proxy) {
if (proxy.empty())
return;
proxy_info_.lpszProxy = GlobalAlloc(proxy);
}
void set_proxy_bypass(const base::string16& proxy_bypass) {
if (proxy_bypass.empty())
return;
proxy_info_.lpszProxyBypass = GlobalAlloc(proxy_bypass);
}
// Return the raw pointer since WinHttpSetOption requires a non const pointer.
const WINHTTP_PROXY_INFO* get() const { return &proxy_info_; }
WINHTTP_PROXY_INFO* receive() { return &proxy_info_; }
private:
base::char16* GlobalAlloc(const base::string16& str) {
const size_t size_in_bytes = (str.length() + 1) * sizeof(base::char16);
base::char16* string_mem =
reinterpret_cast<base::char16*>(::GlobalAlloc(GPTR, size_in_bytes));
if (!string_mem) {
PLOG(ERROR) << "GlobalAlloc failed to allocate " << size_in_bytes
<< " bytes";
return nullptr;
}
memcpy(string_mem, str.data(), size_in_bytes);
return string_mem;
}
WINHTTP_PROXY_INFO proxy_info_ = {};
};
} // namespace updater
#endif // CHROME_UPDATER_WIN_NET_SCOPED_WINTTP_PROXY_INFO_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/updater/win/scoped_impersonation.h"
#include "base/logging.h"
#include "chrome/updater/win/util.h"
namespace updater {
HRESULT ScopedImpersonation::Impersonate(HANDLE token) {
if (!token)
return E_FAIL;
result_ = ::ImpersonateLoggedOnUser(token) ? S_OK : HRESULTFromLastError();
DCHECK_EQ(result_, S_OK);
return result_;
}
ScopedImpersonation::~ScopedImpersonation() {
if (result_ != S_OK)
return;
CHECK(::RevertToSelf());
}
} // namespace updater
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_UPDATER_WIN_SCOPED_IMPERSONATION_H_
#define CHROME_UPDATER_WIN_SCOPED_IMPERSONATION_H_
#include <windows.h>
namespace updater {
class ScopedImpersonation {
public:
ScopedImpersonation() = default;
ScopedImpersonation(const ScopedImpersonation&) = delete;
ScopedImpersonation& operator=(const ScopedImpersonation&) = delete;
~ScopedImpersonation();
HRESULT Impersonate(HANDLE session);
private:
HRESULT result_ = E_FAIL;
};
} // namespace updater
#endif // CHROME_UPDATER_WIN_SCOPED_IMPERSONATION_H_
......@@ -5,10 +5,18 @@
#include "chrome/updater/win/user_info.h"
#include "base/check.h"
#include "base/strings/string16.h"
#include "chrome/updater/win/util.h"
namespace updater {
namespace {
// Sid of NT AUTHORITY\SYSTEM user.
constexpr base::char16 kSystemPrincipalSid[] = L"S-1-5-18";
} // namespace
HRESULT GetProcessUser(base::string16* name,
base::string16* domain,
base::string16* sid) {
......@@ -42,6 +50,12 @@ HRESULT GetProcessUserSid(CSid* sid) {
return S_OK;
}
bool IsLocalSystemUser() {
base::string16 user_sid;
HRESULT hr = GetProcessUser(nullptr, nullptr, &user_sid);
return SUCCEEDED(hr) && user_sid.compare(kSystemPrincipalSid) == 0;
}
HRESULT GetThreadUserSid(base::string16* sid) {
DCHECK(sid);
CAccessToken access_token;
......
......@@ -21,6 +21,9 @@ HRESULT GetProcessUser(base::string16* name,
// Gets SID associated with the access token of the current process.
HRESULT GetProcessUserSid(CSid* sid);
// Returns true if the current user is NT AUTHORITY\SYSTEM.
bool IsLocalSystemUser();
// Gets the user SID associated with the access token of the current thread if
// the thread is impersonating. If the thread is not impersonating, the API
// fails with ERROR_NO_TOKEN.
......
......@@ -7,6 +7,7 @@
#include <aclapi.h>
#include <shlobj.h>
#include <windows.h>
#include <wtsapi32.h>
#include "base/command_line.h"
#include "base/files/file_path.h"
......@@ -14,6 +15,7 @@
#include "base/logging.h"
#include "base/numerics/ranges.h"
#include "base/process/process_iterator.h"
#include "base/scoped_native_library.h"
#include "base/strings/strcat.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
......@@ -358,4 +360,31 @@ bool DeleteInstallerProgress(const std::string& app_id) {
return key.DeleteValue(kRegistryValueInstallerProgress) == ERROR_SUCCESS;
}
base::win::ScopedHandle GetUserTokenFromCurrentSessionId() {
base::win::ScopedHandle token_handle;
DWORD bytes_returned = 0;
DWORD* session_id_ptr = nullptr;
if (!::WTSQuerySessionInformation(
WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSSessionId,
reinterpret_cast<LPTSTR*>(&session_id_ptr), &bytes_returned)) {
PLOG(ERROR) << "WTSQuerySessionInformation failed.";
return token_handle;
}
DCHECK_EQ(bytes_returned, sizeof(*session_id_ptr));
DWORD session_id = *session_id_ptr;
::WTSFreeMemory(session_id_ptr);
DVLOG(1) << "::WTSQuerySessionInformation session id: " << session_id;
HANDLE token_handle_raw = nullptr;
if (!::WTSQueryUserToken(session_id, &token_handle_raw)) {
PLOG(ERROR) << "WTSQueryUserToken failed";
return token_handle;
}
token_handle.Set(token_handle_raw);
return token_handle;
}
} // namespace updater
......@@ -11,8 +11,10 @@
#include <string>
#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/win/atl.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_types.h"
namespace updater {
......@@ -111,6 +113,9 @@ int GetInstallerProgress(const std::string& app_id);
bool DeleteInstallerProgress(const std::string& app_id);
// Returns a logged on user token handle from the current session.
base::win::ScopedHandle GetUserTokenFromCurrentSessionId();
} // namespace updater
#endif // CHROME_UPDATER_WIN_UTIL_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment