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