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

Side by Side Diff: chrome_elf/nt_registry/nt_registry.cc

Issue 1841573002: [Chrome ELF] New NT registry API. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Missed new unit tests for install_static. Created 4 years, 6 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
(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_elf/nt_registry/nt_registry.h"
6
7 namespace {
8
9 // Function pointers used for registry access.
10 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr;
11 NtCreateKeyFunction g_nt_create_key = nullptr;
12 NtDeleteKeyFunction g_nt_delete_key = nullptr;
13 NtOpenKeyExFunction g_nt_open_key_ex = nullptr;
14 NtCloseFunction g_nt_close = nullptr;
15 NtQueryValueKeyFunction g_nt_query_value_key = nullptr;
16 NtSetValueKeyFunction g_nt_set_value_key = nullptr;
17
18 // Lazy init. No concern about concurrency in chrome_elf.
19 bool g_initialized = false;
20 bool g_system_install = false;
21 const size_t g_kRegMaxPathLen = 255;
22 wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\";
23 wchar_t g_kRegPathHKCU[g_kRegMaxPathLen] = L"";
24 std::wstring g_current_user_sid_string;
25 std::wstring g_override_path;
26
27 // Not using install_util, to prevent circular dependency.
28 bool IsThisProcSystem() {
29 wchar_t program_dir[MAX_PATH] = {};
30 wchar_t* cmd_line = GetCommandLineW();
31 // If our command line starts with the "Program Files" or
32 // "Program Files (x86)" path, we're system.
33 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH);
34 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret))
35 return true;
36
37 ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir, MAX_PATH);
38 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret))
39 return true;
40
41 return false;
42 }
43
44 bool InitNativeRegApi() {
45 HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
46
47 // Setup the global function pointers for registry access.
48 g_rtl_init_unicode_string = reinterpret_cast<RtlInitUnicodeStringFunction>(
49 ::GetProcAddress(ntdll, "RtlInitUnicodeString"));
50
51 g_nt_create_key = reinterpret_cast<NtCreateKeyFunction>(
52 ::GetProcAddress(ntdll, "NtCreateKey"));
53
54 g_nt_delete_key = reinterpret_cast<NtDeleteKeyFunction>(
55 ::GetProcAddress(ntdll, "NtDeleteKey"));
56
57 g_nt_open_key_ex = reinterpret_cast<NtOpenKeyExFunction>(
58 ::GetProcAddress(ntdll, "NtOpenKeyEx"));
59
60 g_nt_close =
61 reinterpret_cast<NtCloseFunction>(::GetProcAddress(ntdll, "NtClose"));
62
63 g_nt_query_value_key = reinterpret_cast<NtQueryValueKeyFunction>(
64 ::GetProcAddress(ntdll, "NtQueryValueKey"));
65
66 g_nt_set_value_key = reinterpret_cast<NtSetValueKeyFunction>(
67 ::GetProcAddress(ntdll, "NtSetValueKey"));
68
69 if (!g_rtl_init_unicode_string || !g_nt_create_key || !g_nt_open_key_ex ||
70 !g_nt_delete_key || !g_nt_close || !g_nt_query_value_key ||
71 !g_nt_set_value_key)
72 return false;
73
74 // We need to set HKCU based on the sid of the current user account.
75 RtlFormatCurrentUserKeyPathFunction rtl_current_user_string =
76 reinterpret_cast<RtlFormatCurrentUserKeyPathFunction>(
77 ::GetProcAddress(ntdll, "RtlFormatCurrentUserKeyPath"));
78
79 RtlFreeUnicodeStringFunction rtl_free_unicode_str =
80 reinterpret_cast<RtlFreeUnicodeStringFunction>(
81 ::GetProcAddress(ntdll, "RtlFreeUnicodeString"));
82
83 if (!rtl_current_user_string || !rtl_free_unicode_str)
84 return false;
85
86 UNICODE_STRING current_user_reg_path;
87 if (!NT_SUCCESS(rtl_current_user_string(&current_user_reg_path)))
88 return false;
89
90 // Finish setting up global HKCU path.
91 ::wcsncat(g_kRegPathHKCU, current_user_reg_path.Buffer, g_kRegMaxPathLen - 1);
92 ::wcsncat(g_kRegPathHKCU, L"\\",
93 (g_kRegMaxPathLen - ::wcslen(g_kRegPathHKCU) - 1));
94 // Keep the sid string as well.
95 wchar_t* ptr = ::wcsrchr(current_user_reg_path.Buffer, L'\\');
96 ptr++;
97 g_current_user_sid_string.assign(ptr);
98 rtl_free_unicode_str(&current_user_reg_path);
99
100 // Figure out if we're a system or user install.
101 g_system_install = IsThisProcSystem();
102
103 g_initialized = true;
104 return true;
105 }
106
107 const wchar_t* ConvertRootKey(nt::ROOT_KEY root) {
108 nt::ROOT_KEY key = root;
109
110 if (!root) {
111 // AUTO
112 key = g_system_install ? nt::HKLM : nt::HKCU;
113 }
114
115 if ((key == nt::HKCU) && (!nt::HKCU_override.empty())) {
116 g_override_path.assign(g_kRegPathHKCU);
117 g_override_path.append(nt::HKCU_override.c_str());
118 g_override_path.append(L"\\");
119 return g_override_path.c_str();
120 } else if ((key == nt::HKLM) && (!nt::HKLM_override.empty())) {
121 g_override_path.assign(g_kRegPathHKCU);
122 g_override_path.append(nt::HKLM_override.c_str());
123 g_override_path.append(L"\\");
124 return g_override_path.c_str();
125 }
126
127 if (key == nt::HKCU)
128 return g_kRegPathHKCU;
129 else
130 return g_kRegPathHKLM;
131 }
132
133 } // namespace
134
135 namespace nt {
136
137 std::wstring HKLM_override;
138 std::wstring HKCU_override;
139
140 bool CreateRegKey(ROOT_KEY root,
141 const wchar_t* key_path,
142 ACCESS_MASK access,
143 HANDLE* out_handle OPTIONAL) {
144 if (!g_initialized)
145 InitNativeRegApi();
146
147 NTSTATUS status = STATUS_UNSUCCESSFUL;
148 UNICODE_STRING key_path_uni = {};
149 OBJECT_ATTRIBUTES obj = {};
150 HANDLE key_handle = INVALID_HANDLE_VALUE;
151
152 std::wstring full_path(ConvertRootKey(root));
153 full_path.append(key_path);
154
155 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str());
156 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL,
157 NULL);
158 // Assuming CreateOptions to preserve across reboot, and currently
159 // don't care whether already existed or not.
160 status = g_nt_create_key(&key_handle, access, &obj, 0, nullptr,
161 REG_OPTION_NON_VOLATILE, nullptr);
162
163 if (NT_SUCCESS(status)) {
164 if (out_handle)
165 *out_handle = key_handle;
166 else
167 CloseRegKey(key_handle);
168 return true;
169 }
170
171 return false;
172 }
173
174 bool OpenRegKey(ROOT_KEY root,
175 const wchar_t* key_path,
176 ACCESS_MASK access,
177 HANDLE* out_handle,
178 NTSTATUS* error_code OPTIONAL) {
179 if (!g_initialized)
180 InitNativeRegApi();
181
182 NTSTATUS status = STATUS_UNSUCCESSFUL;
183 UNICODE_STRING key_path_uni = {};
184 OBJECT_ATTRIBUTES obj = {};
185 *out_handle = INVALID_HANDLE_VALUE;
186
187 std::wstring full_path(ConvertRootKey(root));
188 full_path.append(key_path);
189
190 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str());
191 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL,
192 NULL);
193
194 status = g_nt_open_key_ex(out_handle, access, &obj, 0);
195 // See if caller wants the NTSTATUS.
196 if (error_code)
197 *error_code = status;
198
199 if (NT_SUCCESS(status))
200 return true;
201
202 return false;
203 }
204
205 bool DeleteRegKey(HANDLE key) {
206 if (!g_initialized)
207 InitNativeRegApi();
208
209 NTSTATUS status = STATUS_UNSUCCESSFUL;
210
211 status = g_nt_delete_key(key);
212
213 if (NT_SUCCESS(status))
214 return true;
215
216 return false;
217 }
218
219 // wrapper function
220 bool DeleteRegKey(ROOT_KEY root, const wchar_t* key_path) {
221 HANDLE key = INVALID_HANDLE_VALUE;
222
223 if (!OpenRegKey(root, key_path, DELETE, &key, nullptr))
224 return false;
225
226 if (!DeleteRegKey(key)) {
227 CloseRegKey(key);
228 return false;
229 }
230
231 CloseRegKey(key);
232 return true;
233 }
234
235 void CloseRegKey(HANDLE key) {
236 if (!g_initialized)
237 InitNativeRegApi();
238 g_nt_close(key);
239 }
240
241 //------------------------------------------------------------------------------
242 // Getter functions
243 //------------------------------------------------------------------------------
244
245 bool QueryRegKeyValue(HANDLE key,
246 const wchar_t* value_name,
247 ULONG* out_type,
248 BYTE** out_buffer,
249 DWORD* out_size) {
250 if (!g_initialized)
251 InitNativeRegApi();
252
253 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
254 UNICODE_STRING value_uni = {};
255 g_rtl_init_unicode_string(&value_uni, value_name);
256 DWORD size_needed = 0;
257 bool success = false;
258
259 // First call to find out how much room we need for the value!
260 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
261 nullptr, 0, &size_needed);
262 if (ntstatus != STATUS_BUFFER_TOO_SMALL)
263 return false;
264
265 KEY_VALUE_FULL_INFORMATION* value_info =
266 reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(new BYTE[size_needed]);
267
268 // Second call to get the value.
269 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
270 value_info, size_needed, &size_needed);
271 if (NT_SUCCESS(ntstatus)) {
272 *out_type = value_info->Type;
273 *out_size = value_info->DataLength;
274 *out_buffer = new BYTE[*out_size];
275 ::memcpy(*out_buffer,
276 (reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset),
277 *out_size);
278 success = true;
279 }
280
281 delete[] value_info;
282 return success;
283 }
284
285 // wrapper function
286 bool QueryRegValueDWORD(HANDLE key,
287 const wchar_t* value_name,
288 DWORD* out_dword) {
289 ULONG type = REG_NONE;
290 BYTE* value_bytes = nullptr;
291 DWORD ret_size = 0;
292
293 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) ||
294 type != REG_DWORD)
295 return false;
296
297 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes));
298
299 delete[] value_bytes;
300 return true;
301 }
302
303 // wrapper function
304 bool QueryRegValueDWORD(ROOT_KEY root,
305 const wchar_t* key_path,
306 const wchar_t* value_name,
307 DWORD* out_dword) {
308 HANDLE key = INVALID_HANDLE_VALUE;
309
310 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key,
311 NULL))
312 return false;
313
314 if (!QueryRegValueDWORD(key, value_name, out_dword)) {
315 CloseRegKey(key);
316 return false;
317 }
318
319 CloseRegKey(key);
320 return true;
321 }
322
323 // wrapper function
324 bool QueryRegValueSZ(HANDLE key,
325 const wchar_t* value_name,
326 std::wstring* out_sz) {
327 BYTE* value_bytes = nullptr;
328 DWORD ret_size = 0;
329 ULONG type = REG_NONE;
330
331 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) ||
332 type != REG_SZ)
333 return false;
334
335 *out_sz = reinterpret_cast<wchar_t*>(value_bytes);
336
337 delete[] value_bytes;
338 return true;
339 }
340
341 // wrapper function
342 bool QueryRegValueSZ(ROOT_KEY root,
343 const wchar_t* key_path,
344 const wchar_t* value_name,
345 std::wstring* out_sz) {
346 HANDLE key = INVALID_HANDLE_VALUE;
347
348 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key,
349 NULL))
350 return false;
351
352 if (!QueryRegValueSZ(key, value_name, out_sz)) {
353 CloseRegKey(key);
354 return false;
355 }
356
357 CloseRegKey(key);
358 return true;
359 }
360
361 // wrapper function
362 bool QueryRegValueMULTISZ(HANDLE key,
363 const wchar_t* value_name,
364 std::vector<std::wstring>* out_multi_sz) {
365 BYTE* value_bytes = nullptr;
366 DWORD ret_size = 0;
367 ULONG type = REG_NONE;
368
369 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) ||
370 type != REG_MULTI_SZ)
371 return false;
372
373 // Make sure the vector is empty to start.
374 (*out_multi_sz).resize(0);
375
376 wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes);
377 std::wstring temp = pointer;
378 // Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in
379 // a row).
380 while (temp.length() != 0) {
381 (*out_multi_sz).push_back(temp);
382
383 pointer += temp.length() + 1;
384 temp = pointer;
385 }
386
387 // Handle the case of "empty multi_sz".
388 if (out_multi_sz->size() == 0)
389 out_multi_sz->push_back(L"");
390
391 delete[] value_bytes;
392 return true;
393 }
394
395 // wrapper function
396 bool QueryRegValueMULTISZ(ROOT_KEY root,
397 const wchar_t* key_path,
398 const wchar_t* value_name,
399 std::vector<std::wstring>* out_multi_sz) {
400 HANDLE key = INVALID_HANDLE_VALUE;
401
402 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key,
403 NULL))
404 return false;
405
406 if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) {
407 CloseRegKey(key);
408 return false;
409 }
410
411 CloseRegKey(key);
412 return true;
413 }
414
415 //------------------------------------------------------------------------------
416 // Setter functions
417 //------------------------------------------------------------------------------
418
419 bool SetRegKeyValue(HANDLE key,
420 const wchar_t* value_name,
421 ULONG type,
422 const BYTE* data,
423 DWORD data_size) {
424 if (!g_initialized)
425 InitNativeRegApi();
426
427 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
428 UNICODE_STRING value_uni = {};
429 g_rtl_init_unicode_string(&value_uni, value_name);
430
431 BYTE* non_const_data = const_cast<BYTE*>(data);
432 ntstatus =
433 g_nt_set_value_key(key, &value_uni, 0, type, non_const_data, data_size);
434
435 if (NT_SUCCESS(ntstatus))
436 return true;
437
438 return false;
439 }
440
441 // wrapper function
442 bool SetRegValueDWORD(HANDLE key, const wchar_t* value_name, DWORD value) {
443 return SetRegKeyValue(key, value_name, REG_DWORD,
444 reinterpret_cast<BYTE*>(&value), sizeof(value));
445 }
446
447 // wrapper function
448 bool SetRegValueDWORD(ROOT_KEY root,
449 const wchar_t* key_path,
450 const wchar_t* value_name,
451 DWORD value) {
452 HANDLE key = INVALID_HANDLE_VALUE;
453
454 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL))
455 return false;
456
457 if (!SetRegValueDWORD(key, value_name, value)) {
458 CloseRegKey(key);
459 return false;
460 }
461
462 return true;
463 }
464
465 // wrapper function
466 bool SetRegValueSZ(HANDLE key,
467 const wchar_t* value_name,
468 const std::wstring& value) {
469 wchar_t* string = const_cast<wchar_t*>(value.c_str());
470 if (std::numeric_limits<DWORD>::max() < ::wcslen(string))
robertshield 2016/06/17 13:40:03 could use value.length() instead of all this
penny 2016/06/22 23:13:14 Done.
471 return false;
472
473 DWORD length = static_cast<DWORD>(::wcslen(string));
474
475 return SetRegKeyValue(key, value_name, REG_SZ,
476 reinterpret_cast<BYTE*>(string),
477 (length + 1) * sizeof(wchar_t));
478 }
479
480 // wrapper function
481 bool SetRegValueSZ(ROOT_KEY root,
482 const wchar_t* key_path,
483 const wchar_t* value_name,
484 const std::wstring& value) {
485 HANDLE key = INVALID_HANDLE_VALUE;
486
487 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL))
488 return false;
489
490 if (!SetRegValueSZ(key, value_name, value)) {
491 CloseRegKey(key);
492 return false;
493 }
494
495 return true;
496 }
497
498 // wrapper function
499 bool SetRegValueMULTISZ(HANDLE key,
500 const wchar_t* value_name,
501 const std::vector<std::wstring>& values) {
502 std::vector<wchar_t> builder;
503
504 for (auto& string : values) {
505 // Just in case someone is passing in an illegal empty string
506 // (not allowed in REG_MULTI_SZ), ignore it.
507 if (!string.empty()) {
508 for (const wchar_t& w : string) {
509 builder.push_back(w);
510 }
511 builder.push_back(L'\0');
512 }
513 }
514 // Add second null terminator to end REG_MULTI_SZ.
515 builder.push_back(L'\0');
516 // Handle rare case where the vector passed in was empty,
517 // or only had an empty string.
518 if (builder.size() == 1)
519 builder.push_back(L'\0');
520
521 if (std::numeric_limits<DWORD>::max() < builder.size())
522 return false;
523
524 return SetRegKeyValue(
525 key, value_name, REG_MULTI_SZ, reinterpret_cast<BYTE*>(builder.data()),
526 (static_cast<DWORD>(builder.size()) + 1) * sizeof(wchar_t));
527 }
528
529 // wrapper function
530 bool SetRegValueMULTISZ(ROOT_KEY root,
531 const wchar_t* key_path,
532 const wchar_t* value_name,
533 const std::vector<std::wstring>& values) {
534 HANDLE key = INVALID_HANDLE_VALUE;
535
536 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL))
537 return false;
538
539 if (!SetRegValueMULTISZ(key, value_name, values)) {
540 CloseRegKey(key);
541 return false;
542 }
543
544 return true;
545 }
546
547 //------------------------------------------------------------------------------
548 // Utils
549 //------------------------------------------------------------------------------
550
551 std::wstring GetCurrentUserSidString() {
552 if (!g_initialized)
553 InitNativeRegApi();
554
555 return g_current_user_sid_string;
556 }
557
558 }; // namespace nt
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698