| // 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 |