| Index: chrome/installer/setup/user_hive_visitor.cc
|
| diff --git a/chrome/installer/setup/user_hive_visitor.cc b/chrome/installer/setup/user_hive_visitor.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ca2d7fe9c1cedf6f71b3a214dbd9f71be1600813
|
| --- /dev/null
|
| +++ b/chrome/installer/setup/user_hive_visitor.cc
|
| @@ -0,0 +1,166 @@
|
| +// Copyright 2016 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/installer/setup/user_hive_visitor.h"
|
| +
|
| +#include <utility>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/callback.h"
|
| +#include "base/callback_helpers.h"
|
| +#include "base/files/file_path.h"
|
| +#include "base/files/file_util.h"
|
| +#include "base/logging.h"
|
| +#include "base/rand_util.h"
|
| +#include "base/strings/string16.h"
|
| +#include "base/strings/string_piece.h"
|
| +#include "base/win/registry.h"
|
| +#include "chrome/installer/setup/setup_util.h"
|
| +#include "chrome/installer/util/shell_util.h"
|
| +
|
| +namespace installer {
|
| +
|
| +namespace {
|
| +
|
| +// A helper for loading and opening a hive into a random subkey of
|
| +// HKEY_LOCAL_MACHINE.
|
| +class ScopedUserHive {
|
| + public:
|
| + explicit ScopedUserHive(const base::FilePath& hive_file);
|
| + ~ScopedUserHive();
|
| +
|
| + // Returns true if the hive file was loaded.
|
| + bool valid() const { return key_.Valid(); }
|
| +
|
| + // Returns the key at the root of the loaded hive, or nullptr if not valid.
|
| + base::win::RegKey* key() { return key_.Valid() ? &key_ : nullptr; }
|
| +
|
| + private:
|
| + // The randomly-chosen name of the subkey under HKLM where the file is loaded.
|
| + // If empty, the file is not loaded.
|
| + base::string16 subkey_name_;
|
| +
|
| + // The loaded key.
|
| + base::win::RegKey key_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ScopedUserHive);
|
| +};
|
| +
|
| +ScopedUserHive::ScopedUserHive(const base::FilePath& hive_file) {
|
| + // Generate a random name for the key at which the file will be loaded.
|
| + uint8_t buffer[10] = {};
|
| + base::RandBytes(&buffer[0], arraysize(buffer));
|
| + subkey_name_ = ShellUtil::ByteArrayToBase32(&buffer[0], arraysize(buffer));
|
| + DCHECK_EQ(16U, subkey_name_.size());
|
| +
|
| + LONG result = ::RegLoadKey(HKEY_LOCAL_MACHINE, subkey_name_.c_str(),
|
| + hive_file.value().c_str());
|
| + if (result != ERROR_SUCCESS) {
|
| + // Clear subkey_name_ since the load failed so that an unload will not be
|
| + // attempted in the dtor.
|
| + subkey_name_.clear();
|
| + ::SetLastError(result);
|
| + PLOG(ERROR) << "Failed loading user hive file \"" << hive_file.value()
|
| + << "\"";
|
| + return;
|
| + }
|
| +
|
| + // Open the newly-loaded key.
|
| + result = key_.Open(HKEY_LOCAL_MACHINE, subkey_name_.c_str(), KEY_ALL_ACCESS);
|
| + if (result != ERROR_SUCCESS) {
|
| + ::SetLastError(result);
|
| + PLOG(ERROR) << "Failed opening loaded hive file \"" << hive_file.value()
|
| + << "\"";
|
| + }
|
| +}
|
| +
|
| +ScopedUserHive::~ScopedUserHive() {
|
| + key_.Close();
|
| + if (subkey_name_.empty())
|
| + return;
|
| + LONG result = ::RegUnLoadKey(HKEY_LOCAL_MACHINE, subkey_name_.c_str());
|
| + if (result != ERROR_SUCCESS) {
|
| + ::SetLastError(result);
|
| + PLOG(ERROR) << "Failed unloading user hive at \"" << subkey_name_ << "\"";
|
| + }
|
| +}
|
| +
|
| +bool OpenUserHive(const wchar_t* sid, base::win::RegKey* user_hive) {
|
| + DCHECK(user_hive);
|
| + LONG result = user_hive->Open(HKEY_USERS, sid, KEY_ALL_ACCESS);
|
| + if (result == ERROR_SUCCESS)
|
| + return true;
|
| + if (result == ERROR_FILE_NOT_FOUND) {
|
| + VLOG(1) << "Hive is not loaded for user \"" << sid << "\"";
|
| + return false;
|
| + }
|
| + ::SetLastError(result);
|
| + PLOG(ERROR) << "Failed opening hive for user \"" << sid << "\"";
|
| + return false;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +void VisitUserHives(const HiveVisitor& visitor) {
|
| + constexpr wchar_t kProfileListKey[] =
|
| + L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList";
|
| +
|
| + // Privileges required to load a registry hive file.
|
| + ScopedTokenPrivilege se_backup_name_privilege(SE_BACKUP_NAME);
|
| + ScopedTokenPrivilege se_restore_name_privilege(SE_RESTORE_NAME);
|
| +
|
| + for (base::win::RegistryKeyIterator iter(HKEY_LOCAL_MACHINE, kProfileListKey);
|
| + iter.Valid(); ++iter) {
|
| + const wchar_t* sid = iter.Name();
|
| + // First try to access the user hive pre-mounted by the OS.
|
| + VLOG(1) << "Checking for pre-loaded hive for local account \"" << sid
|
| + << "\"";
|
| + base::win::RegKey key;
|
| + if (OpenUserHive(sid, &key)) {
|
| + VLOG(1) << "Found loaded hive for sid \"" << sid << "\"";
|
| + if (!visitor.Run(sid, &key))
|
| + break;
|
| + continue;
|
| + }
|
| +
|
| + // Read the path to the profile directory to load the hive manually.
|
| + base::string16 profile_key_name(kProfileListKey);
|
| + profile_key_name.append(1, L'\\').append(sid);
|
| + LONG result =
|
| + key.Open(HKEY_LOCAL_MACHINE, profile_key_name.c_str(), KEY_QUERY_VALUE);
|
| + if (result != ERROR_SUCCESS) {
|
| + ::SetLastError(result);
|
| + PLOG(ERROR) << "Failed opening profile key \"" << profile_key_name
|
| + << "\"";
|
| + continue;
|
| + }
|
| + base::string16 image_path;
|
| + result = key.ReadValue(L"ProfileImagePath", &image_path);
|
| + if (result != ERROR_SUCCESS) {
|
| + ::SetLastError(result);
|
| + PLOG(ERROR) << "Failed reading ProfileImagePath value of \""
|
| + << profile_key_name << "\"";
|
| + }
|
| + key.Close();
|
| + if (image_path.empty())
|
| + continue;
|
| +
|
| + base::FilePath hive_file(
|
| + base::FilePath(image_path).Append(FILE_PATH_LITERAL("ntuser.dat")));
|
| + VLOG(1) << "Falling back to opening \"" << hive_file.value() << "\"";
|
| + if (!base::PathExists(hive_file)) {
|
| + VPLOG(1) << "Hive file not found or inaccessible \"" << hive_file.value()
|
| + << "\"";
|
| + continue;
|
| + }
|
| + ScopedUserHive user_hive(hive_file);
|
| + if (user_hive.valid()) {
|
| + VLOG(1) << "Loaded and opened hive for sid \"" << sid << "\"";
|
| + if (!visitor.Run(sid, user_hive.key()))
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +} // namespace installer
|
|
|