forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathuser_hive_visitor.cc
169 lines (145 loc) · 5.44 KB
/
user_hive_visitor.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// Copyright 2016 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/installer/setup/user_hive_visitor.h"
#include <string>
#include <utility>
#include <vector>
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "chrome/installer/util/scoped_token_privilege.h"
#include "components/base32/base32.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(const ScopedUserHive&) = delete;
ScopedUserHive& operator=(const ScopedUserHive&) = delete;
~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.
std::wstring subkey_name_;
// The loaded key.
base::win::RegKey key_;
};
ScopedUserHive::ScopedUserHive(const base::FilePath& hive_file) {
// Generate a random name for the key at which the file will be loaded.
subkey_name_ = base::ASCIIToWide(base32::Base32Encode(
base::RandBytesAsVector(10), base32::Base32EncodePolicy::OMIT_PADDING));
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.
std::wstring 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;
}
std::wstring 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