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