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 NtSystemRoot, 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(NtSystemRoot, 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(NtSystemRoot, 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 NtSystemRoot) 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(NtSystemRoot, 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 NtSystemRoot, 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 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 * 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 NtSystemRoot->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 */ 1116