[USETUP] Moving around some code.
[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 PCWSTR SourcePath,
622 PWSTR Filename,
623 PWSTR Section,
624 LCID LocaleId,
625 BOOLEAN Delete)
626 {
627 WCHAR FileNameBuffer[MAX_PATH];
628 HINF hInf;
629 UINT ErrorLine;
630
631 /* Load inf file from install media. */
632 CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2,
633 SourcePath, Filename);
634
635 hInf = SetupOpenInfFileExW(FileNameBuffer,
636 NULL,
637 INF_STYLE_WIN4,
638 LocaleId,
639 &ErrorLine);
640 if (hInf == INVALID_HANDLE_VALUE)
641 {
642 DPRINT1("SetupOpenInfFile() failed\n");
643 return FALSE;
644 }
645
646 #if 0
647 if (!registry_callback(hInf, L"DelReg", FALSE))
648 {
649 DPRINT1("registry_callback() failed\n");
650 InfCloseFile(hInf);
651 return FALSE;
652 }
653 #endif
654
655 if (!registry_callback(hInf, L"AddReg", FALSE))
656 {
657 DPRINT1("registry_callback() failed\n");
658 InfCloseFile(hInf);
659 return FALSE;
660 }
661
662 if (!registry_callback(hInf, L"AddReg.NT" Architecture, FALSE))
663 {
664 DPRINT1("registry_callback() failed\n");
665 InfCloseFile(hInf);
666 return FALSE;
667 }
668
669 InfCloseFile(hInf);
670 return TRUE;
671 }
672
673 /*
674 * Should be called under privileges
675 */
676 static NTSTATUS
677 CreateRegistryFile(
678 IN PUNICODE_STRING InstallPath,
679 IN PCWSTR RegistryKey,
680 IN BOOLEAN IsHiveNew,
681 IN HANDLE ProtoKeyHandle
682 /*
683 IN PUCHAR Descriptor,
684 IN ULONG DescriptorLength
685 */
686 )
687 {
688 /* '.old' is for old valid hives, while '.brk' is for old broken hives */
689 static PCWSTR Extensions[] = {L"old", L"brk"};
690
691 NTSTATUS Status;
692 HANDLE FileHandle;
693 UNICODE_STRING FileName;
694 OBJECT_ATTRIBUTES ObjectAttributes;
695 IO_STATUS_BLOCK IoStatusBlock;
696 PCWSTR Extension;
697 WCHAR PathBuffer[MAX_PATH];
698 WCHAR PathBuffer2[MAX_PATH];
699
700 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 3,
701 InstallPath->Buffer, L"System32\\config", RegistryKey);
702
703 Extension = Extensions[IsHiveNew ? 0 : 1];
704
705 //
706 // FIXME: The best, actually, would be to rename (move) the existing
707 // System32\config\RegistryKey file to System32\config\RegistryKey.old,
708 // and if it already existed some System32\config\RegistryKey.old, we should
709 // first rename this one into System32\config\RegistryKey_N.old before
710 // performing the original rename.
711 //
712
713 /* Check whether the registry hive file already existed, and if so, rename it */
714 if (DoesFileExist(NULL, PathBuffer))
715 {
716 // UINT i;
717
718 DPRINT1("Registry hive '%S' already exists, rename it\n", PathBuffer);
719
720 // i = 1;
721 /* Try first by just appending the '.old' extension */
722 StringCchPrintfW(PathBuffer2, ARRAYSIZE(PathBuffer2), L"%s.%s", PathBuffer, Extension);
723 #if 0
724 while (DoesFileExist(NULL, PathBuffer2))
725 {
726 /* An old file already exists, increments its index, but not too much */
727 if (i <= 0xFFFF)
728 {
729 /* Append '_N.old' extension */
730 StringCchPrintfW(PathBuffer2, ARRAYSIZE(PathBuffer2), L"%s_%lu.%s", PathBuffer, i, Extension);
731 ++i;
732 }
733 else
734 {
735 /*
736 * Too many old files exist, we will rename the file
737 * using the name of the oldest one.
738 */
739 StringCchPrintfW(PathBuffer2, ARRAYSIZE(PathBuffer2), L"%s.%s", PathBuffer, Extension);
740 break;
741 }
742 }
743 #endif
744
745 /* Now rename the file (force the move) */
746 Status = SetupMoveFile(PathBuffer, PathBuffer2, MOVEFILE_REPLACE_EXISTING);
747 }
748
749 /* Create the file */
750 RtlInitUnicodeString(&FileName, PathBuffer);
751 InitializeObjectAttributes(&ObjectAttributes,
752 &FileName,
753 OBJ_CASE_INSENSITIVE,
754 NULL, // Could have been InstallPath, etc...
755 NULL); // Descriptor
756
757 Status = NtCreateFile(&FileHandle,
758 FILE_GENERIC_WRITE,
759 &ObjectAttributes,
760 &IoStatusBlock,
761 NULL,
762 FILE_ATTRIBUTE_NORMAL,
763 0,
764 FILE_OVERWRITE_IF,
765 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
766 NULL,
767 0);
768 if (!NT_SUCCESS(Status))
769 {
770 DPRINT1("NtCreateFile(%wZ) failed, Status 0x%08lx\n", &FileName, Status);
771 return Status;
772 }
773
774 /* Save the selected hive into the file */
775 Status = NtSaveKeyEx(ProtoKeyHandle, FileHandle, REG_LATEST_FORMAT);
776 if (!NT_SUCCESS(Status))
777 {
778 DPRINT1("NtSaveKeyEx(%wZ) failed, Status 0x%08lx\n", &FileName, Status);
779 }
780
781 /* Close the file and return */
782 NtClose(FileHandle);
783 return Status;
784 }
785
786 static BOOLEAN
787 CmpLinkKeyToHive(
788 IN HANDLE RootLinkKeyHandle OPTIONAL,
789 IN PCWSTR LinkKeyName,
790 IN PCWSTR TargetKeyName)
791 {
792 static UNICODE_STRING CmSymbolicLinkValueName =
793 RTL_CONSTANT_STRING(L"SymbolicLinkValue");
794
795 NTSTATUS Status;
796 OBJECT_ATTRIBUTES ObjectAttributes;
797 UNICODE_STRING KeyName;
798 HANDLE TargetKeyHandle;
799 ULONG Disposition;
800
801 /* Initialize the object attributes */
802 RtlInitUnicodeString(&KeyName, LinkKeyName);
803 InitializeObjectAttributes(&ObjectAttributes,
804 &KeyName,
805 OBJ_CASE_INSENSITIVE,
806 RootLinkKeyHandle,
807 NULL);
808
809 /* Create the link key */
810 Status = NtCreateKey(&TargetKeyHandle,
811 KEY_SET_VALUE | KEY_CREATE_LINK,
812 &ObjectAttributes,
813 0,
814 NULL,
815 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
816 &Disposition);
817 if (!NT_SUCCESS(Status))
818 {
819 DPRINT1("CmpLinkKeyToHive: couldn't create %S, Status = 0x%08lx\n",
820 LinkKeyName, Status);
821 return FALSE;
822 }
823
824 /* Check if the new key was actually created */
825 if (Disposition != REG_CREATED_NEW_KEY)
826 {
827 DPRINT1("CmpLinkKeyToHive: %S already exists!\n", LinkKeyName);
828 NtClose(TargetKeyHandle);
829 return FALSE;
830 }
831
832 /* Set the target key name as link target */
833 RtlInitUnicodeString(&KeyName, TargetKeyName);
834 Status = NtSetValueKey(TargetKeyHandle,
835 &CmSymbolicLinkValueName,
836 0,
837 REG_LINK,
838 KeyName.Buffer,
839 KeyName.Length);
840
841 /* Close the link key handle */
842 NtClose(TargetKeyHandle);
843
844 if (!NT_SUCCESS(Status))
845 {
846 DPRINT1("CmpLinkKeyToHive: couldn't create symbolic link for %S, Status = 0x%08lx\n",
847 TargetKeyName, Status);
848 return FALSE;
849 }
850
851 return TRUE;
852 }
853
854 /*
855 * Should be called under privileges
856 */
857 static NTSTATUS
858 ConnectRegistry(
859 IN HKEY RootKey OPTIONAL,
860 IN PCWSTR RegMountPoint,
861 // IN HANDLE RootDirectory OPTIONAL,
862 IN PUNICODE_STRING InstallPath,
863 IN PCWSTR RegistryKey
864 /*
865 IN PUCHAR Descriptor,
866 IN ULONG DescriptorLength
867 */
868 )
869 {
870 UNICODE_STRING KeyName, FileName;
871 OBJECT_ATTRIBUTES KeyObjectAttributes;
872 OBJECT_ATTRIBUTES FileObjectAttributes;
873 WCHAR PathBuffer[MAX_PATH];
874
875 RtlInitUnicodeString(&KeyName, RegMountPoint);
876 InitializeObjectAttributes(&KeyObjectAttributes,
877 &KeyName,
878 OBJ_CASE_INSENSITIVE,
879 RootKey,
880 NULL); // Descriptor
881
882 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 3,
883 InstallPath->Buffer, L"System32\\config", RegistryKey);
884 RtlInitUnicodeString(&FileName, PathBuffer);
885 InitializeObjectAttributes(&FileObjectAttributes,
886 &FileName,
887 OBJ_CASE_INSENSITIVE,
888 NULL, // RootDirectory,
889 NULL);
890
891 /* Mount the registry hive in the registry namespace */
892 return NtLoadKey(&KeyObjectAttributes, &FileObjectAttributes);
893 }
894
895
896 static NTSTATUS
897 VerifyRegistryHive(
898 // IN HKEY RootKey OPTIONAL,
899 // // IN HANDLE RootDirectory OPTIONAL,
900 IN PUNICODE_STRING InstallPath,
901 IN PCWSTR RegistryKey /* ,
902 IN PCWSTR RegMountPoint */)
903 {
904 NTSTATUS Status;
905 UNICODE_STRING KeyName;
906 OBJECT_ATTRIBUTES ObjectAttributes;
907
908 /* Try to mount the specified registry hive */
909 Status = ConnectRegistry(NULL,
910 L"\\Registry\\Machine\\USetup_VerifyHive",
911 InstallPath,
912 RegistryKey
913 /* NULL, 0 */);
914 if (!NT_SUCCESS(Status))
915 {
916 DPRINT1("ConnectRegistry(%S) failed, Status 0x%08lx\n", RegistryKey, Status);
917 }
918
919 DPRINT1("VerifyRegistryHive: ConnectRegistry(%S) returns Status 0x%08lx\n", RegistryKey, Status);
920
921 //
922 // TODO: Check the Status error codes: STATUS_SUCCESS, STATUS_REGISTRY_RECOVERED,
923 // STATUS_REGISTRY_HIVE_RECOVERED, STATUS_REGISTRY_CORRUPT, STATUS_REGISTRY_IO_FAILED,
924 // STATUS_NOT_REGISTRY_FILE, STATUS_CANNOT_LOAD_REGISTRY_FILE ;
925 //(STATUS_HIVE_UNLOADED) ; STATUS_SYSTEM_HIVE_TOO_LARGE
926 //
927
928 if (Status == STATUS_REGISTRY_HIVE_RECOVERED) // NT_SUCCESS is still FALSE in this case!
929 DPRINT1("VerifyRegistryHive: Registry hive %S was recovered but some data may be lost (Status 0x%08lx)\n", RegistryKey, Status);
930
931 if (!NT_SUCCESS(Status))
932 {
933 DPRINT1("VerifyRegistryHive: Registry hive %S is corrupted (Status 0x%08lx)\n", RegistryKey, Status);
934 return Status;
935 }
936
937 if (Status == STATUS_REGISTRY_RECOVERED)
938 DPRINT1("VerifyRegistryHive: Registry hive %S succeeded recovered (Status 0x%08lx)\n", RegistryKey, Status);
939
940 /* Unmount the hive */
941 InitializeObjectAttributes(&ObjectAttributes,
942 &KeyName,
943 OBJ_CASE_INSENSITIVE,
944 NULL,
945 NULL);
946
947 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\USetup_VerifyHive");
948 Status = NtUnloadKey(&ObjectAttributes);
949 if (!NT_SUCCESS(Status))
950 {
951 DPRINT1("NtUnloadKey(%S, %wZ) failed, Status 0x%08lx\n", RegistryKey, &KeyName, Status);
952 }
953
954 return Status;
955 }
956
957
958 typedef enum _HIVE_UPDATE_STATE
959 {
960 Create, // Create a new hive file and save possibly existing old one with a .old extension.
961 Repair, // Re-create a new hive file and save possibly existing old one with a .brk extension.
962 Update // Hive update, do not need to be recreated.
963 } HIVE_UPDATE_STATE;
964
965 typedef struct _HIVE_LIST_ENTRY
966 {
967 PCWSTR HiveName; // HiveFileName;
968 PCWSTR HiveRegistryPath; // HiveRegMountPoint;
969 HANDLE PredefKeyHandle;
970 PCWSTR RegSymLink;
971 HIVE_UPDATE_STATE State;
972 // PUCHAR SecurityDescriptor;
973 // ULONG SecurityDescriptorLength;
974 } HIVE_LIST_ENTRY, *PHIVE_LIST_ENTRY;
975
976 #define NUMBER_OF_STANDARD_REGISTRY_HIVES 3
977
978 HIVE_LIST_ENTRY RegistryHives[/*NUMBER_OF_STANDARD_REGISTRY_HIVES*/] =
979 {
980 { L"SYSTEM" , L"\\Registry\\Machine\\USetup_SYSTEM" , HKEY_LOCAL_MACHINE, L"SYSTEM" , Create /* , SystemSecurity , sizeof(SystemSecurity) */ },
981 { L"SOFTWARE", L"\\Registry\\Machine\\USetup_SOFTWARE", HKEY_LOCAL_MACHINE, L"SOFTWARE", Create /* , SoftwareSecurity, sizeof(SoftwareSecurity) */ },
982 { L"DEFAULT" , L"\\Registry\\User\\USetup_DEFAULT" , HKEY_USERS , L".DEFAULT", Create /* , SystemSecurity , sizeof(SystemSecurity) */ },
983
984 // { L"BCD" , L"\\Registry\\Machine\\USetup_BCD", HKEY_LOCAL_MACHINE, L"BCD00000000", Create /* , BcdSecurity , sizeof(BcdSecurity) */ },
985 };
986 C_ASSERT(_countof(RegistryHives) == NUMBER_OF_STANDARD_REGISTRY_HIVES);
987
988 #define NUMBER_OF_SECURITY_REGISTRY_HIVES 2
989
990 /** These hives are created by LSASS during 2nd stage setup */
991 HIVE_LIST_ENTRY SecurityRegistryHives[/*NUMBER_OF_SECURITY_REGISTRY_HIVES*/] =
992 {
993 { L"SAM" , L"\\Registry\\Machine\\USetup_SAM" , HKEY_LOCAL_MACHINE, L"SAM" , Create /* , SystemSecurity , sizeof(SystemSecurity) */ },
994 { L"SECURITY", L"\\Registry\\Machine\\USetup_SECURITY", HKEY_LOCAL_MACHINE, L"SECURITY", Create /* , NULL , 0 */ },
995 };
996 C_ASSERT(_countof(SecurityRegistryHives) == NUMBER_OF_SECURITY_REGISTRY_HIVES);
997
998
999 NTSTATUS
1000 VerifyRegistryHives(
1001 IN PUNICODE_STRING InstallPath,
1002 OUT PBOOLEAN ShouldRepairRegistry)
1003 {
1004 NTSTATUS Status;
1005 BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
1006 UINT i;
1007
1008 /* Suppose first the registry hives do not have to be fully recreated */
1009 *ShouldRepairRegistry = FALSE;
1010
1011 /* Acquire restore privilege */
1012 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]);
1013 if (!NT_SUCCESS(Status))
1014 {
1015 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1016 /* Exit prematurely here.... */
1017 return Status;
1018 }
1019
1020 /* Acquire backup privilege */
1021 Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
1022 if (!NT_SUCCESS(Status))
1023 {
1024 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1025 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1026 /* Exit prematurely here.... */
1027 return Status;
1028 }
1029
1030 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1031 {
1032 Status = VerifyRegistryHive(InstallPath, RegistryHives[i].HiveName);
1033 if (!NT_SUCCESS(Status))
1034 {
1035 DPRINT1("Registry hive '%S' needs repair!\n", RegistryHives[i].HiveName);
1036 RegistryHives[i].State = Repair;
1037 *ShouldRepairRegistry = TRUE;
1038 }
1039 else
1040 {
1041 RegistryHives[i].State = Update;
1042 }
1043 }
1044
1045 /** These hives are created by LSASS during 2nd stage setup */
1046 for (i = 0; i < ARRAYSIZE(SecurityRegistryHives); ++i)
1047 {
1048 Status = VerifyRegistryHive(InstallPath, SecurityRegistryHives[i].HiveName);
1049 if (!NT_SUCCESS(Status))
1050 {
1051 DPRINT1("Registry hive '%S' needs repair!\n", SecurityRegistryHives[i].HiveName);
1052 SecurityRegistryHives[i].State = Repair;
1053 /*
1054 * Note that it's not the role of the 1st-stage installer to fix
1055 * the security hives. This should be done at 2nd-stage installation
1056 * by LSASS.
1057 */
1058 }
1059 else
1060 {
1061 SecurityRegistryHives[i].State = Update;
1062 }
1063 }
1064
1065 /* Reset the status (we succeeded in checking all the hives) */
1066 Status = STATUS_SUCCESS;
1067
1068 /* Remove restore and backup privileges */
1069 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]);
1070 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1071
1072 return Status;
1073 }
1074
1075
1076 NTSTATUS
1077 RegInitializeRegistry(
1078 IN PUNICODE_STRING InstallPath)
1079 {
1080 NTSTATUS Status;
1081 HANDLE KeyHandle;
1082 UNICODE_STRING KeyName;
1083 OBJECT_ATTRIBUTES ObjectAttributes;
1084 BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
1085 ULONG Disposition;
1086 UINT i;
1087
1088 /* Acquire restore privilege */
1089 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]);
1090 if (!NT_SUCCESS(Status))
1091 {
1092 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1093 /* Exit prematurely here.... */
1094 return Status;
1095 }
1096
1097 /* Acquire backup privilege */
1098 Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
1099 if (!NT_SUCCESS(Status))
1100 {
1101 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1102 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1103 /* Exit prematurely here.... */
1104 return Status;
1105 }
1106
1107 /*
1108 * Create the template proto-hive.
1109 *
1110 * Use a dummy root key name:
1111 * - On 2k/XP/2k3, this is "$$$PROTO.HIV"
1112 * - On Vista+, this is "CMI-CreateHive{guid}"
1113 * See https://github.com/libyal/winreg-kb/blob/master/documentation/Registry%20files.asciidoc
1114 * for more information.
1115 */
1116 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM\\$$$PROTO.HIV");
1117 InitializeObjectAttributes(&ObjectAttributes,
1118 &KeyName,
1119 OBJ_CASE_INSENSITIVE,
1120 NULL,
1121 NULL);
1122 Status = NtCreateKey(&KeyHandle,
1123 KEY_ALL_ACCESS,
1124 &ObjectAttributes,
1125 0,
1126 NULL,
1127 REG_OPTION_NON_VOLATILE,
1128 NULL);
1129 if (!NT_SUCCESS(Status))
1130 {
1131 DPRINT1("NtCreateKey() failed to create the proto-hive (Status %lx)\n", Status);
1132 goto Quit;
1133 }
1134 NtFlushKey(KeyHandle);
1135
1136 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1137 {
1138 if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
1139 continue;
1140
1141 Status = CreateRegistryFile(InstallPath,
1142 RegistryHives[i].HiveName,
1143 RegistryHives[i].State != Repair, // RegistryHives[i].State == Create,
1144 KeyHandle);
1145 if (!NT_SUCCESS(Status))
1146 {
1147 DPRINT1("CreateRegistryFile(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status);
1148 /* Exit prematurely here.... */
1149 /* That is now done, remove the proto-hive */
1150 NtDeleteKey(KeyHandle);
1151 NtClose(KeyHandle);
1152 goto Quit;
1153 }
1154 }
1155
1156 /* That is now done, remove the proto-hive */
1157 NtDeleteKey(KeyHandle);
1158 NtClose(KeyHandle);
1159
1160
1161 /*
1162 * Prepare the registry root keys. Since we cannot create real registry keys
1163 * inside the master keys (\Registry, \Registry\Machine or \Registry\User),
1164 * we need to perform some SymLink tricks instead.
1165 */
1166
1167 /* Our offline HKLM '\Registry\Machine' is inside '\Registry\Machine\SYSTEM\USetup_Machine' */
1168 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].MountPoint);
1169 InitializeObjectAttributes(&ObjectAttributes,
1170 &KeyName,
1171 OBJ_CASE_INSENSITIVE,
1172 NULL,
1173 NULL);
1174 KeyHandle = NULL;
1175 Status = NtCreateKey(&KeyHandle,
1176 KEY_ALL_ACCESS,
1177 &ObjectAttributes,
1178 0,
1179 NULL,
1180 REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE, // FIXME!
1181 &Disposition);
1182 if (!NT_SUCCESS(Status))
1183 {
1184 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status);
1185 // return Status;
1186 }
1187 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle = KeyHandle;
1188
1189 /* Our offline HKU '\Registry\User' is inside '\Registry\Machine\SYSTEM\USetup_User' */
1190 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_USERS)].MountPoint);
1191 InitializeObjectAttributes(&ObjectAttributes,
1192 &KeyName,
1193 OBJ_CASE_INSENSITIVE,
1194 NULL,
1195 NULL);
1196 KeyHandle = NULL;
1197 Status = NtCreateKey(&KeyHandle,
1198 KEY_ALL_ACCESS,
1199 &ObjectAttributes,
1200 0,
1201 NULL,
1202 REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE, // FIXME!
1203 &Disposition);
1204 if (!NT_SUCCESS(Status))
1205 {
1206 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status);
1207 // return Status;
1208 }
1209 RootKeys[GetPredefKeyIndex(HKEY_USERS)].Handle = KeyHandle;
1210
1211
1212 /*
1213 * Now properly mount the offline hive files
1214 */
1215 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1216 {
1217 // if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
1218 // continue;
1219
1220 if (RegistryHives[i].State == Create || RegistryHives[i].State == Repair)
1221 {
1222 Status = ConnectRegistry(NULL,
1223 RegistryHives[i].HiveRegistryPath,
1224 InstallPath,
1225 RegistryHives[i].HiveName
1226 /* SystemSecurity, sizeof(SystemSecurity) */);
1227 if (!NT_SUCCESS(Status))
1228 {
1229 DPRINT1("ConnectRegistry(%S) failed, Status 0x%08lx\n", RegistryHives[i].HiveName, Status);
1230 }
1231
1232 /* Create the registry symlink to this key */
1233 if (!CmpLinkKeyToHive(RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle,
1234 RegistryHives[i].RegSymLink,
1235 RegistryHives[i].HiveRegistryPath))
1236 {
1237 DPRINT1("CmpLinkKeyToHive(%S) failed!\n", RegistryHives[i].HiveName);
1238 }
1239 }
1240 else
1241 {
1242 /* Create *DUMMY* volatile hives just to make the update procedure working */
1243
1244 RtlInitUnicodeString(&KeyName, RegistryHives[i].RegSymLink);
1245 InitializeObjectAttributes(&ObjectAttributes,
1246 &KeyName,
1247 OBJ_CASE_INSENSITIVE,
1248 RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle,
1249 NULL);
1250 KeyHandle = NULL;
1251 Status = NtCreateKey(&KeyHandle,
1252 KEY_ALL_ACCESS,
1253 &ObjectAttributes,
1254 0,
1255 NULL,
1256 REG_OPTION_NON_VOLATILE, // REG_OPTION_VOLATILE, // FIXME!
1257 &Disposition);
1258 if (!NT_SUCCESS(Status))
1259 {
1260 DPRINT1("NtCreateKey(%wZ) failed (Status 0x%08lx)\n", &KeyName, Status);
1261 // return Status;
1262 }
1263 NtClose(KeyHandle);
1264 }
1265 }
1266
1267
1268 /* HKCU is a handle to 'HKU\.DEFAULT' */
1269 #if 0
1270 RtlInitUnicodeString(&KeyName, L".DEFAULT");
1271 InitializeObjectAttributes(&ObjectAttributes,
1272 &KeyName,
1273 OBJ_CASE_INSENSITIVE,
1274 RootKeys[GetPredefKeyIndex(HKEY_USERS)].Handle,
1275 NULL);
1276 #else
1277 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_CURRENT_USER)].MountPoint);
1278 InitializeObjectAttributes(&ObjectAttributes,
1279 &KeyName,
1280 OBJ_CASE_INSENSITIVE,
1281 NULL,
1282 NULL);
1283 #endif
1284 KeyHandle = NULL;
1285 Status = NtOpenKey(&KeyHandle,
1286 KEY_ALL_ACCESS,
1287 &ObjectAttributes);
1288 if (!NT_SUCCESS(Status))
1289 {
1290 DPRINT1("NtOpenKey(%wZ) failed (Status %lx)\n", &KeyName, Status);
1291 }
1292 RootKeys[GetPredefKeyIndex(HKEY_CURRENT_USER)].Handle = KeyHandle;
1293
1294
1295 /* HKCR is a handle to 'HKLM\Software\Classes' */
1296 #if 0
1297 RtlInitUnicodeString(&KeyName, L"Software\\Classes");
1298 InitializeObjectAttributes(&ObjectAttributes,
1299 &KeyName,
1300 OBJ_CASE_INSENSITIVE,
1301 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
1302 NULL);
1303 #else
1304 RtlInitUnicodeString(&KeyName, RootKeys[GetPredefKeyIndex(HKEY_CLASSES_ROOT)].MountPoint);
1305 InitializeObjectAttributes(&ObjectAttributes,
1306 &KeyName,
1307 OBJ_CASE_INSENSITIVE,
1308 NULL,
1309 NULL);
1310 #endif
1311 KeyHandle = NULL;
1312 /* We use NtCreateKey instead of NtOpenKey because Software\Classes doesn't exist originally */
1313 Status = NtCreateKey(&KeyHandle,
1314 KEY_ALL_ACCESS,
1315 &ObjectAttributes,
1316 0,
1317 NULL,
1318 REG_OPTION_NON_VOLATILE,
1319 &Disposition);
1320 if (!NT_SUCCESS(Status))
1321 {
1322 DPRINT1("NtCreateKey(%wZ) failed (Status %lx)\n", &KeyName, Status);
1323 }
1324 else
1325 {
1326 DPRINT1("NtCreateKey() succeeded to %s the %wZ key (Status %lx)\n",
1327 Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
1328 &KeyName, Status);
1329 }
1330 RootKeys[GetPredefKeyIndex(HKEY_CLASSES_ROOT)].Handle = KeyHandle;
1331
1332
1333 Status = STATUS_SUCCESS;
1334
1335
1336 /* Create the 'HKLM\SYSTEM\ControlSet001' key */
1337 // REGISTRY_SETUP_MACHINE L"SYSTEM\\ControlSet001"
1338 RtlInitUnicodeString(&KeyName, L"SYSTEM\\ControlSet001");
1339 InitializeObjectAttributes(&ObjectAttributes,
1340 &KeyName,
1341 OBJ_CASE_INSENSITIVE,
1342 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
1343 NULL);
1344 Status = NtCreateKey(&KeyHandle,
1345 KEY_ALL_ACCESS,
1346 &ObjectAttributes,
1347 0,
1348 NULL,
1349 REG_OPTION_NON_VOLATILE,
1350 &Disposition);
1351 if (!NT_SUCCESS(Status))
1352 {
1353 DPRINT1("NtCreateKey() failed to create the ControlSet001 key (Status %lx)\n", Status);
1354 // return Status;
1355 }
1356 else
1357 {
1358 DPRINT1("NtCreateKey() succeeded to %s the ControlSet001 key (Status %lx)\n",
1359 Disposition == REG_CREATED_NEW_KEY ? "create" : /* REG_OPENED_EXISTING_KEY */ "open",
1360 Status);
1361 }
1362 NtClose(KeyHandle);
1363
1364 /* Create the 'HKLM\SYSTEM\CurrentControlSet' symlink */
1365 if (!CmpLinkKeyToHive(RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
1366 L"SYSTEM\\CurrentControlSet",
1367 REGISTRY_SETUP_MACHINE L"SYSTEM\\ControlSet001"))
1368 {
1369 DPRINT1("CmpLinkKeyToHive(CurrentControlSet) failed!\n");
1370 }
1371
1372
1373 Status = STATUS_SUCCESS;
1374
1375
1376 Quit:
1377 /* Remove restore and backup privileges */
1378 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]);
1379 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1380
1381 return Status;
1382 }
1383
1384 VOID
1385 RegCleanupRegistry(
1386 IN PUNICODE_STRING InstallPath)
1387 {
1388 NTSTATUS Status;
1389 HANDLE KeyHandle;
1390 UNICODE_STRING KeyName;
1391 OBJECT_ATTRIBUTES ObjectAttributes;
1392 BOOLEAN PrivilegeSet[2] = {FALSE, FALSE};
1393 UINT i;
1394 WCHAR SrcPath[MAX_PATH];
1395 WCHAR DstPath[MAX_PATH];
1396
1397 /* Acquire restore privilege */
1398 Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[0]);
1399 if (!NT_SUCCESS(Status))
1400 {
1401 DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1402 /* Exit prematurely here.... */
1403 return;
1404 }
1405
1406 /* Acquire backup privilege */
1407 Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &PrivilegeSet[1]);
1408 if (!NT_SUCCESS(Status))
1409 {
1410 DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Status 0x%08lx)\n", Status);
1411 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1412 /* Exit prematurely here.... */
1413 return;
1414 }
1415
1416 /*
1417 * Note that we don't need to explicitly remove the symlinks we have created
1418 * since they are created volatile, inside registry keys that will be however
1419 * removed explictly in the following.
1420 */
1421
1422 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1423 {
1424 if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
1425 {
1426 RtlInitUnicodeString(&KeyName, RegistryHives[i].RegSymLink);
1427 InitializeObjectAttributes(&ObjectAttributes,
1428 &KeyName,
1429 OBJ_CASE_INSENSITIVE,
1430 RootKeys[GetPredefKeyIndex(RegistryHives[i].PredefKeyHandle)].Handle,
1431 NULL);
1432 KeyHandle = NULL;
1433 Status = NtOpenKey(&KeyHandle,
1434 DELETE,
1435 &ObjectAttributes);
1436 if (!NT_SUCCESS(Status))
1437 {
1438 DPRINT1("NtOpenKey(%wZ) failed, Status 0x%08lx\n", &KeyName, Status);
1439 // return;
1440 }
1441
1442 NtDeleteKey(KeyHandle);
1443 NtClose(KeyHandle);
1444 }
1445 else
1446 {
1447 RtlInitUnicodeString(&KeyName, RegistryHives[i].HiveRegistryPath);
1448 InitializeObjectAttributes(&ObjectAttributes,
1449 &KeyName,
1450 OBJ_CASE_INSENSITIVE,
1451 NULL,
1452 NULL);
1453 // Status = NtUnloadKey(&ObjectAttributes);
1454 Status = NtUnloadKey2(&ObjectAttributes, 1 /* REG_FORCE_UNLOAD */);
1455 DPRINT1("Unmounting '%S' %s\n", RegistryHives[i].HiveRegistryPath, NT_SUCCESS(Status) ? "succeeded" : "failed");
1456
1457 /* Switch the hive state to 'Update' */
1458 RegistryHives[i].State = Update;
1459 }
1460 }
1461
1462 /*
1463 * FIXME: Once force-unloading keys is correctly fixed, I'll fix
1464 * this code that closes some of the registry keys that were opened
1465 * inside the hives we've just unmounted above...
1466 */
1467
1468 /* Remove the registry root keys */
1469 for (i = 0; i < ARRAYSIZE(RootKeys); ++i)
1470 {
1471 if (RootKeys[i].Handle)
1472 {
1473 /**/NtFlushKey(RootKeys[i].Handle);/**/ // FIXME: Why does it hang? Answer: because we have some problems in CMAPI!
1474 NtDeleteKey(RootKeys[i].Handle);
1475 NtClose(RootKeys[i].Handle);
1476 RootKeys[i].Handle = NULL;
1477 }
1478 }
1479
1480 //
1481 // RegBackupRegistry()
1482 //
1483 /* Now backup the hives into .sav files */
1484 for (i = 0; i < ARRAYSIZE(RegistryHives); ++i)
1485 {
1486 if (RegistryHives[i].State != Create && RegistryHives[i].State != Repair)
1487 continue;
1488
1489 CombinePaths(SrcPath, ARRAYSIZE(SrcPath), 3,
1490 InstallPath->Buffer, L"System32\\config", RegistryHives[i].HiveName);
1491 StringCchCopyW(DstPath, ARRAYSIZE(DstPath), SrcPath);
1492 StringCchCatW(DstPath, ARRAYSIZE(DstPath), L".sav");
1493
1494 DPRINT1("Copy hive: %S ==> %S\n", SrcPath, DstPath);
1495 Status = SetupCopyFile(SrcPath, DstPath, FALSE);
1496 if (!NT_SUCCESS(Status))
1497 {
1498 DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
1499 // return Status;
1500 }
1501 }
1502
1503 /* Remove restore and backup privileges */
1504 RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, PrivilegeSet[1], FALSE, &PrivilegeSet[1]);
1505 RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, PrivilegeSet[0], FALSE, &PrivilegeSet[0]);
1506 }
1507
1508
1509 VOID
1510 SetDefaultPagefile(
1511 WCHAR Drive)
1512 {
1513 OBJECT_ATTRIBUTES ObjectAttributes;
1514 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
1515 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"PagingFiles");
1516 WCHAR ValueBuffer[] = L"?:\\pagefile.sys 0 0\0";
1517 HANDLE KeyHandle;
1518 NTSTATUS Status;
1519
1520 InitializeObjectAttributes(&ObjectAttributes,
1521 &KeyName,
1522 OBJ_CASE_INSENSITIVE,
1523 RootKeys[GetPredefKeyIndex(HKEY_LOCAL_MACHINE)].Handle,
1524 NULL);
1525 Status = NtOpenKey(&KeyHandle,
1526 KEY_ALL_ACCESS,
1527 &ObjectAttributes);
1528 if (!NT_SUCCESS(Status))
1529 return;
1530
1531 ValueBuffer[0] = Drive;
1532
1533 NtSetValueKey(KeyHandle,
1534 &ValueName,
1535 0,
1536 REG_MULTI_SZ,
1537 (PVOID)&ValueBuffer,
1538 sizeof(ValueBuffer));
1539
1540 NtClose(KeyHandle);
1541 }
1542
1543 /* EOF */