blob: 18d5d7d05e6a199016ff173c9907713c720933a3 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/policy/browser_dm_token_storage_win.h"
#include <objbase.h>
#include <unknwn.h>
#include <windows.h>
#include <comutil.h>
#include <oleauto.h>
#include <winerror.h>
#include <wrl/client.h>
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>
#include "base/base64.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/thread_pool.h"
#include "base/win/registry.h"
#include "build/branding_buildflags.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/util_constants.h"
#include "content/public/browser/browser_thread.h"
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
#include "chrome/browser/google/google_update_app_command.h"
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
namespace policy {
namespace {
bool StoreDMTokenInRegistry(const std::string& token) {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
if (token.empty())
return false;
auto app_command = GetUpdaterAppCommand(installer::kCmdStoreDMToken);
if (!app_command.has_value()) {
return false;
}
std::string token_base64 = base::Base64Encode(token);
VARIANT var;
VariantInit(&var);
_variant_t token_var = token_base64.c_str();
if (FAILED(app_command.value()->execute(token_var, var, var, var, var, var,
var, var, var))) {
return false;
}
// TODO(crbug.com/41377531): Get the status of the app command execution and
// return a corresponding value for |success|. For now, assume that the call
// to setup.exe succeeds.
return true;
#else
return false;
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
}
bool DeleteDMTokenFromRegistry() {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
auto app_command = GetUpdaterAppCommand(installer::kCmdDeleteDMToken);
if (!app_command.has_value()) {
return false;
}
VARIANT var;
VariantInit(&var);
if (FAILED(app_command.value()->execute(var, var, var, var, var, var, var,
var, var))) {
return false;
}
// TODO(crbug.com/41377531): Get the status of the app command execution and
// return a corresponding value for |success|. For now, assume that the call
// to setup.exe succeeds.
return true;
#else
return false;
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
}
} // namespace
std::string BrowserDMTokenStorageWin::InitClientId() {
// For the client id, use the Windows machine GUID.
base::win::RegKey key;
LSTATUS status =
key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography",
KEY_QUERY_VALUE | KEY_WOW64_64KEY);
if (status != ERROR_SUCCESS)
return std::string();
std::wstring value;
status = key.ReadValue(L"MachineGuid", &value);
if (status != ERROR_SUCCESS)
return std::string();
std::string client_id;
if (!base::WideToUTF8(value.c_str(), value.length(), &client_id))
return std::string();
return client_id;
}
std::string BrowserDMTokenStorageWin::InitEnrollmentToken() {
return base::WideToUTF8(InstallUtil::GetCloudManagementEnrollmentToken());
}
std::string BrowserDMTokenStorageWin::InitDMToken() {
// At the time of writing (January 2018), the DM token is about 200 bytes
// long. The initial size of the buffer should be enough to cover most
// realistic future size-increase scenarios, although we still make an effort
// to support somewhat larger token sizes just to be safe.
constexpr size_t kInitialDMTokenSize = 512;
base::win::RegKey key;
std::wstring dm_token_value_name;
std::vector<char> raw_value(kInitialDMTokenSize);
// Prefer the app-neutral location over the browser's to match Google Update's
// behavior.
for (const auto& location : {InstallUtil::BrowserLocation(false),
InstallUtil::BrowserLocation(true)}) {
std::tie(key, dm_token_value_name) =
InstallUtil::GetCloudManagementDmTokenLocation(
InstallUtil::ReadOnly(true), location);
if (!key.Valid())
continue;
DWORD dtype = REG_NONE;
DWORD size = static_cast<DWORD>(raw_value.size());
auto result = key.ReadValue(dm_token_value_name.c_str(), raw_value.data(),
&size, &dtype);
if (result == ERROR_MORE_DATA && size <= installer::kMaxDMTokenLength) {
raw_value.resize(size);
result = key.ReadValue(dm_token_value_name.c_str(), raw_value.data(),
&size, &dtype);
}
if (result != ERROR_SUCCESS || dtype != REG_BINARY || size == 0)
continue;
DCHECK_LE(size, installer::kMaxDMTokenLength);
return std::string(base::TrimWhitespaceASCII(
std::string_view(raw_value.data(), size), base::TRIM_ALL));
}
DVLOG(1) << "Failed to get DMToken from Registry.";
return std::string();
}
bool BrowserDMTokenStorageWin::InitEnrollmentErrorOption() {
return InstallUtil::ShouldCloudManagementBlockOnFailure();
}
bool BrowserDMTokenStorageWin::CanInitEnrollmentToken() const {
return true;
}
BrowserDMTokenStorage::StoreTask BrowserDMTokenStorageWin::SaveDMTokenTask(
const std::string& token,
const std::string& client_id) {
return base::BindOnce(&StoreDMTokenInRegistry, token);
}
BrowserDMTokenStorage::StoreTask BrowserDMTokenStorageWin::DeleteDMTokenTask(
const std::string& client_id) {
return base::BindOnce(&DeleteDMTokenFromRegistry);
}
scoped_refptr<base::TaskRunner>
BrowserDMTokenStorageWin::SaveDMTokenTaskRunner() {
return com_sta_task_runner_;
}
BrowserDMTokenStorageWin::BrowserDMTokenStorageWin()
: com_sta_task_runner_(
base::ThreadPool::CreateCOMSTATaskRunner({base::MayBlock()})) {}
BrowserDMTokenStorageWin::~BrowserDMTokenStorageWin() = default;
} // namespace policy