[USETUP] Implement work-in-progress code that allows verifying whether registry hives...
[reactos.git] / base / setup / usetup / registry.c
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 text-mode setup
22 * FILE: base/setup/usetup/registry.c
23 * PURPOSE: Registry creation functions
24 * PROGRAMMER:
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "usetup.h"
30
31 // HACK!
32 #include <strsafe.h>
33
34 #define NDEBUG
35 #include <debug.h>
36
37 #define FLG_ADDREG_BINVALUETYPE 0x00000001
38 #define FLG_ADDREG_NOCLOBBER 0x00000002
39 #define FLG_ADDREG_DELVAL 0x00000004
40 #define FLG_ADDREG_APPEND 0x00000008
41 #define FLG_ADDREG_KEYONLY 0x00000010
42 #define FLG_ADDREG_OVERWRITEONLY 0x00000020
43 #define FLG_ADDREG_TYPE_SZ 0x00000000
44 #define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000
45 #define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000
46 #define FLG_ADDREG_TYPE_BINARY (0x00000000 | FLG_ADDREG_BINVALUETYPE)
47 #define FLG_ADDREG_TYPE_DWORD (0x00010000 | FLG_ADDREG_BINVALUETYPE)
48 #define FLG_ADDREG_TYPE_NONE (0x00020000 | FLG_ADDREG_BINVALUETYPE)
49 #define FLG_ADDREG_TYPE_MASK (0xFFFF0000 | FLG_ADDREG_BINVALUETYPE)
50
51 #ifdef _M_IX86
52 #define Architecture L"x86"
53 #elif defined(_M_AMD64)
54 #define Architecture L"amd64"
55 #elif defined(_M_IA64)
56 #define Architecture L"ia64"
57 #elif defined(_M_ARM)
58 #define Architecture L"arm"
59 #elif defined(_M_PPC)
60 #define Architecture L"ppc"
61 #endif
62
63 /* FUNCTIONS ****************************************************************/
64
65 #define REGISTRY_SETUP_MACHINE L"\\Registry\\Machine\\SYSTEM\\USetup_Machine\\"
66 #define REGISTRY_SETUP_USER L"\\Registry\\Machine\\SYSTEM\\USetup_User\\"
67
68 typedef struct _ROOT_KEY
69 {
70 PCWSTR Name;
71 PCWSTR MountPoint;
72 HANDLE Handle;
73 } ROOT_KEY, *PROOT_KEY;
74
75 ROOT_KEY RootKeys[] =
76 {
77 { L"HKCR", REGISTRY_SETUP_MACHINE L"SOFTWARE\\Classes\\", NULL }, /* "\\Registry\\Machine\\SOFTWARE\\Classes\\" */ // HKEY_CLASSES_ROOT
78 { L"HKCU", REGISTRY_SETUP_USER L".DEFAULT\\" , NULL }, /* "\\Registry\\User\\.DEFAULT\\" */ // HKEY_CURRENT_USER
79 { L"HKLM", REGISTRY_SETUP_MACHINE , NULL }, /* "\\Registry\\Machine\\" */ // HKEY_LOCAL_MACHINE
80 { L"HKU" , REGISTRY_SETUP_USER , NULL }, /* "\\Registry\\User\\" */ // HKEY_USERS
81 #if 0
82 { L"HKR", NULL, NULL },
83 #endif
84 };
85
86 #define IsPredefKey(HKey) \
87 (((ULONG_PTR)(HKey) & 0xF0000000) == 0x80000000)
88
89 #define GetPredefKeyIndex(HKey) \
90 ((ULONG_PTR)(HKey) & 0x0FFFFFFF)
91
92 HANDLE
93 GetRootKeyByPredefKey(
94 IN HANDLE KeyHandle,
95 OUT PCWSTR* RootKeyMountPoint OPTIONAL)
96 {
97 ULONG_PTR Index = GetPredefKeyIndex(KeyHandle);
98
99 if (!IsPredefKey(KeyHandle))
100 return NULL;
101 if (GetPredefKeyIndex(KeyHandle) >= ARRAYSIZE(RootKeys))
102 return NULL;
103
104 if (RootKeyMountPoint)
105 *RootKeyMountPoint = RootKeys[Index].MountPoint;
106 return RootKeys[Index].Handle;
107 }
108
109 HANDLE
110 GetRootKeyByName(
111 IN PCWSTR RootKeyName,
112 OUT PCWSTR* RootKeyMountPoint OPTIONAL)
113 {
114 UCHAR i;
115
116 for (i = 0; i < ARRAYSIZE(RootKeys); ++i)
117 {
118 if (!_wcsicmp(RootKeyName, RootKeys[i].Name))
119 {
120 if (RootKeyMountPoint)
121 *RootKeyMountPoint = RootKeys[i].MountPoint;
122 return RootKeys[i].Handle;
123 }
124 }
125
126 return NULL;
127 }
128
129
130 /***********************************************************************
131 * append_multi_sz_value
132 *
133 * Append a multisz string to a multisz registry value.
134 */
135 // NOTE: Synced with setupapi/install.c ; see also mkhive/reginf.c
136 #if 0
137 static void
138 append_multi_sz_value (HANDLE hkey,
139 const WCHAR *value,
140 const WCHAR *strings,
141 DWORD str_size )
142 {
143 DWORD size, type, total;
144 WCHAR *buffer, *p;
145
146 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
147 if (type != REG_MULTI_SZ) return;
148
149 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size + str_size * sizeof(WCHAR) ))) return;
150 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
151
152 /* compare each string against all the existing ones */
153 total = size;
154 while (*strings)
155 {
156 int len = strlenW(strings) + 1;
157
158 for (p = buffer; *p; p += strlenW(p) + 1)
159 if (!strcmpiW( p, strings )) break;
160
161 if (!*p) /* not found, need to append it */
162 {
163 memcpy( p, strings, len * sizeof(WCHAR) );
164 p[len] = 0;
165 total += len;
166 }
167 strings += len;
168 }
169 if (total != size)
170 {
171 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
172 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
173 }
174 done:
175 HeapFree( GetProcessHeap(), 0, buffer );
176 }
177 #endif
178
179 /***********************************************************************
180 * delete_multi_sz_value
181 *
182 * Remove a string from a multisz registry value.
183 */
184 #if 0
185 static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
186 {
187 DWORD size, type;
188 WCHAR *buffer, *src, *dst;
189
190 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
191 if (type != REG_MULTI_SZ) return;
192 /* allocate double the size, one for value before and one for after */
193 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
194 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
195 src = buffer;
196 dst = buffer + size;
197 while (*src)
198 {
199 int len = strlenW(src) + 1;
200 if (strcmpiW( src, string ))
201 {
202 memcpy( dst, src, len * sizeof(WCHAR) );
203 dst += len;
204 }
205 src += len;
206 }
207 *dst++ = 0;
208 if (dst != buffer + 2*size) /* did we remove something? */
209 {
210 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
211 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
212 (BYTE *)(buffer + size), dst - (buffer + size) );
213 }
214 done:
215 HeapFree( GetProcessHeap(), 0, buffer );
216 }
217 #endif
218
219 /***********************************************************************
220 * do_reg_operation
221 *
222 * Perform an add/delete registry operation depending on the flags.
223 */
224 static BOOLEAN
225 do_reg_operation(HANDLE KeyHandle,
226 PUNICODE_STRING ValueName,
227 PINFCONTEXT Context,
228 ULONG Flags)
229 {
230 WCHAR EmptyStr = 0;
231 ULONG Type;
232 ULONG Size;
233
234 if (Flags & FLG_ADDREG_DELVAL) /* deletion */
235 {
236 #if 0
237 if (ValueName)
238 {
239 RegDeleteValueW( KeyHandle, ValueName );
240 }
241 else
242 {
243 RegDeleteKeyW( KeyHandle, NULL );
244 }
245 #endif
246 return TRUE;
247 }
248
249 if (Flags & FLG_ADDREG_KEYONLY)
250 return TRUE;
251
252 #if 0
253 if (Flags & (FLG_ADDREG_NOCLOBBER | FLG_ADDREG_OVERWRITEONLY))
254 {
255 BOOL exists = !RegQueryValueExW( hkey, ValueName, NULL, NULL, NULL, NULL );
256 if (exists && (flags & FLG_ADDREG_NOCLOBBER))
257 return TRUE;
258 if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY))
259 return TRUE;
260 }
261 #endif
262
263 switch (Flags & FLG_ADDREG_TYPE_MASK)
264 {
265 case FLG_ADDREG_TYPE_SZ:
266 Type = REG_SZ;
267 break;
268
269 case FLG_ADDREG_TYPE_MULTI_SZ:
270 Type = REG_MULTI_SZ;
271 break;
272
273 case FLG_ADDREG_TYPE_EXPAND_SZ:
274 Type = REG_EXPAND_SZ;
275 break;
276
277 case FLG_ADDREG_TYPE_BINARY:
278 Type = REG_BINARY;
279 break;
280
281 case FLG_ADDREG_TYPE_DWORD:
282 Type = REG_DWORD;
283 break;
284
285 case FLG_ADDREG_TYPE_NONE:
286 Type = REG_NONE;
287 break;
288
289 default:
290 Type = Flags >> 16;
291 break;
292 }
293
294 if (!(Flags & FLG_ADDREG_BINVALUETYPE) ||
295 (Type == REG_DWORD && SetupGetFieldCount (Context) == 5))
296 {
297 PWCHAR Str = NULL;
298
299 if (Type == REG_MULTI_SZ)
300 {
301 if (!SetupGetMultiSzFieldW (Context, 5, NULL, 0, &Size))
302 Size = 0;
303
304 if (Size)
305 {
306 Str = (WCHAR*) RtlAllocateHeap(ProcessHeap, 0, Size * sizeof(WCHAR));
307 if (Str == NULL)
308 return FALSE;
309
310 SetupGetMultiSzFieldW (Context, 5, Str, Size, NULL);
311 }
312
313 if (Flags & FLG_ADDREG_APPEND)
314 {
315 if (Str == NULL)
316 return TRUE;
317
318 DPRINT1("append_multi_sz_value '%S' commented out, WHY??\n", ValueName);
319 // append_multi_sz_value( hkey, value, str, size );
320
321 RtlFreeHeap (ProcessHeap, 0, Str);
322 return TRUE;
323 }
324 /* else fall through to normal string handling */
325 }
326 else
327 {
328 if (!SetupGetStringFieldW(Context, 5, NULL, 0, &Size))
329 Size = 0;
330
331 if (Size)
332 {
333 Str = (WCHAR*)RtlAllocateHeap(ProcessHeap, 0, Size * sizeof(WCHAR));
334 if (Str == NULL)
335 return FALSE;
336
337 SetupGetStringFieldW(Context, 5, Str, Size, NULL);
338 }
339 }
340
341 if (Type == REG_DWORD)
342 {
343 ULONG dw = Str ? wcstoul (Str, NULL, 0) : 0;
344
345 DPRINT("setting dword %wZ to %lx\n", ValueName, dw);
346
347 NtSetValueKey (KeyHandle,
348 ValueName,
349 0,
350 Type,
351 (PVOID)&dw,
352 sizeof(ULONG));
353 }
354 else
355 {
356 DPRINT("setting value %wZ to %S\n", ValueName, Str);
357
358 if (Str)
359 {
360 NtSetValueKey (KeyHandle,
361 ValueName,
362 0,
363 Type,
364 (PVOID)Str,
365 Size * sizeof(WCHAR));
366 }
367 else
368 {
369 NtSetValueKey (KeyHandle,
370 ValueName,
371 0,
372 Type,
373 (PVOID)&EmptyStr,
374 sizeof(WCHAR));
375 }
376 }
377 RtlFreeHeap (ProcessHeap, 0, Str);
378 }
379 else /* get the binary data */
380 {
381 PUCHAR Data = NULL;
382
383 if (!SetupGetBinaryField (Context, 5, NULL, 0, &Size))
384 Size = 0;
385
386 if (Size)
387 {
388 Data = (unsigned char*) RtlAllocateHeap(ProcessHeap, 0, Size);
389 if (Data == NULL)
390 return FALSE;
391
392 DPRINT("setting binary data %wZ len %lu\n", ValueName, Size);
393 SetupGetBinaryField (Context, 5, Data, Size, NULL);
394 }
395
396 NtSetValueKey (KeyHandle,
397 ValueName,
398 0,
399 Type,
400 (PVOID)Data,
401 Size);
402
403 RtlFreeHeap (ProcessHeap, 0, Data);
404 }
405
406 return TRUE;
407 }
408
409 /*
410 * This function is similar to the one in dlls/win32/advapi32/reg/reg.c
411 * TODO: I should review both of them very carefully, because they may need
412 * some adjustments in their NtCreateKey calls, especially for CreateOptions
413 * stuff etc...
414 */
415 NTSTATUS
416 CreateNestedKey(PHANDLE KeyHandle,
417 ACCESS_MASK DesiredAccess,
418 POBJECT_ATTRIBUTES ObjectAttributes,
419 ULONG CreateOptions)
420 {
421 OBJECT_ATTRIBUTES LocalObjectAttributes;
422 UNICODE_STRING LocalKeyName;
423 ULONG Disposition;
424 NTSTATUS Status;
425 USHORT FullNameLength;
426 PWCHAR Ptr;
427 HANDLE LocalKeyHandle;
428
429 Status = NtCreateKey(KeyHandle,
430 KEY_ALL_ACCESS,
431 ObjectAttributes,
432 0,
433 NULL,
434 CreateOptions,
435 &Disposition);
436 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", ObjectAttributes->ObjectName, Status);
437 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
438 {
439 if (!NT_SUCCESS(Status))
440 DPRINT1("CreateNestedKey: NtCreateKey(%wZ) failed (Status %lx)\n", ObjectAttributes->ObjectName, Status);
441
442 return Status;
443 }
444
445 /* Copy object attributes */
446 RtlCopyMemory(&LocalObjectAttributes,
447 ObjectAttributes,
448 sizeof(OBJECT_ATTRIBUTES));
449 RtlCreateUnicodeString(&LocalKeyName,
450 ObjectAttributes->ObjectName->Buffer);
451 LocalObjectAttributes.ObjectName = &LocalKeyName;
452 FullNameLength = LocalKeyName.Length;
453
454 /* Remove the last part of the key name and try to create the key again. */
455 while (Status == STATUS_OBJECT_NAME_NOT_FOUND)
456 {
457 Ptr = wcsrchr(LocalKeyName.Buffer, '\\');
458 if (Ptr == NULL || Ptr == LocalKeyName.Buffer)
459 {
460 Status = STATUS_UNSUCCESSFUL;
461 break;
462 }
463 *Ptr = (WCHAR)0;
464 LocalKeyName.Length = wcslen(LocalKeyName.Buffer) * sizeof(WCHAR);
465
466 Status = NtCreateKey(&LocalKeyHandle,
467 KEY_CREATE_SUB_KEY,
468 &LocalObjectAttributes,
469 0,
470 NULL,
471 REG_OPTION_NON_VOLATILE,
472 &Disposition);
473 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
474 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND)
475 DPRINT1("CreateNestedKey: NtCreateKey(%wZ) failed (Status %lx)\n", LocalObjectAttributes.ObjectName, Status);
476 }
477
478 if (!NT_SUCCESS(Status))
479 {
480 RtlFreeUnicodeString(&LocalKeyName);
481 return Status;
482 }
483
484 /* Add removed parts of the key name and create them too. */
485 while (TRUE)
486 {
487 if (LocalKeyName.Length == FullNameLength)
488 {
489 Status = STATUS_SUCCESS;
490 *KeyHandle = LocalKeyHandle;
491 break;
492 }
493 NtClose(LocalKeyHandle);
494
495 LocalKeyName.Buffer[LocalKeyName.Length / sizeof(WCHAR)] = L'\\';
496 LocalKeyName.Length = wcslen(LocalKeyName.Buffer) * sizeof(WCHAR);
497
498 Status = NtCreateKey(&LocalKeyHandle,
499 KEY_ALL_ACCESS,
500 &LocalObjectAttributes,
501 0,
502 NULL,
503 CreateOptions,
504 &Disposition);
505 DPRINT("NtCreateKey(%wZ) called (Status %lx)\n", &LocalKeyName, Status);
506 if (!NT_SUCCESS(Status))
507 {
508 DPRINT1("CreateNestedKey: NtCreateKey(%wZ) failed (Status %lx)\n", LocalObjectAttributes.ObjectName, Status);
509 break;
510 }
511 }
512
513 RtlFreeUnicodeString(&LocalKeyName);
514
515 return Status;
516 }
517
518 /***********************************************************************
519 * registry_callback
520 *
521 * Called once for each AddReg and DelReg entry in a given section.
522 */
523 static BOOLEAN
524 registry_callback(HINF hInf, PCWSTR Section, BOOLEAN Delete)
525 {
526 NTSTATUS Status;
527 OBJECT_ATTRIBUTES ObjectAttributes;
528 UNICODE_STRING Name, Value;
529 PUNICODE_STRING ValuePtr;
530 UINT Flags;
531 WCHAR Buffer[MAX_INF_STRING_LENGTH];
532
533 INFCONTEXT Context;
534 PCWSTR RootKeyName;
535 HANDLE RootKeyHandle, KeyHandle;
536 BOOLEAN Ok;
537
538 Ok = SetupFindFirstLineW(hInf, Section, NULL, &Context);
539 if (!Ok)
540 return TRUE; /* Don't fail if the section isn't present */
541
542 for (;Ok; Ok = SetupFindNextLine (&Context, &Context))
543 {
544 /* get root */
545 if (!SetupGetStringFieldW(&Context, 1, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL))
546 continue;
547 RootKeyHandle = GetRootKeyByName(Buffer, &RootKeyName);
548 if (!RootKeyHandle)
549 continue;
550
551 /* get key */
552 if (!SetupGetStringFieldW(&Context, 2, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL))
553 *Buffer = 0;
554
555 DPRINT("KeyName: <%S\\%S>\n", RootKeyName, Buffer);
556
557 /* get flags */
558 if (!SetupGetIntField(&Context, 4, (PINT)&Flags))
559 Flags = 0;
560
561 DPRINT("Flags: %lx\n", Flags);
562
563 RtlInitUnicodeString(&Name, Buffer);
564 InitializeObjectAttributes(&ObjectAttributes,
565 &Name,
566 OBJ_CASE_INSENSITIVE,
567 RootKeyHandle,
568 NULL);
569
570 if (Delete || (Flags & FLG_ADDREG_OVERWRITEONLY))
571 {
572 Status = NtOpenKey(&KeyHandle,
573 KEY_ALL_ACCESS,
574 &ObjectAttributes);
575 if (!NT_SUCCESS(Status))
576 {
577 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &Name, Status);
578 continue; /* ignore if it doesn't exist */
579 }
580 }
581 else
582 {
583 Status = CreateNestedKey(&KeyHandle,
584 KEY_ALL_ACCESS,
585 &ObjectAttributes,
586 REG_OPTION_NON_VOLATILE);
587 if (!NT_SUCCESS(Status))
588 {
589 DPRINT1("CreateNestedKey(%wZ) failed (Status %lx)\n", &Name, Status);
590 continue;
591 }
592 }
593
594 /* get value name */
595 if (SetupGetStringFieldW(&Context, 3, Buffer, sizeof(Buffer)/sizeof(WCHAR), NULL))
596 {
597 RtlInitUnicodeString(&Value, Buffer);
598 ValuePtr = &Value;
599 }
600 else
601 {
602 ValuePtr = NULL;
603 }
604
605 /* and now do it */
606 if (!do_reg_operation(KeyHandle, ValuePtr, &Context, Flags))
607 {
608 NtClose(KeyHandle);
609 return FALSE;
610 }
611
612 NtClose(KeyHandle);
613 }
614
615 return TRUE;
616 }
617
618
619 BOOLEAN
620 ImportRegistryFile(
621 PWSTR Filename,
622 PWSTR Section,
623 LCID LocaleId,
624 BOOLEAN Delete)
625 {
626 WCHAR FileNameBuffer[MAX_PATH];
627 HINF hInf;
628 UINT ErrorLine;
629
630 /* Load inf file from install media. */
631 CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2,
632 SourcePath.Buffer, Filename);
633
634 hInf = SetupOpenInfFileW(FileNameBuffer,
635 NULL,
636 INF_STYLE_WIN4,
637 LocaleId,
638 &ErrorLine);
639 if (hInf == INVALID_HANDLE_VALUE)
640 {
641 DPRINT1("SetupOpenInfFile() failed\n");
642 return FALSE;
643 }
644
645 #if 0
646 if (!registry_callback(hInf, L"DelReg", FALSE))
647 {
648 DPRINT1("registry_callback() failed\n");
649 InfCloseFile(hInf);
650 return FALSE;
651 }
652 #endif
653
654 if (!registry_callback(hInf, L"AddReg", FALSE))
655 {
656 DPRINT1("registry_callback() failed\n");
657 InfCloseFile(hInf);
658 return FALSE;
659 }
660
661 if (!registry_callback(hInf, L"AddReg.NT" Architecture, FALSE))
662 {
663 DPRINT1("registry_callback() failed\n");
664 InfCloseFile(hInf);
665 return FALSE;
666 }
667
668 InfCloseFile(hInf);
669 return TRUE;
670 }
671
672 /*
673 * Should be called under privileges
674 */
675 static NTSTATUS
676 CreateRegistryFile(
677 IN PUNICODE_STRING InstallPath,
678 IN PCWSTR RegistryKey,
679 IN BOOLEAN IsHiveNew,
680 IN HANDLE ProtoKeyHandle
681 /*
682 IN PUCHAR Descriptor,
683 IN ULONG DescriptorLength
684 */
685 )
686 {
687 /* '.old' is for old valid hives, while '.brk' is for old broken hives */
688 static PCWSTR Extensions[] = {L"old", L"brk"};
689
690 NTSTATUS Status;
691 HANDLE FileHandle;
692 UNICODE_STRING FileName;
693 OBJECT_ATTRIBUTES ObjectAttributes;
694 IO_STATUS_BLOCK IoStatusBlock;
695 PCWSTR Extension;
696 WCHAR PathBuffer[MAX_PATH];
697 WCHAR PathBuffer2[MAX_PATH];
698
699 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 3,
700 InstallPath->Buffer, L"System32\\config", RegistryKey);
701
702 Extension = Extensions[IsHiveNew ? 0 : 1];
703
704 //
705 // FIXME: The best, actually, would be to rename (move) the existing
706 // System32\config\RegistryKey file to System32\config\RegistryKey.old,
707 // and if it already existed some System32\config\RegistryKey.old, we should
708 // first rename this one into System32\config\RegistryKey_N.old before
709 // performing the original rename.
710 //
711
712 /* Check whether the registry hive file already existed, and if so, rename it */
713 if (DoesFileExist(NULL, PathBuffer))
714 {
715 // UINT i;
716
717 DPRINT1("Registry hive '%S' already exists, rename it\n", PathBuffer);
718
719 // i = 1;
720 /* Try first by just appending the '.old' extension */
721 StringCchPrintfW(PathBuffer2, ARRAYSIZE(PathBuffer2), L"%s.%s", PathBuffer, Extension);
722 #if 0
723 while (DoesFileExist(NULL, PathBuffer2))
724 {
725 /* An old file already exists, increments its index, but not too much */
726 if (i <= 0xFFFF)
727 {
728 /* Append '_N.old' extension */
729 StringCchPrintfW(PathBuffer2, ARRAYSIZE(PathBuffer2), L"%s_%lu.%s", PathBuffer, i, Extension);
730 ++i;
731 }
732 else
733 {
734 /*
735 * Too many old files exist, we will rename the file
736 * using the name of the oldest one.
737 */
738 StringCchPrintfW(PathBuffer2, ARRAYSIZE(PathBuffer2), L"%s.%s", PathBuffer, Extension);
739 break;
740 }
741 }
742 #endif
743
744 /* Now rename the file (force the move) */
745 Status = SetupMoveFile(PathBuffer, PathBuffer2, MOVEFILE_REPLACE_EXISTING);
746 }
747
748 /* Create the file */
749 RtlInitUnicodeString(&FileName, PathBuffer);
750 InitializeObjectAttributes(&ObjectAttributes,
751 &FileName,
752 OBJ_CASE_INSENSITIVE,
753 NULL, // Could have been installpath, etc...
754 NULL); // Descriptor
755
756 Status = NtCreateFile(&FileHandle,
757 FILE_GENERIC_WRITE,
758 &ObjectAttributes,
759 &IoStatusBlock,
760 NULL,
761 FILE_ATTRIBUTE_NORMAL,
762 0,
763 FILE_OVERWRITE_IF,
764 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
765 NULL,
766 0);
767 if (!NT_SUCCESS(Status))
768 {
769 DPRINT1("NtCreateFile(%wZ) failed, Status 0x%08lx\n", &FileName, Status);
770 return Status;
771 }
772
773 /* Save the selected hive into the file */
774 Status = NtSaveKeyEx(ProtoKeyHandle, FileHandle, REG_LATEST_FORMAT);
775 if (!NT_SUCCESS(Status))
776 {
777 DPRINT1("NtSaveKeyEx(%wZ) failed, Status 0x%08lx\n", &FileName, Status);
778 }
779
780 /* Close the file and return */
781 NtClose(FileHandle);
782 return Status;
783 }
784
785 static BOOLEAN
786 CmpLinkKeyToHive(
787 IN HANDLE RootLinkKeyHandle OPTIONAL,
788 IN PCWSTR LinkKeyName,
789 IN PCWSTR TargetKeyName)
790 {
791 static UNICODE_STRING CmSymbolicLinkValueName =
792 RTL_CONSTANT_STRING(L"SymbolicLinkValue");
793
794 NTSTATUS Status;
795 OBJECT_ATTRIBUTES ObjectAttributes;
796 UNICODE_STRING KeyName;
797 HANDLE TargetKeyHandle;
798 ULONG Disposition;
799
800 /* Initialize the object attributes */
801 RtlInitUnicodeString(&KeyName, LinkKeyName);
802 InitializeObjectAttributes(&ObjectAttributes,
803 &KeyName,
804 OBJ_CASE_INSENSITIVE,
805 RootLinkKeyHandle,
806 NULL);
807
808 /* Create the link key */
809 Status = NtCreateKey(&TargetKeyHandle,
810 KEY_SET_VALUE | KEY_CREATE_LINK,
811 &ObjectAttributes,
812 0,
813 NULL,
814 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
815 &Disposition);
816 if (!NT_SUCCESS(Status))
817 {
818 DPRINT1("CmpLinkKeyToHive: couldn't create %S, Status = 0x%08lx\n",
819 LinkKeyName, Status);
820 return FALSE;
821 }
822
823 /* Check if the new key was actually created */
824 if (Disposition != REG_CREATED_NEW_KEY)
825 {
826 DPRINT1("CmpLinkKeyToHive: %S already exists!\n", LinkKeyName);
827 NtClose(TargetKeyHandle);
828 return FALSE;
829 }
830
831 /* Set the target key name as link target */
832 RtlInitUnicodeString(&KeyName, TargetKeyName);
833 Status = NtSetValueKey(TargetKeyHandle,
834 &CmSymbolicLinkValueName,
835 0,
836 REG_LINK,
837 KeyName.Buffer,
838 KeyName.Length);
839
840 /* Close the link key handle */
841 NtClose(TargetKeyHandle);
842
843 if (!NT_SUCCESS(Status))
844 {
845 DPRINT1("CmpLinkKeyToHive: couldn't create symbolic link for %S, Status = 0x%08lx\n",
846 TargetKeyName, Status);
847 return FALSE;
848 }
849
850 return TRUE;
851 }
852
853 /*
854 * Should be called under privileges
855 */
856 static NTSTATUS
857 ConnectRegistry(
858 IN HKEY RootKey OPTIONAL,
859 IN PCWSTR RegMountPoint,
860 // IN HANDLE RootDirectory OPTIONAL,
861 IN PUNICODE_STRING InstallPath,
862 IN PCWSTR RegistryKey
863 /*
864 IN PUCHAR Descriptor,
865 IN ULONG DescriptorLength
866 */
867 )
868 {
869 UNICODE_STRING KeyName, FileName;
870 OBJECT_ATTRIBUTES KeyObjectAttributes;
871 OBJECT_ATTRIBUTES FileObjectAttributes;
872 WCHAR PathBuffer[MAX_PATH];
873
874 RtlInitUnicodeString(&KeyName, RegMountPoint);
875 InitializeObjectAttributes(&KeyObjectAttributes,
876 &KeyName,
877 OBJ_CASE_INSENSITIVE,
878 RootKey,
879 NULL); // Descriptor
880
881 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 3,
882 InstallPath->Buffer, L"System32\\config", RegistryKey);
883 RtlInitUnicodeString(&FileName, PathBuffer);
884 InitializeObjectAttributes(&FileObjectAttributes,
885 &FileName,
886 OBJ_CASE_INSENSITIVE,
887 NULL, // RootDirectory,
888 NULL);
889
890 /* Mount the registry hive in the registry namespace */
891 return NtLoadKey(&KeyObjectAttributes, &FileObjectAttributes);
892 }
893
894
895 static NTSTATUS
896 VerifyRegistryHive(
897 // IN HKEY RootKey OPTIONAL,
898 // // IN HANDLE RootDirectory OPTIONAL,
899 IN PUNICODE_STRING InstallPath,
900 IN PCWSTR RegistryKey /* ,
901 IN PCWSTR RegMountPoint */)
902 {
903 NTSTATUS Status;
904 UNICODE_STRING KeyName;
905 OBJECT_ATTRIBUTES KeyObjectAttributes;
906
907 /* Try to mount the specified registry hive */
908 Status = ConnectRegistry(NULL,
909 L"\\Registry\\Machine\\USetup_VerifyHive",
910 InstallPath,
911 RegistryKey
912 /* NULL, 0 */);
913 if (!NT_SUCCESS(Status))
914 {
915 DPRINT1("ConnectRegistry(%S) failed, Status 0x%08lx\n", RegistryKey, Status);
916 }
917
918 DPRINT1("VerifyRegistryHive: ConnectRegistry(%S) returns Status 0x%08lx\n", RegistryKey, Status);
919
920 //
921 // TODO: Check the Status error codes: STATUS_SUCCESS, STATUS_REGISTRY_RECOVERED,
922 // STATUS_REGISTRY_HIVE_RECOVERED, STATUS_REGISTRY_CORRUPT, STATUS_REGISTRY_IO_FAILED,
923 // STATUS_NOT_REGISTRY_FILE, STATUS_CANNOT_LOAD_REGISTRY_FILE ;
924 //(STATUS_HIVE_UNLOADED) ; STATUS_SYSTEM_HIVE_TOO_LARGE
925 //
926
927 if (Status == STATUS_REGISTRY_HIVE_RECOVERED) // NT_SUCCESS is still FALSE in this case!
928 DPRINT1("VerifyRegistryHive: Registry hive %S was recovered but some data may be lost (Status 0x%08lx)\n", RegistryKey, Status);
929
930 if (!NT_SUCCESS(Status))
931 {
932 DPRINT1("VerifyRegistryHive: Registry hive %S is corrupted (Status 0x%08lx)\n", RegistryKey, Status);
933 return Status;
934 }
935
936 if (Status == STATUS_REGISTRY_RECOVERED)
937 DPRINT1("VerifyRegistryHive: Registry hive %S succeeded recovered (Status 0x%08lx)\n", RegistryKey, Status);
938
939 /* Unmount the hive */
940 InitializeObjectAttributes(&KeyObjectAttributes,
941 &KeyName,
942 OBJ_CASE_INSENSITIVE,
943 NULL,
944 NULL);
945
946 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\USetup_VerifyHive");
947 Status = NtUnloadKey(&KeyObjectAttributes);
948 if (!NT_SUCCESS(Status))
949 {
950 DPRINT1("NtUnloadKey(%S, %wZ) failed, Status 0x%08lx\n", RegistryKey, &KeyName, Status);
951 }
952
953 return Status;
954 }
955
956
957 typedef enum _HIVE_UPDATE_STATE
958 {
959 Create, // Create a new hive file and save possibly existing old one with a .old extension.
960 Repair, // Re-create a new hive file and save possibly existing old one with a .brk extension.
961 Update // Hive update, do not need to be recreated.
962 } HIVE_UPDATE_STATE;
963
964 typedef struct _HIVE_LIST_ENTRY
965 {
966 PCWSTR HiveName; // HiveFileName;
967 PCWSTR HiveRegistryPath; // HiveRegMountPoint;
968 HANDLE PredefKeyHandle;
969 PCWSTR RegSymLink;
970 HIVE_UPDATE_STATE State;
971 // PUCHAR SecurityDescriptor;
972 // ULONG SecurityDescriptorLength;
973 } HIVE_LIST_ENTRY, *PHIVE_LIST_ENTRY;
974
975 #define NUMBER_OF_STANDARD_REGISTRY_HIVES 3
976
977 HIVE_LIST_ENTRY RegistryHives[/*NUMBER_OF_STANDARD_REGISTRY_HIVES*/] =
978 {
979 { L"SYSTEM" , L"\\Registry\\Machine\\USetup_SYSTEM" , HKEY_LOCAL_MACHINE, L"SYSTEM" , Create /* , SystemSecurity , sizeof(SystemSecurity) */ },
980 { L"SOFTWARE", L"\\Registry\\Machine\\USetup_SOFTWARE", HKEY_LOCAL_MACHINE, L"SOFTWARE", Create /* , SoftwareSecurity, sizeof(SoftwareSecurity) */ },
981 { L"DEFAULT" , L"\\Registry\\User\\USetup_DEFAULT" , HKEY_USERS , L".DEFAULT", Create /* , SystemSecurity , sizeof(SystemSecurity) */ },
982
983 // { L"BCD" , L"\\Registry\\Machine\\USetup_BCD", HKEY_LOCAL_MACHINE, L"BCD00000000", Create /* , BcdSecurity , sizeof(BcdSecurity) */ },
984 };
985 C_ASSERT(_countof(RegistryHives) == NUMBER_OF_STANDARD_REGISTRY_HIVES);
986
987 #define NUMBER_OF_SECURITY_REGISTRY_HIVES 2
988
989 /** These hives are created by LSASS during 2nd stage setup */
990 HIVE_LIST_ENTRY SecurityRegistryHives[/*NUMBER_OF_SECURITY_REGISTRY_HIVES*/] =
991 {
992 { L"SAM" , L"\\Registry\\Machine\\USetup_SAM" , HKEY_LOCAL_MACHINE, L"SAM" , Create /* , SystemSecurity , sizeof(SystemSecurity) */ },
993 { L"SECURITY", L"\\Registry\\Machine\\USetup_SECURITY", HKEY_LOCAL_MACHINE, L"SECURITY", Create /* , NULL , 0 */ },
994 };
995 C_ASSERT(_countof(SecurityRegistryHives) == NUMBER_OF_SECURITY_REGISTRY_HIVES);
996
997
998 NTSTATUS
999 VerifyRegistryHives(
1000 IN PUNICODE_STRING InstallPath,
1001 OUT PBOOLEAN ShouldUpdateRegistry)
1002 {
1003 NTSTATUS Status;
1004 BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
1005 UINT i;
1006
1007 /* Suppose first the registry hives do not have to be updated/recreated */
1008 *ShouldUpdateRegistry = FALSE;
1009
1010 /* Acquire restore privilege */
1011 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]);
1012 if (!NT_SUCCESS(Status))
1013 {
1014 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1015 /* Exit prematurely here.... */
1016 return Status;
1017 }
1018
1019 /* Acquire backup privilege */
1020 Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
1021 if (!NT_SUCCESS(Status))
1022 {
1023 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1024 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1025 /* Exit prematurely here.... */
1026 return Status;
1027 }
1028
1029 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1030 {
1031 Status = VerifyRegistryHive(InstallPath, RegistryHives[i].HiveName);
1032 if (!NT_SUCCESS(Status))
1033 {
1034 DPRINT1("Registry hive '%S' needs repair!\n", RegistryHives[i].HiveName);
1035 RegistryHives[i].State = Repair;
1036 *ShouldUpdateRegistry = TRUE;
1037 }
1038 else
1039 {
1040 RegistryHives[i].State = Update;
1041 }
1042 }
1043
1044 /** These hives are created by LSASS during 2nd stage setup */
1045 for (i = 0; i < ARRAYSIZE(SecurityRegistryHives); ++i)
1046 {
1047 Status = VerifyRegistryHive(InstallPath, SecurityRegistryHives[i].HiveName);
1048 if (!NT_SUCCESS(Status))
1049 {
1050 DPRINT1("Registry hive '%S' needs repair!\n", SecurityRegistryHives[i].HiveName);
1051 SecurityRegistryHives[i].State = Repair;
1052 /*
1053 * Note that it's not the role of the 1st-stage installer to fix
1054 * the security hives. This should be done at 2nd-stage installation
1055 * by LSASS.
1056 */
1057 }
1058 else
1059 {
1060 SecurityRegistryHives[i].State = Update;
1061 }
1062 }
1063
1064 /* Reset the status (we succeeded in checking all the hives) */
1065 Status = STATUS_SUCCESS;
1066
1067 /* Remove restore and backup privileges */
1068 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]);
1069 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1070
1071 return Status;
1072 }
1073
1074
1075 NTSTATUS
1076 RegInitializeRegistry(
1077 IN PUNICODE_STRING InstallPath)
1078 {
1079 NTSTATUS Status;
1080 HANDLE KeyHandle;
1081 UNICODE_STRING KeyName;
1082 OBJECT_ATTRIBUTES ObjectAttributes;
1083 BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
1084 ULONG Disposition;
1085 UINT i;
1086
1087 /* Acquire restore privilege */
1088 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]);
1089 if (!NT_SUCCESS(Status))
1090 {
1091 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1092 /* Exit prematurely here.... */
1093 return Status;
1094 }
1095
1096 /* Acquire backup privilege */
1097 Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
1098 if (!NT_SUCCESS(Status))
1099 {
1100 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1101 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1102 /* Exit prematurely here.... */
1103 return Status;
1104 }
1105
1106 /*
1107 * Create the template proto-hive.
1108 *
1109 * Use a dummy root key name:
1110 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
1111 * - On Vista+, this is "CMI-CreateHive{guid}"
1112 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
1113 * for more information.
1114 */
1115 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM\\$$$PROTO.HIV");
1116 InitializeObjectAttributes(&ObjectAttributes,
1117 &KeyName,
1118 OBJ_CASE_INSENSITIVE,
1119 NULL,
1120 NULL);
1121 Status = NtCreateKey(&KeyHandle,
1122 KEY_ALL_ACCESS,
1123 &ObjectAttributes,
1124 0,
1125 NULL,
1126 REG_OPTION_NON_VOLATILE,
1127 NULL);
1128 if (!NT_SUCCESS(Status))
1129 {
1130 DPRINT1("NtCreateKey() failed to create the proto-hive (Status %lx)\n", Status);
1131 goto Quit;
1132 }
1133 NtFlushKey(KeyHandle);
1134
1135 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1136 {
1137 if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
1138 continue;
1139
1140 Status = CreateRegistryFile(InstallPath,
1141 RegistryHives[i].HiveName,
1142 RegistryHives[i].State != Repair, // RegistryHives[i].State == Create,
1143 KeyHandle);
1144 if (!NT_SUCCESS(Status))
1145 {
1146 DPRINT1("CreateRegistryFile(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status);
1147 /* Exit prematurely here.... */
1148 /* That is now done, clean everything up! */
1149 NtDeleteKey(KeyHandle);
1150 NtClose(KeyHandle);
1151 goto Quit;
1152 }
1153 }
1154
1155 /* That is now done, clean everything up! */
1156 NtDeleteKey(KeyHandle);
1157 NtClose(KeyHandle);
1158
1159
1160 /*
1161 * Prepare the registry root keys. Since we cannot create real registry keys
1162 * inside the master keys (\Registry, \Registry\Machine or \Registry\User),
1163 * we need to perform some SymLink tricks instead.
1164 */
1165
1166 /* Our offline HKLM '\Registry\Machine' is inside '\Registry\Machine\SYSTEM\USetup_Machine' */
1167 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].MountPoint);
1168 InitializeObjectAttributes(&ObjectAttributes,
1169 &KeyName,
1170 OBJ_CASE_INSENSITIVE,
1171 NULL,
1172 NULL);
1173 KeyHandle = NULL;
1174 Status = NtCreateKey(&KeyHandle,
1175 KEY_ALL_ACCESS,
1176 &ObjectAttributes,
1177 0,
1178 NULL,
1179 REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE, // FIXME!
1180 &Disposition);
1181 if (!NT_SUCCESS(Status))
1182 {
1183 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status);
1184 // return Status;
1185 }
1186 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle = KeyHandle;
1187
1188 /* Our offline HKU '\Registry\User' is inside '\Registry\Machine\SYSTEM\USetup_User' */
1189 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_USERS)].MountPoint);
1190 InitializeObjectAttributes(&ObjectAttributes,
1191 &KeyName,
1192 OBJ_CASE_INSENSITIVE,
1193 NULL,
1194 NULL);
1195 KeyHandle = NULL;
1196 Status = NtCreateKey(&KeyHandle,
1197 KEY_ALL_ACCESS,
1198 &ObjectAttributes,
1199 0,
1200 NULL,
1201 REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE, // FIXME!
1202 &Disposition);
1203 if (!NT_SUCCESS(Status))
1204 {
1205 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status);
1206 // return Status;
1207 }
1208 RootKeys[GetPredefKeyIndex(HKEY_USERS)].Handle = KeyHandle;
1209
1210
1211 /*
1212 * Now properly mount the offline hive files
1213 */
1214 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1215 {
1216 // if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
1217 // continue;
1218
1219 if (RegistryHives[i].State == Create || RegistryHives[i].State == Repair)
1220 {
1221 Status = ConnectRegistry(NULL,
1222 RegistryHives[i].HiveRegistryPath,
1223 InstallPath,
1224 RegistryHives[i].HiveName
1225 /* SystemSecurity, sizeof(SystemSecurity) */);
1226 if (!NT_SUCCESS(Status))
1227 {
1228 DPRINT1("ConnectRegistry(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status);
1229 }
1230
1231 /* Create the registry symlink to this key */
1232 if (!CmpLinkKeyToHive(RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle,
1233 RegistryHives[i].RegSymLink,
1234 RegistryHives[i].HiveRegistryPath))
1235 {
1236 DPRINT1("CmpLinkKeyToHive(%S) failed!\n", RegistryHives[i].HiveName);
1237 }
1238 }
1239 else
1240 {
1241 /* Create *DUMMY* volatile hives just to make the update procedure work */
1242
1243 RtlInitUnicodeString(&KeyName, RegistryHives[i].RegSymLink);
1244 InitializeObjectAttributes(&ObjectAttributes,
1245 &KeyName,
1246 OBJ_CASE_INSENSITIVE,
1247 RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle,
1248 NULL);
1249 KeyHandle = NULL;
1250 Status = NtCreateKey(&KeyHandle,
1251 KEY_ALL_ACCESS,
1252 &ObjectAttributes,
1253 0,
1254 NULL,
1255 REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE, // FIXME!
1256 &Disposition);
1257 if (!NT_SUCCESS(Status))
1258 {
1259 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status);
1260 // return Status;
1261 }
1262 NtClose(KeyHandle);
1263 }
1264 }
1265
1266
1267 /* HKCU is a handle to 'HKU\.DEFAULT' */
1268 #if 0
1269 RtlInitUnicodeString(&KeyName, L".DEFAULT");
1270 InitializeObjectAttributes(&ObjectAttributes,
1271 &KeyName,
1272 OBJ_CASE_INSENSITIVE,
1273 RootKeys[GetPredefKeyIndex(HKEY_USERS)].Handle,
1274 NULL);
1275 #else
1276 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_CURRENT_USER)].MountPoint);
1277 InitializeObjectAttributes(&ObjectAttributes,
1278 &KeyName,
1279 OBJ_CASE_INSENSITIVE,
1280 NULL,
1281 NULL);
1282 #endif
1283 KeyHandle = NULL;
1284 Status = NtOpenKey(&KeyHandle,
1285 KEY_ALL_ACCESS,
1286 &ObjectAttributes);
1287 if (!NT_SUCCESS(Status))
1288 {
1289 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &KeyName, Status);
1290 }
1291 RootKeys[GetPredefKeyIndex(HKEY_CURRENT_USER)].Handle = KeyHandle;
1292
1293
1294 /* HKCR is a handle to 'HKLM\Software\Classes' */
1295 #if 0
1296 RtlInitUnicodeString(&KeyName, L"Software\\Classes");
1297 InitializeObjectAttributes(&ObjectAttributes,
1298 &KeyName,
1299 OBJ_CASE_INSENSITIVE,
1300 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
1301 NULL);
1302 #else
1303 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_CLASSES_ROOT)].MountPoint);
1304 InitializeObjectAttributes(&ObjectAttributes,
1305 &KeyName,
1306 OBJ_CASE_INSENSITIVE,
1307 NULL,
1308 NULL);
1309 #endif
1310 KeyHandle = NULL;
1311 /* We use NtCreateKey instead of NtOpenKey because Software\Classes doesn't exist originally */
1312 Status = NtCreateKey(&KeyHandle,
1313 KEY_ALL_ACCESS,
1314 &ObjectAttributes,
1315 0,
1316 NULL,
1317 REG_OPTION_NON_VOLATILE,
1318 &Disposition);
1319 if (!NT_SUCCESS(Status))
1320 {
1321 DPRINT1("NtCreateKey(%wZ) failed (Status %lx)\n", &KeyName, Status);
1322 }
1323 else
1324 {
1325 DPRINT1("NtCreateKey() succeeded to %s the %wZ key (Status %lx)\n",
1326 Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
1327 &KeyName, Status);
1328 }
1329 RootKeys[GetPredefKeyIndex(HKEY_CLASSES_ROOT)].Handle = KeyHandle;
1330
1331
1332 Status = STATUS_SUCCESS;
1333
1334
1335 /* Create the 'HKLM\SYSTEM\ControlSet001' key */
1336 // REGISTRY_SETUP_MACHINE L"SYSTEM\\ControlSet001"
1337 RtlInitUnicodeString(&KeyName, L"SYSTEM\\ControlSet001");
1338 InitializeObjectAttributes(&ObjectAttributes,
1339 &KeyName,
1340 OBJ_CASE_INSENSITIVE,
1341 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
1342 NULL);
1343 Status = NtCreateKey(&KeyHandle,
1344 KEY_ALL_ACCESS,
1345 &ObjectAttributes,
1346 0,
1347 NULL,
1348 REG_OPTION_NON_VOLATILE,
1349 &Disposition);
1350 if (!NT_SUCCESS(Status))
1351 {
1352 DPRINT1("NtCreateKey() failed to create the ControlSet001 key (Status %lx)\n", Status);
1353 // return Status;
1354 }
1355 else
1356 {
1357 DPRINT1("NtCreateKey() succeeded to %s the ControlSet001 key (Status %lx)\n",
1358 Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
1359 Status);
1360 }
1361 NtClose(KeyHandle);
1362
1363 /* Create the 'HKLM\SYSTEM\CurrentControlSet' symlink */
1364 if (!CmpLinkKeyToHive(RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
1365 L"SYSTEM\\CurrentControlSet",
1366 REGISTRY_SETUP_MACHINE L"SYSTEM\\ControlSet001"))
1367 {
1368 DPRINT1("CmpLinkKeyToHive(CurrentControlSet) failed!\n");
1369 }
1370
1371
1372 Status = STATUS_SUCCESS;
1373
1374
1375 Quit:
1376 /* Remove restore and backup privileges */
1377 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]);
1378 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1379
1380 return Status;
1381 }
1382
1383 VOID
1384 RegCleanupRegistry(
1385 IN PUNICODE_STRING InstallPath)
1386 {
1387 NTSTATUS Status;
1388 UNICODE_STRING KeyName;
1389 OBJECT_ATTRIBUTES KeyObjectAttributes;
1390 BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
1391 UINT i;
1392 WCHAR SrcPath[MAX_PATH];
1393 WCHAR DstPath[MAX_PATH];
1394
1395 for (i = 0; i < ARRAYSIZE(RootKeys); ++i)
1396 {
1397 if (RootKeys[i].Handle)
1398 {
1399 NtFlushKey(RootKeys[i].Handle);
1400 NtClose(RootKeys[i].Handle);
1401 RootKeys[i].Handle = NULL;
1402 }
1403 }
1404
1405 /* Acquire restore privilege */
1406 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]);
1407 if (!NT_SUCCESS(Status))
1408 {
1409 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1410 /* Exit prematurely here.... */
1411 return;
1412 }
1413
1414 /* Acquire backup privilege */
1415 Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
1416 if (!NT_SUCCESS(Status))
1417 {
1418 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1419 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1420 /* Exit prematurely here.... */
1421 return;
1422 }
1423
1424 InitializeObjectAttributes(&KeyObjectAttributes,
1425 &KeyName,
1426 OBJ_CASE_INSENSITIVE,
1427 NULL,
1428 NULL);
1429
1430 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1431 {
1432 if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
1433 continue;
1434
1435 RtlInitUnicodeString(&KeyName, RegistryHives[i].HiveRegistryPath);
1436 Status = NtUnloadKey(&KeyObjectAttributes);
1437 DPRINT1("Unmounting '%S' %s\n", RegistryHives[i].HiveRegistryPath, NT_SUCCESS(Status) ? "succeeded" : "failed");
1438 }
1439
1440 //
1441 // RegBackupRegistry()
1442 //
1443 /* Now backup the hives into .sav files */
1444 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1445 {
1446 if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
1447 continue;
1448
1449 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 3,
1450 InstallPath->Buffer, L"System32\\config", RegistryHives[i].HiveName);
1451 StringCchCopyW(DstPath, ARRAYSIZE(DstPath), SrcPath);
1452 StringCchCatW(DstPath, ARRAYSIZE(DstPath), L".sav");
1453
1454 DPRINT1("Copy hive: %S ==> %S\n", SrcPath, DstPath);
1455 Status = SetupCopyFile(SrcPath, DstPath, FALSE);
1456 if (!NT_SUCCESS(Status))
1457 {
1458 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
1459 // return Status;
1460 }
1461 }
1462
1463 /* Remove restore and backup privileges */
1464 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]);
1465 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1466 }
1467
1468 VOID
1469 SetDefaultPagefile(
1470 WCHAR Drive)
1471 {
1472 OBJECT_ATTRIBUTES ObjectAttributes;
1473 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
1474 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"PagingFiles");
1475 WCHAR ValueBuffer[] = L"?:\\pagefile.sys 0 0\0";
1476 HANDLE KeyHandle;
1477 NTSTATUS Status;
1478
1479 InitializeObjectAttributes(&ObjectAttributes,
1480 &KeyName,
1481 OBJ_CASE_INSENSITIVE,
1482 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
1483 NULL);
1484 Status = NtOpenKey(&KeyHandle,
1485 KEY_ALL_ACCESS,
1486 &ObjectAttributes);
1487 if (!NT_SUCCESS(Status))
1488 return;
1489
1490 ValueBuffer[0] = Drive;
1491
1492 NtSetValueKey(KeyHandle,
1493 &ValueName,
1494 0,
1495 REG_MULTI_SZ,
1496 (PVOID)&ValueBuffer,
1497 sizeof(ValueBuffer));
1498
1499 NtClose(KeyHandle);
1500 }
1501
1502 /* EOF */