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) 1113 { 1114 ObDereferenceObject(RootKey); 1115 return FALSE; 1116 } 1117 1118 /* Create the KCB */ 1119 RtlInitUnicodeString(&KeyName, L"\\REGISTRY"); 1120 Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive, 1121 RootIndex, 1122 KeyCell, 1123 NULL, 1124 0, 1125 &KeyName); 1126 if (!Kcb) 1127 { 1128 ObDereferenceObject(RootKey); 1129 return FALSE; 1130 } 1131 1132 /* Initialize the object */ 1133 RootKey->KeyControlBlock = Kcb; 1134 RootKey->Type = CM_KEY_BODY_TYPE; 1135 RootKey->NotifyBlock = NULL; 1136 RootKey->ProcessID = PsGetCurrentProcessId(); 1137 RootKey->KcbLocked = FALSE; 1138 1139 /* Link with KCB */ 1140 EnlistKeyBodyWithKCB(RootKey, 0); 1141 1142 /* Insert the key into the namespace */ 1143 Status = ObInsertObject(RootKey, 1144 NULL, 1145 KEY_ALL_ACCESS, 1146 0, 1147 NULL, 1148 &CmpRegistryRootHandle); 1149 if (!NT_SUCCESS(Status)) 1150 { 1151 return FALSE; 1152 } 1153 1154 /* Reference the key again so that we never lose it */ 1155 Status = ObReferenceObjectByHandle(CmpRegistryRootHandle, 1156 KEY_READ, 1157 NULL, 1158 KernelMode, 1159 (PVOID*)&RootKey, 1160 NULL); 1161 if (!NT_SUCCESS(Status)) 1162 { 1163 ObDereferenceObject(RootKey); 1164 return FALSE; 1165 } 1166 1167 /* Completely successful */ 1168 return TRUE; 1169 } 1170 1171 static PCWSTR 1172 CmpGetRegistryPath(VOID) 1173 { 1174 PCWSTR ConfigPath; 1175 1176 /* Check if we are booted in setup */ 1177 if (!ExpInTextModeSetup) 1178 { 1179 ConfigPath = L"\\SystemRoot\\System32\\Config\\"; 1180 } 1181 else 1182 { 1183 ConfigPath = L"\\SystemRoot\\"; 1184 } 1185 1186 DPRINT1("CmpGetRegistryPath: ConfigPath = '%S'\n", ConfigPath); 1187 1188 return ConfigPath; 1189 } 1190 1191 /** 1192 * @brief 1193 * Checks if the primary and alternate backing hive are 1194 * the same, by determining the time stamp of both hives. 1195 * 1196 * @param[in] FileName 1197 * A pointer to a string containing the file name of the 1198 * primary hive. 1199 * 1200 * @param[in] CmMainmHive 1201 * A pointer to a CM hive descriptor associated with the 1202 * primary hive. 1203 * 1204 * @param[in] AlternateHandle 1205 * A handle to a file that represents the alternate hive. 1206 * 1207 * @param[in] Diverged 1208 * A pointer to a boolean value, if both hives are the same 1209 * it returns TRUE. Otherwise it returns FALSE. 1210 */ 1211 static 1212 VOID 1213 CmpHasAlternateHiveDiverged( 1214 _In_ PCUNICODE_STRING FileName, 1215 _In_ PCMHIVE CmMainmHive, 1216 _In_ HANDLE AlternateHandle, 1217 _Out_ PBOOLEAN Diverged) 1218 { 1219 PHHIVE Hive, AlternateHive; 1220 NTSTATUS Status; 1221 PCMHIVE CmiAlternateHive; 1222 1223 /* Assume it has not diverged */ 1224 *Diverged = FALSE; 1225 1226 /* Initialize the SYSTEM alternate hive */ 1227 Status = CmpInitializeHive(&CmiAlternateHive, 1228 HINIT_FILE, 1229 0, 1230 HFILE_TYPE_PRIMARY, 1231 NULL, 1232 AlternateHandle, 1233 NULL, 1234 NULL, 1235 NULL, 1236 FileName, 1237 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 1238 if (!NT_SUCCESS(Status)) 1239 { 1240 /* Assume it has diverged... */ 1241 DPRINT1("Failed to initialize the alternate hive to check for diversion (Status 0x%lx)\n", Status); 1242 *Diverged = TRUE; 1243 return; 1244 } 1245 1246 /* 1247 * Check the timestamp of both hives. If they do not match they 1248 * have diverged, the kernel has to synchronize the both hives. 1249 */ 1250 Hive = &CmMainmHive->Hive; 1251 AlternateHive = &CmiAlternateHive->Hive; 1252 if (AlternateHive->BaseBlock->TimeStamp.QuadPart != 1253 Hive->BaseBlock->TimeStamp.QuadPart) 1254 { 1255 *Diverged = TRUE; 1256 } 1257 1258 CmpDestroyHive(CmiAlternateHive); 1259 } 1260 1261 _Function_class_(KSTART_ROUTINE) 1262 VOID 1263 NTAPI 1264 CmpLoadHiveThread(IN PVOID StartContext) 1265 { 1266 WCHAR FileBuffer[64], RegBuffer[64]; 1267 PCWSTR ConfigPath; 1268 UNICODE_STRING TempName, FileName, RegName; 1269 ULONG i, ErrorResponse, WorkerCount, Length; 1270 USHORT FileStart; 1271 ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize; 1272 PCMHIVE CmHive; 1273 HANDLE PrimaryHandle = NULL, AlternateHandle = NULL; 1274 NTSTATUS Status = STATUS_SUCCESS; 1275 PVOID ErrorParameters; 1276 BOOLEAN HasDiverged; 1277 PAGED_CODE(); 1278 1279 /* Get the hive index, make sure it makes sense */ 1280 i = PtrToUlong(StartContext); 1281 ASSERT(CmpMachineHiveList[i].Name != NULL); 1282 1283 /* We were started */ 1284 CmpMachineHiveList[i].ThreadStarted = TRUE; 1285 1286 /* Build the file name and registry name strings */ 1287 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer)); 1288 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer)); 1289 1290 /* Now build the system root path */ 1291 ConfigPath = CmpGetRegistryPath(); 1292 RtlInitUnicodeString(&TempName, ConfigPath); 1293 RtlAppendUnicodeStringToString(&FileName, &TempName); 1294 FileStart = FileName.Length; 1295 1296 /* And build the registry root path */ 1297 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); 1298 RtlAppendUnicodeStringToString(&RegName, &TempName); 1299 1300 /* Build the base name */ 1301 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); 1302 RtlAppendUnicodeStringToString(&RegName, &TempName); 1303 1304 /* Check if this is a child of the root */ 1305 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR) 1306 { 1307 /* Then setup the whole name */ 1308 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); 1309 RtlAppendUnicodeStringToString(&RegName, &TempName); 1310 } 1311 1312 /* Now add the rest of the file name */ 1313 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); 1314 FileName.Length = FileStart; 1315 RtlAppendUnicodeStringToString(&FileName, &TempName); 1316 if (!CmpMachineHiveList[i].CmHive) 1317 { 1318 /* We need to allocate a new hive structure */ 1319 CmpMachineHiveList[i].Allocate = TRUE; 1320 1321 /* Load the hive file */ 1322 Status = CmpInitHiveFromFile(&FileName, 1323 CmpMachineHiveList[i].HHiveFlags, 1324 &CmHive, 1325 &CmpMachineHiveList[i].Allocate, 1326 CM_CHECK_REGISTRY_PURGE_VOLATILES); 1327 if (!NT_SUCCESS(Status) || 1328 (!CmpShareSystemHives && !CmHive->FileHandles[HFILE_TYPE_LOG])) 1329 { 1330 /* 1331 * We failed, or could not get a log file (unless 1332 * the hive is shared), raise a hard error. 1333 */ 1334 ErrorParameters = &FileName; 1335 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE, 1336 1, 1337 1, 1338 (PULONG_PTR)&ErrorParameters, 1339 OptionOk, 1340 &ErrorResponse); 1341 } 1342 1343 /* Set the hive flags and newly allocated hive pointer */ 1344 CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags; 1345 CmpMachineHiveList[i].CmHive2 = CmHive; 1346 } 1347 else 1348 { 1349 /* We already have a hive, is it volatile? */ 1350 CmHive = CmpMachineHiveList[i].CmHive; 1351 if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) 1352 { 1353 /* It's now, open the hive file and log */ 1354 Status = CmpOpenHiveFiles(&FileName, 1355 L".ALT", 1356 &PrimaryHandle, 1357 &AlternateHandle, 1358 &PrimaryDisposition, 1359 &SecondaryDisposition, 1360 TRUE, 1361 TRUE, 1362 FALSE, 1363 &ClusterSize); 1364 if (!NT_SUCCESS(Status) || !AlternateHandle) 1365 { 1366 /* Couldn't open the hive or its alternate file, raise a hard error */ 1367 ErrorParameters = &FileName; 1368 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE, 1369 1, 1370 1, 1371 (PULONG_PTR)&ErrorParameters, 1372 OptionOk, 1373 &ErrorResponse); 1374 1375 /* And bugcheck for posterity's sake */ 1376 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status); 1377 } 1378 1379 /* Save the file handles. This should remove our sync hacks */ 1380 /* 1381 * FIXME: Any hive that relies on the alternate hive for recovery purposes 1382 * will only get an alternate hive. As a result, the LOG file would never 1383 * get synced each time a write is done to the hive. In the future it would 1384 * be best to adapt the code so that a primary hive can use a LOG and ALT 1385 * hives at the same time. 1386 */ 1387 CmHive->FileHandles[HFILE_TYPE_ALTERNATE] = AlternateHandle; 1388 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle; 1389 1390 /* Allow lazy flushing since the handles are there -- remove sync hacks */ 1391 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH); 1392 CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH; 1393 1394 /* Get the real size of the hive */ 1395 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE; 1396 1397 /* Check if the cluster size doesn't match */ 1398 if (CmHive->Hive.Cluster != ClusterSize) 1399 { 1400 DPRINT1("FIXME: Support for CmHive->Hive.Cluster (%lu) != ClusterSize (%lu) is unimplemented!\n", 1401 CmHive->Hive.Cluster, ClusterSize); 1402 } 1403 1404 /* Set the file size */ 1405 DPRINT("FIXME: Should set file size: %lu\n", Length); 1406 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length)) 1407 //{ 1408 /* This shouldn't fail */ 1409 //ASSERT(FALSE); 1410 //} 1411 1412 /* FreeLdr has recovered the hive with a log, we must do a flush */ 1413 if (CmHive->Hive.BaseBlock->BootRecover == HBOOT_BOOT_RECOVERED_BY_HIVE_LOG) 1414 { 1415 DPRINT1("FreeLdr recovered the hive (hive 0x%p)\n", CmHive); 1416 RtlSetAllBits(&CmHive->Hive.DirtyVector); 1417 CmHive->Hive.DirtyCount = CmHive->Hive.DirtyVector.SizeOfBitMap; 1418 HvSyncHive((PHHIVE)CmHive); 1419 } 1420 else 1421 { 1422 /* 1423 * Check whether the both primary and alternate hives are the same, 1424 * or that the primary or alternate were created for the first time. 1425 * Do a write against the alternate hive in these cases. 1426 */ 1427 CmpHasAlternateHiveDiverged(&FileName, 1428 CmHive, 1429 AlternateHandle, 1430 &HasDiverged); 1431 if (HasDiverged || 1432 PrimaryDisposition == FILE_CREATED || 1433 SecondaryDisposition == FILE_CREATED) 1434 { 1435 if (!HvWriteAlternateHive((PHHIVE)CmHive)) 1436 { 1437 DPRINT1("Failed to write to alternate hive\n"); 1438 goto Exit; 1439 } 1440 } 1441 } 1442 1443 /* Finally, set our allocated hive to the same hive we've had */ 1444 CmpMachineHiveList[i].CmHive2 = CmHive; 1445 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2); 1446 } 1447 } 1448 1449 Exit: 1450 /* We're done */ 1451 CmpMachineHiveList[i].ThreadFinished = TRUE; 1452 1453 /* Check if we're the last worker */ 1454 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement); 1455 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES) 1456 { 1457 /* Signal the event */ 1458 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE); 1459 } 1460 1461 /* Kill the thread */ 1462 PsTerminateSystemThread(Status); 1463 } 1464 1465 VOID 1466 NTAPI 1467 CmpInitializeHiveList(VOID) 1468 { 1469 WCHAR FileBuffer[64], RegBuffer[64]; 1470 PCWSTR ConfigPath; 1471 UNICODE_STRING TempName, FileName, RegName; 1472 HANDLE Thread; 1473 NTSTATUS Status; 1474 ULONG i; 1475 USHORT RegStart; 1476 PSECURITY_DESCRIPTOR SecurityDescriptor; 1477 1478 PAGED_CODE(); 1479 1480 /* Reenable hive writes now */ 1481 CmpNoWrite = FALSE; 1482 1483 /* Build the file name and registry name strings */ 1484 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer)); 1485 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer)); 1486 1487 /* Now build the system root path */ 1488 ConfigPath = CmpGetRegistryPath(); 1489 RtlInitUnicodeString(&TempName, ConfigPath); 1490 RtlAppendUnicodeStringToString(&FileName, &TempName); 1491 1492 /* And build the registry root path */ 1493 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); 1494 RtlAppendUnicodeStringToString(&RegName, &TempName); 1495 RegStart = RegName.Length; 1496 1497 /* Setup the event to synchronize workers */ 1498 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE); 1499 1500 /* Enter special boot condition */ 1501 CmpSpecialBootCondition = TRUE; 1502 1503 /* Create the SD for the root hives */ 1504 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1505 1506 /* Loop every hive we care about */ 1507 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) 1508 { 1509 /* Make sure the list is set up */ 1510 ASSERT(CmpMachineHiveList[i].Name != NULL); 1511 1512 /* Load this root hive as volatile, if opened in shared mode */ 1513 if (CmpShareSystemHives) 1514 CmpMachineHiveList[i].HHiveFlags |= HIVE_VOLATILE; 1515 1516 /* Create a thread to handle this hive */ 1517 Status = PsCreateSystemThread(&Thread, 1518 THREAD_ALL_ACCESS, 1519 NULL, 1520 0, 1521 NULL, 1522 CmpLoadHiveThread, 1523 UlongToPtr(i)); 1524 if (NT_SUCCESS(Status)) 1525 { 1526 /* We don't care about the handle -- the thread self-terminates */ 1527 ZwClose(Thread); 1528 } 1529 else 1530 { 1531 /* Can't imagine this happening */ 1532 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status); 1533 } 1534 } 1535 1536 /* Make sure we've reached the end of the list */ 1537 ASSERT(CmpMachineHiveList[i].Name == NULL); 1538 1539 /* Wait for hive loading to finish */ 1540 KeWaitForSingleObject(&CmpLoadWorkerEvent, 1541 Executive, 1542 KernelMode, 1543 FALSE, 1544 NULL); 1545 1546 /* Exit the special boot condition and make sure all workers completed */ 1547 CmpSpecialBootCondition = FALSE; 1548 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES); 1549 1550 /* Loop hives again */ 1551 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) 1552 { 1553 /* Make sure the thread ran and finished */ 1554 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE); 1555 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE); 1556 1557 /* Check if this was a new hive */ 1558 if (!CmpMachineHiveList[i].CmHive) 1559 { 1560 /* Make sure we allocated something */ 1561 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL); 1562 1563 /* Build the base name */ 1564 RegName.Length = RegStart; 1565 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); 1566 RtlAppendUnicodeStringToString(&RegName, &TempName); 1567 1568 /* Check if this is a child of the root */ 1569 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR) 1570 { 1571 /* Then setup the whole name */ 1572 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); 1573 RtlAppendUnicodeStringToString(&RegName, &TempName); 1574 } 1575 1576 /* Now link the hive to its master */ 1577 Status = CmpLinkHiveToMaster(&RegName, 1578 NULL, 1579 CmpMachineHiveList[i].CmHive2, 1580 CmpMachineHiveList[i].Allocate, 1581 SecurityDescriptor); 1582 if (Status != STATUS_SUCCESS) 1583 { 1584 /* Linking needs to work */ 1585 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName); 1586 } 1587 1588 /* Check if we had to allocate a new hive */ 1589 if (CmpMachineHiveList[i].Allocate) 1590 { 1591 /* Sync the new hive */ 1592 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2)); 1593 } 1594 } 1595 1596 /* Check if we created a new hive */ 1597 if (CmpMachineHiveList[i].CmHive2) 1598 { 1599 /* Add to HiveList key */ 1600 CmpAddToHiveFileList(CmpMachineHiveList[i].CmHive2); 1601 } 1602 } 1603 1604 /* Get rid of the SD */ 1605 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1606 1607 /* Link SECURITY to SAM */ 1608 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM", 1609 L"\\Registry\\Machine\\SAM\\SAM"); 1610 1611 /* Link S-1-5-18 to .Default */ 1612 CmpNoVolatileCreates = FALSE; 1613 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18", 1614 L"\\Registry\\User\\.Default"); 1615 CmpNoVolatileCreates = TRUE; 1616 } 1617 1618 CODE_SEG("INIT") 1619 BOOLEAN 1620 NTAPI 1621 CmInitSystem1(VOID) 1622 { 1623 OBJECT_ATTRIBUTES ObjectAttributes; 1624 UNICODE_STRING KeyName; 1625 HANDLE KeyHandle; 1626 NTSTATUS Status; 1627 PCMHIVE HardwareHive; 1628 PSECURITY_DESCRIPTOR SecurityDescriptor; 1629 PAGED_CODE(); 1630 1631 /* Check if this is PE-boot */ 1632 if (InitIsWinPEMode) 1633 { 1634 /* Set the registry in PE mode and load the system hives in shared mode */ 1635 CmpMiniNTBoot = TRUE; 1636 CmpShareSystemHives = TRUE; 1637 } 1638 /* If we are in volatile boot mode, ALL hives without exception 1639 * (system hives and others) will be loaded in shared mode */ 1640 if (CmpVolatileBoot) 1641 CmpShareSystemHives = TRUE; 1642 1643 /* Initialize the hive list and lock */ 1644 InitializeListHead(&CmpHiveListHead); 1645 ExInitializePushLock(&CmpHiveListHeadLock); 1646 ExInitializePushLock(&CmpLoadHiveLock); 1647 1648 /* Initialize registry lock */ 1649 ExInitializeResourceLite(&CmpRegistryLock); 1650 1651 /* Initialize the cache */ 1652 CmpInitializeCache(); 1653 1654 /* Initialize allocation and delayed dereferencing */ 1655 CmpInitCmPrivateAlloc(); 1656 CmpInitCmPrivateDelayAlloc(); 1657 CmpInitDelayDerefKCBEngine(); 1658 1659 /* Initialize callbacks */ 1660 CmpInitCallback(); 1661 1662 /* Initialize self healing */ 1663 KeInitializeGuardedMutex(&CmpSelfHealQueueLock); 1664 InitializeListHead(&CmpSelfHealQueueListHead); 1665 1666 /* Save the current process and lock the registry */ 1667 CmpSystemProcess = PsGetCurrentProcess(); 1668 1669 /* Create the key object types */ 1670 Status = CmpCreateObjectTypes(); 1671 if (!NT_SUCCESS(Status)) 1672 { 1673 /* Bugcheck */ 1674 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0); 1675 } 1676 1677 /* Build the master hive */ 1678 Status = CmpInitializeHive(&CmiVolatileHive, 1679 HINIT_CREATE, 1680 HIVE_VOLATILE, 1681 HFILE_TYPE_PRIMARY, 1682 NULL, 1683 NULL, 1684 NULL, 1685 NULL, 1686 NULL, 1687 NULL, 1688 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 1689 if (!NT_SUCCESS(Status)) 1690 { 1691 /* Bugcheck */ 1692 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0); 1693 } 1694 1695 /* Create the \REGISTRY key node */ 1696 if (!CmpCreateRegistryRoot()) 1697 { 1698 /* Bugcheck */ 1699 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0); 1700 } 1701 1702 /* Create the default security descriptor */ 1703 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1704 1705 /* Create '\Registry\Machine' key */ 1706 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE"); 1707 InitializeObjectAttributes(&ObjectAttributes, 1708 &KeyName, 1709 OBJ_CASE_INSENSITIVE, 1710 NULL, 1711 SecurityDescriptor); 1712 Status = NtCreateKey(&KeyHandle, 1713 KEY_READ | KEY_WRITE, 1714 &ObjectAttributes, 1715 0, 1716 NULL, 1717 0, 1718 NULL); 1719 if (!NT_SUCCESS(Status)) 1720 { 1721 /* Bugcheck */ 1722 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0); 1723 } 1724 1725 /* Close the handle */ 1726 NtClose(KeyHandle); 1727 1728 /* Create '\Registry\User' key */ 1729 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER"); 1730 InitializeObjectAttributes(&ObjectAttributes, 1731 &KeyName, 1732 OBJ_CASE_INSENSITIVE, 1733 NULL, 1734 SecurityDescriptor); 1735 Status = NtCreateKey(&KeyHandle, 1736 KEY_READ | KEY_WRITE, 1737 &ObjectAttributes, 1738 0, 1739 NULL, 1740 0, 1741 NULL); 1742 if (!NT_SUCCESS(Status)) 1743 { 1744 /* Bugcheck */ 1745 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0); 1746 } 1747 1748 /* Close the handle */ 1749 NtClose(KeyHandle); 1750 1751 /* After this point, do not allow creating keys in the master hive */ 1752 CmpNoVolatileCreates = TRUE; 1753 1754 /* Initialize the system hive */ 1755 if (!CmpInitializeSystemHive(KeLoaderBlock)) 1756 { 1757 /* Bugcheck */ 1758 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0); 1759 } 1760 1761 /* Create the 'CurrentControlSet' link */ 1762 Status = CmpCreateControlSet(KeLoaderBlock); 1763 if (!NT_SUCCESS(Status)) 1764 { 1765 /* Bugcheck */ 1766 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0); 1767 } 1768 1769 /* Create the hardware hive */ 1770 Status = CmpInitializeHive(&HardwareHive, 1771 HINIT_CREATE, 1772 HIVE_VOLATILE, 1773 HFILE_TYPE_PRIMARY, 1774 NULL, 1775 NULL, 1776 NULL, 1777 NULL, 1778 NULL, 1779 NULL, 1780 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 1781 if (!NT_SUCCESS(Status)) 1782 { 1783 /* Bugcheck */ 1784 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0); 1785 } 1786 1787 /* Add the hive to the hive list */ 1788 CmpMachineHiveList[0].CmHive = HardwareHive; 1789 1790 /* Attach it to the machine key */ 1791 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE"); 1792 Status = CmpLinkHiveToMaster(&KeyName, 1793 NULL, 1794 HardwareHive, 1795 TRUE, 1796 SecurityDescriptor); 1797 if (!NT_SUCCESS(Status)) 1798 { 1799 /* Bugcheck */ 1800 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0); 1801 } 1802 1803 /* Add to HiveList key */ 1804 CmpAddToHiveFileList(HardwareHive); 1805 1806 /* Free the security descriptor */ 1807 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1808 1809 /* Fill out the Hardware key with the ARC Data from the Loader */ 1810 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock); 1811 if (!NT_SUCCESS(Status)) 1812 { 1813 /* Bugcheck */ 1814 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0); 1815 } 1816 1817 /* Initialize machine-dependent information into the registry */ 1818 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock); 1819 if (!NT_SUCCESS(Status)) 1820 { 1821 /* Bugcheck */ 1822 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0); 1823 } 1824 1825 /* Initialize volatile registry settings */ 1826 Status = CmpSetSystemValues(KeLoaderBlock); 1827 if (!NT_SUCCESS(Status)) 1828 { 1829 /* Bugcheck */ 1830 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0); 1831 } 1832 1833 /* Free the load options */ 1834 ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM); 1835 1836 /* If we got here, all went well */ 1837 return TRUE; 1838 } 1839 1840 CODE_SEG("INIT") 1841 PUNICODE_STRING* 1842 NTAPI 1843 CmGetSystemDriverList(VOID) 1844 { 1845 LIST_ENTRY DriverList; 1846 OBJECT_ATTRIBUTES ObjectAttributes; 1847 NTSTATUS Status; 1848 PCM_KEY_BODY KeyBody; 1849 PHHIVE Hive; 1850 HCELL_INDEX RootCell, ControlCell; 1851 HANDLE KeyHandle; 1852 UNICODE_STRING KeyName; 1853 PLIST_ENTRY NextEntry; 1854 ULONG i; 1855 PUNICODE_STRING* ServicePath = NULL; 1856 BOOLEAN Success, AutoSelect; 1857 PBOOT_DRIVER_LIST_ENTRY DriverEntry; 1858 PAGED_CODE(); 1859 1860 /* Initialize the driver list */ 1861 InitializeListHead(&DriverList); 1862 1863 /* Open the system hive key */ 1864 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System"); 1865 InitializeObjectAttributes(&ObjectAttributes, 1866 &KeyName, 1867 OBJ_CASE_INSENSITIVE, 1868 NULL, 1869 NULL); 1870 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 1871 if (!NT_SUCCESS(Status)) return NULL; 1872 1873 /* Reference the key object to get the root hive/cell to access directly */ 1874 Status = ObReferenceObjectByHandle(KeyHandle, 1875 KEY_QUERY_VALUE, 1876 CmpKeyObjectType, 1877 KernelMode, 1878 (PVOID*)&KeyBody, 1879 NULL); 1880 if (!NT_SUCCESS(Status)) 1881 { 1882 /* Fail */ 1883 NtClose(KeyHandle); 1884 return NULL; 1885 } 1886 1887 /* Do all this under the registry lock */ 1888 CmpLockRegistryExclusive(); 1889 1890 /* Get the hive and key cell */ 1891 Hive = KeyBody->KeyControlBlock->KeyHive; 1892 RootCell = KeyBody->KeyControlBlock->KeyCell; 1893 1894 /* Open the current control set key */ 1895 RtlInitUnicodeString(&KeyName, L"Current"); 1896 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect); 1897 if (ControlCell == HCELL_NIL) goto EndPath; 1898 1899 /* Find all system drivers */ 1900 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList); 1901 if (!Success) goto EndPath; 1902 1903 /* Sort by group/tag */ 1904 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath; 1905 1906 /* Remove circular dependencies (cycles) and sort */ 1907 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath; 1908 1909 /* Loop the list to count drivers */ 1910 for (i = 0, NextEntry = DriverList.Flink; 1911 NextEntry != &DriverList; 1912 i++, NextEntry = NextEntry->Flink); 1913 1914 /* Allocate the array */ 1915 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING)); 1916 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1917 1918 /* Loop the driver list */ 1919 for (i = 0, NextEntry = DriverList.Flink; 1920 NextEntry != &DriverList; 1921 i++, NextEntry = NextEntry->Flink) 1922 { 1923 /* Get the entry */ 1924 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link); 1925 1926 /* Allocate the path for the caller */ 1927 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING)); 1928 if (!ServicePath[i]) 1929 { 1930 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1931 } 1932 1933 /* Duplicate the registry path */ 1934 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 1935 &DriverEntry->RegistryPath, 1936 ServicePath[i]); 1937 if (!NT_SUCCESS(Status)) 1938 { 1939 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1940 } 1941 } 1942 1943 /* Terminate the list */ 1944 ServicePath[i] = NULL; 1945 1946 EndPath: 1947 /* Free the driver list if we had one */ 1948 if (!IsListEmpty(&DriverList)) CmpFreeDriverList(Hive, &DriverList); 1949 1950 /* Unlock the registry */ 1951 CmpUnlockRegistry(); 1952 1953 /* Close the key handle and dereference the object, then return the path */ 1954 ObDereferenceObject(KeyBody); 1955 NtClose(KeyHandle); 1956 return ServicePath; 1957 } 1958 1959 VOID 1960 NTAPI 1961 CmpLockRegistryExclusive(VOID) 1962 { 1963 /* Enter a critical region and lock the registry */ 1964 KeEnterCriticalRegion(); 1965 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); 1966 1967 /* Sanity check */ 1968 ASSERT(CmpFlushStarveWriters == 0); 1969 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller); 1970 } 1971 1972 VOID 1973 NTAPI 1974 CmpLockRegistry(VOID) 1975 { 1976 /* Enter a critical region */ 1977 KeEnterCriticalRegion(); 1978 1979 /* Check if we have to starve writers */ 1980 if (CmpFlushStarveWriters) 1981 { 1982 /* Starve exlusive waiters */ 1983 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE); 1984 } 1985 else 1986 { 1987 /* Just grab the lock */ 1988 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE); 1989 } 1990 } 1991 1992 BOOLEAN 1993 NTAPI 1994 CmpTestRegistryLock(VOID) 1995 { 1996 /* Test the lock */ 1997 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE; 1998 } 1999 2000 BOOLEAN 2001 NTAPI 2002 CmpTestRegistryLockExclusive(VOID) 2003 { 2004 /* Test the lock */ 2005 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE; 2006 } 2007 2008 VOID 2009 NTAPI 2010 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive) 2011 { 2012 /* Lock the flusher. We should already be in a critical section */ 2013 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2014 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 2015 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 2016 ExAcquireResourceExclusiveLite(Hive->FlusherLock, TRUE); 2017 } 2018 2019 VOID 2020 NTAPI 2021 CmpLockHiveFlusherShared(IN PCMHIVE Hive) 2022 { 2023 /* Lock the flusher. We should already be in a critical section */ 2024 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2025 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 2026 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 2027 ExAcquireResourceSharedLite(Hive->FlusherLock, TRUE); 2028 } 2029 2030 VOID 2031 NTAPI 2032 CmpUnlockHiveFlusher(IN PCMHIVE Hive) 2033 { 2034 /* Sanity check */ 2035 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2036 CMP_ASSERT_FLUSH_LOCK(Hive); 2037 2038 /* Release the lock */ 2039 ExReleaseResourceLite(Hive->FlusherLock); 2040 } 2041 2042 BOOLEAN 2043 NTAPI 2044 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive) 2045 { 2046 /* Test the lock */ 2047 return !ExIsResourceAcquiredSharedLite(Hive->FlusherLock) ? FALSE : TRUE; 2048 } 2049 2050 BOOLEAN 2051 NTAPI 2052 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive) 2053 { 2054 /* Test the lock */ 2055 return !ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) ? FALSE : TRUE; 2056 } 2057 2058 VOID 2059 NTAPI 2060 CmpUnlockRegistry(VOID) 2061 { 2062 /* Sanity check */ 2063 CMP_ASSERT_REGISTRY_LOCK(); 2064 2065 /* Check if we should flush the registry */ 2066 if (CmpFlushOnLockRelease) 2067 { 2068 /* The registry should be exclusively locked for this */ 2069 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK(); 2070 2071 /* Flush the registry */ 2072 CmpDoFlushAll(TRUE); 2073 CmpFlushOnLockRelease = FALSE; 2074 } 2075 2076 /* Release the lock and leave the critical region */ 2077 ExReleaseResourceLite(&CmpRegistryLock); 2078 KeLeaveCriticalRegion(); 2079 } 2080 2081 VOID 2082 NTAPI 2083 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1, 2084 IN ULONG ConvKey2) 2085 { 2086 ULONG Index1, Index2; 2087 2088 /* Sanity check */ 2089 CMP_ASSERT_REGISTRY_LOCK(); 2090 2091 /* Get hash indexes */ 2092 Index1 = GET_HASH_INDEX(ConvKey1); 2093 Index2 = GET_HASH_INDEX(ConvKey2); 2094 2095 /* See which one is highest */ 2096 if (Index1 < Index2) 2097 { 2098 /* Grab them in the proper order */ 2099 CmpAcquireKcbLockExclusiveByKey(ConvKey1); 2100 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 2101 } 2102 else 2103 { 2104 /* Grab the second one first, then the first */ 2105 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 2106 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1); 2107 } 2108 } 2109 2110 VOID 2111 NTAPI 2112 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1, 2113 IN ULONG ConvKey2) 2114 { 2115 ULONG Index1, Index2; 2116 2117 /* Sanity check */ 2118 CMP_ASSERT_REGISTRY_LOCK(); 2119 2120 /* Get hash indexes */ 2121 Index1 = GET_HASH_INDEX(ConvKey1); 2122 Index2 = GET_HASH_INDEX(ConvKey2); 2123 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2)->Owner == KeGetCurrentThread()) || 2124 CmpTestRegistryLockExclusive()); 2125 2126 /* See which one is highest */ 2127 if (Index1 < Index2) 2128 { 2129 /* Grab them in the proper order */ 2130 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2131 CmpTestRegistryLockExclusive()); 2132 CmpReleaseKcbLockByKey(ConvKey2); 2133 CmpReleaseKcbLockByKey(ConvKey1); 2134 } 2135 else 2136 { 2137 /* Release the first one first, then the second */ 2138 if (Index1 != Index2) 2139 { 2140 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2141 CmpTestRegistryLockExclusive()); 2142 CmpReleaseKcbLockByKey(ConvKey1); 2143 } 2144 CmpReleaseKcbLockByKey(ConvKey2); 2145 } 2146 } 2147 2148 VOID 2149 NTAPI 2150 CmShutdownSystem(VOID) 2151 { 2152 PLIST_ENTRY ListEntry; 2153 PCMHIVE Hive; 2154 2155 /* Kill the workers */ 2156 if (!CmFirstTime) CmpShutdownWorkers(); 2157 2158 /* Flush all hives */ 2159 CmpLockRegistryExclusive(); 2160 CmpDoFlushAll(TRUE); 2161 2162 /* Close all hive files */ 2163 ListEntry = CmpHiveListHead.Flink; 2164 while (ListEntry != &CmpHiveListHead) 2165 { 2166 Hive = CONTAINING_RECORD(ListEntry, CMHIVE, HiveList); 2167 2168 CmpCloseHiveFiles(Hive); 2169 2170 ListEntry = ListEntry->Flink; 2171 } 2172 2173 /* 2174 * As we flushed all the hives on the disk, 2175 * tell the system we do not want any further 2176 * registry flushing or syncing at this point 2177 * since we are shutting down the registry anyway. 2178 */ 2179 HvShutdownComplete = TRUE; 2180 2181 CmpUnlockRegistry(); 2182 } 2183 2184 VOID 2185 NTAPI 2186 CmpSetVersionData(VOID) 2187 { 2188 NTSTATUS Status; 2189 OBJECT_ATTRIBUTES ObjectAttributes; 2190 UNICODE_STRING KeyName; 2191 UNICODE_STRING ValueName; 2192 UNICODE_STRING ValueData; 2193 ANSI_STRING TempString; 2194 HANDLE SoftwareKeyHandle = NULL; 2195 HANDLE MicrosoftKeyHandle = NULL; 2196 HANDLE WindowsNtKeyHandle = NULL; 2197 HANDLE CurrentVersionKeyHandle = NULL; 2198 WCHAR Buffer[128]; // Buffer large enough to contain a full ULONG in decimal 2199 // representation, and the full 'CurrentType' string. 2200 2201 /* 2202 * Open the 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' key 2203 * (create the intermediate subkeys if needed). 2204 */ 2205 2206 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SOFTWARE"); 2207 InitializeObjectAttributes(&ObjectAttributes, 2208 &KeyName, 2209 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2210 NULL, 2211 NULL); 2212 Status = NtCreateKey(&SoftwareKeyHandle, 2213 KEY_CREATE_SUB_KEY, 2214 &ObjectAttributes, 2215 0, 2216 NULL, 2217 0, 2218 NULL); 2219 if (!NT_SUCCESS(Status)) 2220 { 2221 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2222 return; 2223 } 2224 2225 RtlInitUnicodeString(&KeyName, L"Microsoft"); 2226 InitializeObjectAttributes(&ObjectAttributes, 2227 &KeyName, 2228 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2229 SoftwareKeyHandle, 2230 NULL); 2231 Status = NtCreateKey(&MicrosoftKeyHandle, 2232 KEY_CREATE_SUB_KEY, 2233 &ObjectAttributes, 2234 0, 2235 NULL, 2236 0, 2237 NULL); 2238 if (!NT_SUCCESS(Status)) 2239 { 2240 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2241 goto Quit; 2242 } 2243 2244 RtlInitUnicodeString(&KeyName, L"Windows NT"); 2245 InitializeObjectAttributes(&ObjectAttributes, 2246 &KeyName, 2247 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2248 MicrosoftKeyHandle, 2249 NULL); 2250 Status = NtCreateKey(&WindowsNtKeyHandle, 2251 KEY_CREATE_SUB_KEY, 2252 &ObjectAttributes, 2253 0, 2254 NULL, 2255 0, 2256 NULL); 2257 if (!NT_SUCCESS(Status)) 2258 { 2259 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2260 goto Quit; 2261 } 2262 2263 RtlInitUnicodeString(&KeyName, L"CurrentVersion"); 2264 InitializeObjectAttributes(&ObjectAttributes, 2265 &KeyName, 2266 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2267 WindowsNtKeyHandle, 2268 NULL); 2269 Status = NtCreateKey(&CurrentVersionKeyHandle, 2270 KEY_CREATE_SUB_KEY | KEY_SET_VALUE, 2271 &ObjectAttributes, 2272 0, 2273 NULL, 2274 0, 2275 NULL); 2276 if (!NT_SUCCESS(Status)) 2277 { 2278 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2279 goto Quit; 2280 } 2281 2282 /* Set the 'CurrentVersion' value */ 2283 RtlInitUnicodeString(&ValueName, L"CurrentVersion"); 2284 NtSetValueKey(CurrentVersionKeyHandle, 2285 &ValueName, 2286 0, 2287 REG_SZ, 2288 CmVersionString.Buffer, 2289 CmVersionString.Length + sizeof(WCHAR)); 2290 2291 /* Set the 'CurrentBuildNumber' value */ 2292 RtlInitUnicodeString(&ValueName, L"CurrentBuildNumber"); 2293 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2294 RtlIntegerToUnicodeString(NtBuildNumber & 0xFFFF, 10, &ValueData); 2295 NtSetValueKey(CurrentVersionKeyHandle, 2296 &ValueName, 2297 0, 2298 REG_SZ, 2299 ValueData.Buffer, 2300 ValueData.Length + sizeof(WCHAR)); 2301 2302 /* Set the 'BuildLab' value */ 2303 RtlInitUnicodeString(&ValueName, L"BuildLab"); 2304 RtlInitAnsiString(&TempString, NtBuildLab); 2305 Status = RtlAnsiStringToUnicodeString(&ValueData, &TempString, FALSE); 2306 if (NT_SUCCESS(Status)) 2307 { 2308 NtSetValueKey(CurrentVersionKeyHandle, 2309 &ValueName, 2310 0, 2311 REG_SZ, 2312 ValueData.Buffer, 2313 ValueData.Length + sizeof(WCHAR)); 2314 } 2315 2316 /* Set the 'CurrentType' value */ 2317 RtlInitUnicodeString(&ValueName, L"CurrentType"); 2318 RtlStringCbPrintfW(Buffer, sizeof(Buffer), 2319 L"%s %s", 2320 #ifdef CONFIG_SMP 2321 L"Multiprocessor" 2322 #else 2323 L"Uniprocessor" 2324 #endif 2325 , 2326 #if (DBG == 1) 2327 L"Checked" 2328 #else 2329 L"Free" 2330 #endif 2331 ); 2332 RtlInitUnicodeString(&ValueData, Buffer); 2333 NtSetValueKey(CurrentVersionKeyHandle, 2334 &ValueName, 2335 0, 2336 REG_SZ, 2337 ValueData.Buffer, 2338 ValueData.Length + sizeof(WCHAR)); 2339 2340 /* Set the 'CSDVersion' value */ 2341 RtlInitUnicodeString(&ValueName, L"CSDVersion"); 2342 if (CmCSDVersionString.Length != 0) 2343 { 2344 NtSetValueKey(CurrentVersionKeyHandle, 2345 &ValueName, 2346 0, 2347 REG_SZ, 2348 CmCSDVersionString.Buffer, 2349 CmCSDVersionString.Length + sizeof(WCHAR)); 2350 } 2351 else 2352 { 2353 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2354 } 2355 2356 /* Set the 'CSDBuildNumber' value */ 2357 RtlInitUnicodeString(&ValueName, L"CSDBuildNumber"); 2358 if (CmNtSpBuildNumber != 0) 2359 { 2360 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2361 RtlIntegerToUnicodeString(CmNtSpBuildNumber, 10, &ValueData); 2362 NtSetValueKey(CurrentVersionKeyHandle, 2363 &ValueName, 2364 0, 2365 REG_SZ, 2366 ValueData.Buffer, 2367 ValueData.Length + sizeof(WCHAR)); 2368 } 2369 else 2370 { 2371 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2372 } 2373 2374 /* Set the 'SystemRoot' value */ 2375 RtlInitUnicodeString(&ValueName, L"SystemRoot"); 2376 NtSetValueKey(CurrentVersionKeyHandle, 2377 &ValueName, 2378 0, 2379 REG_SZ, 2380 NtSystemRoot.Buffer, 2381 NtSystemRoot.Length + sizeof(WCHAR)); 2382 2383 Quit: 2384 /* Close the keys */ 2385 if (CurrentVersionKeyHandle != NULL) 2386 NtClose(CurrentVersionKeyHandle); 2387 2388 if (WindowsNtKeyHandle != NULL) 2389 NtClose(WindowsNtKeyHandle); 2390 2391 if (MicrosoftKeyHandle != NULL) 2392 NtClose(MicrosoftKeyHandle); 2393 2394 if (SoftwareKeyHandle != NULL) 2395 NtClose(SoftwareKeyHandle); 2396 } 2397 2398 /* EOF */ 2399