Reactos
1/*
2 * ReactOS kernel
3 * Copyright (C) 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19/*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS Setup Library
22 * FILE: base/setup/lib/registry.c
23 * PURPOSE: Registry creation functions
24 * PROGRAMMERS: ...
25 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
26 */
27
28/* INCLUDES *****************************************************************/
29
30#include "precomp.h"
31#include "filesup.h"
32#include "infsupp.h"
33#include "regutil.h"
34
35#include "registry.h"
36
37#define NDEBUG
38#include <debug.h>
39
40
41// #ifdef __REACTOS__
42#if 1 // FIXME: Disable if setupapi.h is included in the code...
43#define FLG_ADDREG_BINVALUETYPE 0x00000001
44#define FLG_ADDREG_NOCLOBBER 0x00000002
45#define FLG_ADDREG_DELVAL 0x00000004
46#define FLG_ADDREG_APPEND 0x00000008
47#define FLG_ADDREG_KEYONLY 0x00000010
48#define FLG_ADDREG_OVERWRITEONLY 0x00000020
49#define FLG_ADDREG_TYPE_SZ 0x00000000
50#define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
51#define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
52#define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
53#define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
54#define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
55#define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
56#endif
57
58/* GLOBALS ******************************************************************/
59
60#define REGISTRY_SETUP_MACHINE L"\\Registry\\Machine\\SYSTEM\\USetup_Machine\\"
61#define REGISTRY_SETUP_USER L"\\Registry\\Machine\\SYSTEM\\USetup_User\\"
62
63typedef struct _ROOT_KEY
64{
65 PCWSTR Name;
66 PCWSTR MountPoint;
67 HANDLE Handle;
68} ROOT_KEY, *PROOT_KEY;
69
70ROOT_KEY RootKeys[] =
71{
72 { L"HKCR", REGISTRY_SETUP_MACHINE L"SOFTWARE\\Classes\\", NULL }, /* "\\Registry\\Machine\\SOFTWARE\\Classes\\" */ // HKEY_CLASSES_ROOT
73 { L"HKCU", REGISTRY_SETUP_USER L".DEFAULT\\" , NULL }, /* "\\Registry\\User\\.DEFAULT\\" */ // HKEY_CURRENT_USER
74 { L"HKLM", REGISTRY_SETUP_MACHINE , NULL }, /* "\\Registry\\Machine\\" */ // HKEY_LOCAL_MACHINE
75 { L"HKU" , REGISTRY_SETUP_USER , NULL }, /* "\\Registry\\User\\" */ // HKEY_USERS
76#if 0
77 { L"HKR", NULL, NULL },
78#endif
79};
80
81/* FUNCTIONS ****************************************************************/
82
83#define IsPredefKey(HKey) \
84 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
85
86#define GetPredefKeyIndex(HKey) \
87 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
88
89HANDLE
90GetRootKeyByPredefKey(
91 IN HANDLE KeyHandle,
92 OUT PCWSTR* RootKeyMountPoint OPTIONAL)
93{
94 ULONG_PTR Index = GetPredefKeyIndex(KeyHandle);
95
96 if (!IsPredefKey(KeyHandle))
97 return NULL;
98 if (Index >= ARRAYSIZE(RootKeys))
99 return NULL;
100
101 if (RootKeyMountPoint)
102 *RootKeyMountPoint = RootKeys[Index].MountPoint;
103 return RootKeys[Index].Handle;
104}
105
106HANDLE
107GetRootKeyByName(
108 IN PCWSTR RootKeyName,
109 OUT PCWSTR* RootKeyMountPoint OPTIONAL)
110{
111 UCHAR i;
112
113 for (i = 0; i < ARRAYSIZE(RootKeys); ++i)
114 {
115 if (!_wcsicmp(RootKeyName, RootKeys[i].Name))
116 {
117 if (RootKeyMountPoint)
118 *RootKeyMountPoint = RootKeys[i].MountPoint;
119 return RootKeys[i].Handle;
120 }
121 }
122
123 return NULL;
124}
125
126
127/***********************************************************************
128 * append_multi_sz_value
129 *
130 * Append a multisz string to a multisz registry value.
131 */
132// NOTE: Synced with setupapi/install.c ; see also mkhive/reginf.c
133#if 0
134static void
135append_multi_sz_value (HANDLE hkey,
136 const WCHAR *value,
137 const WCHAR *strings,
138 DWORD str_size )
139{
140 DWORD size, type, total;
141 WCHAR *buffer, *p;
142
143 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
144 if (type != REG_MULTI_SZ) return;
145
146 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size + str_size * sizeof(WCHAR) ))) return;
147 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
148
149 /* compare each string against all the existing ones */
150 total = size;
151 while (*strings)
152 {
153 int len = strlenW(strings) + 1;
154
155 for (p = buffer; *p; p += strlenW(p) + 1)
156 if (!strcmpiW( p, strings )) break;
157
158 if (!*p) /* not found, need to append it */
159 {
160 memcpy( p, strings, len * sizeof(WCHAR) );
161 p[len] = 0;
162 total += len;
163 }
164 strings += len;
165 }
166 if (total != size)
167 {
168 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
169 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
170 }
171 done:
172 HeapFree( GetProcessHeap(), 0, buffer );
173}
174#endif
175
176/***********************************************************************
177 * delete_multi_sz_value
178 *
179 * Remove a string from a multisz registry value.
180 */
181#if 0
182static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
183{
184 DWORD size, type;
185 WCHAR *buffer, *src, *dst;
186
187 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
188 if (type != REG_MULTI_SZ) return;
189 /* allocate double the size, one for value before and one for after */
190 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
191 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
192 src = buffer;
193 dst = buffer + size;
194 while (*src)
195 {
196 int len = strlenW(src) + 1;
197 if (strcmpiW( src, string ))
198 {
199 memcpy( dst, src, len * sizeof(WCHAR) );
200 dst += len;
201 }
202 src += len;
203 }
204 *dst++ = 0;
205 if (dst != buffer + 2*size) /* did we remove something? */
206 {
207 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
208 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
209 (BYTE *)(buffer + size), dst - (buffer + size) );
210 }
211 done:
212 HeapFree( GetProcessHeap(), 0, buffer );
213}
214#endif
215
216/***********************************************************************
217 * do_reg_operation
218 *
219 * Perform an add/delete registry operation depending on the flags.
220 */
221static BOOLEAN
222do_reg_operation(HANDLE KeyHandle,
223 PUNICODE_STRING ValueName,
224 PINFCONTEXT Context,
225 ULONG Flags)
226{
227 WCHAR EmptyStr = 0;
228 ULONG Type;
229 ULONG Size;
230
231 if (Flags & FLG_ADDREG_DELVAL) /* deletion */
232 {
233#if 0
234 if (ValueName)
235 {
236 RegDeleteValueW( KeyHandle, ValueName );
237 }
238 else
239 {
240 RegDeleteKeyW( KeyHandle, NULL );
241 }
242#endif
243 return TRUE;
244 }
245
246 if (Flags & FLG_ADDREG_KEYONLY)
247 return TRUE;
248
249#if 0
250 if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY))
251 {
252 BOOL exists = !RegQueryValueExW( hkey, ValueName, NULL, NULL, NULL, NULL );
253 if (exists && (flags & FLG_ADDREG_NOCLOBBER))
254 return TRUE;
255 if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY))
256 return TRUE;
257 }
258#endif
259
260 switch (Flags & FLG_ADDREG_TYPE_MASK)
261 {
262 case FLG_ADDREG_TYPE_SZ:
263 Type = REG_SZ;
264 break;
265
266 case FLG_ADDREG_TYPE_MULTI_SZ:
267 Type = REG_MULTI_SZ;
268 break;
269
270 case FLG_ADDREG_TYPE_EXPAND_SZ:
271 Type = REG_EXPAND_SZ;
272 break;
273
274 case FLG_ADDREG_TYPE_BINARY:
275 Type = REG_BINARY;
276 break;
277
278 case FLG_ADDREG_TYPE_DWORD:
279 Type = REG_DWORD;
280 break;
281
282 case FLG_ADDREG_TYPE_NONE:
283 Type = REG_NONE;
284 break;
285
286 default:
287 Type = Flags >> 16;
288 break;
289 }
290
291 if (!(Flags & FLG_ADDREG_BINVALUETYPE) ||
292 (Type == REG_DWORD && SpInfGetFieldCount(Context) == 5))
293 {
294 PWCHAR Str = NULL;
295
296 if (Type == REG_MULTI_SZ)
297 {
298 if (!SpInfGetMultiSzField(Context, 5, NULL, 0, &Size))
299 Size = 0;
300
301 if (Size)
302 {
303 Str = (WCHAR*) RtlAllocateHeap(ProcessHeap, 0, Size * sizeof(WCHAR));
304 if (Str == NULL)
305 return FALSE;
306
307 SpInfGetMultiSzField(Context, 5, Str, Size, NULL);
308 }
309
310 if (Flags & FLG_ADDREG_APPEND)
311 {
312 if (Str == NULL)
313 return TRUE;
314
315 DPRINT1("append_multi_sz_value '%S' commented out, WHY??\n", ValueName);
316// append_multi_sz_value( hkey, value, str, size );
317
318 RtlFreeHeap (ProcessHeap, 0, Str);
319 return TRUE;
320 }
321 /* else fall through to normal string handling */
322 }
323 else
324 {
325 if (!SpInfGetStringField(Context, 5, NULL, 0, &Size))
326 Size = 0;
327
328 if (Size)
329 {
330 Str = (WCHAR*)RtlAllocateHeap(ProcessHeap, 0, Size * sizeof(WCHAR));
331 if (Str == NULL)
332 return FALSE;
333
334 SpInfGetStringField(Context, 5, Str, Size, NULL);
335 }
336 }
337
338 if (Type == REG_DWORD)
339 {
340 ULONG dw = Str ? wcstoul (Str, NULL, 0) : 0;
341
342 DPRINT("setting dword %wZ to %lx\n", ValueName, dw);
343
344 NtSetValueKey (KeyHandle,
345 ValueName,
346 0,
347 Type,
348 (PVOID)&dw,
349 sizeof(ULONG));
350 }
351 else
352 {
353 DPRINT("setting value %wZ to %S\n", ValueName, Str);
354
355 if (Str)
356 {
357 NtSetValueKey (KeyHandle,
358 ValueName,
359 0,
360 Type,
361 (PVOID)Str,
362 Size * sizeof(WCHAR));
363 }
364 else
365 {
366 NtSetValueKey (KeyHandle,
367 ValueName,
368 0,
369 Type,
370 (PVOID)&EmptyStr,
371 sizeof(WCHAR));
372 }
373 }
374 RtlFreeHeap (ProcessHeap, 0, Str);
375 }
376 else /* get the binary data */
377 {
378 PUCHAR Data = NULL;
379
380 if (!SpInfGetBinaryField(Context, 5, NULL, 0, &Size))
381 Size = 0;
382
383 if (Size)
384 {
385 Data = (unsigned char*) RtlAllocateHeap(ProcessHeap, 0, Size);
386 if (Data == NULL)
387 return FALSE;
388
389 DPRINT("setting binary data %wZ len %lu\n", ValueName, Size);
390 SpInfGetBinaryField(Context, 5, Data, Size, NULL);
391 }
392
393 NtSetValueKey (KeyHandle,
394 ValueName,
395 0,
396 Type,
397 (PVOID)Data,
398 Size);
399
400 RtlFreeHeap (ProcessHeap, 0, Data);
401 }
402
403 return TRUE;
404}
405
406/***********************************************************************
407 * registry_callback
408 *
409 * Called once for each AddReg and DelReg entry in a given section.
410 */
411static BOOLEAN
412registry_callback(HINF hInf, PCWSTR Section, BOOLEAN Delete)
413{
414 NTSTATUS Status;
415 OBJECT_ATTRIBUTES ObjectAttributes;
416 UNICODE_STRING Name, Value;
417 PUNICODE_STRING ValuePtr;
418 UINT Flags;
419 WCHAR Buffer[MAX_INF_STRING_LENGTH];
420
421 INFCONTEXT Context;
422 PCWSTR RootKeyName;
423 HANDLE RootKeyHandle, KeyHandle;
424 BOOLEAN Ok;
425
426 Ok = SpInfFindFirstLine(hInf, Section, NULL, &Context);
427 if (!Ok)
428 return TRUE; /* Don't fail if the section isn't present */
429
430 for (;Ok; Ok = SpInfFindNextLine(&Context, &Context))
431 {
432 /* get root */
433 if (!SpInfGetStringField(&Context, 1, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL))
434 continue;
435 RootKeyHandle = GetRootKeyByName(Buffer, &RootKeyName);
436 if (!RootKeyHandle)
437 continue;
438
439 /* get key */
440 if (!SpInfGetStringField(&Context, 2, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL))
441 *Buffer = 0;
442
443 DPRINT("KeyName: <%S\\%S>\n", RootKeyName, Buffer);
444
445 /* get flags */
446 if (!SpInfGetIntField(&Context, 4, (PINT)&Flags))
447 Flags = 0;
448
449 DPRINT("Flags: %lx\n", Flags);
450
451 RtlInitUnicodeString(&Name, Buffer);
452 InitializeObjectAttributes(&ObjectAttributes,
453 &Name,
454 OBJ_CASE_INSENSITIVE,
455 RootKeyHandle,
456 NULL);
457
458 if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
459 {
460 Status = NtOpenKey(&KeyHandle,
461 KEY_ALL_ACCESS,
462 &ObjectAttributes);
463 if (!NT_SUCCESS(Status))
464 {
465 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &Name, Status);
466 continue; /* ignore if it doesn't exist */
467 }
468 }
469 else
470 {
471 Status = CreateNestedKey(&KeyHandle,
472 KEY_ALL_ACCESS,
473 &ObjectAttributes,
474 REG_OPTION_NON_VOLATILE);
475 if (!NT_SUCCESS(Status))
476 {
477 DPRINT1("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name, Status);
478 continue;
479 }
480 }
481
482 /* get value name */
483 if (SpInfGetStringField(&Context, 3, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL))
484 {
485 RtlInitUnicodeString(&Value, Buffer);
486 ValuePtr = &Value;
487 }
488 else
489 {
490 ValuePtr = NULL;
491 }
492
493 /* and now do it */
494 if (!do_reg_operation(KeyHandle, ValuePtr, &Context, Flags))
495 {
496 NtClose(KeyHandle);
497 return FALSE;
498 }
499
500 NtClose(KeyHandle);
501 }
502
503 return TRUE;
504}
505
506BOOLEAN
507ImportRegistryFile(
508 IN PCWSTR SourcePath,
509 IN PCWSTR FileName,
510 IN PCWSTR Section,
511 IN LCID LocaleId,
512 IN BOOLEAN Delete)
513{
514 HINF hInf;
515 UINT ErrorLine;
516 WCHAR FileNameBuffer[MAX_PATH];
517
518 /* Load the INF file from the installation media */
519 CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2,
520 SourcePath, FileName);
521
522 hInf = SpInfOpenInfFile(FileNameBuffer,
523 NULL,
524 INF_STYLE_WIN4,
525 LocaleId,
526 &ErrorLine);
527 if (hInf == INVALID_HANDLE_VALUE)
528 {
529 DPRINT1("SpInfOpenInfFile() failed\n");
530 return FALSE;
531 }
532
533#if 0
534 if (!registry_callback(hInf, L"DelReg", FALSE))
535 {
536 DPRINT1("registry_callback() failed\n");
537 SpInfCloseInfFile(hInf);
538 return FALSE;
539 }
540#endif
541
542 if (!registry_callback(hInf, L"AddReg", FALSE))
543 {
544 DPRINT1("registry_callback() failed\n");
545 SpInfCloseInfFile(hInf);
546 return FALSE;
547 }
548
549 if (!registry_callback(hInf, L"AddReg.NT" INF_ARCH, FALSE))
550 {
551 DPRINT1("registry_callback() failed\n");
552 SpInfCloseInfFile(hInf);
553 return FALSE;
554 }
555
556 SpInfCloseInfFile(hInf);
557 return TRUE;
558}
559
560
561typedef enum _HIVE_UPDATE_STATE
562{
563 Create, // Create a new hive file and save possibly existing old one with a .old extension.
564 Repair, // Re-create a new hive file and save possibly existing old one with a .brk extension.
565 Update // Hive update, do not need to be recreated.
566} HIVE_UPDATE_STATE;
567
568typedef struct _HIVE_LIST_ENTRY
569{
570 PCWSTR HiveName; // HiveFileName;
571 PCWSTR HiveRegistryPath; // HiveRegMountPoint;
572 HANDLE PredefKeyHandle;
573 PCWSTR RegSymLink;
574 HIVE_UPDATE_STATE State;
575 // PUCHAR SecurityDescriptor;
576 // ULONG SecurityDescriptorLength;
577} HIVE_LIST_ENTRY, *PHIVE_LIST_ENTRY;
578
579#define NUMBER_OF_STANDARD_REGISTRY_HIVES 3
580
581HIVE_LIST_ENTRY RegistryHives[/*NUMBER_OF_STANDARD_REGISTRY_HIVES*/] =
582{
583 { L"SYSTEM" , L"\\Registry\\Machine\\USetup_SYSTEM" , HKEY_LOCAL_MACHINE, L"SYSTEM" , Create /* , SystemSecurity , sizeof(SystemSecurity) */ },
584 { L"SOFTWARE", L"\\Registry\\Machine\\USetup_SOFTWARE", HKEY_LOCAL_MACHINE, L"SOFTWARE", Create /* , SoftwareSecurity, sizeof(SoftwareSecurity) */ },
585 { L"DEFAULT" , L"\\Registry\\User\\USetup_DEFAULT" , HKEY_USERS , L".DEFAULT", Create /* , SystemSecurity , sizeof(SystemSecurity) */ },
586
587// { L"BCD" , L"\\Registry\\Machine\\USetup_BCD", HKEY_LOCAL_MACHINE, L"BCD00000000", Create /* , BcdSecurity , sizeof(BcdSecurity) */ },
588};
589C_ASSERT(_countof(RegistryHives) == NUMBER_OF_STANDARD_REGISTRY_HIVES);
590
591#define NUMBER_OF_SECURITY_REGISTRY_HIVES 2
592
593/** These hives are created by LSASS during 2nd stage setup */
594HIVE_LIST_ENTRY SecurityRegistryHives[/*NUMBER_OF_SECURITY_REGISTRY_HIVES*/] =
595{
596 { L"SAM" , L"\\Registry\\Machine\\USetup_SAM" , HKEY_LOCAL_MACHINE, L"SAM" , Create /* , SystemSecurity , sizeof(SystemSecurity) */ },
597 { L"SECURITY", L"\\Registry\\Machine\\USetup_SECURITY", HKEY_LOCAL_MACHINE, L"SECURITY", Create /* , NULL , 0 */ },
598};
599C_ASSERT(_countof(SecurityRegistryHives) == NUMBER_OF_SECURITY_REGISTRY_HIVES);
600
601
602NTSTATUS
603VerifyRegistryHives(
604 IN PUNICODE_STRING NtSystemRoot,
605 OUT PBOOLEAN ShouldRepairRegistry)
606{
607 NTSTATUS Status;
608 BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
609 UINT i;
610
611 /* Suppose first the registry hives do not have to be fully recreated */
612 *ShouldRepairRegistry = FALSE;
613
614 /* Acquire restore privilege */
615 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]);
616 if (!NT_SUCCESS(Status))
617 {
618 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
619 /* Exit prematurely here.... */
620 return Status;
621 }
622
623 /* Acquire backup privilege */
624 Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
625 if (!NT_SUCCESS(Status))
626 {
627 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
628 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
629 /* Exit prematurely here.... */
630 return Status;
631 }
632
633 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
634 {
635 Status = VerifyRegistryHive(NtSystemRoot, RegistryHives[i].HiveName);
636 if (!NT_SUCCESS(Status))
637 {
638 DPRINT1("Registry hive '%S' needs repair!\n", RegistryHives[i].HiveName);
639 RegistryHives[i].State = Repair;
640 *ShouldRepairRegistry = TRUE;
641 }
642 else
643 {
644 RegistryHives[i].State = Update;
645 }
646 }
647
648 /** These hives are created by LSASS during 2nd stage setup */
649 for (i = 0; i < ARRAYSIZE(SecurityRegistryHives); ++i)
650 {
651 Status = VerifyRegistryHive(NtSystemRoot, SecurityRegistryHives[i].HiveName);
652 if (!NT_SUCCESS(Status))
653 {
654 DPRINT1("Registry hive '%S' needs repair!\n", SecurityRegistryHives[i].HiveName);
655 SecurityRegistryHives[i].State = Repair;
656 /*
657 * Note that it's not the role of the 1st-stage installer to fix
658 * the security hives. This should be done at 2nd-stage installation
659 * by LSASS.
660 */
661 }
662 else
663 {
664 SecurityRegistryHives[i].State = Update;
665 }
666 }
667
668 /* Reset the status (we succeeded in checking all the hives) */
669 Status = STATUS_SUCCESS;
670
671 /* Remove restore and backup privileges */
672 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]);
673 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
674
675 return Status;
676}
677
678NTSTATUS
679RegInitializeRegistry(
680 IN PUNICODE_STRING NtSystemRoot)
681{
682 NTSTATUS Status;
683 HANDLE KeyHandle;
684 UNICODE_STRING KeyName;
685 OBJECT_ATTRIBUTES ObjectAttributes;
686 BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
687 ULONG Disposition;
688 UINT i;
689
690 /* Acquire restore privilege */
691 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]);
692 if (!NT_SUCCESS(Status))
693 {
694 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
695 /* Exit prematurely here.... */
696 return Status;
697 }
698
699 /* Acquire backup privilege */
700 Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
701 if (!NT_SUCCESS(Status))
702 {
703 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
704 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
705 /* Exit prematurely here.... */
706 return Status;
707 }
708
709 /*
710 * Create the template proto-hive.
711 *
712 * Use a dummy root key name:
713 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
714 * - On Vista+, this is "CMI-CreateHive{guid}"
715 * See https://github.com/libyal/winreg-kb/blob/main/docs/sources/windows-registry/Files.md
716 * for more information.
717 */
718 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM\\$$$PROTO.HIV");
719 InitializeObjectAttributes(&ObjectAttributes,
720 &KeyName,
721 OBJ_CASE_INSENSITIVE,
722 NULL,
723 NULL);
724 Status = NtCreateKey(&KeyHandle,
725 KEY_ALL_ACCESS,
726 &ObjectAttributes,
727 0,
728 NULL,
729 REG_OPTION_NON_VOLATILE,
730 NULL);
731 if (!NT_SUCCESS(Status))
732 {
733 DPRINT1("NtCreateKey() failed to create the proto-hive (Status %lx)\n", Status);
734 goto Quit;
735 }
736 NtFlushKey(KeyHandle);
737
738 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
739 {
740 if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
741 continue;
742
743 Status = CreateRegistryFile(NtSystemRoot,
744 RegistryHives[i].HiveName,
745 RegistryHives[i].State != Repair, // RegistryHives[i].State == Create,
746 KeyHandle);
747 if (!NT_SUCCESS(Status))
748 {
749 DPRINT1("CreateRegistryFile(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status);
750 /* Exit prematurely here.... */
751 /* That is now done, remove the proto-hive */
752 NtDeleteKey(KeyHandle);
753 NtClose(KeyHandle);
754 goto Quit;
755 }
756 }
757
758 /* That is now done, remove the proto-hive */
759 NtDeleteKey(KeyHandle);
760 NtClose(KeyHandle);
761
762
763 /*
764 * Prepare the registry root keys. Since we cannot create real registry keys
765 * inside the master keys (\Registry, \Registry\Machine or \Registry\User),
766 * we need to perform some SymLink tricks instead.
767 */
768
769 /* Our offline HKLM '\Registry\Machine' is inside '\Registry\Machine\SYSTEM\USetup_Machine' */
770 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].MountPoint);
771 InitializeObjectAttributes(&ObjectAttributes,
772 &KeyName,
773 OBJ_CASE_INSENSITIVE,
774 NULL,
775 NULL);
776 KeyHandle = NULL;
777 Status = NtCreateKey(&KeyHandle,
778 KEY_ALL_ACCESS,
779 &ObjectAttributes,
780 0,
781 NULL,
782 // FIXME: Using REG_OPTION_VOLATILE works OK on Windows,
783 // but I need to check whether it works OK on ReactOS too.
784 REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE,
785 &Disposition);
786 if (!NT_SUCCESS(Status))
787 {
788 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status);
789 // return Status;
790 }
791 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle = KeyHandle;
792
793 /* Our offline HKU '\Registry\User' is inside '\Registry\Machine\SYSTEM\USetup_User' */
794 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_USERS)].MountPoint);
795 InitializeObjectAttributes(&ObjectAttributes,
796 &KeyName,
797 OBJ_CASE_INSENSITIVE,
798 NULL,
799 NULL);
800 KeyHandle = NULL;
801 Status = NtCreateKey(&KeyHandle,
802 KEY_ALL_ACCESS,
803 &ObjectAttributes,
804 0,
805 NULL,
806 // FIXME: Using REG_OPTION_VOLATILE works OK on Windows,
807 // but I need to check whether it works OK on ReactOS too.
808 REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE,
809 &Disposition);
810 if (!NT_SUCCESS(Status))
811 {
812 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status);
813 // return Status;
814 }
815 RootKeys[GetPredefKeyIndex(HKEY_USERS)].Handle = KeyHandle;
816
817
818 /*
819 * Now properly mount the offline hive files
820 */
821 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
822 {
823 // if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
824 // continue;
825
826 if (RegistryHives[i].State == Create || RegistryHives[i].State == Repair)
827 {
828 Status = ConnectRegistry(NULL,
829 RegistryHives[i].HiveRegistryPath,
830 NtSystemRoot,
831 RegistryHives[i].HiveName
832 /* SystemSecurity, sizeof(SystemSecurity) */);
833 if (!NT_SUCCESS(Status))
834 {
835 DPRINT1("ConnectRegistry(%S) failed, Status 0x%08lx\n",
836 RegistryHives[i].HiveName, Status);
837 }
838
839 /* Create the registry symlink to this key */
840 Status = CreateSymLinkKey(RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle,
841 RegistryHives[i].RegSymLink,
842 RegistryHives[i].HiveRegistryPath);
843 if (!NT_SUCCESS(Status))
844 {
845 DPRINT1("CreateSymLinkKey(%S) failed, Status 0x%08lx\n",
846 RegistryHives[i].RegSymLink, Status);
847 }
848 }
849 else
850 {
851 /* Create *DUMMY* volatile hives just to make the update procedure working */
852
853 RtlInitUnicodeString(&KeyName, RegistryHives[i].RegSymLink);
854 InitializeObjectAttributes(&ObjectAttributes,
855 &KeyName,
856 OBJ_CASE_INSENSITIVE,
857 RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle,
858 NULL);
859 KeyHandle = NULL;
860 Status = NtCreateKey(&KeyHandle,
861 KEY_ALL_ACCESS,
862 &ObjectAttributes,
863 0,
864 NULL,
865 // FIXME: Using REG_OPTION_VOLATILE works OK on Windows,
866 // but I need to check whether it works OK on ReactOS too.
867 REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE,
868 &Disposition);
869 if (!NT_SUCCESS(Status))
870 {
871 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status);
872 // return Status;
873 }
874 NtClose(KeyHandle);
875 }
876 }
877
878
879 /* HKCU is a handle to 'HKU\.DEFAULT' */
880#if 0
881 RtlInitUnicodeString(&KeyName, L".DEFAULT");
882 InitializeObjectAttributes(&ObjectAttributes,
883 &KeyName,
884 OBJ_CASE_INSENSITIVE,
885 RootKeys[GetPredefKeyIndex(HKEY_USERS)].Handle,
886 NULL);
887#else
888 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_CURRENT_USER)].MountPoint);
889 InitializeObjectAttributes(&ObjectAttributes,
890 &KeyName,
891 OBJ_CASE_INSENSITIVE,
892 NULL,
893 NULL);
894#endif
895 KeyHandle = NULL;
896 Status = NtOpenKey(&KeyHandle,
897 KEY_ALL_ACCESS,
898 &ObjectAttributes);
899 if (!NT_SUCCESS(Status))
900 {
901 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &KeyName, Status);
902 }
903 RootKeys[GetPredefKeyIndex(HKEY_CURRENT_USER)].Handle = KeyHandle;
904
905
906 /* HKCR is a handle to 'HKLM\Software\Classes' */
907#if 0
908 RtlInitUnicodeString(&KeyName, L"Software\\Classes");
909 InitializeObjectAttributes(&ObjectAttributes,
910 &KeyName,
911 OBJ_CASE_INSENSITIVE,
912 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
913 NULL);
914#else
915 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_CLASSES_ROOT)].MountPoint);
916 InitializeObjectAttributes(&ObjectAttributes,
917 &KeyName,
918 OBJ_CASE_INSENSITIVE,
919 NULL,
920 NULL);
921#endif
922 KeyHandle = NULL;
923 /* We use NtCreateKey instead of NtOpenKey because Software\Classes doesn't exist originally */
924 Status = NtCreateKey(&KeyHandle,
925 KEY_ALL_ACCESS,
926 &ObjectAttributes,
927 0,
928 NULL,
929 REG_OPTION_NON_VOLATILE,
930 &Disposition);
931 if (!NT_SUCCESS(Status))
932 {
933 DPRINT1("NtCreateKey(%wZ) failed (Status %lx)\n", &KeyName, Status);
934 }
935 else
936 {
937 DPRINT("NtCreateKey() succeeded to %s the %wZ key (Status %lx)\n",
938 Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
939 &KeyName, Status);
940 }
941 RootKeys[GetPredefKeyIndex(HKEY_CLASSES_ROOT)].Handle = KeyHandle;
942
943
944 Status = STATUS_SUCCESS;
945
946
947 /* Create the 'HKLM\SYSTEM\ControlSet001' key */
948 // REGISTRY_SETUP_MACHINE L"SYSTEM\\ControlSet001"
949 RtlInitUnicodeString(&KeyName, L"SYSTEM\\ControlSet001");
950 InitializeObjectAttributes(&ObjectAttributes,
951 &KeyName,
952 OBJ_CASE_INSENSITIVE,
953 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
954 NULL);
955 Status = NtCreateKey(&KeyHandle,
956 KEY_ALL_ACCESS,
957 &ObjectAttributes,
958 0,
959 NULL,
960 REG_OPTION_NON_VOLATILE,
961 &Disposition);
962 if (!NT_SUCCESS(Status))
963 {
964 DPRINT1("NtCreateKey() failed to create the ControlSet001 key (Status %lx)\n", Status);
965 // return Status;
966 }
967 else
968 {
969 DPRINT("NtCreateKey() succeeded to %s the ControlSet001 key (Status %lx)\n",
970 Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
971 Status);
972 }
973 NtClose(KeyHandle);
974
975 /* Create the 'HKLM\SYSTEM\CurrentControlSet' symlink */
976 Status = CreateSymLinkKey(RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
977 L"SYSTEM\\CurrentControlSet",
978 REGISTRY_SETUP_MACHINE L"SYSTEM\\ControlSet001");
979 if (!NT_SUCCESS(Status))
980 {
981 DPRINT1("CreateSymLinkKey(CurrentControlSet) failed, Status 0x%08lx\n", Status);
982 }
983
984
985 Status = STATUS_SUCCESS;
986
987
988Quit:
989 /* Remove restore and backup privileges */
990 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]);
991 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
992
993 return Status;
994}
995
996VOID
997RegCleanupRegistry(
998 IN PUNICODE_STRING NtSystemRoot)
999{
1000 NTSTATUS Status;
1001 HANDLE KeyHandle;
1002 UNICODE_STRING KeyName;
1003 OBJECT_ATTRIBUTES ObjectAttributes;
1004 BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
1005 UINT i;
1006 WCHAR SrcPath[MAX_PATH];
1007 WCHAR DstPath[MAX_PATH];
1008
1009 /* Acquire restore privilege */
1010 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]);
1011 if (!NT_SUCCESS(Status))
1012 {
1013 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1014 /* Exit prematurely here.... */
1015 return;
1016 }
1017
1018 /* Acquire backup privilege */
1019 Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
1020 if (!NT_SUCCESS(Status))
1021 {
1022 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1023 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1024 /* Exit prematurely here.... */
1025 return;
1026 }
1027
1028 /*
1029 * To keep the running system clean we need first to remove the symlinks
1030 * we have created and then unmounting the hives. Finally we delete the
1031 * master registry keys.
1032 */
1033
1034 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1035 {
1036 if (RegistryHives[i].State == Create || RegistryHives[i].State == Repair)
1037 {
1038 /* Delete the registry symlink to this key */
1039 Status = DeleteSymLinkKey(RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle,
1040 RegistryHives[i].RegSymLink);
1041 if (!NT_SUCCESS(Status))
1042 {
1043 DPRINT1("DeleteSymLinkKey(%S) failed, Status 0x%08lx\n",
1044 RegistryHives[i].RegSymLink, Status);
1045 }
1046
1047 /* Unmount the hive */
1048 Status = DisconnectRegistry(NULL,
1049 RegistryHives[i].HiveRegistryPath,
1050 1 /* REG_FORCE_UNLOAD */);
1051 if (!NT_SUCCESS(Status))
1052 {
1053 DPRINT1("Unmounting '%S' failed\n", RegistryHives[i].HiveRegistryPath);
1054 }
1055
1056 /* Switch the hive state to 'Update' */
1057 RegistryHives[i].State = Update;
1058 }
1059 else
1060 {
1061 /* Delete the *DUMMY* volatile hives created for the update procedure */
1062
1063 RtlInitUnicodeString(&KeyName, RegistryHives[i].RegSymLink);
1064 InitializeObjectAttributes(&ObjectAttributes,
1065 &KeyName,
1066 OBJ_CASE_INSENSITIVE,
1067 RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle,
1068 NULL);
1069 KeyHandle = NULL;
1070 Status = NtOpenKey(&KeyHandle,
1071 DELETE,
1072 &ObjectAttributes);
1073 if (!NT_SUCCESS(Status))
1074 {
1075 DPRINT1("NtOpenKey(%wZ) failed, Status 0x%08lx\n", &KeyName, Status);
1076 // return;
1077 }
1078
1079 NtDeleteKey(KeyHandle);
1080 NtClose(KeyHandle);
1081 }
1082 }
1083
1084 /*
1085 * FIXME: Once force-unloading keys is correctly fixed, I'll fix
1086 * this code that closes some of the registry keys that were opened
1087 * inside the hives we've just unmounted above...
1088 */
1089
1090 /* Remove the registry root keys */
1091 for (i = 0; i < ARRAYSIZE(RootKeys); ++i)
1092 {
1093 if (RootKeys[i].Handle)
1094 {
1095 /**/NtFlushKey(RootKeys[i].Handle);/**/ // FIXME: Why does it hang? Answer: because we have some problems in CMAPI!
1096 NtDeleteKey(RootKeys[i].Handle);
1097 NtClose(RootKeys[i].Handle);
1098 RootKeys[i].Handle = NULL;
1099 }
1100 }
1101
1102 //
1103 // RegBackupRegistry()
1104 //
1105 /* Now backup the hives into .sav files */
1106 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1107 {
1108 if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
1109 continue;
1110
1111 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 3,
1112 NtSystemRoot->Buffer, L"System32\\config", RegistryHives[i].HiveName);
1113 RtlStringCchCopyW(DstPath, ARRAYSIZE(DstPath), SrcPath);
1114 RtlStringCchCatW(DstPath, ARRAYSIZE(DstPath), L".sav");
1115
1116 DPRINT1("Copy hive: %S ==> %S\n", SrcPath, DstPath);
1117 Status = SetupCopyFile(SrcPath, DstPath, FALSE);
1118 if (!NT_SUCCESS(Status))
1119 {
1120 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
1121 // return Status;
1122 }
1123 }
1124
1125 /* Remove restore and backup privileges */
1126 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]);
1127 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1128}
1129
1130/* EOF */