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