OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/installer/setup/user_hive_visitor.h" |
| 6 |
| 7 #include <utility> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/callback.h" |
| 11 #include "base/callback_helpers.h" |
| 12 #include "base/files/file_path.h" |
| 13 #include "base/files/file_util.h" |
| 14 #include "base/logging.h" |
| 15 #include "base/rand_util.h" |
| 16 #include "base/strings/string16.h" |
| 17 #include "base/strings/string_piece.h" |
| 18 #include "base/win/registry.h" |
| 19 #include "chrome/installer/setup/setup_util.h" |
| 20 #include "chrome/installer/util/shell_util.h" |
| 21 |
| 22 namespace installer { |
| 23 |
| 24 namespace { |
| 25 |
| 26 // A helper for loading and opening a hive into a random subkey of |
| 27 // HKEY_LOCAL_MACHINE. |
| 28 class ScopedUserHive { |
| 29 public: |
| 30 explicit ScopedUserHive(const base::FilePath& hive_file); |
| 31 ~ScopedUserHive(); |
| 32 |
| 33 // Returns true if the hive file was loaded. |
| 34 bool valid() const { return key_.Valid(); } |
| 35 |
| 36 // Returns the key at the root of the loaded hive, or nullptr if not valid. |
| 37 base::win::RegKey* key() { return key_.Valid() ? &key_ : nullptr; } |
| 38 |
| 39 private: |
| 40 // The randomly-chosen name of the subkey under HKLM where the file is loaded. |
| 41 // If empty, the file is not loaded. |
| 42 base::string16 subkey_name_; |
| 43 |
| 44 // The loaded key. |
| 45 base::win::RegKey key_; |
| 46 |
| 47 DISALLOW_COPY_AND_ASSIGN(ScopedUserHive); |
| 48 }; |
| 49 |
| 50 ScopedUserHive::ScopedUserHive(const base::FilePath& hive_file) { |
| 51 // Generate a random name for the key at which the file will be loaded. |
| 52 uint8_t buffer[10] = {}; |
| 53 base::RandBytes(&buffer[0], arraysize(buffer)); |
| 54 subkey_name_ = ShellUtil::ByteArrayToBase32(&buffer[0], arraysize(buffer)); |
| 55 DCHECK_EQ(16U, subkey_name_.size()); |
| 56 |
| 57 LONG result = ::RegLoadKey(HKEY_LOCAL_MACHINE, subkey_name_.c_str(), |
| 58 hive_file.value().c_str()); |
| 59 if (result != ERROR_SUCCESS) { |
| 60 // Clear subkey_name_ since the load failed so that an unload will not be |
| 61 // attempted in the dtor. |
| 62 subkey_name_.clear(); |
| 63 ::SetLastError(result); |
| 64 PLOG(ERROR) << "Failed loading user hive file \"" << hive_file.value() |
| 65 << "\""; |
| 66 return; |
| 67 } |
| 68 |
| 69 // Open the newly-loaded key. |
| 70 result = key_.Open(HKEY_LOCAL_MACHINE, subkey_name_.c_str(), KEY_ALL_ACCESS); |
| 71 if (result != ERROR_SUCCESS) { |
| 72 ::SetLastError(result); |
| 73 PLOG(ERROR) << "Failed opening loaded hive file \"" << hive_file.value() |
| 74 << "\""; |
| 75 } |
| 76 } |
| 77 |
| 78 ScopedUserHive::~ScopedUserHive() { |
| 79 key_.Close(); |
| 80 if (subkey_name_.empty()) |
| 81 return; |
| 82 LONG result = ::RegUnLoadKey(HKEY_LOCAL_MACHINE, subkey_name_.c_str()); |
| 83 if (result != ERROR_SUCCESS) { |
| 84 ::SetLastError(result); |
| 85 PLOG(ERROR) << "Failed unloading user hive at \"" << subkey_name_ << "\""; |
| 86 } |
| 87 } |
| 88 |
| 89 bool OpenUserHive(const wchar_t* sid, base::win::RegKey* user_hive) { |
| 90 DCHECK(user_hive); |
| 91 LONG result = user_hive->Open(HKEY_USERS, sid, KEY_ALL_ACCESS); |
| 92 if (result == ERROR_SUCCESS) |
| 93 return true; |
| 94 if (result == ERROR_FILE_NOT_FOUND) { |
| 95 VLOG(1) << "Hive is not loaded for user \"" << sid << "\""; |
| 96 return false; |
| 97 } |
| 98 ::SetLastError(result); |
| 99 PLOG(ERROR) << "Failed opening hive for user \"" << sid << "\""; |
| 100 return false; |
| 101 } |
| 102 |
| 103 } // namespace |
| 104 |
| 105 void VisitUserHives(const HiveVisitor& visitor) { |
| 106 constexpr wchar_t kProfileListKey[] = |
| 107 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"; |
| 108 |
| 109 // Privileges required to load a registry hive file. |
| 110 ScopedTokenPrivilege se_backup_name_privilege(SE_BACKUP_NAME); |
| 111 ScopedTokenPrivilege se_restore_name_privilege(SE_RESTORE_NAME); |
| 112 |
| 113 for (base::win::RegistryKeyIterator iter(HKEY_LOCAL_MACHINE, kProfileListKey); |
| 114 iter.Valid(); ++iter) { |
| 115 const wchar_t* sid = iter.Name(); |
| 116 // First try to access the user hive pre-mounted by the OS. |
| 117 VLOG(1) << "Checking for pre-loaded hive for local account \"" << sid |
| 118 << "\""; |
| 119 base::win::RegKey key; |
| 120 if (OpenUserHive(sid, &key)) { |
| 121 VLOG(1) << "Found loaded hive for sid \"" << sid << "\""; |
| 122 if (!visitor.Run(sid, &key)) |
| 123 break; |
| 124 continue; |
| 125 } |
| 126 |
| 127 // Read the path to the profile directory to load the hive manually. |
| 128 base::string16 profile_key_name(kProfileListKey); |
| 129 profile_key_name.append(1, L'\\').append(sid); |
| 130 LONG result = |
| 131 key.Open(HKEY_LOCAL_MACHINE, profile_key_name.c_str(), KEY_QUERY_VALUE); |
| 132 if (result != ERROR_SUCCESS) { |
| 133 ::SetLastError(result); |
| 134 PLOG(ERROR) << "Failed opening profile key \"" << profile_key_name |
| 135 << "\""; |
| 136 continue; |
| 137 } |
| 138 base::string16 image_path; |
| 139 result = key.ReadValue(L"ProfileImagePath", &image_path); |
| 140 if (result != ERROR_SUCCESS) { |
| 141 ::SetLastError(result); |
| 142 PLOG(ERROR) << "Failed reading ProfileImagePath value of \"" |
| 143 << profile_key_name << "\""; |
| 144 } |
| 145 key.Close(); |
| 146 if (image_path.empty()) |
| 147 continue; |
| 148 |
| 149 base::FilePath hive_file( |
| 150 base::FilePath(image_path).Append(FILE_PATH_LITERAL("ntuser.dat"))); |
| 151 VLOG(1) << "Falling back to opening \"" << hive_file.value() << "\""; |
| 152 if (!base::PathExists(hive_file)) { |
| 153 VPLOG(1) << "Hive file not found or inaccessible \"" << hive_file.value() |
| 154 << "\""; |
| 155 continue; |
| 156 } |
| 157 ScopedUserHive user_hive(hive_file); |
| 158 if (user_hive.valid()) { |
| 159 VLOG(1) << "Loaded and opened hive for sid \"" << sid << "\""; |
| 160 if (!visitor.Run(sid, user_hive.key())) |
| 161 break; |
| 162 } |
| 163 } |
| 164 } |
| 165 |
| 166 } // namespace installer |
OLD | NEW |