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) ASSERT(FALSE); 1373 1374 /* Set the file size */ 1375 DPRINT("FIXME: Should set file size: %lx\n", Length); 1376 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length)) 1377 { 1378 /* This shouldn't fail */ 1379 //ASSERT(FALSE); 1380 } 1381 1382 /* Another thing we don't support is NTLDR-recovery */ 1383 if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE); 1384 1385 /* Finally, set our allocated hive to the same hive we've had */ 1386 CmpMachineHiveList[i].CmHive2 = CmHive; 1387 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2); 1388 } 1389 } 1390 1391 /* We're done */ 1392 CmpMachineHiveList[i].ThreadFinished = TRUE; 1393 1394 /* Check if we're the last worker */ 1395 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement); 1396 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES) 1397 { 1398 /* Signal the event */ 1399 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE); 1400 } 1401 1402 /* Kill the thread */ 1403 PsTerminateSystemThread(Status); 1404 } 1405 1406 VOID 1407 NTAPI 1408 CmpInitializeHiveList(IN USHORT Flag) 1409 { 1410 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH]; 1411 UNICODE_STRING TempName, FileName, RegName; 1412 HANDLE Thread; 1413 NTSTATUS Status; 1414 ULONG i; 1415 USHORT RegStart; 1416 PSECURITY_DESCRIPTOR SecurityDescriptor; 1417 PAGED_CODE(); 1418 1419 /* Allow writing for now */ 1420 CmpNoWrite = FALSE; 1421 1422 /* Build the file name and registry name strings */ 1423 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer)); 1424 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer)); 1425 1426 /* Now build the system root path */ 1427 CmpGetRegistryPath(ConfigPath); 1428 RtlInitUnicodeString(&TempName, ConfigPath); 1429 RtlAppendUnicodeStringToString(&FileName, &TempName); 1430 1431 /* And build the registry root path */ 1432 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); 1433 RtlAppendUnicodeStringToString(&RegName, &TempName); 1434 RegStart = RegName.Length; 1435 1436 /* Setup the event to synchronize workers */ 1437 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE); 1438 1439 /* Enter special boot condition */ 1440 CmpSpecialBootCondition = TRUE; 1441 1442 /* Create the SD for the root hives */ 1443 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1444 1445 /* Loop every hive we care about */ 1446 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) 1447 { 1448 /* Make sure the list is set up */ 1449 ASSERT(CmpMachineHiveList[i].Name != NULL); 1450 1451 /* Load the hive as volatile, if in LiveCD mode */ 1452 if (CmpShareSystemHives) 1453 CmpMachineHiveList[i].HHiveFlags |= HIVE_VOLATILE; 1454 1455 /* Create a thread to handle this hive */ 1456 Status = PsCreateSystemThread(&Thread, 1457 THREAD_ALL_ACCESS, 1458 NULL, 1459 0, 1460 NULL, 1461 CmpLoadHiveThread, 1462 UlongToPtr(i)); 1463 if (NT_SUCCESS(Status)) 1464 { 1465 /* We don't care about the handle -- the thread self-terminates */ 1466 ZwClose(Thread); 1467 } 1468 else 1469 { 1470 /* Can't imagine this happening */ 1471 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status); 1472 } 1473 } 1474 1475 /* Make sure we've reached the end of the list */ 1476 ASSERT(CmpMachineHiveList[i].Name == NULL); 1477 1478 /* Wait for hive loading to finish */ 1479 KeWaitForSingleObject(&CmpLoadWorkerEvent, 1480 Executive, 1481 KernelMode, 1482 FALSE, 1483 NULL); 1484 1485 /* Exit the special boot condition and make sure all workers completed */ 1486 CmpSpecialBootCondition = FALSE; 1487 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES); 1488 1489 /* Loop hives again */ 1490 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) 1491 { 1492 /* Make sure the thread ran and finished */ 1493 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE); 1494 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE); 1495 1496 /* Check if this was a new hive */ 1497 if (!CmpMachineHiveList[i].CmHive) 1498 { 1499 /* Make sure we allocated something */ 1500 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL); 1501 1502 /* Build the base name */ 1503 RegName.Length = RegStart; 1504 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); 1505 RtlAppendUnicodeStringToString(&RegName, &TempName); 1506 1507 /* Check if this is a child of the root */ 1508 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR) 1509 { 1510 /* Then setup the whole name */ 1511 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); 1512 RtlAppendUnicodeStringToString(&RegName, &TempName); 1513 } 1514 1515 /* Now link the hive to its master */ 1516 Status = CmpLinkHiveToMaster(&RegName, 1517 NULL, 1518 CmpMachineHiveList[i].CmHive2, 1519 CmpMachineHiveList[i].Allocate, 1520 SecurityDescriptor); 1521 if (Status != STATUS_SUCCESS) 1522 { 1523 /* Linking needs to work */ 1524 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName); 1525 } 1526 1527 /* Check if we had to allocate a new hive */ 1528 if (CmpMachineHiveList[i].Allocate) 1529 { 1530 /* Sync the new hive */ 1531 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2)); 1532 } 1533 } 1534 1535 /* Check if we created a new hive */ 1536 if (CmpMachineHiveList[i].CmHive2) 1537 { 1538 /* Add to HiveList key */ 1539 CmpAddToHiveFileList(CmpMachineHiveList[i].CmHive2); 1540 } 1541 } 1542 1543 /* Get rid of the SD */ 1544 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1545 1546 /* Link SECURITY to SAM */ 1547 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM", 1548 L"\\Registry\\Machine\\SAM\\SAM"); 1549 1550 /* Link S-1-5-18 to .Default */ 1551 CmpNoVolatileCreates = FALSE; 1552 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18", 1553 L"\\Registry\\User\\.Default"); 1554 CmpNoVolatileCreates = TRUE; 1555 } 1556 1557 BOOLEAN 1558 NTAPI 1559 INIT_FUNCTION 1560 CmInitSystem1(VOID) 1561 { 1562 OBJECT_ATTRIBUTES ObjectAttributes; 1563 UNICODE_STRING KeyName; 1564 HANDLE KeyHandle; 1565 NTSTATUS Status; 1566 PCMHIVE HardwareHive; 1567 PSECURITY_DESCRIPTOR SecurityDescriptor; 1568 PAGED_CODE(); 1569 1570 /* Check if this is PE-boot */ 1571 if (InitIsWinPEMode) 1572 { 1573 /* Set registry to PE mode */ 1574 CmpMiniNTBoot = TRUE; 1575 CmpShareSystemHives = TRUE; 1576 } 1577 1578 /* Initialize the hive list and lock */ 1579 InitializeListHead(&CmpHiveListHead); 1580 ExInitializePushLock(&CmpHiveListHeadLock); 1581 ExInitializePushLock(&CmpLoadHiveLock); 1582 1583 /* Initialize registry lock */ 1584 ExInitializeResourceLite(&CmpRegistryLock); 1585 1586 /* Initialize the cache */ 1587 CmpInitializeCache(); 1588 1589 /* Initialize allocation and delayed dereferencing */ 1590 CmpInitCmPrivateAlloc(); 1591 CmpInitCmPrivateDelayAlloc(); 1592 CmpInitDelayDerefKCBEngine(); 1593 1594 /* Initialize callbacks */ 1595 CmpInitCallback(); 1596 1597 /* Initialize self healing */ 1598 KeInitializeGuardedMutex(&CmpSelfHealQueueLock); 1599 InitializeListHead(&CmpSelfHealQueueListHead); 1600 1601 /* Save the current process and lock the registry */ 1602 CmpSystemProcess = PsGetCurrentProcess(); 1603 1604 /* Create the key object types */ 1605 Status = CmpCreateObjectTypes(); 1606 if (!NT_SUCCESS(Status)) 1607 { 1608 /* Bugcheck */ 1609 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0); 1610 } 1611 1612 /* Build the master hive */ 1613 Status = CmpInitializeHive(&CmiVolatileHive, 1614 HINIT_CREATE, 1615 HIVE_VOLATILE, 1616 HFILE_TYPE_PRIMARY, 1617 NULL, 1618 NULL, 1619 NULL, 1620 NULL, 1621 NULL, 1622 0); 1623 if (!NT_SUCCESS(Status)) 1624 { 1625 /* Bugcheck */ 1626 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0); 1627 } 1628 1629 /* Create the \REGISTRY key node */ 1630 if (!CmpCreateRegistryRoot()) 1631 { 1632 /* Bugcheck */ 1633 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0); 1634 } 1635 1636 /* Create the default security descriptor */ 1637 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1638 1639 /* Create '\Registry\Machine' key */ 1640 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE"); 1641 InitializeObjectAttributes(&ObjectAttributes, 1642 &KeyName, 1643 OBJ_CASE_INSENSITIVE, 1644 NULL, 1645 SecurityDescriptor); 1646 Status = NtCreateKey(&KeyHandle, 1647 KEY_READ | KEY_WRITE, 1648 &ObjectAttributes, 1649 0, 1650 NULL, 1651 0, 1652 NULL); 1653 if (!NT_SUCCESS(Status)) 1654 { 1655 /* Bugcheck */ 1656 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0); 1657 } 1658 1659 /* Close the handle */ 1660 NtClose(KeyHandle); 1661 1662 /* Create '\Registry\User' key */ 1663 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER"); 1664 InitializeObjectAttributes(&ObjectAttributes, 1665 &KeyName, 1666 OBJ_CASE_INSENSITIVE, 1667 NULL, 1668 SecurityDescriptor); 1669 Status = NtCreateKey(&KeyHandle, 1670 KEY_READ | KEY_WRITE, 1671 &ObjectAttributes, 1672 0, 1673 NULL, 1674 0, 1675 NULL); 1676 if (!NT_SUCCESS(Status)) 1677 { 1678 /* Bugcheck */ 1679 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0); 1680 } 1681 1682 /* Close the handle */ 1683 NtClose(KeyHandle); 1684 1685 /* After this point, do not allow creating keys in the master hive */ 1686 CmpNoVolatileCreates = TRUE; 1687 1688 /* Initialize the system hive */ 1689 if (!CmpInitializeSystemHive(KeLoaderBlock)) 1690 { 1691 /* Bugcheck */ 1692 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0); 1693 } 1694 1695 /* Create the 'CurrentControlSet' link */ 1696 Status = CmpCreateControlSet(KeLoaderBlock); 1697 if (!NT_SUCCESS(Status)) 1698 { 1699 /* Bugcheck */ 1700 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0); 1701 } 1702 1703 /* Create the hardware hive */ 1704 Status = CmpInitializeHive(&HardwareHive, 1705 HINIT_CREATE, 1706 HIVE_VOLATILE, 1707 HFILE_TYPE_PRIMARY, 1708 NULL, 1709 NULL, 1710 NULL, 1711 NULL, 1712 NULL, 1713 0); 1714 if (!NT_SUCCESS(Status)) 1715 { 1716 /* Bugcheck */ 1717 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0); 1718 } 1719 1720 /* Add the hive to the hive list */ 1721 CmpMachineHiveList[0].CmHive = HardwareHive; 1722 1723 /* Attach it to the machine key */ 1724 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE"); 1725 Status = CmpLinkHiveToMaster(&KeyName, 1726 NULL, 1727 HardwareHive, 1728 TRUE, 1729 SecurityDescriptor); 1730 if (!NT_SUCCESS(Status)) 1731 { 1732 /* Bugcheck */ 1733 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0); 1734 } 1735 1736 /* Add to HiveList key */ 1737 CmpAddToHiveFileList(HardwareHive); 1738 1739 /* Free the security descriptor */ 1740 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1741 1742 /* Fill out the Hardware key with the ARC Data from the Loader */ 1743 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock); 1744 if (!NT_SUCCESS(Status)) 1745 { 1746 /* Bugcheck */ 1747 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0); 1748 } 1749 1750 /* Initialize machine-dependent information into the registry */ 1751 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock); 1752 if (!NT_SUCCESS(Status)) 1753 { 1754 /* Bugcheck */ 1755 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0); 1756 } 1757 1758 /* Initialize volatile registry settings */ 1759 Status = CmpSetSystemValues(KeLoaderBlock); 1760 if (!NT_SUCCESS(Status)) 1761 { 1762 /* Bugcheck */ 1763 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0); 1764 } 1765 1766 /* Free the load options */ 1767 ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM); 1768 1769 /* If we got here, all went well */ 1770 return TRUE; 1771 } 1772 1773 VOID 1774 NTAPI 1775 INIT_FUNCTION 1776 CmpFreeDriverList(IN PHHIVE Hive, 1777 IN PLIST_ENTRY DriverList) 1778 { 1779 PLIST_ENTRY NextEntry, OldEntry; 1780 PBOOT_DRIVER_NODE DriverNode; 1781 PAGED_CODE(); 1782 1783 /* Parse the current list */ 1784 NextEntry = DriverList->Flink; 1785 while (NextEntry != DriverList) 1786 { 1787 /* Get the driver node */ 1788 DriverNode = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_NODE, ListEntry.Link); 1789 1790 /* Get the next entry now, since we're going to free it later */ 1791 OldEntry = NextEntry; 1792 NextEntry = NextEntry->Flink; 1793 1794 /* Was there a name? */ 1795 if (DriverNode->Name.Buffer) 1796 { 1797 /* Free it */ 1798 CmpFree(DriverNode->Name.Buffer, DriverNode->Name.Length); 1799 } 1800 1801 /* Was there a registry path? */ 1802 if (DriverNode->ListEntry.RegistryPath.Buffer) 1803 { 1804 /* Free it */ 1805 CmpFree(DriverNode->ListEntry.RegistryPath.Buffer, 1806 DriverNode->ListEntry.RegistryPath.MaximumLength); 1807 } 1808 1809 /* Was there a file path? */ 1810 if (DriverNode->ListEntry.FilePath.Buffer) 1811 { 1812 /* Free it */ 1813 CmpFree(DriverNode->ListEntry.FilePath.Buffer, 1814 DriverNode->ListEntry.FilePath.MaximumLength); 1815 } 1816 1817 /* Now free the node, and move on */ 1818 CmpFree(OldEntry, sizeof(BOOT_DRIVER_NODE)); 1819 } 1820 } 1821 1822 PUNICODE_STRING* 1823 NTAPI 1824 INIT_FUNCTION 1825 CmGetSystemDriverList(VOID) 1826 { 1827 LIST_ENTRY DriverList; 1828 OBJECT_ATTRIBUTES ObjectAttributes; 1829 NTSTATUS Status; 1830 PCM_KEY_BODY KeyBody; 1831 PHHIVE Hive; 1832 HCELL_INDEX RootCell, ControlCell; 1833 HANDLE KeyHandle; 1834 UNICODE_STRING KeyName; 1835 PLIST_ENTRY NextEntry; 1836 ULONG i; 1837 PUNICODE_STRING* ServicePath = NULL; 1838 BOOLEAN Success, AutoSelect; 1839 PBOOT_DRIVER_LIST_ENTRY DriverEntry; 1840 PAGED_CODE(); 1841 1842 /* Initialize the driver list */ 1843 InitializeListHead(&DriverList); 1844 1845 /* Open the system hive key */ 1846 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System"); 1847 InitializeObjectAttributes(&ObjectAttributes, 1848 &KeyName, 1849 OBJ_CASE_INSENSITIVE, 1850 NULL, 1851 NULL); 1852 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 1853 if (!NT_SUCCESS(Status)) return NULL; 1854 1855 /* Reference the key object to get the root hive/cell to access directly */ 1856 Status = ObReferenceObjectByHandle(KeyHandle, 1857 KEY_QUERY_VALUE, 1858 CmpKeyObjectType, 1859 KernelMode, 1860 (PVOID*)&KeyBody, 1861 NULL); 1862 if (!NT_SUCCESS(Status)) 1863 { 1864 /* Fail */ 1865 NtClose(KeyHandle); 1866 return NULL; 1867 } 1868 1869 /* Do all this under the registry lock */ 1870 CmpLockRegistryExclusive(); 1871 1872 /* Get the hive and key cell */ 1873 Hive = KeyBody->KeyControlBlock->KeyHive; 1874 RootCell = KeyBody->KeyControlBlock->KeyCell; 1875 1876 /* Open the current control set key */ 1877 RtlInitUnicodeString(&KeyName, L"Current"); 1878 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect); 1879 if (ControlCell == HCELL_NIL) goto EndPath; 1880 1881 /* Find all system drivers */ 1882 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList); 1883 if (!Success) goto EndPath; 1884 1885 /* Sort by group/tag */ 1886 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath; 1887 1888 /* Remove circular dependencies (cycles) and sort */ 1889 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath; 1890 1891 /* Loop the list to count drivers */ 1892 for (i = 0, NextEntry = DriverList.Flink; 1893 NextEntry != &DriverList; 1894 i++, NextEntry = NextEntry->Flink); 1895 1896 /* Allocate the array */ 1897 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING)); 1898 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1899 1900 /* Loop the driver list */ 1901 for (i = 0, NextEntry = DriverList.Flink; 1902 NextEntry != &DriverList; 1903 i++, NextEntry = NextEntry->Flink) 1904 { 1905 /* Get the entry */ 1906 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link); 1907 1908 /* Allocate the path for the caller */ 1909 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING)); 1910 if (!ServicePath[i]) 1911 { 1912 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1913 } 1914 1915 /* Duplicate the registry path */ 1916 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 1917 &DriverEntry->RegistryPath, 1918 ServicePath[i]); 1919 if (!NT_SUCCESS(Status)) 1920 { 1921 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1922 } 1923 } 1924 1925 /* Terminate the list */ 1926 ServicePath[i] = NULL; 1927 1928 EndPath: 1929 /* Free the driver list if we had one */ 1930 if (!IsListEmpty(&DriverList)) CmpFreeDriverList(Hive, &DriverList); 1931 1932 /* Unlock the registry */ 1933 CmpUnlockRegistry(); 1934 1935 /* Close the key handle and dereference the object, then return the path */ 1936 ObDereferenceObject(KeyBody); 1937 NtClose(KeyHandle); 1938 return ServicePath; 1939 } 1940 1941 VOID 1942 NTAPI 1943 CmpLockRegistryExclusive(VOID) 1944 { 1945 /* Enter a critical region and lock the registry */ 1946 KeEnterCriticalRegion(); 1947 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); 1948 1949 /* Sanity check */ 1950 ASSERT(CmpFlushStarveWriters == 0); 1951 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller); 1952 } 1953 1954 VOID 1955 NTAPI 1956 CmpLockRegistry(VOID) 1957 { 1958 /* Enter a critical region */ 1959 KeEnterCriticalRegion(); 1960 1961 /* Check if we have to starve writers */ 1962 if (CmpFlushStarveWriters) 1963 { 1964 /* Starve exlusive waiters */ 1965 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE); 1966 } 1967 else 1968 { 1969 /* Just grab the lock */ 1970 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE); 1971 } 1972 } 1973 1974 BOOLEAN 1975 NTAPI 1976 CmpTestRegistryLock(VOID) 1977 { 1978 /* Test the lock */ 1979 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE; 1980 } 1981 1982 BOOLEAN 1983 NTAPI 1984 CmpTestRegistryLockExclusive(VOID) 1985 { 1986 /* Test the lock */ 1987 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE; 1988 } 1989 1990 VOID 1991 NTAPI 1992 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive) 1993 { 1994 /* Lock the flusher. We should already be in a critical section */ 1995 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 1996 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 1997 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 1998 ExAcquireResourceExclusiveLite(Hive->FlusherLock, TRUE); 1999 } 2000 2001 VOID 2002 NTAPI 2003 CmpLockHiveFlusherShared(IN PCMHIVE Hive) 2004 { 2005 /* Lock the flusher. We should already be in a critical section */ 2006 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2007 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 2008 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 2009 ExAcquireResourceSharedLite(Hive->FlusherLock, TRUE); 2010 } 2011 2012 VOID 2013 NTAPI 2014 CmpUnlockHiveFlusher(IN PCMHIVE Hive) 2015 { 2016 /* Sanity check */ 2017 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 2018 CMP_ASSERT_FLUSH_LOCK(Hive); 2019 2020 /* Release the lock */ 2021 ExReleaseResourceLite(Hive->FlusherLock); 2022 } 2023 2024 BOOLEAN 2025 NTAPI 2026 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive) 2027 { 2028 /* Test the lock */ 2029 return !ExIsResourceAcquiredSharedLite(Hive->FlusherLock) ? FALSE : TRUE; 2030 } 2031 2032 BOOLEAN 2033 NTAPI 2034 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive) 2035 { 2036 /* Test the lock */ 2037 return !ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) ? FALSE : TRUE; 2038 } 2039 2040 VOID 2041 NTAPI 2042 CmpUnlockRegistry(VOID) 2043 { 2044 /* Sanity check */ 2045 CMP_ASSERT_REGISTRY_LOCK(); 2046 2047 /* Check if we should flush the registry */ 2048 if (CmpFlushOnLockRelease) 2049 { 2050 /* The registry should be exclusively locked for this */ 2051 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK(); 2052 2053 /* Flush the registry */ 2054 CmpDoFlushAll(TRUE); 2055 CmpFlushOnLockRelease = FALSE; 2056 } 2057 else 2058 { 2059 /* Lazy flush the registry */ 2060 CmpLazyFlush(); 2061 } 2062 2063 /* Release the lock and leave the critical region */ 2064 ExReleaseResourceLite(&CmpRegistryLock); 2065 KeLeaveCriticalRegion(); 2066 } 2067 2068 VOID 2069 NTAPI 2070 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1, 2071 IN ULONG ConvKey2) 2072 { 2073 ULONG Index1, Index2; 2074 2075 /* Sanity check */ 2076 CMP_ASSERT_REGISTRY_LOCK(); 2077 2078 /* Get hash indexes */ 2079 Index1 = GET_HASH_INDEX(ConvKey1); 2080 Index2 = GET_HASH_INDEX(ConvKey2); 2081 2082 /* See which one is highest */ 2083 if (Index1 < Index2) 2084 { 2085 /* Grab them in the proper order */ 2086 CmpAcquireKcbLockExclusiveByKey(ConvKey1); 2087 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 2088 } 2089 else 2090 { 2091 /* Grab the second one first, then the first */ 2092 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 2093 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1); 2094 } 2095 } 2096 2097 VOID 2098 NTAPI 2099 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1, 2100 IN ULONG ConvKey2) 2101 { 2102 ULONG Index1, Index2; 2103 2104 /* Sanity check */ 2105 CMP_ASSERT_REGISTRY_LOCK(); 2106 2107 /* Get hash indexes */ 2108 Index1 = GET_HASH_INDEX(ConvKey1); 2109 Index2 = GET_HASH_INDEX(ConvKey2); 2110 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2)->Owner == KeGetCurrentThread()) || 2111 (CmpTestRegistryLockExclusive())); 2112 2113 /* See which one is highest */ 2114 if (Index1 < Index2) 2115 { 2116 /* Grab them in the proper order */ 2117 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2118 (CmpTestRegistryLockExclusive())); 2119 CmpReleaseKcbLockByKey(ConvKey2); 2120 CmpReleaseKcbLockByKey(ConvKey1); 2121 } 2122 else 2123 { 2124 /* Release the first one first, then the second */ 2125 if (Index1 != Index2) 2126 { 2127 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2128 (CmpTestRegistryLockExclusive())); 2129 CmpReleaseKcbLockByKey(ConvKey1); 2130 } 2131 CmpReleaseKcbLockByKey(ConvKey2); 2132 } 2133 } 2134 2135 VOID 2136 NTAPI 2137 CmShutdownSystem(VOID) 2138 { 2139 PLIST_ENTRY ListEntry; 2140 PCMHIVE Hive; 2141 2142 /* Kill the workers */ 2143 if (!CmFirstTime) CmpShutdownWorkers(); 2144 2145 /* Flush all hives */ 2146 CmpLockRegistryExclusive(); 2147 CmpDoFlushAll(TRUE); 2148 2149 /* Close all hive files */ 2150 ListEntry = CmpHiveListHead.Flink; 2151 while (ListEntry != &CmpHiveListHead) 2152 { 2153 Hive = CONTAINING_RECORD(ListEntry, CMHIVE, HiveList); 2154 2155 CmpCloseHiveFiles(Hive); 2156 2157 ListEntry = ListEntry->Flink; 2158 } 2159 2160 CmpUnlockRegistry(); 2161 } 2162 2163 VOID 2164 NTAPI 2165 CmpSetVersionData(VOID) 2166 { 2167 NTSTATUS Status; 2168 OBJECT_ATTRIBUTES ObjectAttributes; 2169 UNICODE_STRING KeyName; 2170 UNICODE_STRING ValueName; 2171 UNICODE_STRING ValueData; 2172 ANSI_STRING TempString; 2173 HANDLE SoftwareKeyHandle = NULL; 2174 HANDLE MicrosoftKeyHandle = NULL; 2175 HANDLE WindowsNtKeyHandle = NULL; 2176 HANDLE CurrentVersionKeyHandle = NULL; 2177 WCHAR Buffer[128]; // Buffer large enough to contain a full ULONG in decimal 2178 // representation, and the full 'CurrentType' string. 2179 2180 /* 2181 * Open the 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' key 2182 * (create the intermediate subkeys if needed). 2183 */ 2184 2185 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SOFTWARE"); 2186 InitializeObjectAttributes(&ObjectAttributes, 2187 &KeyName, 2188 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2189 NULL, 2190 NULL); 2191 Status = NtCreateKey(&SoftwareKeyHandle, 2192 KEY_CREATE_SUB_KEY, 2193 &ObjectAttributes, 2194 0, 2195 NULL, 2196 0, 2197 NULL); 2198 if (!NT_SUCCESS(Status)) 2199 { 2200 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2201 return; 2202 } 2203 2204 RtlInitUnicodeString(&KeyName, L"Microsoft"); 2205 InitializeObjectAttributes(&ObjectAttributes, 2206 &KeyName, 2207 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2208 SoftwareKeyHandle, 2209 NULL); 2210 Status = NtCreateKey(&MicrosoftKeyHandle, 2211 KEY_CREATE_SUB_KEY, 2212 &ObjectAttributes, 2213 0, 2214 NULL, 2215 0, 2216 NULL); 2217 if (!NT_SUCCESS(Status)) 2218 { 2219 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2220 goto Quit; 2221 } 2222 2223 RtlInitUnicodeString(&KeyName, L"Windows NT"); 2224 InitializeObjectAttributes(&ObjectAttributes, 2225 &KeyName, 2226 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2227 MicrosoftKeyHandle, 2228 NULL); 2229 Status = NtCreateKey(&WindowsNtKeyHandle, 2230 KEY_CREATE_SUB_KEY, 2231 &ObjectAttributes, 2232 0, 2233 NULL, 2234 0, 2235 NULL); 2236 if (!NT_SUCCESS(Status)) 2237 { 2238 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2239 goto Quit; 2240 } 2241 2242 RtlInitUnicodeString(&KeyName, L"CurrentVersion"); 2243 InitializeObjectAttributes(&ObjectAttributes, 2244 &KeyName, 2245 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2246 WindowsNtKeyHandle, 2247 NULL); 2248 Status = NtCreateKey(&CurrentVersionKeyHandle, 2249 KEY_CREATE_SUB_KEY | KEY_SET_VALUE, 2250 &ObjectAttributes, 2251 0, 2252 NULL, 2253 0, 2254 NULL); 2255 if (!NT_SUCCESS(Status)) 2256 { 2257 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2258 goto Quit; 2259 } 2260 2261 /* Set the 'CurrentVersion' value */ 2262 RtlInitUnicodeString(&ValueName, L"CurrentVersion"); 2263 NtSetValueKey(CurrentVersionKeyHandle, 2264 &ValueName, 2265 0, 2266 REG_SZ, 2267 CmVersionString.Buffer, 2268 CmVersionString.Length + sizeof(WCHAR)); 2269 2270 /* Set the 'CurrentBuildNumber' value */ 2271 RtlInitUnicodeString(&ValueName, L"CurrentBuildNumber"); 2272 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2273 RtlIntegerToUnicodeString(NtBuildNumber & 0xFFFF, 10, &ValueData); 2274 NtSetValueKey(CurrentVersionKeyHandle, 2275 &ValueName, 2276 0, 2277 REG_SZ, 2278 ValueData.Buffer, 2279 ValueData.Length + sizeof(WCHAR)); 2280 2281 /* Set the 'BuildLab' value */ 2282 RtlInitUnicodeString(&ValueName, L"BuildLab"); 2283 RtlInitAnsiString(&TempString, NtBuildLab); 2284 Status = RtlAnsiStringToUnicodeString(&ValueData, &TempString, FALSE); 2285 if (NT_SUCCESS(Status)) 2286 { 2287 NtSetValueKey(CurrentVersionKeyHandle, 2288 &ValueName, 2289 0, 2290 REG_SZ, 2291 ValueData.Buffer, 2292 ValueData.Length + sizeof(WCHAR)); 2293 } 2294 2295 /* Set the 'CurrentType' value */ 2296 RtlInitUnicodeString(&ValueName, L"CurrentType"); 2297 RtlStringCbPrintfW(Buffer, sizeof(Buffer), 2298 L"%s %s", 2299 #ifdef CONFIG_SMP 2300 L"Multiprocessor" 2301 #else 2302 L"Uniprocessor" 2303 #endif 2304 , 2305 #if (DBG == 1) 2306 L"Checked" 2307 #else 2308 L"Free" 2309 #endif 2310 ); 2311 RtlInitUnicodeString(&ValueData, Buffer); 2312 NtSetValueKey(CurrentVersionKeyHandle, 2313 &ValueName, 2314 0, 2315 REG_SZ, 2316 ValueData.Buffer, 2317 ValueData.Length + sizeof(WCHAR)); 2318 2319 /* Set the 'CSDVersion' value */ 2320 RtlInitUnicodeString(&ValueName, L"CSDVersion"); 2321 if (CmCSDVersionString.Length != 0) 2322 { 2323 NtSetValueKey(CurrentVersionKeyHandle, 2324 &ValueName, 2325 0, 2326 REG_SZ, 2327 CmCSDVersionString.Buffer, 2328 CmCSDVersionString.Length + sizeof(WCHAR)); 2329 } 2330 else 2331 { 2332 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2333 } 2334 2335 /* Set the 'CSDBuildNumber' value */ 2336 RtlInitUnicodeString(&ValueName, L"CSDBuildNumber"); 2337 if (CmNtSpBuildNumber != 0) 2338 { 2339 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2340 RtlIntegerToUnicodeString(CmNtSpBuildNumber, 10, &ValueData); 2341 NtSetValueKey(CurrentVersionKeyHandle, 2342 &ValueName, 2343 0, 2344 REG_SZ, 2345 ValueData.Buffer, 2346 ValueData.Length + sizeof(WCHAR)); 2347 } 2348 else 2349 { 2350 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2351 } 2352 2353 /* Set the 'SystemRoot' value */ 2354 RtlInitUnicodeString(&ValueName, L"SystemRoot"); 2355 NtSetValueKey(CurrentVersionKeyHandle, 2356 &ValueName, 2357 0, 2358 REG_SZ, 2359 NtSystemRoot.Buffer, 2360 NtSystemRoot.Length + sizeof(WCHAR)); 2361 2362 Quit: 2363 /* Close the keys */ 2364 if (CurrentVersionKeyHandle != NULL) 2365 NtClose(CurrentVersionKeyHandle); 2366 2367 if (WindowsNtKeyHandle != NULL) 2368 NtClose(WindowsNtKeyHandle); 2369 2370 if (MicrosoftKeyHandle != NULL) 2371 NtClose(MicrosoftKeyHandle); 2372 2373 if (SoftwareKeyHandle != NULL) 2374 NtClose(SoftwareKeyHandle); 2375 } 2376 2377 /* EOF */ 2378