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 sucessful */ 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 1639 /* Initialize the hive list and lock */ 1640 InitializeListHead(&CmpHiveListHead); 1641 ExInitializePushLock(&CmpHiveListHeadLock); 1642 ExInitializePushLock(&CmpLoadHiveLock); 1643 1644 /* Initialize registry lock */ 1645 ExInitializeResourceLite(&CmpRegistryLock); 1646 1647 /* Initialize the cache */ 1648 CmpInitializeCache(); 1649 1650 /* Initialize allocation and delayed dereferencing */ 1651 CmpInitCmPrivateAlloc(); 1652 CmpInitCmPrivateDelayAlloc(); 1653 CmpInitDelayDerefKCBEngine(); 1654 1655 /* Initialize callbacks */ 1656 CmpInitCallback(); 1657 1658 /* Initialize self healing */ 1659 KeInitializeGuardedMutex(&CmpSelfHealQueueLock); 1660 InitializeListHead(&CmpSelfHealQueueListHead); 1661 1662 /* Save the current process and lock the registry */ 1663 CmpSystemProcess = PsGetCurrentProcess(); 1664 1665 /* Create the key object types */ 1666 Status = CmpCreateObjectTypes(); 1667 if (!NT_SUCCESS(Status)) 1668 { 1669 /* Bugcheck */ 1670 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0); 1671 } 1672 1673 /* Build the master hive */ 1674 Status = CmpInitializeHive(&CmiVolatileHive, 1675 HINIT_CREATE, 1676 HIVE_VOLATILE, 1677 HFILE_TYPE_PRIMARY, 1678 NULL, 1679 NULL, 1680 NULL, 1681 NULL, 1682 NULL, 1683 NULL, 1684 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 1685 if (!NT_SUCCESS(Status)) 1686 { 1687 /* Bugcheck */ 1688 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0); 1689 } 1690 1691 /* Create the \REGISTRY key node */ 1692 if (!CmpCreateRegistryRoot()) 1693 { 1694 /* Bugcheck */ 1695 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0); 1696 } 1697 1698 /* Create the default security descriptor */ 1699 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1700 1701 /* Create '\Registry\Machine' key */ 1702 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE"); 1703 InitializeObjectAttributes(&ObjectAttributes, 1704 &KeyName, 1705 OBJ_CASE_INSENSITIVE, 1706 NULL, 1707 SecurityDescriptor); 1708 Status = NtCreateKey(&KeyHandle, 1709 KEY_READ | KEY_WRITE, 1710 &ObjectAttributes, 1711 0, 1712 NULL, 1713 0, 1714 NULL); 1715 if (!NT_SUCCESS(Status)) 1716 { 1717 /* Bugcheck */ 1718 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0); 1719 } 1720 1721 /* Close the handle */ 1722 NtClose(KeyHandle); 1723 1724 /* Create '\Registry\User' key */ 1725 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER"); 1726 InitializeObjectAttributes(&ObjectAttributes, 1727 &KeyName, 1728 OBJ_CASE_INSENSITIVE, 1729 NULL, 1730 SecurityDescriptor); 1731 Status = NtCreateKey(&KeyHandle, 1732 KEY_READ | KEY_WRITE, 1733 &ObjectAttributes, 1734 0, 1735 NULL, 1736 0, 1737 NULL); 1738 if (!NT_SUCCESS(Status)) 1739 { 1740 /* Bugcheck */ 1741 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0); 1742 } 1743 1744 /* Close the handle */ 1745 NtClose(KeyHandle); 1746 1747 /* After this point, do not allow creating keys in the master hive */ 1748 CmpNoVolatileCreates = TRUE; 1749 1750 /* Initialize the system hive */ 1751 if (!CmpInitializeSystemHive(KeLoaderBlock)) 1752 { 1753 /* Bugcheck */ 1754 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0); 1755 } 1756 1757 /* Create the 'CurrentControlSet' link */ 1758 Status = CmpCreateControlSet(KeLoaderBlock); 1759 if (!NT_SUCCESS(Status)) 1760 { 1761 /* Bugcheck */ 1762 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0); 1763 } 1764 1765 /* Create the hardware hive */ 1766 Status = CmpInitializeHive(&HardwareHive, 1767 HINIT_CREATE, 1768 HIVE_VOLATILE, 1769 HFILE_TYPE_PRIMARY, 1770 NULL, 1771 NULL, 1772 NULL, 1773 NULL, 1774 NULL, 1775 NULL, 1776 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 1777 if (!NT_SUCCESS(Status)) 1778 { 1779 /* Bugcheck */ 1780 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0); 1781 } 1782 1783 /* Add the hive to the hive list */ 1784 CmpMachineHiveList[0].CmHive = HardwareHive; 1785 1786 /* Attach it to the machine key */ 1787 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE"); 1788 Status = CmpLinkHiveToMaster(&KeyName, 1789 NULL, 1790 HardwareHive, 1791 TRUE, 1792 SecurityDescriptor); 1793 if (!NT_SUCCESS(Status)) 1794 { 1795 /* Bugcheck */ 1796 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0); 1797 } 1798 1799 /* Add to HiveList key */ 1800 CmpAddToHiveFileList(HardwareHive); 1801 1802 /* Free the security descriptor */ 1803 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1804 1805 /* Fill out the Hardware key with the ARC Data from the Loader */ 1806 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock); 1807 if (!NT_SUCCESS(Status)) 1808 { 1809 /* Bugcheck */ 1810 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0); 1811 } 1812 1813 /* Initialize machine-dependent information into the registry */ 1814 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock); 1815 if (!NT_SUCCESS(Status)) 1816 { 1817 /* Bugcheck */ 1818 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0); 1819 } 1820 1821 /* Initialize volatile registry settings */ 1822 Status = CmpSetSystemValues(KeLoaderBlock); 1823 if (!NT_SUCCESS(Status)) 1824 { 1825 /* Bugcheck */ 1826 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0); 1827 } 1828 1829 /* Free the load options */ 1830 ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM); 1831 1832 /* If we got here, all went well */ 1833 return TRUE; 1834 } 1835 1836 CODE_SEG("INIT") 1837 PUNICODE_STRING* 1838 NTAPI 1839 CmGetSystemDriverList(VOID) 1840 { 1841 LIST_ENTRY DriverList; 1842 OBJECT_ATTRIBUTES ObjectAttributes; 1843 NTSTATUS Status; 1844 PCM_KEY_BODY KeyBody; 1845 PHHIVE Hive; 1846 HCELL_INDEX RootCell, ControlCell; 1847 HANDLE KeyHandle; 1848 UNICODE_STRING KeyName; 1849 PLIST_ENTRY NextEntry; 1850 ULONG i; 1851 PUNICODE_STRING* ServicePath = NULL; 1852 BOOLEAN Success, AutoSelect; 1853 PBOOT_DRIVER_LIST_ENTRY DriverEntry; 1854 PAGED_CODE(); 1855 1856 /* Initialize the driver list */ 1857 InitializeListHead(&DriverList); 1858 1859 /* Open the system hive key */ 1860 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System"); 1861 InitializeObjectAttributes(&ObjectAttributes, 1862 &KeyName, 1863 OBJ_CASE_INSENSITIVE, 1864 NULL, 1865 NULL); 1866 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 1867 if (!NT_SUCCESS(Status)) return NULL; 1868 1869 /* Reference the key object to get the root hive/cell to access directly */ 1870 Status = ObReferenceObjectByHandle(KeyHandle, 1871 KEY_QUERY_VALUE, 1872 CmpKeyObjectType, 1873 KernelMode, 1874 (PVOID*)&KeyBody, 1875 NULL); 1876 if (!NT_SUCCESS(Status)) 1877 { 1878 /* Fail */ 1879 NtClose(KeyHandle); 1880 return NULL; 1881 } 1882 1883 /* Do all this under the registry lock */ 1884 CmpLockRegistryExclusive(); 1885 1886 /* Get the hive and key cell */ 1887 Hive = KeyBody->KeyControlBlock->KeyHive; 1888 RootCell = KeyBody->KeyControlBlock->KeyCell; 1889 1890 /* Open the current control set key */ 1891 RtlInitUnicodeString(&KeyName, L"Current"); 1892 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect); 1893 if (ControlCell == HCELL_NIL) goto EndPath; 1894 1895 /* Find all system drivers */ 1896 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList); 1897 if (!Success) goto EndPath; 1898 1899 /* Sort by group/tag */ 1900 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath; 1901 1902 /* Remove circular dependencies (cycles) and sort */ 1903 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath; 1904 1905 /* Loop the list to count drivers */ 1906 for (i = 0, NextEntry = DriverList.Flink; 1907 NextEntry != &DriverList; 1908 i++, NextEntry = NextEntry->Flink); 1909 1910 /* Allocate the array */ 1911 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING)); 1912 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1913 1914 /* Loop the driver list */ 1915 for (i = 0, NextEntry = DriverList.Flink; 1916 NextEntry != &DriverList; 1917 i++, NextEntry = NextEntry->Flink) 1918 { 1919 /* Get the entry */ 1920 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link); 1921 1922 /* Allocate the path for the caller */ 1923 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING)); 1924 if (!ServicePath[i]) 1925 { 1926 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1927 } 1928 1929 /* Duplicate the registry path */ 1930 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 1931 &DriverEntry->RegistryPath, 1932 ServicePath[i]); 1933 if (!NT_SUCCESS(Status)) 1934 { 1935 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1936 } 1937 } 1938 1939 /* Terminate the list */ 1940 ServicePath[i] = NULL; 1941 1942 EndPath: 1943 /* Free the driver list if we had one */ 1944 if (!IsListEmpty(&DriverList)) CmpFreeDriverList(Hive, &DriverList); 1945 1946 /* Unlock the registry */ 1947 CmpUnlockRegistry(); 1948 1949 /* Close the key handle and dereference the object, then return the path */ 1950 ObDereferenceObject(KeyBody); 1951 NtClose(KeyHandle); 1952 return ServicePath; 1953 } 1954 1955 VOID 1956 NTAPI 1957 CmpLockRegistryExclusive(VOID) 1958 { 1959 /* Enter a critical region and lock the registry */ 1960 KeEnterCriticalRegion(); 1961 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); 1962 1963 /* Sanity check */ 1964 ASSERT(CmpFlushStarveWriters == 0); 1965 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller); 1966 } 1967 1968 VOID 1969 NTAPI 1970 CmpLockRegistry(VOID) 1971 { 1972 /* Enter a critical region */ 1973 KeEnterCriticalRegion(); 1974 1975 /* Check if we have to starve writers */ 1976 if (CmpFlushStarveWriters) 1977 { 1978 /* Starve exlusive waiters */ 1979 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE); 1980 } 1981 else 1982 { 1983 /* Just grab the lock */ 1984 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE); 1985 } 1986 } 1987 1988 BOOLEAN 1989 NTAPI 1990 CmpTestRegistryLock(VOID) 1991 { 1992 /* Test the lock */ 1993 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE; 1994 } 1995 1996 BOOLEAN 1997 NTAPI 1998 CmpTestRegistryLockExclusive(VOID) 1999 { 2000 /* Test the lock */ 2001 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE; 2002 } 2003 2004 VOID 2005 NTAPI 2006 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive) 2007 { 2008 /* Lock the flusher. We should already be in a critical section */ 2009 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2010 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 2011 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 2012 ExAcquireResourceExclusiveLite(Hive->FlusherLock, TRUE); 2013 } 2014 2015 VOID 2016 NTAPI 2017 CmpLockHiveFlusherShared(IN PCMHIVE Hive) 2018 { 2019 /* Lock the flusher. We should already be in a critical section */ 2020 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2021 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 2022 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 2023 ExAcquireResourceSharedLite(Hive->FlusherLock, TRUE); 2024 } 2025 2026 VOID 2027 NTAPI 2028 CmpUnlockHiveFlusher(IN PCMHIVE Hive) 2029 { 2030 /* Sanity check */ 2031 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2032 CMP_ASSERT_FLUSH_LOCK(Hive); 2033 2034 /* Release the lock */ 2035 ExReleaseResourceLite(Hive->FlusherLock); 2036 } 2037 2038 BOOLEAN 2039 NTAPI 2040 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive) 2041 { 2042 /* Test the lock */ 2043 return !ExIsResourceAcquiredSharedLite(Hive->FlusherLock) ? FALSE : TRUE; 2044 } 2045 2046 BOOLEAN 2047 NTAPI 2048 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive) 2049 { 2050 /* Test the lock */ 2051 return !ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) ? FALSE : TRUE; 2052 } 2053 2054 VOID 2055 NTAPI 2056 CmpUnlockRegistry(VOID) 2057 { 2058 /* Sanity check */ 2059 CMP_ASSERT_REGISTRY_LOCK(); 2060 2061 /* Check if we should flush the registry */ 2062 if (CmpFlushOnLockRelease) 2063 { 2064 /* The registry should be exclusively locked for this */ 2065 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK(); 2066 2067 /* Flush the registry */ 2068 CmpDoFlushAll(TRUE); 2069 CmpFlushOnLockRelease = FALSE; 2070 } 2071 2072 /* Release the lock and leave the critical region */ 2073 ExReleaseResourceLite(&CmpRegistryLock); 2074 KeLeaveCriticalRegion(); 2075 } 2076 2077 VOID 2078 NTAPI 2079 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1, 2080 IN ULONG ConvKey2) 2081 { 2082 ULONG Index1, Index2; 2083 2084 /* Sanity check */ 2085 CMP_ASSERT_REGISTRY_LOCK(); 2086 2087 /* Get hash indexes */ 2088 Index1 = GET_HASH_INDEX(ConvKey1); 2089 Index2 = GET_HASH_INDEX(ConvKey2); 2090 2091 /* See which one is highest */ 2092 if (Index1 < Index2) 2093 { 2094 /* Grab them in the proper order */ 2095 CmpAcquireKcbLockExclusiveByKey(ConvKey1); 2096 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 2097 } 2098 else 2099 { 2100 /* Grab the second one first, then the first */ 2101 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 2102 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1); 2103 } 2104 } 2105 2106 VOID 2107 NTAPI 2108 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1, 2109 IN ULONG ConvKey2) 2110 { 2111 ULONG Index1, Index2; 2112 2113 /* Sanity check */ 2114 CMP_ASSERT_REGISTRY_LOCK(); 2115 2116 /* Get hash indexes */ 2117 Index1 = GET_HASH_INDEX(ConvKey1); 2118 Index2 = GET_HASH_INDEX(ConvKey2); 2119 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2)->Owner == KeGetCurrentThread()) || 2120 CmpTestRegistryLockExclusive()); 2121 2122 /* See which one is highest */ 2123 if (Index1 < Index2) 2124 { 2125 /* Grab them in the proper order */ 2126 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2127 CmpTestRegistryLockExclusive()); 2128 CmpReleaseKcbLockByKey(ConvKey2); 2129 CmpReleaseKcbLockByKey(ConvKey1); 2130 } 2131 else 2132 { 2133 /* Release the first one first, then the second */ 2134 if (Index1 != Index2) 2135 { 2136 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2137 CmpTestRegistryLockExclusive()); 2138 CmpReleaseKcbLockByKey(ConvKey1); 2139 } 2140 CmpReleaseKcbLockByKey(ConvKey2); 2141 } 2142 } 2143 2144 VOID 2145 NTAPI 2146 CmShutdownSystem(VOID) 2147 { 2148 PLIST_ENTRY ListEntry; 2149 PCMHIVE Hive; 2150 2151 /* Kill the workers */ 2152 if (!CmFirstTime) CmpShutdownWorkers(); 2153 2154 /* Flush all hives */ 2155 CmpLockRegistryExclusive(); 2156 CmpDoFlushAll(TRUE); 2157 2158 /* Close all hive files */ 2159 ListEntry = CmpHiveListHead.Flink; 2160 while (ListEntry != &CmpHiveListHead) 2161 { 2162 Hive = CONTAINING_RECORD(ListEntry, CMHIVE, HiveList); 2163 2164 CmpCloseHiveFiles(Hive); 2165 2166 ListEntry = ListEntry->Flink; 2167 } 2168 2169 /* 2170 * As we flushed all the hives on the disk, 2171 * tell the system we do not want any further 2172 * registry flushing or syncing at this point 2173 * since we are shutting down the registry anyway. 2174 */ 2175 HvShutdownComplete = TRUE; 2176 2177 CmpUnlockRegistry(); 2178 } 2179 2180 VOID 2181 NTAPI 2182 CmpSetVersionData(VOID) 2183 { 2184 NTSTATUS Status; 2185 OBJECT_ATTRIBUTES ObjectAttributes; 2186 UNICODE_STRING KeyName; 2187 UNICODE_STRING ValueName; 2188 UNICODE_STRING ValueData; 2189 ANSI_STRING TempString; 2190 HANDLE SoftwareKeyHandle = NULL; 2191 HANDLE MicrosoftKeyHandle = NULL; 2192 HANDLE WindowsNtKeyHandle = NULL; 2193 HANDLE CurrentVersionKeyHandle = NULL; 2194 WCHAR Buffer[128]; // Buffer large enough to contain a full ULONG in decimal 2195 // representation, and the full 'CurrentType' string. 2196 2197 /* 2198 * Open the 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' key 2199 * (create the intermediate subkeys if needed). 2200 */ 2201 2202 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SOFTWARE"); 2203 InitializeObjectAttributes(&ObjectAttributes, 2204 &KeyName, 2205 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2206 NULL, 2207 NULL); 2208 Status = NtCreateKey(&SoftwareKeyHandle, 2209 KEY_CREATE_SUB_KEY, 2210 &ObjectAttributes, 2211 0, 2212 NULL, 2213 0, 2214 NULL); 2215 if (!NT_SUCCESS(Status)) 2216 { 2217 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2218 return; 2219 } 2220 2221 RtlInitUnicodeString(&KeyName, L"Microsoft"); 2222 InitializeObjectAttributes(&ObjectAttributes, 2223 &KeyName, 2224 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2225 SoftwareKeyHandle, 2226 NULL); 2227 Status = NtCreateKey(&MicrosoftKeyHandle, 2228 KEY_CREATE_SUB_KEY, 2229 &ObjectAttributes, 2230 0, 2231 NULL, 2232 0, 2233 NULL); 2234 if (!NT_SUCCESS(Status)) 2235 { 2236 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2237 goto Quit; 2238 } 2239 2240 RtlInitUnicodeString(&KeyName, L"Windows NT"); 2241 InitializeObjectAttributes(&ObjectAttributes, 2242 &KeyName, 2243 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2244 MicrosoftKeyHandle, 2245 NULL); 2246 Status = NtCreateKey(&WindowsNtKeyHandle, 2247 KEY_CREATE_SUB_KEY, 2248 &ObjectAttributes, 2249 0, 2250 NULL, 2251 0, 2252 NULL); 2253 if (!NT_SUCCESS(Status)) 2254 { 2255 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2256 goto Quit; 2257 } 2258 2259 RtlInitUnicodeString(&KeyName, L"CurrentVersion"); 2260 InitializeObjectAttributes(&ObjectAttributes, 2261 &KeyName, 2262 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2263 WindowsNtKeyHandle, 2264 NULL); 2265 Status = NtCreateKey(&CurrentVersionKeyHandle, 2266 KEY_CREATE_SUB_KEY | KEY_SET_VALUE, 2267 &ObjectAttributes, 2268 0, 2269 NULL, 2270 0, 2271 NULL); 2272 if (!NT_SUCCESS(Status)) 2273 { 2274 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2275 goto Quit; 2276 } 2277 2278 /* Set the 'CurrentVersion' value */ 2279 RtlInitUnicodeString(&ValueName, L"CurrentVersion"); 2280 NtSetValueKey(CurrentVersionKeyHandle, 2281 &ValueName, 2282 0, 2283 REG_SZ, 2284 CmVersionString.Buffer, 2285 CmVersionString.Length + sizeof(WCHAR)); 2286 2287 /* Set the 'CurrentBuildNumber' value */ 2288 RtlInitUnicodeString(&ValueName, L"CurrentBuildNumber"); 2289 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2290 RtlIntegerToUnicodeString(NtBuildNumber & 0xFFFF, 10, &ValueData); 2291 NtSetValueKey(CurrentVersionKeyHandle, 2292 &ValueName, 2293 0, 2294 REG_SZ, 2295 ValueData.Buffer, 2296 ValueData.Length + sizeof(WCHAR)); 2297 2298 /* Set the 'BuildLab' value */ 2299 RtlInitUnicodeString(&ValueName, L"BuildLab"); 2300 RtlInitAnsiString(&TempString, NtBuildLab); 2301 Status = RtlAnsiStringToUnicodeString(&ValueData, &TempString, FALSE); 2302 if (NT_SUCCESS(Status)) 2303 { 2304 NtSetValueKey(CurrentVersionKeyHandle, 2305 &ValueName, 2306 0, 2307 REG_SZ, 2308 ValueData.Buffer, 2309 ValueData.Length + sizeof(WCHAR)); 2310 } 2311 2312 /* Set the 'CurrentType' value */ 2313 RtlInitUnicodeString(&ValueName, L"CurrentType"); 2314 RtlStringCbPrintfW(Buffer, sizeof(Buffer), 2315 L"%s %s", 2316 #ifdef CONFIG_SMP 2317 L"Multiprocessor" 2318 #else 2319 L"Uniprocessor" 2320 #endif 2321 , 2322 #if (DBG == 1) 2323 L"Checked" 2324 #else 2325 L"Free" 2326 #endif 2327 ); 2328 RtlInitUnicodeString(&ValueData, Buffer); 2329 NtSetValueKey(CurrentVersionKeyHandle, 2330 &ValueName, 2331 0, 2332 REG_SZ, 2333 ValueData.Buffer, 2334 ValueData.Length + sizeof(WCHAR)); 2335 2336 /* Set the 'CSDVersion' value */ 2337 RtlInitUnicodeString(&ValueName, L"CSDVersion"); 2338 if (CmCSDVersionString.Length != 0) 2339 { 2340 NtSetValueKey(CurrentVersionKeyHandle, 2341 &ValueName, 2342 0, 2343 REG_SZ, 2344 CmCSDVersionString.Buffer, 2345 CmCSDVersionString.Length + sizeof(WCHAR)); 2346 } 2347 else 2348 { 2349 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2350 } 2351 2352 /* Set the 'CSDBuildNumber' value */ 2353 RtlInitUnicodeString(&ValueName, L"CSDBuildNumber"); 2354 if (CmNtSpBuildNumber != 0) 2355 { 2356 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2357 RtlIntegerToUnicodeString(CmNtSpBuildNumber, 10, &ValueData); 2358 NtSetValueKey(CurrentVersionKeyHandle, 2359 &ValueName, 2360 0, 2361 REG_SZ, 2362 ValueData.Buffer, 2363 ValueData.Length + sizeof(WCHAR)); 2364 } 2365 else 2366 { 2367 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2368 } 2369 2370 /* Set the 'SystemRoot' value */ 2371 RtlInitUnicodeString(&ValueName, L"SystemRoot"); 2372 NtSetValueKey(CurrentVersionKeyHandle, 2373 &ValueName, 2374 0, 2375 REG_SZ, 2376 NtSystemRoot.Buffer, 2377 NtSystemRoot.Length + sizeof(WCHAR)); 2378 2379 Quit: 2380 /* Close the keys */ 2381 if (CurrentVersionKeyHandle != NULL) 2382 NtClose(CurrentVersionKeyHandle); 2383 2384 if (WindowsNtKeyHandle != NULL) 2385 NtClose(WindowsNtKeyHandle); 2386 2387 if (MicrosoftKeyHandle != NULL) 2388 NtClose(MicrosoftKeyHandle); 2389 2390 if (SoftwareKeyHandle != NULL) 2391 NtClose(SoftwareKeyHandle); 2392 } 2393 2394 /* EOF */ 2395