Commit 98239d31 authored by Greg Thompson's avatar Greg Thompson Committed by Commit Bot

Prefer the product-neutral DM token storage location over the browser-specific one.

This aligns Chrome's DM token storage with Google Update's.

This CL also makes base::win::RegKey a movable type.

BUG=970162

Change-Id: Id6270411d2417501746ad85f8061cd7d93841618
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1997184
Commit-Queue: Greg Thompson <grt@chromium.org>
Reviewed-by: default avatarOwen Min <zmin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#731691}
parent 2289de62
...@@ -106,6 +106,22 @@ RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) { ...@@ -106,6 +106,22 @@ RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
} }
} }
RegKey::RegKey(RegKey&& other)
: key_(other.key_),
wow64access_(other.wow64access_),
key_watcher_(std::move(other.key_watcher_)) {
other.key_ = nullptr;
other.wow64access_ = 0;
}
RegKey& RegKey::operator=(RegKey&& other) {
Close();
std::swap(key_, other.key_);
std::swap(wow64access_, other.wow64access_);
key_watcher_ = std::move(other.key_watcher_);
return *this;
}
RegKey::~RegKey() { RegKey::~RegKey() {
Close(); Close();
} }
......
...@@ -38,6 +38,8 @@ class BASE_EXPORT RegKey { ...@@ -38,6 +38,8 @@ class BASE_EXPORT RegKey {
RegKey(); RegKey();
explicit RegKey(HKEY key); explicit RegKey(HKEY key);
RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access); RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
RegKey(RegKey&& other) noexcept;
RegKey& operator=(RegKey&& other);
~RegKey(); ~RegKey();
LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access); LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access);
......
...@@ -402,6 +402,47 @@ TEST_F(RegistryTest, ChangeCallback) { ...@@ -402,6 +402,47 @@ TEST_F(RegistryTest, ChangeCallback) {
EXPECT_FALSE(delegate.WasCalled()); EXPECT_FALSE(delegate.WasCalled());
} }
TEST_F(RegistryTest, TestMoveConstruct) {
RegKey key;
std::wstring foo_key(kRootKey);
ASSERT_EQ(key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_SET_VALUE),
ERROR_SUCCESS);
RegKey key2(std::move(key));
// The old key should be meaningless now.
EXPECT_EQ(key.Handle(), nullptr);
// And the new one should work just fine.
EXPECT_NE(key2.Handle(), nullptr);
EXPECT_EQ(key2.WriteValue(L"foo", 1U), ERROR_SUCCESS);
}
TEST_F(RegistryTest, TestMoveAssign) {
RegKey key;
RegKey key2;
std::wstring foo_key(kRootKey);
const wchar_t kFooValueName[] = L"foo";
ASSERT_EQ(key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
KEY_SET_VALUE | KEY_QUERY_VALUE),
ERROR_SUCCESS);
ASSERT_EQ(key.WriteValue(kFooValueName, 1U), ERROR_SUCCESS);
ASSERT_EQ(key2.Create(HKEY_CURRENT_USER, (foo_key + L"\\child").c_str(),
KEY_SET_VALUE),
ERROR_SUCCESS);
key2 = std::move(key);
// The old key should be meaningless now.
EXPECT_EQ(key.Handle(), nullptr);
// And the new one should hold what was the old one.
EXPECT_NE(key2.Handle(), nullptr);
DWORD foo = 0;
ASSERT_EQ(key2.ReadValueDW(kFooValueName, &foo), ERROR_SUCCESS);
EXPECT_EQ(foo, 1U);
}
} // namespace } // namespace
} // namespace win } // namespace win
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <wrl/client.h> #include <wrl/client.h>
#include <memory> #include <memory>
#include <tuple>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
...@@ -155,41 +157,46 @@ std::string BrowserDMTokenStorageWin::InitEnrollmentToken() { ...@@ -155,41 +157,46 @@ std::string BrowserDMTokenStorageWin::InitEnrollmentToken() {
} }
std::string BrowserDMTokenStorageWin::InitDMToken() { std::string BrowserDMTokenStorageWin::InitDMToken() {
base::win::RegKey key;
base::string16 dm_token_key_path;
base::string16 dm_token_value_name;
InstallUtil::GetMachineLevelUserCloudPolicyDMTokenRegistryPath(
&dm_token_key_path, &dm_token_value_name);
LONG result = key.Open(HKEY_LOCAL_MACHINE, dm_token_key_path.c_str(),
KEY_QUERY_VALUE | KEY_WOW64_64KEY);
if (result != ERROR_SUCCESS)
return std::string();
// At the time of writing (January 2018), the DM token is about 200 bytes // 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 // long. The initial size of the buffer should be enough to cover most
// realistic future size-increase scenarios, although we still make an effort // realistic future size-increase scenarios, although we still make an effort
// to support somewhat larger token sizes just to be safe. // to support somewhat larger token sizes just to be safe.
constexpr size_t kInitialDMTokenSize = 512; constexpr size_t kInitialDMTokenSize = 512;
DWORD size = kInitialDMTokenSize; base::win::RegKey key;
std::vector<char> raw_value(size); base::string16 dm_token_value_name;
DWORD dtype = REG_NONE; std::vector<char> raw_value(kInitialDMTokenSize);
result = key.ReadValue(dm_token_value_name.c_str(), raw_value.data(), &size,
&dtype); // Prefer the app-neutral location over the browser's to match Google Update's
if (result == ERROR_MORE_DATA && size <= installer::kMaxDMTokenLength) { // behavior.
raw_value.resize(size); for (const auto& location : {InstallUtil::BrowserLocation(false),
result = key.ReadValue(dm_token_value_name.c_str(), raw_value.data(), &size, InstallUtil::BrowserLocation(true)}) {
&dtype); std::tie(key, dm_token_value_name) =
InstallUtil::GetCloudManagementDmTokenLocation(
InstallUtil::ReadOnly(true), location);
if (!key.Valid())
continue;
DWORD dtype = REG_NONE;
DWORD size = 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 base::TrimWhitespaceASCII(base::StringPiece(raw_value.data(), size),
base::TRIM_ALL)
.as_string();
} }
if (result != ERROR_SUCCESS || dtype != REG_BINARY || size == 0) { DVLOG(1) << "Failed to get DMToken from Registry.";
DVLOG(1) << "Failed to get DMToken from Registry."; return std::string();
return std::string();
}
DCHECK_LE(size, installer::kMaxDMTokenLength);
std::string dm_token;
dm_token.assign(raw_value.data(), size);
return base::TrimWhitespaceASCII(dm_token, base::TRIM_ALL).as_string();
} }
bool BrowserDMTokenStorageWin::InitEnrollmentErrorOption() { bool BrowserDMTokenStorageWin::InitEnrollmentErrorOption() {
......
...@@ -44,6 +44,8 @@ class BrowserDMTokenStorageWin : public BrowserDMTokenStorage { ...@@ -44,6 +44,8 @@ class BrowserDMTokenStorageWin : public BrowserDMTokenStorage {
FRIEND_TEST_ALL_PREFIXES(BrowserDMTokenStorageWinTest, FRIEND_TEST_ALL_PREFIXES(BrowserDMTokenStorageWinTest,
InitEnrollmentTokenFromSecondary); InitEnrollmentTokenFromSecondary);
FRIEND_TEST_ALL_PREFIXES(BrowserDMTokenStorageWinTest, InitDMToken); FRIEND_TEST_ALL_PREFIXES(BrowserDMTokenStorageWinTest, InitDMToken);
FRIEND_TEST_ALL_PREFIXES(BrowserDMTokenStorageWinTest,
InitDMTokenFromBrowserLocation);
DISALLOW_COPY_AND_ASSIGN(BrowserDMTokenStorageWin); DISALLOW_COPY_AND_ASSIGN(BrowserDMTokenStorageWin);
}; };
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "chrome/browser/policy/browser_dm_token_storage_win.h" #include "chrome/browser/policy/browser_dm_token_storage_win.h"
#include <tuple>
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/test_reg_util_win.h" #include "base/test/test_reg_util_win.h"
...@@ -23,6 +25,7 @@ constexpr wchar_t kClientId1[] = L"fake-client-id-1"; ...@@ -23,6 +25,7 @@ constexpr wchar_t kClientId1[] = L"fake-client-id-1";
constexpr wchar_t kEnrollmentToken1[] = L"fake-enrollment-token-1"; constexpr wchar_t kEnrollmentToken1[] = L"fake-enrollment-token-1";
constexpr wchar_t kEnrollmentToken2[] = L"fake-enrollment-token-2"; constexpr wchar_t kEnrollmentToken2[] = L"fake-enrollment-token-2";
constexpr char kDMToken1[] = "fake-dm-token-1"; constexpr char kDMToken1[] = "fake-dm-token-1";
constexpr char kDMToken2[] = "fake-dm-token-2";
} // namespace } // namespace
...@@ -66,16 +69,18 @@ class BrowserDMTokenStorageWinTest : public testing::Test { ...@@ -66,16 +69,18 @@ class BrowserDMTokenStorageWinTest : public testing::Test {
ERROR_SUCCESS; ERROR_SUCCESS;
} }
bool SetDMToken(const std::string& dm_token) { // Sets a DM token in either the app-neutral or browser-specific location in
// the registry.
bool SetDMToken(const std::string& dm_token,
InstallUtil::BrowserLocation browser_location) {
base::win::RegKey key; base::win::RegKey key;
base::string16 dm_token_key_path;
base::string16 dm_token_value_name; base::string16 dm_token_value_name;
InstallUtil::GetMachineLevelUserCloudPolicyDMTokenRegistryPath( std::tie(key, dm_token_value_name) =
&dm_token_key_path, &dm_token_value_name); InstallUtil::GetCloudManagementDmTokenLocation(
return (key.Create(HKEY_LOCAL_MACHINE, dm_token_key_path.c_str(), InstallUtil::ReadOnly(false), browser_location);
KEY_SET_VALUE | KEY_WOW64_64KEY) == ERROR_SUCCESS) && return key.Valid() &&
(key.WriteValue(dm_token_value_name.c_str(), dm_token.c_str(), key.WriteValue(dm_token_value_name.c_str(), dm_token.c_str(),
dm_token.size(), REG_BINARY) == ERROR_SUCCESS); dm_token.size(), REG_BINARY) == ERROR_SUCCESS;
} }
content::BrowserTaskEnvironment task_environment_; content::BrowserTaskEnvironment task_environment_;
...@@ -108,9 +113,20 @@ TEST_F(BrowserDMTokenStorageWinTest, InitEnrollmentTokenFromSecondary) { ...@@ -108,9 +113,20 @@ TEST_F(BrowserDMTokenStorageWinTest, InitEnrollmentTokenFromSecondary) {
TEST_F(BrowserDMTokenStorageWinTest, InitDMToken) { TEST_F(BrowserDMTokenStorageWinTest, InitDMToken) {
ASSERT_TRUE(SetMachineGuid(kClientId1)); ASSERT_TRUE(SetMachineGuid(kClientId1));
ASSERT_TRUE(SetDMToken(kDMToken1)); // The app-neutral location should be preferred.
ASSERT_TRUE(SetDMToken(kDMToken1, InstallUtil::BrowserLocation(false)));
ASSERT_TRUE(SetDMToken(kDMToken2, InstallUtil::BrowserLocation(true)));
BrowserDMTokenStorageWin storage; BrowserDMTokenStorageWin storage;
EXPECT_EQ(std::string(kDMToken1), storage.InitDMToken()); EXPECT_EQ(std::string(kDMToken1), storage.InitDMToken());
} }
TEST_F(BrowserDMTokenStorageWinTest, InitDMTokenFromBrowserLocation) {
ASSERT_TRUE(SetMachineGuid(kClientId1));
// If there's no app-neutral token, the browser-specific one should be used.
ASSERT_TRUE(SetDMToken(kDMToken2, InstallUtil::BrowserLocation(true)));
BrowserDMTokenStorageWin storage;
EXPECT_EQ(std::string(kDMToken2), storage.InitDMToken());
}
} // namespace policy } // namespace policy
...@@ -879,31 +879,37 @@ bool StoreDMToken(const std::string& token) { ...@@ -879,31 +879,37 @@ bool StoreDMToken(const std::string& token) {
return false; return false;
} }
std::wstring path; // Write the token both to the app-neutral and browser-specific locations.
std::wstring name; // Only the former is mandatory -- the latter is best-effort.
InstallUtil::GetMachineLevelUserCloudPolicyDMTokenRegistryPath(&path,
&name);
base::win::RegKey key; base::win::RegKey key;
LONG result = key.Create(HKEY_LOCAL_MACHINE, path.c_str(), std::wstring value_name;
KEY_WRITE | KEY_WOW64_64KEY); bool succeeded = false;
if (result != ERROR_SUCCESS) { for (const auto& is_browser_location : {InstallUtil::BrowserLocation(false),
LOG(ERROR) << "Unable to create/open registry key HKLM\\" << path InstallUtil::BrowserLocation(true)}) {
<< " for writing result=" << result; std::tie(key, value_name) = InstallUtil::GetCloudManagementDmTokenLocation(
return false; InstallUtil::ReadOnly(false), is_browser_location);
} // If the key couldn't be opened on the first iteration (the mandatory
// location), return failure straight away. Otherwise, continue iterating.
if (!key.Valid()) {
if (succeeded)
continue;
// Logging already performed in GetCloudManagementDmTokenLocation.
return false;
}
result = auto result =
key.WriteValue(name.c_str(), token.data(), key.WriteValue(value_name.c_str(), token.data(),
base::saturated_cast<DWORD>(token.size()), REG_BINARY); base::saturated_cast<DWORD>(token.size()), REG_BINARY);
if (result != ERROR_SUCCESS) { if (result == ERROR_SUCCESS) {
LOG(ERROR) << "Unable to write specified DMToken to the registry at HKLM\\" succeeded = true;
<< path << "\\" << name << " result=" << result; } else if (!succeeded) {
return false; ::SetLastError(result);
PLOG(ERROR) << "Unable to write specified DMToken to the registry";
return false;
} // Else ignore the failure to write to the best-effort location.
} }
VLOG(1) << "Successfully stored specified DMToken in the registry."; VLOG(1) << "Successfully stored specified DMToken in the registry.";
return true; return true;
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <ios> #include <ios>
#include <memory> #include <memory>
#include <string> #include <string>
#include <tuple>
#include "base/base64.h" #include "base/base64.h"
#include "base/command_line.h" #include "base/command_line.h"
...@@ -488,12 +489,11 @@ TEST(SetupUtilTest, StoreDMTokenToRegistrySuccess) { ...@@ -488,12 +489,11 @@ TEST(SetupUtilTest, StoreDMTokenToRegistrySuccess) {
ASSERT_EQ(kExpectedSize, token.length()); ASSERT_EQ(kExpectedSize, token.length());
EXPECT_TRUE(installer::StoreDMToken(token)); EXPECT_TRUE(installer::StoreDMToken(token));
std::wstring path;
std::wstring name;
InstallUtil::GetMachineLevelUserCloudPolicyDMTokenRegistryPath(&path, &name);
base::win::RegKey key; base::win::RegKey key;
ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, path.c_str(), std::wstring name;
KEY_QUERY_VALUE | KEY_WOW64_64KEY)); std::tie(key, name) = InstallUtil::GetCloudManagementDmTokenLocation(
InstallUtil::ReadOnly(true), InstallUtil::BrowserLocation(false));
ASSERT_TRUE(key.Valid());
DWORD size = kExpectedSize; DWORD size = kExpectedSize;
std::vector<char> raw_value(size); std::vector<char> raw_value(size);
...@@ -503,6 +503,17 @@ TEST(SetupUtilTest, StoreDMTokenToRegistrySuccess) { ...@@ -503,6 +503,17 @@ TEST(SetupUtilTest, StoreDMTokenToRegistrySuccess) {
EXPECT_EQ(REG_BINARY, dtype); EXPECT_EQ(REG_BINARY, dtype);
ASSERT_EQ(kExpectedSize, size); ASSERT_EQ(kExpectedSize, size);
EXPECT_EQ(0, memcmp(token.data(), raw_value.data(), kExpectedSize)); EXPECT_EQ(0, memcmp(token.data(), raw_value.data(), kExpectedSize));
std::tie(key, name) = InstallUtil::GetCloudManagementDmTokenLocation(
InstallUtil::ReadOnly(true), InstallUtil::BrowserLocation(true));
ASSERT_TRUE(key.Valid());
size = kExpectedSize;
ASSERT_EQ(ERROR_SUCCESS,
key.ReadValue(name.c_str(), raw_value.data(), &size, &dtype));
EXPECT_EQ(REG_BINARY, dtype);
ASSERT_EQ(kExpectedSize, size);
EXPECT_EQ(0, memcmp(token.data(), raw_value.data(), kExpectedSize));
} }
TEST(SetupUtilTest, StoreDMTokenToRegistryShouldFailWhenDMTokenTooLarge) { TEST(SetupUtilTest, StoreDMTokenToRegistryShouldFailWhenDMTokenTooLarge) {
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
#include "base/values.h" #include "base/values.h"
#include "base/win/registry.h"
#include "base/win/shlwapi.h" #include "base/win/shlwapi.h"
#include "base/win/shortcut.h" #include "base/win/shortcut.h"
#include "base/win/win_util.h" #include "base/win/win_util.h"
...@@ -599,18 +598,39 @@ InstallUtil::GetCloudManagementEnrollmentTokenRegistryPaths() { ...@@ -599,18 +598,39 @@ InstallUtil::GetCloudManagementEnrollmentTokenRegistryPaths() {
} }
// static // static
void InstallUtil::GetMachineLevelUserCloudPolicyDMTokenRegistryPath( std::pair<base::win::RegKey, std::wstring>
base::string16* key_path, InstallUtil::GetCloudManagementDmTokenLocation(
base::string16* value_name) { ReadOnly read_only,
// This token applies to all installs on the machine, even though only a BrowserLocation browser_location) {
// system install can set it. This is to prevent users from doing a user // The location dictates the path and WoW bit.
// install of chrome to get around policies. REGSAM wow_access = 0;
*key_path = L"SOFTWARE\\"; std::wstring key_path(L"SOFTWARE\\");
install_static::AppendChromeInstallSubDirectory( if (browser_location) {
install_static::InstallDetails::Get().mode(), false /* !include_suffix */, wow_access |= KEY_WOW64_64KEY;
key_path); install_static::AppendChromeInstallSubDirectory(
key_path->append(L"\\Enrollment"); install_static::InstallDetails::Get().mode(), /*include_suffix=*/false,
*value_name = L"dmtoken"; &key_path);
} else {
wow_access |= KEY_WOW64_32KEY;
key_path.append(install_static::kCompanyPathName);
}
key_path.append(L"\\Enrollment");
base::win::RegKey key;
if (read_only) {
key.Open(HKEY_LOCAL_MACHINE, key_path.c_str(),
KEY_QUERY_VALUE | wow_access);
} else {
auto result = key.Create(HKEY_LOCAL_MACHINE, key_path.c_str(),
KEY_SET_VALUE | wow_access);
if (result != ERROR_SUCCESS) {
::SetLastError(result);
PLOG(ERROR) << "Failed to create/open registry key HKLM\\" << key_path
<< " for writing";
}
}
return {std::move(key), L"dmtoken"};
} }
// static // static
......
...@@ -21,7 +21,9 @@ ...@@ -21,7 +21,9 @@
#include "base/optional.h" #include "base/optional.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/util/type_safety/strong_alias.h"
#include "base/version.h" #include "base/version.h"
#include "base/win/registry.h"
#include "base/win/scoped_handle.h" #include "base/win/scoped_handle.h"
#include "chrome/installer/util/util_constants.h" #include "chrome/installer/util/util_constants.h"
...@@ -183,11 +185,18 @@ class InstallUtil { ...@@ -183,11 +185,18 @@ class InstallUtil {
static std::vector<std::pair<std::wstring, std::wstring>> static std::vector<std::pair<std::wstring, std::wstring>>
GetCloudManagementEnrollmentTokenRegistryPaths(); GetCloudManagementEnrollmentTokenRegistryPaths();
// Returns the registry key path and value name where the DM token is stored using ReadOnly = util::StrongAlias<class ReadOnlyTag, bool>;
// for machine level user cloud policies. using BrowserLocation = util::StrongAlias<class BrowserLocationTag, bool>;
static void GetMachineLevelUserCloudPolicyDMTokenRegistryPath(
base::string16* key_path, // Returns the registry key and value name from/to which a cloud management DM
base::string16* value_name); // token may be read/written. |read_only| indicates whether they key is opened
// for reading the value or writing it. |browser_location| indicates whether
// the legacy browser-specific location is returned rather than the
// app-neutral location. The returned key will be invalid if it could not be
// opened/created.
static std::pair<base::win::RegKey, std::wstring>
GetCloudManagementDmTokenLocation(ReadOnly read_only,
BrowserLocation browser_location);
// Returns the token used to enroll this chrome instance for machine level // Returns the token used to enroll this chrome instance for machine level
// user cloud policies. Returns an empty string if this machine should not // user cloud policies. Returns an empty string if this machine should not
......
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