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