Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(165)

Side by Side Diff: chrome/installer/util/registry_key_backup.cc

Issue 7890069: Added CopyRegKeyWorkItem in support of IE low rights policy fixes. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: sync'd to ToT again Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/installer/util/delete_reg_key_work_item.h" 5 #include "chrome/installer/util/registry_key_backup.h"
6 6
7 #include <shlwapi.h>
8 #include <algorithm> 7 #include <algorithm>
9 #include <limits> 8 #include <limits>
10 #include <vector> 9 #include <vector>
11 10
12 #include "base/logging.h" 11 #include "base/logging.h"
13 #include "base/rand_util.h"
14 #include "base/stringprintf.h"
15 #include "base/win/registry.h" 12 #include "base/win/registry.h"
16 #include "chrome/installer/util/logging_installer.h"
17 13
18 using base::win::RegKey; 14 using base::win::RegKey;
19 15
20 namespace { 16 namespace {
21 const REGSAM kKeyReadNoNotify = (KEY_READ) & ~(KEY_NOTIFY); 17 const REGSAM kKeyReadNoNotify = (KEY_READ) & ~(KEY_NOTIFY);
22 } 18 } // namespace
23 19
24 // A container for a registry key, its values, and its subkeys. We don't use 20 // A container for a registry key, its values, and its subkeys.
25 // more obvious methods for various reasons: 21 class RegistryKeyBackup::KeyData {
26 // - RegCopyTree isn't supported pre-Vista, so we'd have to do something
27 // different for XP anyway.
28 // - SHCopyKey can't copy subkeys into a volatile destination, so we'd have to
29 // worry about polluting the registry.
30 // We don't persist security attributes since we only delete keys that we own,
31 // and we don't set custom attributes on them anyway.
32 class DeleteRegKeyWorkItem::RegKeyBackup {
33 public: 22 public:
34 RegKeyBackup(); 23 KeyData();
24 ~KeyData();
35 bool Initialize(const RegKey& key); 25 bool Initialize(const RegKey& key);
36 bool WriteTo(RegKey* key) const; 26 bool WriteTo(RegKey* key) const;
37 27
38 private: 28 private:
39 // A container for a registry value. 29 class ValueData;
40 class RegValueBackup {
41 public:
42 RegValueBackup();
43 void Initialize(const wchar_t* name_buffer, DWORD name_size,
44 DWORD type, const uint8* data, DWORD data_size);
45 const std::wstring& name_str() const { return name_; }
46 const wchar_t* name() const { return name_.empty() ? NULL : name_.c_str(); }
47 DWORD type() const { return type_; }
48 const uint8* data() const { return data_.empty() ? NULL : &data_[0]; }
49 DWORD data_len() const { return static_cast<DWORD>(data_.size()); }
50 30
51 private: 31 scoped_array<ValueData> values_;
52 std::wstring name_; 32 scoped_array<std::wstring> subkey_names_;
53 std::vector<uint8> data_; 33 scoped_array<KeyData> subkeys_;
54 DWORD type_; 34 DWORD num_values_;
35 DWORD num_subkeys_;
55 36
56 DISALLOW_COPY_AND_ASSIGN(RegValueBackup); 37 DISALLOW_COPY_AND_ASSIGN(KeyData);
57 };
58
59 scoped_array<RegValueBackup> values_;
60 scoped_array<std::wstring> subkey_names_;
61 scoped_array<RegKeyBackup> subkeys_;
62 ptrdiff_t num_values_;
63 ptrdiff_t num_subkeys_;
64
65 DISALLOW_COPY_AND_ASSIGN(RegKeyBackup);
66 }; 38 };
67 39
68 DeleteRegKeyWorkItem::RegKeyBackup::RegValueBackup::RegValueBackup() 40 // A container for a registry value.
41 class RegistryKeyBackup::KeyData::ValueData {
42 public:
43 ValueData();
44 ~ValueData();
45 void Initialize(const wchar_t* name_buffer, DWORD name_size,
46 DWORD type, const uint8* data, DWORD data_size);
47 const std::wstring& name_str() const { return name_; }
48 const wchar_t* name() const { return name_.empty() ? NULL : name_.c_str(); }
49 DWORD type() const { return type_; }
50 const uint8* data() const { return data_.empty() ? NULL : &data_[0]; }
51 DWORD data_len() const { return static_cast<DWORD>(data_.size()); }
52
53 private:
54 std::wstring name_;
55 std::vector<uint8> data_;
56 DWORD type_;
57
58 DISALLOW_COPY_AND_ASSIGN(ValueData);
59 };
60
61 RegistryKeyBackup::KeyData::ValueData::ValueData()
69 : type_(REG_NONE) { 62 : type_(REG_NONE) {
70 } 63 }
71 64
72 void DeleteRegKeyWorkItem::RegKeyBackup::RegValueBackup::Initialize( 65 RegistryKeyBackup::KeyData::ValueData::~ValueData()
66 {
67 }
68
69 void RegistryKeyBackup::KeyData::ValueData::Initialize(
73 const wchar_t* name_buffer, 70 const wchar_t* name_buffer,
74 DWORD name_size, 71 DWORD name_size,
75 DWORD type, const uint8* data, 72 DWORD type,
73 const uint8* data,
76 DWORD data_size) { 74 DWORD data_size) {
77 name_.assign(name_buffer, name_size); 75 name_.assign(name_buffer, name_size);
78 type_ = type; 76 type_ = type;
79 data_.assign(data, data + data_size); 77 data_.assign(data, data + data_size);
80 } 78 }
81 79
82 DeleteRegKeyWorkItem::RegKeyBackup::RegKeyBackup() 80 RegistryKeyBackup::KeyData::KeyData()
83 : num_values_(0), 81 : num_values_(0),
84 num_subkeys_(0) { 82 num_subkeys_(0) {
85 } 83 }
86 84
85 RegistryKeyBackup::KeyData::~KeyData()
86 {
87 }
88
87 // Initializes this object by reading the values and subkeys of |key|. 89 // Initializes this object by reading the values and subkeys of |key|.
88 // Security descriptors are not backed up. 90 // Security descriptors are not backed up.
89 bool DeleteRegKeyWorkItem::RegKeyBackup::Initialize(const RegKey& key) { 91 bool RegistryKeyBackup::KeyData::Initialize(const RegKey& key) {
90 DCHECK(key.Valid()); 92 scoped_array<ValueData> values;
91
92 scoped_array<RegValueBackup> values;
93 scoped_array<std::wstring> subkey_names; 93 scoped_array<std::wstring> subkey_names;
94 scoped_array<RegKeyBackup> subkeys; 94 scoped_array<KeyData> subkeys;
95 95
96 DWORD num_subkeys = 0; 96 DWORD num_subkeys = 0;
97 DWORD max_subkey_name_len = 0; 97 DWORD max_subkey_name_len = 0;
98 DWORD num_values = 0; 98 DWORD num_values = 0;
99 DWORD max_value_name_len = 0; 99 DWORD max_value_name_len = 0;
100 DWORD max_value_len = 0; 100 DWORD max_value_len = 0;
101 LONG result = RegQueryInfoKey(key.Handle(), NULL, NULL, NULL, 101 LONG result = RegQueryInfoKey(key.Handle(), NULL, NULL, NULL,
102 &num_subkeys, &max_subkey_name_len, NULL, 102 &num_subkeys, &max_subkey_name_len, NULL,
103 &num_values, &max_value_name_len, 103 &num_values, &max_value_name_len,
104 &max_value_len, NULL, NULL); 104 &max_value_len, NULL, NULL);
105 if (result != ERROR_SUCCESS) { 105 if (result != ERROR_SUCCESS) {
106 LOG(ERROR) << "Failed getting info of key to backup, result: " << result; 106 LOG(ERROR) << "Failed getting info of key to backup, result: " << result;
107 return false; 107 return false;
108 } 108 }
109 if (max_subkey_name_len >= std::numeric_limits<DWORD>::max() - 1 || 109 if (max_subkey_name_len >= std::numeric_limits<DWORD>::max() - 1 ||
110 max_value_name_len >= std::numeric_limits<DWORD>::max() - 1) { 110 max_value_name_len >= std::numeric_limits<DWORD>::max() - 1) {
111 LOG(ERROR) 111 LOG(ERROR)
112 << "Failed backing up key; subkeys and/or names are out of range."; 112 << "Failed backing up key; subkeys and/or names are out of range.";
113 return false; 113 return false;
114 } 114 }
115 DWORD max_name_len = std::max(max_subkey_name_len, max_value_name_len) + 1; 115 DWORD max_name_len = std::max(max_subkey_name_len, max_value_name_len) + 1;
116 scoped_array<wchar_t> name_buffer(new wchar_t[max_name_len]); 116 scoped_array<wchar_t> name_buffer(new wchar_t[max_name_len]);
117 117
118 // Backup the values. 118 // Backup the values.
119 if (num_values != 0) { 119 if (num_values != 0) {
120 values.reset(new RegValueBackup[num_values]); 120 values.reset(new ValueData[num_values]);
121 scoped_array<uint8> value_buffer(new uint8[max_value_len]); 121 scoped_array<uint8> value_buffer(new uint8[max_value_len]);
122 DWORD name_size = 0; 122 DWORD name_size = 0;
123 DWORD value_type = REG_NONE; 123 DWORD value_type = REG_NONE;
124 DWORD value_size = 0; 124 DWORD value_size = 0;
125 125
126 for (DWORD i = 0; i < num_values; ) { 126 for (DWORD i = 0; i < num_values; ) {
127 name_size = max_name_len; 127 name_size = max_name_len;
128 value_size = max_value_len; 128 value_size = max_value_len;
129 result = RegEnumValue(key.Handle(), i, name_buffer.get(), &name_size, 129 result = RegEnumValue(key.Handle(), i, name_buffer.get(), &name_size,
130 NULL, &value_type, value_buffer.get(), &value_size); 130 NULL, &value_type, value_buffer.get(), &value_size);
131 switch (result) { 131 switch (result) {
132 case ERROR_NO_MORE_ITEMS: 132 case ERROR_NO_MORE_ITEMS:
133 num_values = i; 133 num_values = i;
134 break; 134 break;
135 case ERROR_SUCCESS: 135 case ERROR_SUCCESS:
136 values[i].Initialize(name_buffer.get(), name_size, value_type, 136 values[i].Initialize(name_buffer.get(), name_size, value_type,
137 value_buffer.get(), value_size); 137 value_buffer.get(), value_size);
138 ++i; 138 ++i;
139 break; 139 break;
140 case ERROR_MORE_DATA: 140 case ERROR_MORE_DATA:
141 if (value_size > max_value_len) { 141 if (value_size > max_value_len) {
142 max_value_len = value_size; 142 max_value_len = value_size;
143 value_buffer.reset(); // Release to heap before new allocation.
143 value_buffer.reset(new uint8[max_value_len]); 144 value_buffer.reset(new uint8[max_value_len]);
144 } else { 145 } else {
145 DCHECK(max_name_len - 1 < name_size); 146 DCHECK_LT(max_name_len - 1, name_size);
146 if (name_size >= std::numeric_limits<DWORD>::max() - 1) { 147 if (name_size >= std::numeric_limits<DWORD>::max() - 1) {
147 LOG(ERROR) << "Failed backing up key; value name out of range."; 148 LOG(ERROR) << "Failed backing up key; value name out of range.";
148 return false; 149 return false;
149 } 150 }
150 max_name_len = name_size + 1; 151 max_name_len = name_size + 1;
152 name_buffer.reset(); // Release to heap before new allocation.
151 name_buffer.reset(new wchar_t[max_name_len]); 153 name_buffer.reset(new wchar_t[max_name_len]);
152 } 154 }
153 break; 155 break;
154 default: 156 default:
155 LOG(ERROR) << "Failed backing up value " << i << ", result: " 157 LOG(ERROR) << "Failed backing up value " << i << ", result: "
156 << result; 158 << result;
157 return false; 159 return false;
158 } 160 }
159 } 161 }
160 DLOG_IF(WARNING, RegEnumValue(key.Handle(), num_values, name_buffer.get(), 162 DLOG_IF(WARNING, RegEnumValue(key.Handle(), num_values, name_buffer.get(),
161 &name_size, NULL, &value_type, NULL, 163 &name_size, NULL, &value_type, NULL,
162 NULL) != ERROR_NO_MORE_ITEMS) 164 NULL) != ERROR_NO_MORE_ITEMS)
163 << "Concurrent modifications to registry key during backup operation."; 165 << "Concurrent modifications to registry key during backup operation.";
164 } 166 }
165 167
166 // Backup the subkeys. 168 // Backup the subkeys.
167 if (num_subkeys != 0) { 169 if (num_subkeys != 0) {
168 subkey_names.reset(new std::wstring[num_subkeys]); 170 subkey_names.reset(new std::wstring[num_subkeys]);
169 subkeys.reset(new RegKeyBackup[num_subkeys]); 171 subkeys.reset(new KeyData[num_subkeys]);
170 DWORD name_size = 0; 172 DWORD name_size = 0;
171 173
172 // Get the names of them. 174 // Get the names of them.
173 for (DWORD i = 0; i < num_subkeys; ) { 175 for (DWORD i = 0; i < num_subkeys; ) {
174 name_size = max_name_len; 176 name_size = max_name_len;
175 result = RegEnumKeyEx(key.Handle(), i, name_buffer.get(), &name_size, 177 result = RegEnumKeyEx(key.Handle(), i, name_buffer.get(), &name_size,
176 NULL, NULL, NULL, NULL); 178 NULL, NULL, NULL, NULL);
177 switch (result) { 179 switch (result) {
178 case ERROR_NO_MORE_ITEMS: 180 case ERROR_NO_MORE_ITEMS:
179 num_subkeys = i; 181 num_subkeys = i;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 values_.swap(values); 223 values_.swap(values);
222 subkey_names_.swap(subkey_names); 224 subkey_names_.swap(subkey_names);
223 subkeys_.swap(subkeys); 225 subkeys_.swap(subkeys);
224 num_values_ = num_values; 226 num_values_ = num_values;
225 num_subkeys_ = num_subkeys; 227 num_subkeys_ = num_subkeys;
226 228
227 return true; 229 return true;
228 } 230 }
229 231
230 // Writes the values and subkeys of this object into |key|. 232 // Writes the values and subkeys of this object into |key|.
231 bool DeleteRegKeyWorkItem::RegKeyBackup::WriteTo(RegKey* key) const { 233 bool RegistryKeyBackup::KeyData::WriteTo(RegKey* key) const {
234 DCHECK(key);
235
232 LONG result = ERROR_SUCCESS; 236 LONG result = ERROR_SUCCESS;
233 237
234 // Write the values. 238 // Write the values.
235 for (int i = 0; i < num_values_; ++i) { 239 for (DWORD i = 0; i < num_values_; ++i) {
236 const RegValueBackup& value = values_[i]; 240 const ValueData& value = values_[i];
237 result = RegSetValueEx(key->Handle(), value.name(), 0, value.type(), 241 result = RegSetValueEx(key->Handle(), value.name(), 0, value.type(),
238 value.data(), value.data_len()); 242 value.data(), value.data_len());
239 if (result != ERROR_SUCCESS) { 243 if (result != ERROR_SUCCESS) {
240 LOG(ERROR) << "Failed writing value \"" << value.name_str() 244 LOG(ERROR) << "Failed writing value \"" << value.name_str()
241 << "\", result: " << result; 245 << "\", result: " << result;
242 return false; 246 return false;
243 } 247 }
244 } 248 }
245 249
246 // Write the subkeys. 250 // Write the subkeys.
247 RegKey subkey; 251 RegKey subkey;
248 for (int i = 0; i < num_subkeys_; ++i) { 252 for (DWORD i = 0; i < num_subkeys_; ++i) {
249 const std::wstring& name = subkey_names_[i]; 253 const std::wstring& name = subkey_names_[i];
250 254
251 result = subkey.Create(key->Handle(), name.c_str(), KEY_WRITE); 255 result = subkey.Create(key->Handle(), name.c_str(), KEY_WRITE);
252 if (result != ERROR_SUCCESS) { 256 if (result != ERROR_SUCCESS) {
253 LOG(ERROR) << "Failed creating subkey \"" << name << "\", result: " 257 LOG(ERROR) << "Failed creating subkey \"" << name << "\", result: "
254 << result; 258 << result;
255 return false; 259 return false;
256 } 260 }
257 if (!subkeys_[i].WriteTo(&subkey)) { 261 if (!subkeys_[i].WriteTo(&subkey)) {
258 LOG(ERROR) << "Failed writing subkey \"" << name << "\", result: " 262 LOG(ERROR) << "Failed writing subkey \"" << name << "\", result: "
259 << result; 263 << result;
260 return false; 264 return false;
261 } 265 }
262 } 266 }
263 267
264 return true; 268 return true;
265 } 269 }
266 270
267 DeleteRegKeyWorkItem::~DeleteRegKeyWorkItem() { 271 RegistryKeyBackup::RegistryKeyBackup() {
268 } 272 }
269 273
270 DeleteRegKeyWorkItem::DeleteRegKeyWorkItem(HKEY predefined_root, 274 RegistryKeyBackup::~RegistryKeyBackup() {
271 const std::wstring& path)
272 : predefined_root_(predefined_root),
273 path_(path) {
274 // It's a safe bet that we don't want to delete one of the root trees.
275 DCHECK(!path.empty());
276 } 275 }
277 276
278 bool DeleteRegKeyWorkItem::Do() { 277 bool RegistryKeyBackup::Initialize(HKEY root, const wchar_t* key_path) {
279 scoped_ptr<RegKeyBackup> backup; 278 DCHECK(key_path);
280 279
281 // Only try to make a backup if we're not configured to ignore failures. 280 RegKey key;
282 if (!ignore_failure_) { 281 scoped_ptr<KeyData> key_data;
283 RegKey original_key;
284 282
285 // Does the key exist? 283 // Does the key exist?
286 LONG result = original_key.Open(predefined_root_, path_.c_str(), 284 LONG result = key.Open(root, key_path, kKeyReadNoNotify);
287 kKeyReadNoNotify); 285 if (result == ERROR_SUCCESS) {
288 if (result == ERROR_SUCCESS) { 286 key_data.reset(new KeyData());
289 backup.reset(new RegKeyBackup()); 287 if (!key_data->Initialize(key)) {
290 if (!backup->Initialize(original_key)) { 288 LOG(ERROR) << "Failed to backup key at " << key_path;
291 LOG(ERROR) << "Failed to backup key at " << path_; 289 return false;
292 return ignore_failure_;
293 }
294 } else if (result != ERROR_FILE_NOT_FOUND) {
295 LOG(ERROR) << "Failed to open key at " << path_
296 << " to create backup, result: " << result;
297 return ignore_failure_;
298 } 290 }
291 } else if (result != ERROR_FILE_NOT_FOUND) {
292 LOG(ERROR) << "Failed to open key at " << key_path
293 << " to create backup, result: " << result;
294 return false;
299 } 295 }
300 296
301 // Delete the key. 297 key_data_.swap(key_data);
302 LONG result = SHDeleteKey(predefined_root_, path_.c_str());
303 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
304 LOG(ERROR) << "Failed to delete key at " << path_ << ", result: "
305 << result;
306 return ignore_failure_;
307 }
308
309 // We've succeeded, so remember any backup we may have made.
310 backup_.swap(backup);
311
312 return true; 298 return true;
313 } 299 }
314 300
315 void DeleteRegKeyWorkItem::Rollback() { 301 bool RegistryKeyBackup::WriteTo(HKEY root, const wchar_t* key_path) const {
316 if (ignore_failure_ || backup_.get() == NULL) 302 DCHECK(key_path);
317 return;
318 303
319 // Delete anything in the key before restoring the backup in case someone else 304 bool success = false;
320 // put new data in the key after Do(). 305
321 LONG result = SHDeleteKey(predefined_root_, path_.c_str()); 306 if (key_data_.get() != NULL) {
322 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) { 307 RegKey dest_key;
323 LOG(ERROR) << "Failed to delete key at " << path_ << " in rollback, " 308 LONG result = dest_key.Create(root, key_path, KEY_WRITE);
324 "result: " << result; 309 if (result != ERROR_SUCCESS) {
310 LOG(ERROR) << "Failed to create destination key at " << key_path
311 << " to write backup, result: " << result;
312 } else {
313 success = key_data_->WriteTo(&dest_key);
314 LOG_IF(ERROR, !success) << "Failed to write key data.";
315 }
316 } else {
317 success = true;
325 } 318 }
326 319
327 // Restore the old contents. The restoration takes on its default security 320 return success;
328 // attributes; any custom attributes are lost.
329 RegKey original_key;
330 result = original_key.Create(predefined_root_, path_.c_str(), KEY_WRITE);
331 if (result != ERROR_SUCCESS) {
332 LOG(ERROR) << "Failed to create original key at " << path_
333 << " in rollback, result: " << result;
334 } else {
335 if (!backup_->WriteTo(&original_key))
336 LOG(ERROR) << "Failed to restore key in rollback, result: " << result;
337 }
338 } 321 }
OLDNEW
« no previous file with comments | « chrome/installer/util/registry_key_backup.h ('k') | chrome/installer/util/registry_key_backup_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698