1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * PURPOSE: Configuration Manager - System Initialization Code 5 * PROGRAMMERS: ReactOS Portable Systems Group 6 * Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "ntoskrnl.h" 12 #define NDEBUG 13 #include "debug.h" 14 15 POBJECT_TYPE CmpKeyObjectType; 16 PCMHIVE CmiVolatileHive; 17 LIST_ENTRY CmpHiveListHead; 18 ERESOURCE CmpRegistryLock; 19 KGUARDED_MUTEX CmpSelfHealQueueLock; 20 LIST_ENTRY CmpSelfHealQueueListHead; 21 KEVENT CmpLoadWorkerEvent; 22 LONG CmpLoadWorkerIncrement; 23 PEPROCESS CmpSystemProcess; 24 PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller; 25 BOOLEAN CmpFlushOnLockRelease; 26 BOOLEAN CmpSpecialBootCondition; 27 28 /* Disable registry hive writes, until the IO subsystem is initialized 29 * and disk access is enabled (when the SM signals so after AUTOCHK) */ 30 BOOLEAN CmpNoWrite = TRUE; 31 32 BOOLEAN CmpWasSetupBoot; 33 BOOLEAN CmpProfileLoaded; 34 BOOLEAN CmpNoVolatileCreates; 35 ULONG CmpTraceLevel = 0; 36 BOOLEAN HvShutdownComplete = FALSE; 37 38 extern LONG CmpFlushStarveWriters; 39 extern BOOLEAN CmFirstTime; 40 41 /* FUNCTIONS ******************************************************************/ 42 43 BOOLEAN 44 NTAPI 45 CmpLinkKeyToHive( 46 _In_z_ PCWSTR LinkKeyName, 47 _In_z_ PCWSTR TargetKeyName) 48 { 49 NTSTATUS Status; 50 OBJECT_ATTRIBUTES ObjectAttributes; 51 UNICODE_STRING KeyName; 52 HANDLE LinkKeyHandle; 53 ULONG Disposition; 54 55 PAGED_CODE(); 56 57 /* Initialize the object attributes */ 58 RtlInitUnicodeString(&KeyName, LinkKeyName); 59 InitializeObjectAttributes(&ObjectAttributes, 60 &KeyName, 61 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 62 NULL, 63 NULL); 64 65 /* Create the link key */ 66 Status = ZwCreateKey(&LinkKeyHandle, 67 KEY_CREATE_LINK, 68 &ObjectAttributes, 69 0, 70 NULL, 71 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, 72 &Disposition); 73 if (!NT_SUCCESS(Status)) 74 { 75 DPRINT1("CM: CmpLinkKeyToHive: couldn't create %S, Status = 0x%lx\n", 76 LinkKeyName, Status); 77 return FALSE; 78 } 79 80 /* Check if the new key was actually created */ 81 if (Disposition != REG_CREATED_NEW_KEY) 82 { 83 DPRINT1("CM: CmpLinkKeyToHive: %S already exists!\n", LinkKeyName); 84 ZwClose(LinkKeyHandle); 85 return FALSE; 86 } 87 88 /* Set the target key name as link target */ 89 RtlInitUnicodeString(&KeyName, TargetKeyName); 90 Status = ZwSetValueKey(LinkKeyHandle, 91 &CmSymbolicLinkValueName, 92 0, 93 REG_LINK, 94 KeyName.Buffer, 95 KeyName.Length); 96 97 /* Close the link key handle */ 98 ObCloseHandle(LinkKeyHandle, KernelMode); 99 100 if (!NT_SUCCESS(Status)) 101 { 102 DPRINT1("CM: CmpLinkKeyToHive: couldn't create symbolic link for %S, Status = 0x%lx\n", 103 TargetKeyName, Status); 104 return FALSE; 105 } 106 107 return TRUE; 108 } 109 110 VOID 111 NTAPI 112 CmpDeleteKeyObject(PVOID DeletedObject) 113 { 114 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)DeletedObject; 115 PCM_KEY_CONTROL_BLOCK Kcb; 116 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo; 117 REG_POST_OPERATION_INFORMATION PostOperationInfo; 118 NTSTATUS Status; 119 PAGED_CODE(); 120 121 /* First off, prepare the handle close information callback */ 122 PostOperationInfo.Object = KeyBody; 123 KeyHandleCloseInfo.Object = KeyBody; 124 Status = CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose, 125 &KeyHandleCloseInfo); 126 if (!NT_SUCCESS(Status)) 127 { 128 /* If we failed, notify the post routine */ 129 PostOperationInfo.Status = Status; 130 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo); 131 return; 132 } 133 134 /* Acquire hive lock */ 135 CmpLockRegistry(); 136 137 /* Make sure this is a valid key body */ 138 if (KeyBody->Type == CM_KEY_BODY_TYPE) 139 { 140 /* Get the KCB */ 141 Kcb = KeyBody->KeyControlBlock; 142 if (Kcb) 143 { 144 /* Delist the key */ 145 DelistKeyBodyFromKCB(KeyBody, KeyBody->KcbLocked); 146 147 /* Dereference the KCB */ 148 CmpDelayDerefKeyControlBlock(Kcb); 149 } 150 } 151 152 /* Release the registry lock */ 153 CmpUnlockRegistry(); 154 155 /* Do the post callback */ 156 PostOperationInfo.Status = STATUS_SUCCESS; 157 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo); 158 } 159 160 VOID 161 NTAPI 162 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL, 163 IN PVOID Object, 164 IN ACCESS_MASK GrantedAccess, 165 IN ULONG ProcessHandleCount, 166 IN ULONG SystemHandleCount) 167 { 168 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)Object; 169 PAGED_CODE(); 170 171 /* Don't do anything if we're not the last handle */ 172 if (SystemHandleCount > 1) return; 173 174 /* Make sure we're a valid key body */ 175 if (KeyBody->Type == CM_KEY_BODY_TYPE) 176 { 177 /* Don't do anything if we don't have a notify block */ 178 if (!KeyBody->NotifyBlock) return; 179 180 /* This shouldn't happen yet */ 181 ASSERT(FALSE); 182 } 183 } 184 185 NTSTATUS 186 NTAPI 187 CmpQueryKeyName(IN PVOID ObjectBody, 188 IN BOOLEAN HasName, 189 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo, 190 IN ULONG Length, 191 OUT PULONG ReturnLength, 192 IN KPROCESSOR_MODE PreviousMode) 193 { 194 PUNICODE_STRING KeyName; 195 ULONG BytesToCopy; 196 NTSTATUS Status = STATUS_SUCCESS; 197 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)ObjectBody; 198 PCM_KEY_CONTROL_BLOCK Kcb = KeyBody->KeyControlBlock; 199 200 /* Acquire hive lock */ 201 CmpLockRegistry(); 202 203 /* Lock KCB shared */ 204 CmpAcquireKcbLockShared(Kcb); 205 206 /* Check if it's a deleted block */ 207 if (Kcb->Delete) 208 { 209 /* Release the locks */ 210 CmpReleaseKcbLock(Kcb); 211 CmpUnlockRegistry(); 212 213 /* Let the caller know it's deleted */ 214 return STATUS_KEY_DELETED; 215 } 216 217 /* Get the name */ 218 KeyName = CmpConstructName(Kcb); 219 220 /* Release the locks */ 221 CmpReleaseKcbLock(Kcb); 222 CmpUnlockRegistry(); 223 224 /* Check if we got the name */ 225 if (!KeyName) return STATUS_INSUFFICIENT_RESOURCES; 226 227 /* Set the returned length */ 228 *ReturnLength = KeyName->Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR); 229 230 /* Calculate amount of bytes to copy into the buffer */ 231 BytesToCopy = KeyName->Length + sizeof(WCHAR); 232 233 /* Check if the provided buffer is too small to fit even anything */ 234 if ((Length <= sizeof(OBJECT_NAME_INFORMATION)) || 235 ((Length < *ReturnLength) && (BytesToCopy < sizeof(WCHAR)))) 236 { 237 /* Free the buffer allocated by CmpConstructName */ 238 ExFreePoolWithTag(KeyName, TAG_CM); 239 240 /* Return buffer length failure without writing anything there because nothing fits */ 241 return STATUS_INFO_LENGTH_MISMATCH; 242 } 243 244 /* Check if the provided buffer can be partially written */ 245 if (Length < *ReturnLength) 246 { 247 /* Yes, indicate so in the return status */ 248 Status = STATUS_INFO_LENGTH_MISMATCH; 249 250 /* Calculate amount of bytes which the provided buffer could handle */ 251 BytesToCopy = Length - sizeof(OBJECT_NAME_INFORMATION); 252 } 253 254 /* Remove the null termination character from the size */ 255 BytesToCopy -= sizeof(WCHAR); 256 257 /* Fill in the result */ 258 _SEH2_TRY 259 { 260 /* Return data to user */ 261 ObjectNameInfo->Name.Buffer = (PWCHAR)(ObjectNameInfo + 1); 262 ObjectNameInfo->Name.MaximumLength = KeyName->Length; 263 ObjectNameInfo->Name.Length = KeyName->Length; 264 265 /* Copy string content*/ 266 RtlCopyMemory(ObjectNameInfo->Name.Buffer, 267 KeyName->Buffer, 268 BytesToCopy); 269 270 /* Null terminate it */ 271 ObjectNameInfo->Name.Buffer[BytesToCopy / sizeof(WCHAR)] = UNICODE_NULL; 272 } 273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 274 { 275 /* Get the status */ 276 Status = _SEH2_GetExceptionCode(); 277 } 278 _SEH2_END; 279 280 /* Free the buffer allocated by CmpConstructName */ 281 ExFreePoolWithTag(KeyName, TAG_CM); 282 283 /* Return status */ 284 return Status; 285 } 286 287 NTSTATUS 288 NTAPI 289 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName, 290 IN ULONG HiveFlags, 291 OUT PCMHIVE *Hive, 292 IN OUT PBOOLEAN New, 293 IN ULONG CheckFlags) 294 { 295 ULONG HiveDisposition, LogDisposition; 296 HANDLE FileHandle = NULL, LogHandle = NULL; 297 NTSTATUS Status; 298 ULONG Operation, FileType; 299 PCMHIVE NewHive; 300 PAGED_CODE(); 301 302 /* Assume failure */ 303 *Hive = NULL; 304 305 /* Open or create the hive files */ 306 Status = CmpOpenHiveFiles(HiveName, 307 L".LOG", 308 &FileHandle, 309 &LogHandle, 310 &HiveDisposition, 311 &LogDisposition, 312 *New, 313 FALSE, 314 TRUE, 315 NULL); 316 if (!NT_SUCCESS(Status)) return Status; 317 318 /* Check if we have a log handle */ 319 FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY; 320 321 /* Check if we created or opened the hive */ 322 if (HiveDisposition == FILE_CREATED) 323 { 324 /* Do a create operation */ 325 Operation = HINIT_CREATE; 326 *New = TRUE; 327 } 328 else 329 { 330 /* Open it as a file */ 331 Operation = HINIT_FILE; 332 *New = FALSE; 333 } 334 335 /* Check if the system hives are opened in shared mode */ 336 if (CmpShareSystemHives) 337 { 338 /* Then force using the primary hive */ 339 FileType = HFILE_TYPE_PRIMARY; 340 if (LogHandle) 341 { 342 /* Get rid of the log handle */ 343 ZwClose(LogHandle); 344 LogHandle = NULL; 345 } 346 } 347 348 /* Check if we're too late */ 349 if (HvShutdownComplete) 350 { 351 /* Fail */ 352 ZwClose(FileHandle); 353 if (LogHandle) ZwClose(LogHandle); 354 return STATUS_TOO_LATE; 355 } 356 357 /* Initialize the hive */ 358 Status = CmpInitializeHive(&NewHive, 359 Operation, 360 HiveFlags, 361 FileType, 362 NULL, 363 FileHandle, 364 LogHandle, 365 NULL, 366 NULL, 367 HiveName, 368 CheckFlags); 369 if (!NT_SUCCESS(Status)) 370 { 371 /* Fail */ 372 ZwClose(FileHandle); 373 if (LogHandle) ZwClose(LogHandle); 374 return Status; 375 } 376 377 /* Success, return hive */ 378 *Hive = NewHive; 379 380 /* Duplicate the hive name */ 381 NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool, 382 HiveName->Length, 383 TAG_CM); 384 if (NewHive->FileFullPath.Buffer) 385 { 386 /* Copy the string */ 387 RtlCopyMemory(NewHive->FileFullPath.Buffer, 388 HiveName->Buffer, 389 HiveName->Length); 390 NewHive->FileFullPath.Length = HiveName->Length; 391 NewHive->FileFullPath.MaximumLength = HiveName->Length; 392 } 393 394 /* Return success */ 395 return STATUS_SUCCESS; 396 } 397 398 CODE_SEG("INIT") 399 NTSTATUS 400 NTAPI 401 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 402 { 403 NTSTATUS Status; 404 OBJECT_ATTRIBUTES ObjectAttributes; 405 HANDLE KeyHandle; 406 UNICODE_STRING KeyName, ValueName = { 0, 0, NULL }; 407 408 ASSERT(LoaderBlock != NULL); 409 410 /* Setup attributes for loader options */ 411 RtlInitUnicodeString(&KeyName, 412 L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\" 413 L"Control"); 414 InitializeObjectAttributes(&ObjectAttributes, 415 &KeyName, 416 OBJ_CASE_INSENSITIVE, 417 NULL, 418 NULL); 419 Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes); 420 if (!NT_SUCCESS(Status)) 421 return Status; 422 423 /* Setup the value for the system start options */ 424 RtlInitUnicodeString(&KeyName, L"SystemStartOptions"); 425 Status = NtSetValueKey(KeyHandle, 426 &KeyName, 427 0, 428 REG_SZ, 429 CmpLoadOptions.Buffer, 430 CmpLoadOptions.Length); 431 if (!NT_SUCCESS(Status)) 432 goto Quit; 433 434 /* Setup the value for the system boot device in ARC format */ 435 RtlInitUnicodeString(&KeyName, L"SystemBootDevice"); 436 RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->ArcBootDeviceName); 437 Status = NtSetValueKey(KeyHandle, 438 &KeyName, 439 0, 440 REG_SZ, 441 ValueName.Buffer, 442 ValueName.Length); 443 444 /* Free the temporary string */ 445 RtlFreeUnicodeString(&ValueName); 446 447 Quit: 448 /* Close the key and return */ 449 NtClose(KeyHandle); 450 return Status; 451 } 452 453 static 454 CODE_SEG("INIT") 455 NTSTATUS 456 CmpCreateHardwareProfile(HANDLE ControlSetHandle) 457 { 458 OBJECT_ATTRIBUTES ObjectAttributes; 459 UNICODE_STRING KeyName; 460 HANDLE ProfilesHandle = NULL; 461 HANDLE ProfileHandle = NULL; 462 ULONG Disposition; 463 NTSTATUS Status; 464 465 DPRINT("CmpCreateHardwareProfile()\n"); 466 467 /* Create the Hardware Profiles key */ 468 RtlInitUnicodeString(&KeyName, L"Hardware Profiles"); 469 InitializeObjectAttributes(&ObjectAttributes, 470 &KeyName, 471 OBJ_CASE_INSENSITIVE, 472 ControlSetHandle, 473 NULL); 474 Status = NtCreateKey(&ProfilesHandle, 475 KEY_ALL_ACCESS, 476 &ObjectAttributes, 477 0, 478 NULL, 479 0, 480 &Disposition); 481 if (!NT_SUCCESS(Status)) 482 { 483 DPRINT1("Creating the Hardware Profile key failed\n"); 484 goto done; 485 } 486 487 /* Sanity check */ 488 ASSERT(Disposition == REG_CREATED_NEW_KEY); 489 490 /* Create the 0000 key */ 491 RtlInitUnicodeString(&KeyName, L"0000"); 492 InitializeObjectAttributes(&ObjectAttributes, 493 &KeyName, 494 OBJ_CASE_INSENSITIVE, 495 ProfilesHandle, 496 NULL); 497 Status = NtCreateKey(&ProfileHandle, 498 KEY_ALL_ACCESS, 499 &ObjectAttributes, 500 0, 501 NULL, 502 0, 503 &Disposition); 504 if (!NT_SUCCESS(Status)) 505 { 506 DPRINT1("Creating the Hardware Profile\\0000 key failed\n"); 507 goto done; 508 } 509 510 /* Sanity check */ 511 ASSERT(Disposition == REG_CREATED_NEW_KEY); 512 513 done: 514 if (ProfilesHandle) 515 NtClose(ProfilesHandle); 516 517 if (ProfileHandle) 518 NtClose(ProfileHandle); 519 520 DPRINT("CmpCreateHardwareProfile() done\n"); 521 522 return Status; 523 } 524 525 CODE_SEG("INIT") 526 NTSTATUS 527 NTAPI 528 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 529 { 530 UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB"); 531 UNICODE_STRING SelectName = 532 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select"); 533 UNICODE_STRING KeyName; 534 OBJECT_ATTRIBUTES ObjectAttributes; 535 CHAR ValueInfoBuffer[128]; 536 PKEY_VALUE_FULL_INFORMATION ValueInfo; 537 WCHAR UnicodeBuffer[128]; 538 HANDLE SelectHandle = NULL; 539 HANDLE KeyHandle = NULL; 540 HANDLE ConfigHandle = NULL; 541 HANDLE ProfileHandle = NULL; 542 HANDLE ParentHandle = NULL; 543 ULONG ControlSet, HwProfile; 544 NTSTATUS Status; 545 ULONG ResultLength, Disposition; 546 PLOADER_PARAMETER_EXTENSION LoaderExtension; 547 PAGED_CODE(); 548 549 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */ 550 if (LoaderBlock->RegistryBase == NULL) 551 { 552 /* Build the ControlSet001 key */ 553 RtlInitUnicodeString(&KeyName, 554 L"\\Registry\\Machine\\System\\ControlSet001"); 555 InitializeObjectAttributes(&ObjectAttributes, 556 &KeyName, 557 OBJ_CASE_INSENSITIVE, 558 NULL, 559 NULL); 560 Status = NtCreateKey(&KeyHandle, 561 KEY_ALL_ACCESS, 562 &ObjectAttributes, 563 0, 564 NULL, 565 0, 566 &Disposition); 567 if (!NT_SUCCESS(Status)) 568 { 569 DPRINT1("Failed to create ControlSet001 key: 0x%lx\n", Status); 570 goto Cleanup; 571 } 572 573 /* Create the Hardware Profile keys */ 574 Status = CmpCreateHardwareProfile(KeyHandle); 575 if (!NT_SUCCESS(Status)) 576 { 577 DPRINT1("Failed to create Hardware profile keys: 0x%lx\n", Status); 578 goto Cleanup; 579 } 580 581 /* Use hard-coded setting */ 582 ControlSet = 1; 583 } 584 else 585 { 586 /* Open the select key */ 587 InitializeObjectAttributes(&ObjectAttributes, 588 &SelectName, 589 OBJ_CASE_INSENSITIVE, 590 NULL, 591 NULL); 592 Status = NtOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes); 593 if (!NT_SUCCESS(Status)) 594 { 595 DPRINT1("Failed to open select key: 0x%lx\n", Status); 596 goto Cleanup; 597 } 598 599 /* Open the current value */ 600 RtlInitUnicodeString(&KeyName, L"Current"); 601 Status = NtQueryValueKey(SelectHandle, 602 &KeyName, 603 KeyValueFullInformation, 604 ValueInfoBuffer, 605 sizeof(ValueInfoBuffer), 606 &ResultLength); 607 if (!NT_SUCCESS(Status)) 608 { 609 DPRINT1("Failed to open the Current value: 0x%lx\n", Status); 610 goto Cleanup; 611 } 612 613 /* Get the actual value pointer, and get the control set ID */ 614 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer; 615 ControlSet = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset); 616 } 617 618 /* Create the current control set key */ 619 RtlInitUnicodeString(&KeyName, 620 L"\\Registry\\Machine\\System\\CurrentControlSet"); 621 InitializeObjectAttributes(&ObjectAttributes, 622 &KeyName, 623 OBJ_CASE_INSENSITIVE, 624 NULL, 625 NULL); 626 Status = NtCreateKey(&KeyHandle, 627 KEY_CREATE_LINK, 628 &ObjectAttributes, 629 0, 630 NULL, 631 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, 632 &Disposition); 633 if (!NT_SUCCESS(Status)) 634 goto Cleanup; 635 636 /* Sanity check */ 637 ASSERT(Disposition == REG_CREATED_NEW_KEY); 638 639 /* Initialize the target link name */ 640 Status = RtlStringCbPrintfW(UnicodeBuffer, sizeof(UnicodeBuffer), 641 L"\\Registry\\Machine\\System\\ControlSet%03ld", 642 ControlSet); 643 if (!NT_SUCCESS(Status)) 644 goto Cleanup; 645 646 RtlInitUnicodeString(&KeyName, UnicodeBuffer); 647 648 /* Set the value */ 649 Status = NtSetValueKey(KeyHandle, 650 &CmSymbolicLinkValueName, 651 0, 652 REG_LINK, 653 KeyName.Buffer, 654 KeyName.Length); 655 if (!NT_SUCCESS(Status)) 656 goto Cleanup; 657 658 /* Get the configuration database key */ 659 InitializeObjectAttributes(&ObjectAttributes, 660 &ConfigName, 661 OBJ_CASE_INSENSITIVE, 662 KeyHandle, 663 NULL); 664 Status = NtOpenKey(&ConfigHandle, KEY_READ, &ObjectAttributes); 665 666 /* Check if we don't have one */ 667 if (!NT_SUCCESS(Status)) 668 { 669 /* Cleanup and exit */ 670 Status = STATUS_SUCCESS; 671 goto Cleanup; 672 } 673 674 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */ 675 if (LoaderBlock->RegistryBase == NULL) 676 { 677 HwProfile = 0; 678 } 679 else 680 { 681 /* Now get the current config */ 682 RtlInitUnicodeString(&KeyName, L"CurrentConfig"); 683 Status = NtQueryValueKey(ConfigHandle, 684 &KeyName, 685 KeyValueFullInformation, 686 ValueInfoBuffer, 687 sizeof(ValueInfoBuffer), 688 &ResultLength); 689 690 /* Set pointer to buffer */ 691 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer; 692 693 /* Check if we failed or got a non DWORD-value */ 694 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_DWORD)) 695 { 696 Status = STATUS_SUCCESS; 697 goto Cleanup; 698 } 699 700 /* Get the hadware profile */ 701 HwProfile = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset); 702 } 703 704 /* Open the hardware profile key */ 705 RtlInitUnicodeString(&KeyName, 706 L"\\Registry\\Machine\\System\\CurrentControlSet" 707 L"\\Hardware Profiles"); 708 InitializeObjectAttributes(&ObjectAttributes, 709 &KeyName, 710 OBJ_CASE_INSENSITIVE, 711 NULL, 712 NULL); 713 Status = NtOpenKey(&ParentHandle, KEY_READ, &ObjectAttributes); 714 if (!NT_SUCCESS(Status)) 715 { 716 /* Exit and clean up */ 717 Status = STATUS_SUCCESS; 718 goto Cleanup; 719 } 720 721 /* Build the profile name */ 722 RtlStringCbPrintfW(UnicodeBuffer, sizeof(UnicodeBuffer), 723 L"%04ld", HwProfile); 724 RtlInitUnicodeString(&KeyName, UnicodeBuffer); 725 726 /* Open the associated key */ 727 InitializeObjectAttributes(&ObjectAttributes, 728 &KeyName, 729 OBJ_CASE_INSENSITIVE, 730 ParentHandle, 731 NULL); 732 Status = NtOpenKey(&ProfileHandle, 733 KEY_READ | KEY_WRITE, 734 &ObjectAttributes); 735 if (!NT_SUCCESS(Status)) 736 { 737 /* Cleanup and exit */ 738 Status = STATUS_SUCCESS; 739 goto Cleanup; 740 } 741 742 /* Check if we have a loader block extension */ 743 LoaderExtension = LoaderBlock->Extension; 744 if (LoaderExtension) 745 { 746 DPRINT("ReactOS doesn't support NTLDR Profiles yet!\n"); 747 } 748 749 /* Create the current hardware profile key */ 750 RtlInitUnicodeString(&KeyName, 751 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 752 L"Hardware Profiles\\Current"); 753 InitializeObjectAttributes(&ObjectAttributes, 754 &KeyName, 755 OBJ_CASE_INSENSITIVE, 756 NULL, 757 NULL); 758 Status = NtCreateKey(&KeyHandle, 759 KEY_CREATE_LINK, 760 &ObjectAttributes, 761 0, 762 NULL, 763 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, 764 &Disposition); 765 if (NT_SUCCESS(Status)) 766 { 767 /* Sanity check */ 768 ASSERT(Disposition == REG_CREATED_NEW_KEY); 769 770 /* Create the profile name */ 771 RtlStringCbPrintfW(UnicodeBuffer, sizeof(UnicodeBuffer), 772 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 773 L"Hardware Profiles\\%04ld", 774 HwProfile); 775 RtlInitUnicodeString(&KeyName, UnicodeBuffer); 776 777 /* Set it */ 778 Status = NtSetValueKey(KeyHandle, 779 &CmSymbolicLinkValueName, 780 0, 781 REG_LINK, 782 KeyName.Buffer, 783 KeyName.Length); 784 } 785 786 Status = STATUS_SUCCESS; 787 788 Cleanup: 789 /* Close every opened handle */ 790 if (SelectHandle) NtClose(SelectHandle); 791 if (KeyHandle) NtClose(KeyHandle); 792 if (ConfigHandle) NtClose(ConfigHandle); 793 if (ProfileHandle) NtClose(ProfileHandle); 794 if (ParentHandle) NtClose(ParentHandle); 795 796 DPRINT("CmpCreateControlSet() done\n"); 797 return Status; 798 } 799 800 NTSTATUS 801 NTAPI 802 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName, 803 IN HANDLE RootDirectory, 804 IN PCMHIVE RegistryHive, 805 IN BOOLEAN Allocate, 806 IN PSECURITY_DESCRIPTOR SecurityDescriptor) 807 { 808 OBJECT_ATTRIBUTES ObjectAttributes; 809 NTSTATUS Status; 810 CM_PARSE_CONTEXT ParseContext = {0}; 811 HANDLE KeyHandle; 812 PCM_KEY_BODY KeyBody; 813 PAGED_CODE(); 814 815 /* Setup the object attributes */ 816 InitializeObjectAttributes(&ObjectAttributes, 817 LinkName, 818 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 819 RootDirectory, 820 SecurityDescriptor); 821 822 /* Setup the parse context */ 823 ParseContext.CreateLink = TRUE; 824 ParseContext.CreateOperation = TRUE; 825 ParseContext.ChildHive.KeyHive = &RegistryHive->Hive; 826 827 /* Check if we have a root keycell or if we need to create it */ 828 if (Allocate) 829 { 830 /* Create it */ 831 ParseContext.ChildHive.KeyCell = HCELL_NIL; 832 } 833 else 834 { 835 /* We have one */ 836 ParseContext.ChildHive.KeyCell = RegistryHive->Hive.BaseBlock->RootCell; 837 } 838 839 /* Create the link node */ 840 Status = ObOpenObjectByName(&ObjectAttributes, 841 CmpKeyObjectType, 842 KernelMode, 843 NULL, 844 KEY_READ | KEY_WRITE, 845 (PVOID)&ParseContext, 846 &KeyHandle); 847 if (!NT_SUCCESS(Status)) return Status; 848 849 /* Mark the hive as clean */ 850 RegistryHive->Hive.DirtyFlag = FALSE; 851 852 /* ReactOS Hack: Keep alive */ 853 Status = ObReferenceObjectByHandle(KeyHandle, 854 0, 855 CmpKeyObjectType, 856 KernelMode, 857 (PVOID*)&KeyBody, 858 NULL); 859 ASSERT(NT_SUCCESS(Status)); 860 861 /* Close the extra handle */ 862 ZwClose(KeyHandle); 863 return STATUS_SUCCESS; 864 } 865 866 CODE_SEG("INIT") 867 BOOLEAN 868 NTAPI 869 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 870 { 871 static const UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM"); 872 PVOID HiveBase; 873 ANSI_STRING LoadString; 874 PVOID Buffer; 875 ULONG Length; 876 NTSTATUS Status; 877 UNICODE_STRING KeyName; 878 PCMHIVE SystemHive = NULL; 879 PSECURITY_DESCRIPTOR SecurityDescriptor; 880 881 PAGED_CODE(); 882 883 /* Setup the ansi string */ 884 RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions); 885 886 /* Allocate the unicode buffer */ 887 Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL); 888 Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); 889 if (!Buffer) 890 { 891 /* Fail */ 892 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0); 893 } 894 895 /* Setup the unicode string */ 896 RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length); 897 898 /* Add the load options and null-terminate */ 899 Status = RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE); 900 if (!NT_SUCCESS(Status)) 901 { 902 return FALSE; 903 } 904 905 CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL; 906 CmpLoadOptions.Length += sizeof(WCHAR); 907 908 /* Get the System Hive base address */ 909 HiveBase = LoaderBlock->RegistryBase; 910 911 Status = CmpInitializeHive(&SystemHive, 912 HiveBase ? HINIT_MEMORY : HINIT_CREATE, 913 HIVE_NOLAZYFLUSH, 914 HFILE_TYPE_ALTERNATE, 915 HiveBase, 916 NULL, 917 NULL, 918 NULL, 919 NULL, 920 &HiveName, 921 HiveBase ? CM_CHECK_REGISTRY_PURGE_VOLATILES : CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 922 if (!NT_SUCCESS(Status)) 923 { 924 return FALSE; 925 } 926 927 /* Set the hive filename */ 928 if (!RtlCreateUnicodeString(&SystemHive->FileFullPath, L"\\SystemRoot\\System32\\Config\\SYSTEM")) 929 return FALSE; 930 931 /* Load the system hive as volatile, if opened in shared mode */ 932 if (HiveBase && CmpShareSystemHives) 933 SystemHive->Hive.HiveFlags = HIVE_VOLATILE; 934 935 /* Save the boot type */ 936 CmpBootType = SystemHive->Hive.BaseBlock->BootType; 937 938 /* Are we in self-healing mode? */ 939 if (!CmSelfHeal) 940 { 941 /* Disable self-healing internally and check if boot type wanted it */ 942 CmpSelfHeal = FALSE; 943 if (CmpBootType & HBOOT_TYPE_SELF_HEAL) 944 { 945 /* We're disabled, so bugcheck */ 946 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 947 3, 948 3, 949 (ULONG_PTR)SystemHive, 950 0); 951 } 952 } 953 954 /* Create the default security descriptor */ 955 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 956 957 /* Attach it to the system key */ 958 /* Let CmpLinkHiveToMaster allocate a new hive if we got none from the LoaderBlock. */ 959 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM"); 960 Status = CmpLinkHiveToMaster(&KeyName, 961 NULL, 962 SystemHive, 963 !HiveBase, 964 SecurityDescriptor); 965 966 /* Free the security descriptor */ 967 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 968 if (!NT_SUCCESS(Status)) return FALSE; 969 970 /* Add the hive to the hive list */ 971 CmpMachineHiveList[3].CmHive = SystemHive; 972 973 /* Success! */ 974 return TRUE; 975 } 976 977 CODE_SEG("INIT") 978 NTSTATUS 979 NTAPI 980 CmpCreateObjectTypes(VOID) 981 { 982 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 983 UNICODE_STRING Name; 984 GENERIC_MAPPING CmpKeyMapping = {KEY_READ, 985 KEY_WRITE, 986 KEY_EXECUTE, 987 KEY_ALL_ACCESS}; 988 PAGED_CODE(); 989 990 /* Initialize the Key object type */ 991 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 992 RtlInitUnicodeString(&Name, L"Key"); 993 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 994 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY); 995 ObjectTypeInitializer.GenericMapping = CmpKeyMapping; 996 ObjectTypeInitializer.PoolType = PagedPool; 997 ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS; 998 ObjectTypeInitializer.UseDefaultObject = TRUE; 999 ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject; 1000 ObjectTypeInitializer.ParseProcedure = CmpParseKey; 1001 ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod; 1002 ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName; 1003 ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject; 1004 ObjectTypeInitializer.SecurityRequired = TRUE; 1005 ObjectTypeInitializer.InvalidAttributes = OBJ_EXCLUSIVE | OBJ_PERMANENT; 1006 1007 /* Create it */ 1008 return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType); 1009 } 1010 1011 CODE_SEG("INIT") 1012 BOOLEAN 1013 NTAPI 1014 CmpCreateRootNode(IN PHHIVE Hive, 1015 IN PCWSTR Name, 1016 OUT PHCELL_INDEX Index) 1017 { 1018 UNICODE_STRING KeyName; 1019 PCM_KEY_NODE KeyCell; 1020 PAGED_CODE(); 1021 1022 /* Initialize the node name and allocate it */ 1023 RtlInitUnicodeString(&KeyName, Name); 1024 *Index = HvAllocateCell(Hive, 1025 FIELD_OFFSET(CM_KEY_NODE, Name) + 1026 CmpNameSize(Hive, &KeyName), 1027 Stable, 1028 HCELL_NIL); 1029 if (*Index == HCELL_NIL) return FALSE; 1030 1031 /* Set the cell index and get the data */ 1032 Hive->BaseBlock->RootCell = *Index; 1033 KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index); 1034 if (!KeyCell) return FALSE; 1035 1036 /* Setup the cell */ 1037 KeyCell->Signature = CM_KEY_NODE_SIGNATURE; 1038 KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE; 1039 KeQuerySystemTime(&KeyCell->LastWriteTime); 1040 KeyCell->Parent = HCELL_NIL; 1041 KeyCell->SubKeyCounts[Stable] = 0; 1042 KeyCell->SubKeyCounts[Volatile] = 0; 1043 KeyCell->SubKeyLists[Stable] = HCELL_NIL; 1044 KeyCell->SubKeyLists[Volatile] = HCELL_NIL; 1045 KeyCell->ValueList.Count = 0; 1046 KeyCell->ValueList.List = HCELL_NIL; 1047 KeyCell->Security = HCELL_NIL; 1048 KeyCell->Class = HCELL_NIL; 1049 KeyCell->ClassLength = 0; 1050 KeyCell->MaxNameLen = 0; 1051 KeyCell->MaxClassLen = 0; 1052 KeyCell->MaxValueNameLen = 0; 1053 KeyCell->MaxValueDataLen = 0; 1054 1055 /* Copy the name (this will also set the length) */ 1056 KeyCell->NameLength = CmpCopyName(Hive, KeyCell->Name, &KeyName); 1057 1058 /* Check if the name was compressed and set the flag if so */ 1059 if (KeyCell->NameLength < KeyName.Length) 1060 KeyCell->Flags |= KEY_COMP_NAME; 1061 1062 /* Return success */ 1063 HvReleaseCell(Hive, *Index); 1064 return TRUE; 1065 } 1066 1067 CODE_SEG("INIT") 1068 BOOLEAN 1069 NTAPI 1070 CmpCreateRegistryRoot(VOID) 1071 { 1072 UNICODE_STRING KeyName; 1073 OBJECT_ATTRIBUTES ObjectAttributes; 1074 PCM_KEY_BODY RootKey; 1075 HCELL_INDEX RootIndex; 1076 NTSTATUS Status; 1077 PCM_KEY_NODE KeyCell; 1078 PSECURITY_DESCRIPTOR SecurityDescriptor; 1079 PCM_KEY_CONTROL_BLOCK Kcb; 1080 PAGED_CODE(); 1081 1082 /* Setup the root node */ 1083 if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex)) 1084 { 1085 /* We failed */ 1086 return FALSE; 1087 } 1088 1089 /* Create '\Registry' key. */ 1090 RtlInitUnicodeString(&KeyName, L"\\REGISTRY"); 1091 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1092 InitializeObjectAttributes(&ObjectAttributes, 1093 &KeyName, 1094 OBJ_CASE_INSENSITIVE, 1095 NULL, 1096 SecurityDescriptor); 1097 Status = ObCreateObject(KernelMode, 1098 CmpKeyObjectType, 1099 &ObjectAttributes, 1100 KernelMode, 1101 NULL, 1102 sizeof(CM_KEY_BODY), 1103 0, 1104 0, 1105 (PVOID*)&RootKey); 1106 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1107 if (!NT_SUCCESS(Status)) return FALSE; 1108 1109 /* Sanity check, and get the key cell */ 1110 ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL); 1111 KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex); 1112 if (!KeyCell) return FALSE; 1113 1114 /* Create the KCB */ 1115 RtlInitUnicodeString(&KeyName, L"\\REGISTRY"); 1116 Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive, 1117 RootIndex, 1118 KeyCell, 1119 NULL, 1120 0, 1121 &KeyName); 1122 if (!Kcb) 1123 { 1124 ObDereferenceObject(RootKey); 1125 return FALSE; 1126 } 1127 1128 /* Initialize the object */ 1129 RootKey->KeyControlBlock = Kcb; 1130 RootKey->Type = CM_KEY_BODY_TYPE; 1131 RootKey->NotifyBlock = NULL; 1132 RootKey->ProcessID = PsGetCurrentProcessId(); 1133 RootKey->KcbLocked = FALSE; 1134 1135 /* Link with KCB */ 1136 EnlistKeyBodyWithKCB(RootKey, 0); 1137 1138 /* Insert the key into the namespace */ 1139 Status = ObInsertObject(RootKey, 1140 NULL, 1141 KEY_ALL_ACCESS, 1142 0, 1143 NULL, 1144 &CmpRegistryRootHandle); 1145 if (!NT_SUCCESS(Status)) 1146 { 1147 ObDereferenceObject(RootKey); 1148 return FALSE; 1149 } 1150 1151 /* Reference the key again so that we never lose it */ 1152 Status = ObReferenceObjectByHandle(CmpRegistryRootHandle, 1153 KEY_READ, 1154 NULL, 1155 KernelMode, 1156 (PVOID*)&RootKey, 1157 NULL); 1158 if (!NT_SUCCESS(Status)) 1159 { 1160 ObDereferenceObject(RootKey); 1161 return FALSE; 1162 } 1163 1164 /* Completely sucessful */ 1165 return TRUE; 1166 } 1167 1168 static PCWSTR 1169 CmpGetRegistryPath(VOID) 1170 { 1171 PCWSTR ConfigPath; 1172 1173 /* Check if we are booted in setup */ 1174 if (!ExpInTextModeSetup) 1175 { 1176 ConfigPath = L"\\SystemRoot\\System32\\Config\\"; 1177 } 1178 else 1179 { 1180 ConfigPath = L"\\SystemRoot\\"; 1181 } 1182 1183 DPRINT1("CmpGetRegistryPath: ConfigPath = '%S'\n", ConfigPath); 1184 1185 return ConfigPath; 1186 } 1187 1188 /** 1189 * @brief 1190 * Checks if the primary and alternate backing hive are 1191 * the same, by determining the time stamp of both hives. 1192 * 1193 * @param[in] FileName 1194 * A pointer to a string containing the file name of the 1195 * primary hive. 1196 * 1197 * @param[in] CmMainmHive 1198 * A pointer to a CM hive descriptor associated with the 1199 * primary hive. 1200 * 1201 * @param[in] AlternateHandle 1202 * A handle to a file that represents the alternate hive. 1203 * 1204 * @param[in] Diverged 1205 * A pointer to a boolean value, if both hives are the same 1206 * it returns TRUE. Otherwise it returns FALSE. 1207 */ 1208 static 1209 VOID 1210 CmpHasAlternateHiveDiverged( 1211 _In_ PCUNICODE_STRING FileName, 1212 _In_ PCMHIVE CmMainmHive, 1213 _In_ HANDLE AlternateHandle, 1214 _Out_ PBOOLEAN Diverged) 1215 { 1216 PHHIVE Hive, AlternateHive; 1217 NTSTATUS Status; 1218 PCMHIVE CmiAlternateHive; 1219 1220 /* Assume it has not diverged */ 1221 *Diverged = FALSE; 1222 1223 /* Initialize the SYSTEM alternate hive */ 1224 Status = CmpInitializeHive(&CmiAlternateHive, 1225 HINIT_FILE, 1226 0, 1227 HFILE_TYPE_PRIMARY, 1228 NULL, 1229 AlternateHandle, 1230 NULL, 1231 NULL, 1232 NULL, 1233 FileName, 1234 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 1235 if (!NT_SUCCESS(Status)) 1236 { 1237 /* Assume it has diverged... */ 1238 DPRINT1("Failed to initialize the alternate hive to check for diversion (Status 0x%lx)\n", Status); 1239 *Diverged = TRUE; 1240 return; 1241 } 1242 1243 /* 1244 * Check the timestamp of both hives. If they do not match they 1245 * have diverged, the kernel has to synchronize the both hives. 1246 */ 1247 Hive = &CmMainmHive->Hive; 1248 AlternateHive = &CmiAlternateHive->Hive; 1249 if (AlternateHive->BaseBlock->TimeStamp.QuadPart != 1250 Hive->BaseBlock->TimeStamp.QuadPart) 1251 { 1252 *Diverged = TRUE; 1253 } 1254 1255 CmpDestroyHive(CmiAlternateHive); 1256 } 1257 1258 _Function_class_(KSTART_ROUTINE) 1259 VOID 1260 NTAPI 1261 CmpLoadHiveThread(IN PVOID StartContext) 1262 { 1263 WCHAR FileBuffer[64], RegBuffer[64]; 1264 PCWSTR ConfigPath; 1265 UNICODE_STRING TempName, FileName, RegName; 1266 ULONG i, ErrorResponse, WorkerCount, Length; 1267 USHORT FileStart; 1268 ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize; 1269 PCMHIVE CmHive; 1270 HANDLE PrimaryHandle = NULL, AlternateHandle = NULL; 1271 NTSTATUS Status = STATUS_SUCCESS; 1272 PVOID ErrorParameters; 1273 BOOLEAN HasDiverged; 1274 PAGED_CODE(); 1275 1276 /* Get the hive index, make sure it makes sense */ 1277 i = PtrToUlong(StartContext); 1278 ASSERT(CmpMachineHiveList[i].Name != NULL); 1279 1280 /* We were started */ 1281 CmpMachineHiveList[i].ThreadStarted = TRUE; 1282 1283 /* Build the file name and registry name strings */ 1284 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer)); 1285 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer)); 1286 1287 /* Now build the system root path */ 1288 ConfigPath = CmpGetRegistryPath(); 1289 RtlInitUnicodeString(&TempName, ConfigPath); 1290 RtlAppendUnicodeStringToString(&FileName, &TempName); 1291 FileStart = FileName.Length; 1292 1293 /* And build the registry root path */ 1294 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); 1295 RtlAppendUnicodeStringToString(&RegName, &TempName); 1296 1297 /* Build the base name */ 1298 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); 1299 RtlAppendUnicodeStringToString(&RegName, &TempName); 1300 1301 /* Check if this is a child of the root */ 1302 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR) 1303 { 1304 /* Then setup the whole name */ 1305 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); 1306 RtlAppendUnicodeStringToString(&RegName, &TempName); 1307 } 1308 1309 /* Now add the rest of the file name */ 1310 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); 1311 FileName.Length = FileStart; 1312 RtlAppendUnicodeStringToString(&FileName, &TempName); 1313 if (!CmpMachineHiveList[i].CmHive) 1314 { 1315 /* We need to allocate a new hive structure */ 1316 CmpMachineHiveList[i].Allocate = TRUE; 1317 1318 /* Load the hive file */ 1319 Status = CmpInitHiveFromFile(&FileName, 1320 CmpMachineHiveList[i].HHiveFlags, 1321 &CmHive, 1322 &CmpMachineHiveList[i].Allocate, 1323 CM_CHECK_REGISTRY_PURGE_VOLATILES); 1324 if (!NT_SUCCESS(Status) || 1325 (!CmpShareSystemHives && !CmHive->FileHandles[HFILE_TYPE_LOG])) 1326 { 1327 /* 1328 * We failed, or could not get a log file (unless 1329 * the hive is shared), raise a hard error. 1330 */ 1331 ErrorParameters = &FileName; 1332 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE, 1333 1, 1334 1, 1335 (PULONG_PTR)&ErrorParameters, 1336 OptionOk, 1337 &ErrorResponse); 1338 } 1339 1340 /* Set the hive flags and newly allocated hive pointer */ 1341 CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags; 1342 CmpMachineHiveList[i].CmHive2 = CmHive; 1343 } 1344 else 1345 { 1346 /* We already have a hive, is it volatile? */ 1347 CmHive = CmpMachineHiveList[i].CmHive; 1348 if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) 1349 { 1350 /* It's now, open the hive file and log */ 1351 Status = CmpOpenHiveFiles(&FileName, 1352 L".ALT", 1353 &PrimaryHandle, 1354 &AlternateHandle, 1355 &PrimaryDisposition, 1356 &SecondaryDisposition, 1357 TRUE, 1358 TRUE, 1359 FALSE, 1360 &ClusterSize); 1361 if (!NT_SUCCESS(Status) || !AlternateHandle) 1362 { 1363 /* Couldn't open the hive or its alternate file, raise a hard error */ 1364 ErrorParameters = &FileName; 1365 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE, 1366 1, 1367 1, 1368 (PULONG_PTR)&ErrorParameters, 1369 OptionOk, 1370 &ErrorResponse); 1371 1372 /* And bugcheck for posterity's sake */ 1373 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status); 1374 } 1375 1376 /* Save the file handles. This should remove our sync hacks */ 1377 /* 1378 * FIXME: Any hive that relies on the alternate hive for recovery purposes 1379 * will only get an alternate hive. As a result, the LOG file would never 1380 * get synced each time a write is done to the hive. In the future it would 1381 * be best to adapt the code so that a primary hive can use a LOG and ALT 1382 * hives at the same time. 1383 */ 1384 CmHive->FileHandles[HFILE_TYPE_ALTERNATE] = AlternateHandle; 1385 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle; 1386 1387 /* Allow lazy flushing since the handles are there -- remove sync hacks */ 1388 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH); 1389 CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH; 1390 1391 /* Get the real size of the hive */ 1392 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE; 1393 1394 /* Check if the cluster size doesn't match */ 1395 if (CmHive->Hive.Cluster != ClusterSize) 1396 { 1397 DPRINT1("FIXME: Support for CmHive->Hive.Cluster (%lu) != ClusterSize (%lu) is unimplemented!\n", 1398 CmHive->Hive.Cluster, ClusterSize); 1399 } 1400 1401 /* Set the file size */ 1402 DPRINT("FIXME: Should set file size: %lu\n", Length); 1403 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length)) 1404 //{ 1405 /* This shouldn't fail */ 1406 //ASSERT(FALSE); 1407 //} 1408 1409 /* FreeLdr has recovered the hive with a log, we must do a flush */ 1410 if (CmHive->Hive.BaseBlock->BootRecover == HBOOT_BOOT_RECOVERED_BY_HIVE_LOG) 1411 { 1412 DPRINT1("FreeLdr recovered the hive (hive 0x%p)\n", CmHive); 1413 RtlSetAllBits(&CmHive->Hive.DirtyVector); 1414 CmHive->Hive.DirtyCount = CmHive->Hive.DirtyVector.SizeOfBitMap; 1415 HvSyncHive((PHHIVE)CmHive); 1416 } 1417 else 1418 { 1419 /* 1420 * Check whether the both primary and alternate hives are the same, 1421 * or that the primary or alternate were created for the first time. 1422 * Do a write against the alternate hive in these cases. 1423 */ 1424 CmpHasAlternateHiveDiverged(&FileName, 1425 CmHive, 1426 AlternateHandle, 1427 &HasDiverged); 1428 if (HasDiverged || 1429 PrimaryDisposition == FILE_CREATED || 1430 SecondaryDisposition == FILE_CREATED) 1431 { 1432 if (!HvWriteAlternateHive((PHHIVE)CmHive)) 1433 { 1434 DPRINT1("Failed to write to alternate hive\n"); 1435 goto Exit; 1436 } 1437 } 1438 } 1439 1440 /* Finally, set our allocated hive to the same hive we've had */ 1441 CmpMachineHiveList[i].CmHive2 = CmHive; 1442 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2); 1443 } 1444 } 1445 1446 Exit: 1447 /* We're done */ 1448 CmpMachineHiveList[i].ThreadFinished = TRUE; 1449 1450 /* Check if we're the last worker */ 1451 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement); 1452 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES) 1453 { 1454 /* Signal the event */ 1455 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE); 1456 } 1457 1458 /* Kill the thread */ 1459 PsTerminateSystemThread(Status); 1460 } 1461 1462 VOID 1463 NTAPI 1464 CmpInitializeHiveList(VOID) 1465 { 1466 WCHAR FileBuffer[64], RegBuffer[64]; 1467 PCWSTR ConfigPath; 1468 UNICODE_STRING TempName, FileName, RegName; 1469 HANDLE Thread; 1470 NTSTATUS Status; 1471 ULONG i; 1472 USHORT RegStart; 1473 PSECURITY_DESCRIPTOR SecurityDescriptor; 1474 1475 PAGED_CODE(); 1476 1477 /* Reenable hive writes now */ 1478 CmpNoWrite = FALSE; 1479 1480 /* Build the file name and registry name strings */ 1481 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer)); 1482 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer)); 1483 1484 /* Now build the system root path */ 1485 ConfigPath = CmpGetRegistryPath(); 1486 RtlInitUnicodeString(&TempName, ConfigPath); 1487 RtlAppendUnicodeStringToString(&FileName, &TempName); 1488 1489 /* And build the registry root path */ 1490 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); 1491 RtlAppendUnicodeStringToString(&RegName, &TempName); 1492 RegStart = RegName.Length; 1493 1494 /* Setup the event to synchronize workers */ 1495 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE); 1496 1497 /* Enter special boot condition */ 1498 CmpSpecialBootCondition = TRUE; 1499 1500 /* Create the SD for the root hives */ 1501 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1502 1503 /* Loop every hive we care about */ 1504 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) 1505 { 1506 /* Make sure the list is set up */ 1507 ASSERT(CmpMachineHiveList[i].Name != NULL); 1508 1509 /* Load this root hive as volatile, if opened in shared mode */ 1510 if (CmpShareSystemHives) 1511 CmpMachineHiveList[i].HHiveFlags |= HIVE_VOLATILE; 1512 1513 /* Create a thread to handle this hive */ 1514 Status = PsCreateSystemThread(&Thread, 1515 THREAD_ALL_ACCESS, 1516 NULL, 1517 0, 1518 NULL, 1519 CmpLoadHiveThread, 1520 UlongToPtr(i)); 1521 if (NT_SUCCESS(Status)) 1522 { 1523 /* We don't care about the handle -- the thread self-terminates */ 1524 ZwClose(Thread); 1525 } 1526 else 1527 { 1528 /* Can't imagine this happening */ 1529 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status); 1530 } 1531 } 1532 1533 /* Make sure we've reached the end of the list */ 1534 ASSERT(CmpMachineHiveList[i].Name == NULL); 1535 1536 /* Wait for hive loading to finish */ 1537 KeWaitForSingleObject(&CmpLoadWorkerEvent, 1538 Executive, 1539 KernelMode, 1540 FALSE, 1541 NULL); 1542 1543 /* Exit the special boot condition and make sure all workers completed */ 1544 CmpSpecialBootCondition = FALSE; 1545 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES); 1546 1547 /* Loop hives again */ 1548 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) 1549 { 1550 /* Make sure the thread ran and finished */ 1551 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE); 1552 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE); 1553 1554 /* Check if this was a new hive */ 1555 if (!CmpMachineHiveList[i].CmHive) 1556 { 1557 /* Make sure we allocated something */ 1558 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL); 1559 1560 /* Build the base name */ 1561 RegName.Length = RegStart; 1562 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); 1563 RtlAppendUnicodeStringToString(&RegName, &TempName); 1564 1565 /* Check if this is a child of the root */ 1566 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR) 1567 { 1568 /* Then setup the whole name */ 1569 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); 1570 RtlAppendUnicodeStringToString(&RegName, &TempName); 1571 } 1572 1573 /* Now link the hive to its master */ 1574 Status = CmpLinkHiveToMaster(&RegName, 1575 NULL, 1576 CmpMachineHiveList[i].CmHive2, 1577 CmpMachineHiveList[i].Allocate, 1578 SecurityDescriptor); 1579 if (Status != STATUS_SUCCESS) 1580 { 1581 /* Linking needs to work */ 1582 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName); 1583 } 1584 1585 /* Check if we had to allocate a new hive */ 1586 if (CmpMachineHiveList[i].Allocate) 1587 { 1588 /* Sync the new hive */ 1589 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2)); 1590 } 1591 } 1592 1593 /* Check if we created a new hive */ 1594 if (CmpMachineHiveList[i].CmHive2) 1595 { 1596 /* Add to HiveList key */ 1597 CmpAddToHiveFileList(CmpMachineHiveList[i].CmHive2); 1598 } 1599 } 1600 1601 /* Get rid of the SD */ 1602 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1603 1604 /* Link SECURITY to SAM */ 1605 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM", 1606 L"\\Registry\\Machine\\SAM\\SAM"); 1607 1608 /* Link S-1-5-18 to .Default */ 1609 CmpNoVolatileCreates = FALSE; 1610 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18", 1611 L"\\Registry\\User\\.Default"); 1612 CmpNoVolatileCreates = TRUE; 1613 } 1614 1615 CODE_SEG("INIT") 1616 BOOLEAN 1617 NTAPI 1618 CmInitSystem1(VOID) 1619 { 1620 OBJECT_ATTRIBUTES ObjectAttributes; 1621 UNICODE_STRING KeyName; 1622 HANDLE KeyHandle; 1623 NTSTATUS Status; 1624 PCMHIVE HardwareHive; 1625 PSECURITY_DESCRIPTOR SecurityDescriptor; 1626 PAGED_CODE(); 1627 1628 /* Check if this is PE-boot */ 1629 if (InitIsWinPEMode) 1630 { 1631 /* Set the registry in PE mode and load the system hives in shared mode */ 1632 CmpMiniNTBoot = TRUE; 1633 CmpShareSystemHives = TRUE; 1634 } 1635 1636 /* Initialize the hive list and lock */ 1637 InitializeListHead(&CmpHiveListHead); 1638 ExInitializePushLock(&CmpHiveListHeadLock); 1639 ExInitializePushLock(&CmpLoadHiveLock); 1640 1641 /* Initialize registry lock */ 1642 ExInitializeResourceLite(&CmpRegistryLock); 1643 1644 /* Initialize the cache */ 1645 CmpInitializeCache(); 1646 1647 /* Initialize allocation and delayed dereferencing */ 1648 CmpInitCmPrivateAlloc(); 1649 CmpInitCmPrivateDelayAlloc(); 1650 CmpInitDelayDerefKCBEngine(); 1651 1652 /* Initialize callbacks */ 1653 CmpInitCallback(); 1654 1655 /* Initialize self healing */ 1656 KeInitializeGuardedMutex(&CmpSelfHealQueueLock); 1657 InitializeListHead(&CmpSelfHealQueueListHead); 1658 1659 /* Save the current process and lock the registry */ 1660 CmpSystemProcess = PsGetCurrentProcess(); 1661 1662 /* Create the key object types */ 1663 Status = CmpCreateObjectTypes(); 1664 if (!NT_SUCCESS(Status)) 1665 { 1666 /* Bugcheck */ 1667 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0); 1668 } 1669 1670 /* Build the master hive */ 1671 Status = CmpInitializeHive(&CmiVolatileHive, 1672 HINIT_CREATE, 1673 HIVE_VOLATILE, 1674 HFILE_TYPE_PRIMARY, 1675 NULL, 1676 NULL, 1677 NULL, 1678 NULL, 1679 NULL, 1680 NULL, 1681 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 1682 if (!NT_SUCCESS(Status)) 1683 { 1684 /* Bugcheck */ 1685 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0); 1686 } 1687 1688 /* Create the \REGISTRY key node */ 1689 if (!CmpCreateRegistryRoot()) 1690 { 1691 /* Bugcheck */ 1692 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0); 1693 } 1694 1695 /* Create the default security descriptor */ 1696 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1697 1698 /* Create '\Registry\Machine' key */ 1699 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE"); 1700 InitializeObjectAttributes(&ObjectAttributes, 1701 &KeyName, 1702 OBJ_CASE_INSENSITIVE, 1703 NULL, 1704 SecurityDescriptor); 1705 Status = NtCreateKey(&KeyHandle, 1706 KEY_READ | KEY_WRITE, 1707 &ObjectAttributes, 1708 0, 1709 NULL, 1710 0, 1711 NULL); 1712 if (!NT_SUCCESS(Status)) 1713 { 1714 /* Bugcheck */ 1715 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0); 1716 } 1717 1718 /* Close the handle */ 1719 NtClose(KeyHandle); 1720 1721 /* Create '\Registry\User' key */ 1722 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER"); 1723 InitializeObjectAttributes(&ObjectAttributes, 1724 &KeyName, 1725 OBJ_CASE_INSENSITIVE, 1726 NULL, 1727 SecurityDescriptor); 1728 Status = NtCreateKey(&KeyHandle, 1729 KEY_READ | KEY_WRITE, 1730 &ObjectAttributes, 1731 0, 1732 NULL, 1733 0, 1734 NULL); 1735 if (!NT_SUCCESS(Status)) 1736 { 1737 /* Bugcheck */ 1738 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0); 1739 } 1740 1741 /* Close the handle */ 1742 NtClose(KeyHandle); 1743 1744 /* After this point, do not allow creating keys in the master hive */ 1745 CmpNoVolatileCreates = TRUE; 1746 1747 /* Initialize the system hive */ 1748 if (!CmpInitializeSystemHive(KeLoaderBlock)) 1749 { 1750 /* Bugcheck */ 1751 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0); 1752 } 1753 1754 /* Create the 'CurrentControlSet' link */ 1755 Status = CmpCreateControlSet(KeLoaderBlock); 1756 if (!NT_SUCCESS(Status)) 1757 { 1758 /* Bugcheck */ 1759 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0); 1760 } 1761 1762 /* Create the hardware hive */ 1763 Status = CmpInitializeHive(&HardwareHive, 1764 HINIT_CREATE, 1765 HIVE_VOLATILE, 1766 HFILE_TYPE_PRIMARY, 1767 NULL, 1768 NULL, 1769 NULL, 1770 NULL, 1771 NULL, 1772 NULL, 1773 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 1774 if (!NT_SUCCESS(Status)) 1775 { 1776 /* Bugcheck */ 1777 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0); 1778 } 1779 1780 /* Add the hive to the hive list */ 1781 CmpMachineHiveList[0].CmHive = HardwareHive; 1782 1783 /* Attach it to the machine key */ 1784 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE"); 1785 Status = CmpLinkHiveToMaster(&KeyName, 1786 NULL, 1787 HardwareHive, 1788 TRUE, 1789 SecurityDescriptor); 1790 if (!NT_SUCCESS(Status)) 1791 { 1792 /* Bugcheck */ 1793 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0); 1794 } 1795 1796 /* Add to HiveList key */ 1797 CmpAddToHiveFileList(HardwareHive); 1798 1799 /* Free the security descriptor */ 1800 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1801 1802 /* Fill out the Hardware key with the ARC Data from the Loader */ 1803 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock); 1804 if (!NT_SUCCESS(Status)) 1805 { 1806 /* Bugcheck */ 1807 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0); 1808 } 1809 1810 /* Initialize machine-dependent information into the registry */ 1811 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock); 1812 if (!NT_SUCCESS(Status)) 1813 { 1814 /* Bugcheck */ 1815 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0); 1816 } 1817 1818 /* Initialize volatile registry settings */ 1819 Status = CmpSetSystemValues(KeLoaderBlock); 1820 if (!NT_SUCCESS(Status)) 1821 { 1822 /* Bugcheck */ 1823 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0); 1824 } 1825 1826 /* Free the load options */ 1827 ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM); 1828 1829 /* If we got here, all went well */ 1830 return TRUE; 1831 } 1832 1833 CODE_SEG("INIT") 1834 PUNICODE_STRING* 1835 NTAPI 1836 CmGetSystemDriverList(VOID) 1837 { 1838 LIST_ENTRY DriverList; 1839 OBJECT_ATTRIBUTES ObjectAttributes; 1840 NTSTATUS Status; 1841 PCM_KEY_BODY KeyBody; 1842 PHHIVE Hive; 1843 HCELL_INDEX RootCell, ControlCell; 1844 HANDLE KeyHandle; 1845 UNICODE_STRING KeyName; 1846 PLIST_ENTRY NextEntry; 1847 ULONG i; 1848 PUNICODE_STRING* ServicePath = NULL; 1849 BOOLEAN Success, AutoSelect; 1850 PBOOT_DRIVER_LIST_ENTRY DriverEntry; 1851 PAGED_CODE(); 1852 1853 /* Initialize the driver list */ 1854 InitializeListHead(&DriverList); 1855 1856 /* Open the system hive key */ 1857 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System"); 1858 InitializeObjectAttributes(&ObjectAttributes, 1859 &KeyName, 1860 OBJ_CASE_INSENSITIVE, 1861 NULL, 1862 NULL); 1863 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 1864 if (!NT_SUCCESS(Status)) return NULL; 1865 1866 /* Reference the key object to get the root hive/cell to access directly */ 1867 Status = ObReferenceObjectByHandle(KeyHandle, 1868 KEY_QUERY_VALUE, 1869 CmpKeyObjectType, 1870 KernelMode, 1871 (PVOID*)&KeyBody, 1872 NULL); 1873 if (!NT_SUCCESS(Status)) 1874 { 1875 /* Fail */ 1876 NtClose(KeyHandle); 1877 return NULL; 1878 } 1879 1880 /* Do all this under the registry lock */ 1881 CmpLockRegistryExclusive(); 1882 1883 /* Get the hive and key cell */ 1884 Hive = KeyBody->KeyControlBlock->KeyHive; 1885 RootCell = KeyBody->KeyControlBlock->KeyCell; 1886 1887 /* Open the current control set key */ 1888 RtlInitUnicodeString(&KeyName, L"Current"); 1889 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect); 1890 if (ControlCell == HCELL_NIL) goto EndPath; 1891 1892 /* Find all system drivers */ 1893 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList); 1894 if (!Success) goto EndPath; 1895 1896 /* Sort by group/tag */ 1897 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath; 1898 1899 /* Remove circular dependencies (cycles) and sort */ 1900 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath; 1901 1902 /* Loop the list to count drivers */ 1903 for (i = 0, NextEntry = DriverList.Flink; 1904 NextEntry != &DriverList; 1905 i++, NextEntry = NextEntry->Flink); 1906 1907 /* Allocate the array */ 1908 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING)); 1909 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1910 1911 /* Loop the driver list */ 1912 for (i = 0, NextEntry = DriverList.Flink; 1913 NextEntry != &DriverList; 1914 i++, NextEntry = NextEntry->Flink) 1915 { 1916 /* Get the entry */ 1917 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link); 1918 1919 /* Allocate the path for the caller */ 1920 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING)); 1921 if (!ServicePath[i]) 1922 { 1923 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1924 } 1925 1926 /* Duplicate the registry path */ 1927 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 1928 &DriverEntry->RegistryPath, 1929 ServicePath[i]); 1930 if (!NT_SUCCESS(Status)) 1931 { 1932 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1933 } 1934 } 1935 1936 /* Terminate the list */ 1937 ServicePath[i] = NULL; 1938 1939 EndPath: 1940 /* Free the driver list if we had one */ 1941 if (!IsListEmpty(&DriverList)) CmpFreeDriverList(Hive, &DriverList); 1942 1943 /* Unlock the registry */ 1944 CmpUnlockRegistry(); 1945 1946 /* Close the key handle and dereference the object, then return the path */ 1947 ObDereferenceObject(KeyBody); 1948 NtClose(KeyHandle); 1949 return ServicePath; 1950 } 1951 1952 VOID 1953 NTAPI 1954 CmpLockRegistryExclusive(VOID) 1955 { 1956 /* Enter a critical region and lock the registry */ 1957 KeEnterCriticalRegion(); 1958 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); 1959 1960 /* Sanity check */ 1961 ASSERT(CmpFlushStarveWriters == 0); 1962 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller); 1963 } 1964 1965 VOID 1966 NTAPI 1967 CmpLockRegistry(VOID) 1968 { 1969 /* Enter a critical region */ 1970 KeEnterCriticalRegion(); 1971 1972 /* Check if we have to starve writers */ 1973 if (CmpFlushStarveWriters) 1974 { 1975 /* Starve exlusive waiters */ 1976 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE); 1977 } 1978 else 1979 { 1980 /* Just grab the lock */ 1981 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE); 1982 } 1983 } 1984 1985 BOOLEAN 1986 NTAPI 1987 CmpTestRegistryLock(VOID) 1988 { 1989 /* Test the lock */ 1990 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE; 1991 } 1992 1993 BOOLEAN 1994 NTAPI 1995 CmpTestRegistryLockExclusive(VOID) 1996 { 1997 /* Test the lock */ 1998 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE; 1999 } 2000 2001 VOID 2002 NTAPI 2003 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive) 2004 { 2005 /* Lock the flusher. We should already be in a critical section */ 2006 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2007 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 2008 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 2009 ExAcquireResourceExclusiveLite(Hive->FlusherLock, TRUE); 2010 } 2011 2012 VOID 2013 NTAPI 2014 CmpLockHiveFlusherShared(IN PCMHIVE Hive) 2015 { 2016 /* Lock the flusher. We should already be in a critical section */ 2017 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2018 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 2019 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 2020 ExAcquireResourceSharedLite(Hive->FlusherLock, TRUE); 2021 } 2022 2023 VOID 2024 NTAPI 2025 CmpUnlockHiveFlusher(IN PCMHIVE Hive) 2026 { 2027 /* Sanity check */ 2028 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2029 CMP_ASSERT_FLUSH_LOCK(Hive); 2030 2031 /* Release the lock */ 2032 ExReleaseResourceLite(Hive->FlusherLock); 2033 } 2034 2035 BOOLEAN 2036 NTAPI 2037 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive) 2038 { 2039 /* Test the lock */ 2040 return !ExIsResourceAcquiredSharedLite(Hive->FlusherLock) ? FALSE : TRUE; 2041 } 2042 2043 BOOLEAN 2044 NTAPI 2045 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive) 2046 { 2047 /* Test the lock */ 2048 return !ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) ? FALSE : TRUE; 2049 } 2050 2051 VOID 2052 NTAPI 2053 CmpUnlockRegistry(VOID) 2054 { 2055 /* Sanity check */ 2056 CMP_ASSERT_REGISTRY_LOCK(); 2057 2058 /* Check if we should flush the registry */ 2059 if (CmpFlushOnLockRelease) 2060 { 2061 /* The registry should be exclusively locked for this */ 2062 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK(); 2063 2064 /* Flush the registry */ 2065 CmpDoFlushAll(TRUE); 2066 CmpFlushOnLockRelease = FALSE; 2067 } 2068 2069 /* Release the lock and leave the critical region */ 2070 ExReleaseResourceLite(&CmpRegistryLock); 2071 KeLeaveCriticalRegion(); 2072 } 2073 2074 VOID 2075 NTAPI 2076 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1, 2077 IN ULONG ConvKey2) 2078 { 2079 ULONG Index1, Index2; 2080 2081 /* Sanity check */ 2082 CMP_ASSERT_REGISTRY_LOCK(); 2083 2084 /* Get hash indexes */ 2085 Index1 = GET_HASH_INDEX(ConvKey1); 2086 Index2 = GET_HASH_INDEX(ConvKey2); 2087 2088 /* See which one is highest */ 2089 if (Index1 < Index2) 2090 { 2091 /* Grab them in the proper order */ 2092 CmpAcquireKcbLockExclusiveByKey(ConvKey1); 2093 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 2094 } 2095 else 2096 { 2097 /* Grab the second one first, then the first */ 2098 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 2099 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1); 2100 } 2101 } 2102 2103 VOID 2104 NTAPI 2105 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1, 2106 IN ULONG ConvKey2) 2107 { 2108 ULONG Index1, Index2; 2109 2110 /* Sanity check */ 2111 CMP_ASSERT_REGISTRY_LOCK(); 2112 2113 /* Get hash indexes */ 2114 Index1 = GET_HASH_INDEX(ConvKey1); 2115 Index2 = GET_HASH_INDEX(ConvKey2); 2116 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2)->Owner == KeGetCurrentThread()) || 2117 CmpTestRegistryLockExclusive()); 2118 2119 /* See which one is highest */ 2120 if (Index1 < Index2) 2121 { 2122 /* Grab them in the proper order */ 2123 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2124 CmpTestRegistryLockExclusive()); 2125 CmpReleaseKcbLockByKey(ConvKey2); 2126 CmpReleaseKcbLockByKey(ConvKey1); 2127 } 2128 else 2129 { 2130 /* Release the first one first, then the second */ 2131 if (Index1 != Index2) 2132 { 2133 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2134 CmpTestRegistryLockExclusive()); 2135 CmpReleaseKcbLockByKey(ConvKey1); 2136 } 2137 CmpReleaseKcbLockByKey(ConvKey2); 2138 } 2139 } 2140 2141 VOID 2142 NTAPI 2143 CmShutdownSystem(VOID) 2144 { 2145 PLIST_ENTRY ListEntry; 2146 PCMHIVE Hive; 2147 2148 /* Kill the workers */ 2149 if (!CmFirstTime) CmpShutdownWorkers(); 2150 2151 /* Flush all hives */ 2152 CmpLockRegistryExclusive(); 2153 CmpDoFlushAll(TRUE); 2154 2155 /* Close all hive files */ 2156 ListEntry = CmpHiveListHead.Flink; 2157 while (ListEntry != &CmpHiveListHead) 2158 { 2159 Hive = CONTAINING_RECORD(ListEntry, CMHIVE, HiveList); 2160 2161 CmpCloseHiveFiles(Hive); 2162 2163 ListEntry = ListEntry->Flink; 2164 } 2165 2166 /* 2167 * As we flushed all the hives on the disk, 2168 * tell the system we do not want any further 2169 * registry flushing or syncing at this point 2170 * since we are shutting down the registry anyway. 2171 */ 2172 HvShutdownComplete = TRUE; 2173 2174 CmpUnlockRegistry(); 2175 } 2176 2177 VOID 2178 NTAPI 2179 CmpSetVersionData(VOID) 2180 { 2181 NTSTATUS Status; 2182 OBJECT_ATTRIBUTES ObjectAttributes; 2183 UNICODE_STRING KeyName; 2184 UNICODE_STRING ValueName; 2185 UNICODE_STRING ValueData; 2186 ANSI_STRING TempString; 2187 HANDLE SoftwareKeyHandle = NULL; 2188 HANDLE MicrosoftKeyHandle = NULL; 2189 HANDLE WindowsNtKeyHandle = NULL; 2190 HANDLE CurrentVersionKeyHandle = NULL; 2191 WCHAR Buffer[128]; // Buffer large enough to contain a full ULONG in decimal 2192 // representation, and the full 'CurrentType' string. 2193 2194 /* 2195 * Open the 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' key 2196 * (create the intermediate subkeys if needed). 2197 */ 2198 2199 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SOFTWARE"); 2200 InitializeObjectAttributes(&ObjectAttributes, 2201 &KeyName, 2202 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2203 NULL, 2204 NULL); 2205 Status = NtCreateKey(&SoftwareKeyHandle, 2206 KEY_CREATE_SUB_KEY, 2207 &ObjectAttributes, 2208 0, 2209 NULL, 2210 0, 2211 NULL); 2212 if (!NT_SUCCESS(Status)) 2213 { 2214 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2215 return; 2216 } 2217 2218 RtlInitUnicodeString(&KeyName, L"Microsoft"); 2219 InitializeObjectAttributes(&ObjectAttributes, 2220 &KeyName, 2221 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2222 SoftwareKeyHandle, 2223 NULL); 2224 Status = NtCreateKey(&MicrosoftKeyHandle, 2225 KEY_CREATE_SUB_KEY, 2226 &ObjectAttributes, 2227 0, 2228 NULL, 2229 0, 2230 NULL); 2231 if (!NT_SUCCESS(Status)) 2232 { 2233 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2234 goto Quit; 2235 } 2236 2237 RtlInitUnicodeString(&KeyName, L"Windows NT"); 2238 InitializeObjectAttributes(&ObjectAttributes, 2239 &KeyName, 2240 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2241 MicrosoftKeyHandle, 2242 NULL); 2243 Status = NtCreateKey(&WindowsNtKeyHandle, 2244 KEY_CREATE_SUB_KEY, 2245 &ObjectAttributes, 2246 0, 2247 NULL, 2248 0, 2249 NULL); 2250 if (!NT_SUCCESS(Status)) 2251 { 2252 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2253 goto Quit; 2254 } 2255 2256 RtlInitUnicodeString(&KeyName, L"CurrentVersion"); 2257 InitializeObjectAttributes(&ObjectAttributes, 2258 &KeyName, 2259 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2260 WindowsNtKeyHandle, 2261 NULL); 2262 Status = NtCreateKey(&CurrentVersionKeyHandle, 2263 KEY_CREATE_SUB_KEY | KEY_SET_VALUE, 2264 &ObjectAttributes, 2265 0, 2266 NULL, 2267 0, 2268 NULL); 2269 if (!NT_SUCCESS(Status)) 2270 { 2271 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2272 goto Quit; 2273 } 2274 2275 /* Set the 'CurrentVersion' value */ 2276 RtlInitUnicodeString(&ValueName, L"CurrentVersion"); 2277 NtSetValueKey(CurrentVersionKeyHandle, 2278 &ValueName, 2279 0, 2280 REG_SZ, 2281 CmVersionString.Buffer, 2282 CmVersionString.Length + sizeof(WCHAR)); 2283 2284 /* Set the 'CurrentBuildNumber' value */ 2285 RtlInitUnicodeString(&ValueName, L"CurrentBuildNumber"); 2286 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2287 RtlIntegerToUnicodeString(NtBuildNumber & 0xFFFF, 10, &ValueData); 2288 NtSetValueKey(CurrentVersionKeyHandle, 2289 &ValueName, 2290 0, 2291 REG_SZ, 2292 ValueData.Buffer, 2293 ValueData.Length + sizeof(WCHAR)); 2294 2295 /* Set the 'BuildLab' value */ 2296 RtlInitUnicodeString(&ValueName, L"BuildLab"); 2297 RtlInitAnsiString(&TempString, NtBuildLab); 2298 Status = RtlAnsiStringToUnicodeString(&ValueData, &TempString, FALSE); 2299 if (NT_SUCCESS(Status)) 2300 { 2301 NtSetValueKey(CurrentVersionKeyHandle, 2302 &ValueName, 2303 0, 2304 REG_SZ, 2305 ValueData.Buffer, 2306 ValueData.Length + sizeof(WCHAR)); 2307 } 2308 2309 /* Set the 'CurrentType' value */ 2310 RtlInitUnicodeString(&ValueName, L"CurrentType"); 2311 RtlStringCbPrintfW(Buffer, sizeof(Buffer), 2312 L"%s %s", 2313 #ifdef CONFIG_SMP 2314 L"Multiprocessor" 2315 #else 2316 L"Uniprocessor" 2317 #endif 2318 , 2319 #if (DBG == 1) 2320 L"Checked" 2321 #else 2322 L"Free" 2323 #endif 2324 ); 2325 RtlInitUnicodeString(&ValueData, Buffer); 2326 NtSetValueKey(CurrentVersionKeyHandle, 2327 &ValueName, 2328 0, 2329 REG_SZ, 2330 ValueData.Buffer, 2331 ValueData.Length + sizeof(WCHAR)); 2332 2333 /* Set the 'CSDVersion' value */ 2334 RtlInitUnicodeString(&ValueName, L"CSDVersion"); 2335 if (CmCSDVersionString.Length != 0) 2336 { 2337 NtSetValueKey(CurrentVersionKeyHandle, 2338 &ValueName, 2339 0, 2340 REG_SZ, 2341 CmCSDVersionString.Buffer, 2342 CmCSDVersionString.Length + sizeof(WCHAR)); 2343 } 2344 else 2345 { 2346 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2347 } 2348 2349 /* Set the 'CSDBuildNumber' value */ 2350 RtlInitUnicodeString(&ValueName, L"CSDBuildNumber"); 2351 if (CmNtSpBuildNumber != 0) 2352 { 2353 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2354 RtlIntegerToUnicodeString(CmNtSpBuildNumber, 10, &ValueData); 2355 NtSetValueKey(CurrentVersionKeyHandle, 2356 &ValueName, 2357 0, 2358 REG_SZ, 2359 ValueData.Buffer, 2360 ValueData.Length + sizeof(WCHAR)); 2361 } 2362 else 2363 { 2364 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2365 } 2366 2367 /* Set the 'SystemRoot' value */ 2368 RtlInitUnicodeString(&ValueName, L"SystemRoot"); 2369 NtSetValueKey(CurrentVersionKeyHandle, 2370 &ValueName, 2371 0, 2372 REG_SZ, 2373 NtSystemRoot.Buffer, 2374 NtSystemRoot.Length + sizeof(WCHAR)); 2375 2376 Quit: 2377 /* Close the keys */ 2378 if (CurrentVersionKeyHandle != NULL) 2379 NtClose(CurrentVersionKeyHandle); 2380 2381 if (WindowsNtKeyHandle != NULL) 2382 NtClose(WindowsNtKeyHandle); 2383 2384 if (MicrosoftKeyHandle != NULL) 2385 NtClose(MicrosoftKeyHandle); 2386 2387 if (SoftwareKeyHandle != NULL) 2388 NtClose(SoftwareKeyHandle); 2389 } 2390 2391 /* EOF */ 2392