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