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