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
63 typedef struct _ROOT_KEY
64 {
65 PCWSTR Name;
66 PCWSTR MountPoint;
67 HANDLE Handle;
68 } ROOT_KEY, *PROOT_KEY;
69
70 ROOT_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
89 HANDLE
GetRootKeyByPredefKey(IN HANDLE KeyHandle,OUT PCWSTR * RootKeyMountPoint OPTIONAL)90 GetRootKeyByPredefKey(
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
106 HANDLE
GetRootKeyByName(IN PCWSTR RootKeyName,OUT PCWSTR * RootKeyMountPoint OPTIONAL)107 GetRootKeyByName(
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
134 static void
135 append_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
182 static 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 */
221 static BOOLEAN
do_reg_operation(HANDLE KeyHandle,PUNICODE_STRING ValueName,PINFCONTEXT Context,ULONG Flags)222 do_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 */
411 static BOOLEAN
registry_callback(HINF hInf,PCWSTR Section,BOOLEAN Delete)412 registry_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
506 BOOLEAN
ImportRegistryFile(IN PCWSTR SourcePath,IN PCWSTR FileName,IN PCWSTR Section,IN LCID LocaleId,IN BOOLEAN Delete)507 ImportRegistryFile(
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
561 typedef 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
568 typedef 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
581 HIVE_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 };
589 C_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 */
594 HIVE_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 };
599 C_ASSERT(_countof(SecurityRegistryHives) == NUMBER_OF_SECURITY_REGISTRY_HIVES);
600
601
602 NTSTATUS
VerifyRegistryHives(IN PUNICODE_STRING NtSystemRoot,OUT PBOOLEAN ShouldRepairRegistry)603 VerifyRegistryHives(
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
678 NTSTATUS
RegInitializeRegistry(IN PUNICODE_STRING NtSystemRoot)679 RegInitializeRegistry(
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/master/documentation/Registry%20files.asciidoc
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
988 Quit:
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
996 VOID
RegCleanupRegistry(IN PUNICODE_STRING NtSystemRoot)997 RegCleanupRegistry(
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 */
1131