1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * PURPOSE: Configuration Manager - System Initialization Code 5 * PROGRAMMERS: ReactOS Portable Systems Group 6 * Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "ntoskrnl.h" 12 #define NDEBUG 13 #include "debug.h" 14 15 POBJECT_TYPE CmpKeyObjectType; 16 PCMHIVE CmiVolatileHive; 17 LIST_ENTRY CmpHiveListHead; 18 ERESOURCE CmpRegistryLock; 19 KGUARDED_MUTEX CmpSelfHealQueueLock; 20 LIST_ENTRY CmpSelfHealQueueListHead; 21 KEVENT CmpLoadWorkerEvent; 22 LONG CmpLoadWorkerIncrement; 23 PEPROCESS CmpSystemProcess; 24 PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller; 25 BOOLEAN CmpFlushOnLockRelease; 26 BOOLEAN CmpSpecialBootCondition; 27 BOOLEAN CmpNoWrite; 28 BOOLEAN CmpWasSetupBoot; 29 BOOLEAN CmpProfileLoaded; 30 BOOLEAN CmpNoVolatileCreates; 31 ULONG CmpTraceLevel = 0; 32 BOOLEAN HvShutdownComplete = FALSE; 33 34 extern LONG CmpFlushStarveWriters; 35 extern BOOLEAN CmFirstTime; 36 37 /* FUNCTIONS ******************************************************************/ 38 39 BOOLEAN 40 NTAPI 41 CmpLinkKeyToHive( 42 _In_z_ PCWSTR LinkKeyName, 43 _In_z_ PCWSTR TargetKeyName) 44 { 45 NTSTATUS Status; 46 OBJECT_ATTRIBUTES ObjectAttributes; 47 UNICODE_STRING KeyName; 48 HANDLE LinkKeyHandle; 49 ULONG Disposition; 50 51 PAGED_CODE(); 52 53 /* Initialize the object attributes */ 54 RtlInitUnicodeString(&KeyName, LinkKeyName); 55 InitializeObjectAttributes(&ObjectAttributes, 56 &KeyName, 57 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 58 NULL, 59 NULL); 60 61 /* Create the link key */ 62 Status = ZwCreateKey(&LinkKeyHandle, 63 KEY_CREATE_LINK, 64 &ObjectAttributes, 65 0, 66 NULL, 67 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, 68 &Disposition); 69 if (!NT_SUCCESS(Status)) 70 { 71 DPRINT1("CM: CmpLinkKeyToHive: couldn't create %S, Status = 0x%lx\n", 72 LinkKeyName, Status); 73 return FALSE; 74 } 75 76 /* Check if the new key was actually created */ 77 if (Disposition != REG_CREATED_NEW_KEY) 78 { 79 DPRINT1("CM: CmpLinkKeyToHive: %S already exists!\n", LinkKeyName); 80 ZwClose(LinkKeyHandle); 81 return FALSE; 82 } 83 84 /* Set the target key name as link target */ 85 RtlInitUnicodeString(&KeyName, TargetKeyName); 86 Status = ZwSetValueKey(LinkKeyHandle, 87 &CmSymbolicLinkValueName, 88 0, 89 REG_LINK, 90 KeyName.Buffer, 91 KeyName.Length); 92 93 /* Close the link key handle */ 94 ObCloseHandle(LinkKeyHandle, KernelMode); 95 96 if (!NT_SUCCESS(Status)) 97 { 98 DPRINT1("CM: CmpLinkKeyToHive: couldn't create symbolic link for %S, Status = 0x%lx\n", 99 TargetKeyName, Status); 100 return FALSE; 101 } 102 103 return TRUE; 104 } 105 106 VOID 107 NTAPI 108 CmpDeleteKeyObject(PVOID DeletedObject) 109 { 110 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)DeletedObject; 111 PCM_KEY_CONTROL_BLOCK Kcb; 112 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo; 113 REG_POST_OPERATION_INFORMATION PostOperationInfo; 114 NTSTATUS Status; 115 PAGED_CODE(); 116 117 /* First off, prepare the handle close information callback */ 118 PostOperationInfo.Object = KeyBody; 119 KeyHandleCloseInfo.Object = KeyBody; 120 Status = CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose, 121 &KeyHandleCloseInfo); 122 if (!NT_SUCCESS(Status)) 123 { 124 /* If we failed, notify the post routine */ 125 PostOperationInfo.Status = Status; 126 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo); 127 return; 128 } 129 130 /* Acquire hive lock */ 131 CmpLockRegistry(); 132 133 /* Make sure this is a valid key body */ 134 if (KeyBody->Type == CM_KEY_BODY_TYPE) 135 { 136 /* Get the KCB */ 137 Kcb = KeyBody->KeyControlBlock; 138 if (Kcb) 139 { 140 /* Delist the key */ 141 DelistKeyBodyFromKCB(KeyBody, KeyBody->KcbLocked); 142 143 /* Dereference the KCB */ 144 CmpDelayDerefKeyControlBlock(Kcb); 145 } 146 } 147 148 /* Release the registry lock */ 149 CmpUnlockRegistry(); 150 151 /* Do the post callback */ 152 PostOperationInfo.Status = STATUS_SUCCESS; 153 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo); 154 } 155 156 VOID 157 NTAPI 158 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL, 159 IN PVOID Object, 160 IN ACCESS_MASK GrantedAccess, 161 IN ULONG ProcessHandleCount, 162 IN ULONG SystemHandleCount) 163 { 164 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)Object; 165 PAGED_CODE(); 166 167 /* Don't do anything if we're not the last handle */ 168 if (SystemHandleCount > 1) return; 169 170 /* Make sure we're a valid key body */ 171 if (KeyBody->Type == CM_KEY_BODY_TYPE) 172 { 173 /* Don't do anything if we don't have a notify block */ 174 if (!KeyBody->NotifyBlock) return; 175 176 /* This shouldn't happen yet */ 177 ASSERT(FALSE); 178 } 179 } 180 181 NTSTATUS 182 NTAPI 183 CmpQueryKeyName(IN PVOID ObjectBody, 184 IN BOOLEAN HasName, 185 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo, 186 IN ULONG Length, 187 OUT PULONG ReturnLength, 188 IN KPROCESSOR_MODE PreviousMode) 189 { 190 PUNICODE_STRING KeyName; 191 ULONG BytesToCopy; 192 NTSTATUS Status = STATUS_SUCCESS; 193 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)ObjectBody; 194 PCM_KEY_CONTROL_BLOCK Kcb = KeyBody->KeyControlBlock; 195 196 /* Acquire hive lock */ 197 CmpLockRegistry(); 198 199 /* Lock KCB shared */ 200 CmpAcquireKcbLockShared(Kcb); 201 202 /* Check if it's a deleted block */ 203 if (Kcb->Delete) 204 { 205 /* Release the locks */ 206 CmpReleaseKcbLock(Kcb); 207 CmpUnlockRegistry(); 208 209 /* Let the caller know it's deleted */ 210 return STATUS_KEY_DELETED; 211 } 212 213 /* Get the name */ 214 KeyName = CmpConstructName(Kcb); 215 216 /* Release the locks */ 217 CmpReleaseKcbLock(Kcb); 218 CmpUnlockRegistry(); 219 220 /* Check if we got the name */ 221 if (!KeyName) return STATUS_INSUFFICIENT_RESOURCES; 222 223 /* Set the returned length */ 224 *ReturnLength = KeyName->Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR); 225 226 /* Calculate amount of bytes to copy into the buffer */ 227 BytesToCopy = KeyName->Length + sizeof(WCHAR); 228 229 /* Check if the provided buffer is too small to fit even anything */ 230 if ((Length <= sizeof(OBJECT_NAME_INFORMATION)) || 231 ((Length < (*ReturnLength)) && (BytesToCopy < sizeof(WCHAR)))) 232 { 233 /* Free the buffer allocated by CmpConstructName */ 234 ExFreePoolWithTag(KeyName, TAG_CM); 235 236 /* Return buffer length failure without writing anything there because nothing fits */ 237 return STATUS_INFO_LENGTH_MISMATCH; 238 } 239 240 /* Check if the provided buffer can be partially written */ 241 if (Length < (*ReturnLength)) 242 { 243 /* Yes, indicate so in the return status */ 244 Status = STATUS_INFO_LENGTH_MISMATCH; 245 246 /* Calculate amount of bytes which the provided buffer could handle */ 247 BytesToCopy = Length - sizeof(OBJECT_NAME_INFORMATION); 248 } 249 250 /* Remove the null termination character from the size */ 251 BytesToCopy -= sizeof(WCHAR); 252 253 /* Fill in the result */ 254 _SEH2_TRY 255 { 256 /* Return data to user */ 257 ObjectNameInfo->Name.Buffer = (PWCHAR)(ObjectNameInfo + 1); 258 ObjectNameInfo->Name.MaximumLength = KeyName->Length; 259 ObjectNameInfo->Name.Length = KeyName->Length; 260 261 /* Copy string content*/ 262 RtlCopyMemory(ObjectNameInfo->Name.Buffer, 263 KeyName->Buffer, 264 BytesToCopy); 265 266 /* Null terminate it */ 267 ObjectNameInfo->Name.Buffer[BytesToCopy / sizeof(WCHAR)] = UNICODE_NULL; 268 } 269 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 270 { 271 /* Get the status */ 272 Status = _SEH2_GetExceptionCode(); 273 } 274 _SEH2_END; 275 276 /* Free the buffer allocated by CmpConstructName */ 277 ExFreePoolWithTag(KeyName, TAG_CM); 278 279 /* Return status */ 280 return Status; 281 } 282 283 NTSTATUS 284 NTAPI 285 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName, 286 IN ULONG HiveFlags, 287 OUT PCMHIVE *Hive, 288 IN OUT PBOOLEAN New, 289 IN ULONG CheckFlags) 290 { 291 ULONG HiveDisposition, LogDisposition; 292 HANDLE FileHandle = NULL, LogHandle = NULL; 293 NTSTATUS Status; 294 ULONG Operation, FileType; 295 PCMHIVE NewHive; 296 PAGED_CODE(); 297 298 /* Assume failure */ 299 *Hive = NULL; 300 301 /* Open or create the hive files */ 302 Status = CmpOpenHiveFiles(HiveName, 303 L".LOG", 304 &FileHandle, 305 &LogHandle, 306 &HiveDisposition, 307 &LogDisposition, 308 *New, 309 FALSE, 310 TRUE, 311 NULL); 312 if (!NT_SUCCESS(Status)) return Status; 313 314 /* Check if we have a log handle */ 315 FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY; 316 317 /* Check if we created or opened the hive */ 318 if (HiveDisposition == FILE_CREATED) 319 { 320 /* Do a create operation */ 321 Operation = HINIT_CREATE; 322 *New = TRUE; 323 } 324 else 325 { 326 /* Open it as a file */ 327 Operation = HINIT_FILE; 328 *New = FALSE; 329 } 330 331 /* Check if we're sharing hives */ 332 if (CmpShareSystemHives) 333 { 334 /* Then force using the primary hive */ 335 FileType = HFILE_TYPE_PRIMARY; 336 if (LogHandle) 337 { 338 /* Get rid of the log handle */ 339 ZwClose(LogHandle); 340 LogHandle = NULL; 341 } 342 } 343 344 /* Check if we're too late */ 345 if (HvShutdownComplete) 346 { 347 /* Fail */ 348 ZwClose(FileHandle); 349 if (LogHandle) ZwClose(LogHandle); 350 return STATUS_TOO_LATE; 351 } 352 353 /* Initialize the hive */ 354 Status = CmpInitializeHive(&NewHive, 355 Operation, 356 HiveFlags, 357 FileType, 358 NULL, 359 FileHandle, 360 LogHandle, 361 NULL, 362 HiveName, 363 CheckFlags); 364 if (!NT_SUCCESS(Status)) 365 { 366 /* Fail */ 367 ZwClose(FileHandle); 368 if (LogHandle) ZwClose(LogHandle); 369 return Status; 370 } 371 372 /* Success, return hive */ 373 *Hive = NewHive; 374 375 /* Duplicate the hive name */ 376 NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool, 377 HiveName->Length, 378 TAG_CM); 379 if (NewHive->FileFullPath.Buffer) 380 { 381 /* Copy the string */ 382 RtlCopyMemory(NewHive->FileFullPath.Buffer, 383 HiveName->Buffer, 384 HiveName->Length); 385 NewHive->FileFullPath.Length = HiveName->Length; 386 NewHive->FileFullPath.MaximumLength = HiveName->Length; 387 } 388 389 /* Return success */ 390 return STATUS_SUCCESS; 391 } 392 393 CODE_SEG("INIT") 394 NTSTATUS 395 NTAPI 396 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 397 { 398 NTSTATUS Status; 399 OBJECT_ATTRIBUTES ObjectAttributes; 400 HANDLE KeyHandle; 401 UNICODE_STRING KeyName, ValueName = { 0, 0, NULL }; 402 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)) 416 return Status; 417 418 /* Setup the value for the system start options */ 419 RtlInitUnicodeString(&KeyName, L"SystemStartOptions"); 420 Status = NtSetValueKey(KeyHandle, 421 &KeyName, 422 0, 423 REG_SZ, 424 CmpLoadOptions.Buffer, 425 CmpLoadOptions.Length); 426 if (!NT_SUCCESS(Status)) 427 goto Quit; 428 429 /* Setup the value for the system boot device in ARC format */ 430 RtlInitUnicodeString(&KeyName, L"SystemBootDevice"); 431 RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->ArcBootDeviceName); 432 Status = NtSetValueKey(KeyHandle, 433 &KeyName, 434 0, 435 REG_SZ, 436 ValueName.Buffer, 437 ValueName.Length); 438 439 /* Free the temporary string */ 440 RtlFreeUnicodeString(&ValueName); 441 442 Quit: 443 /* Close the key and return */ 444 NtClose(KeyHandle); 445 return Status; 446 } 447 448 static 449 CODE_SEG("INIT") 450 NTSTATUS 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 CODE_SEG("INIT") 521 NTSTATUS 522 NTAPI 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 CODE_SEG("INIT") 862 BOOLEAN 863 NTAPI 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 876 PAGED_CODE(); 877 878 /* Setup the ansi string */ 879 RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions); 880 881 /* Allocate the unicode buffer */ 882 Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL); 883 Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM); 884 if (!Buffer) 885 { 886 /* Fail */ 887 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0); 888 } 889 890 /* Setup the unicode string */ 891 RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length); 892 893 /* Add the load options and null-terminate */ 894 Status = RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE); 895 if (!NT_SUCCESS(Status)) 896 { 897 return FALSE; 898 } 899 900 CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL; 901 CmpLoadOptions.Length += sizeof(WCHAR); 902 903 /* Get the System Hive base address */ 904 HiveBase = LoaderBlock->RegistryBase; 905 906 Status = CmpInitializeHive(&SystemHive, 907 HiveBase ? HINIT_MEMORY : HINIT_CREATE, 908 HIVE_NOLAZYFLUSH, 909 HFILE_TYPE_LOG, 910 HiveBase, 911 NULL, 912 NULL, 913 NULL, 914 &HiveName, 915 HiveBase ? CM_CHECK_REGISTRY_PURGE_VOLATILES : CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 916 if (!NT_SUCCESS(Status)) 917 { 918 return FALSE; 919 } 920 921 /* Set the hive filename */ 922 if (!RtlCreateUnicodeString(&SystemHive->FileFullPath, L"\\SystemRoot\\System32\\Config\\SYSTEM")) 923 return FALSE; 924 925 /* Manually set the hive as volatile, if in Live CD mode */ 926 if (HiveBase && CmpShareSystemHives) 927 { 928 SystemHive->Hive.HiveFlags = HIVE_VOLATILE; 929 } 930 931 /* Save the boot type */ 932 CmpBootType = SystemHive->Hive.BaseBlock->BootType; 933 934 /* Are we in self-healing mode? */ 935 if (!CmSelfHeal) 936 { 937 /* Disable self-healing internally and check if boot type wanted it */ 938 CmpSelfHeal = FALSE; 939 if (CmpBootType & HBOOT_TYPE_SELF_HEAL) 940 { 941 /* We're disabled, so bugcheck */ 942 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 943 3, 944 3, 945 (ULONG_PTR)SystemHive, 946 0); 947 } 948 } 949 950 /* Create the default security descriptor */ 951 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 952 953 /* Attach it to the system key */ 954 /* Let CmpLinkHiveToMaster allocate a new hive if we got none from the LoaderBlock. */ 955 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM"); 956 Status = CmpLinkHiveToMaster(&KeyName, 957 NULL, 958 SystemHive, 959 !HiveBase, 960 SecurityDescriptor); 961 962 /* Free the security descriptor */ 963 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 964 if (!NT_SUCCESS(Status)) return FALSE; 965 966 /* Add the hive to the hive list */ 967 CmpMachineHiveList[3].CmHive = SystemHive; 968 969 /* Success! */ 970 return TRUE; 971 } 972 973 CODE_SEG("INIT") 974 NTSTATUS 975 NTAPI 976 CmpCreateObjectTypes(VOID) 977 { 978 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 979 UNICODE_STRING Name; 980 GENERIC_MAPPING CmpKeyMapping = {KEY_READ, 981 KEY_WRITE, 982 KEY_EXECUTE, 983 KEY_ALL_ACCESS}; 984 PAGED_CODE(); 985 986 /* Initialize the Key object type */ 987 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 988 RtlInitUnicodeString(&Name, L"Key"); 989 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 990 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY); 991 ObjectTypeInitializer.GenericMapping = CmpKeyMapping; 992 ObjectTypeInitializer.PoolType = PagedPool; 993 ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS; 994 ObjectTypeInitializer.UseDefaultObject = TRUE; 995 ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject; 996 ObjectTypeInitializer.ParseProcedure = CmpParseKey; 997 ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod; 998 ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName; 999 ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject; 1000 ObjectTypeInitializer.SecurityRequired = TRUE; 1001 ObjectTypeInitializer.InvalidAttributes = OBJ_EXCLUSIVE | OBJ_PERMANENT; 1002 1003 /* Create it */ 1004 return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType); 1005 } 1006 1007 CODE_SEG("INIT") 1008 BOOLEAN 1009 NTAPI 1010 CmpCreateRootNode(IN PHHIVE Hive, 1011 IN PCWSTR Name, 1012 OUT PHCELL_INDEX Index) 1013 { 1014 UNICODE_STRING KeyName; 1015 PCM_KEY_NODE KeyCell; 1016 PAGED_CODE(); 1017 1018 /* Initialize the node name and allocate it */ 1019 RtlInitUnicodeString(&KeyName, Name); 1020 *Index = HvAllocateCell(Hive, 1021 FIELD_OFFSET(CM_KEY_NODE, Name) + 1022 CmpNameSize(Hive, &KeyName), 1023 Stable, 1024 HCELL_NIL); 1025 if (*Index == HCELL_NIL) return FALSE; 1026 1027 /* Set the cell index and get the data */ 1028 Hive->BaseBlock->RootCell = *Index; 1029 KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index); 1030 if (!KeyCell) return FALSE; 1031 1032 /* Setup the cell */ 1033 KeyCell->Signature = CM_KEY_NODE_SIGNATURE; 1034 KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE; 1035 KeQuerySystemTime(&KeyCell->LastWriteTime); 1036 KeyCell->Parent = HCELL_NIL; 1037 KeyCell->SubKeyCounts[Stable] = 0; 1038 KeyCell->SubKeyCounts[Volatile] = 0; 1039 KeyCell->SubKeyLists[Stable] = HCELL_NIL; 1040 KeyCell->SubKeyLists[Volatile] = HCELL_NIL; 1041 KeyCell->ValueList.Count = 0; 1042 KeyCell->ValueList.List = HCELL_NIL; 1043 KeyCell->Security = HCELL_NIL; 1044 KeyCell->Class = HCELL_NIL; 1045 KeyCell->ClassLength = 0; 1046 KeyCell->MaxNameLen = 0; 1047 KeyCell->MaxClassLen = 0; 1048 KeyCell->MaxValueNameLen = 0; 1049 KeyCell->MaxValueDataLen = 0; 1050 1051 /* Copy the name (this will also set the length) */ 1052 KeyCell->NameLength = CmpCopyName(Hive, KeyCell->Name, &KeyName); 1053 1054 /* Check if the name was compressed and set the flag if so */ 1055 if (KeyCell->NameLength < KeyName.Length) 1056 KeyCell->Flags |= KEY_COMP_NAME; 1057 1058 /* Return success */ 1059 HvReleaseCell(Hive, *Index); 1060 return TRUE; 1061 } 1062 1063 CODE_SEG("INIT") 1064 BOOLEAN 1065 NTAPI 1066 CmpCreateRegistryRoot(VOID) 1067 { 1068 UNICODE_STRING KeyName; 1069 OBJECT_ATTRIBUTES ObjectAttributes; 1070 PCM_KEY_BODY RootKey; 1071 HCELL_INDEX RootIndex; 1072 NTSTATUS Status; 1073 PCM_KEY_NODE KeyCell; 1074 PSECURITY_DESCRIPTOR SecurityDescriptor; 1075 PCM_KEY_CONTROL_BLOCK Kcb; 1076 PAGED_CODE(); 1077 1078 /* Setup the root node */ 1079 if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex)) 1080 { 1081 /* We failed */ 1082 return FALSE; 1083 } 1084 1085 /* Create '\Registry' key. */ 1086 RtlInitUnicodeString(&KeyName, L"\\REGISTRY"); 1087 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1088 InitializeObjectAttributes(&ObjectAttributes, 1089 &KeyName, 1090 OBJ_CASE_INSENSITIVE, 1091 NULL, 1092 SecurityDescriptor); 1093 Status = ObCreateObject(KernelMode, 1094 CmpKeyObjectType, 1095 &ObjectAttributes, 1096 KernelMode, 1097 NULL, 1098 sizeof(CM_KEY_BODY), 1099 0, 1100 0, 1101 (PVOID*)&RootKey); 1102 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1103 if (!NT_SUCCESS(Status)) return FALSE; 1104 1105 /* Sanity check, and get the key cell */ 1106 ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL); 1107 KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex); 1108 if (!KeyCell) return FALSE; 1109 1110 /* Create the KCB */ 1111 RtlInitUnicodeString(&KeyName, L"\\REGISTRY"); 1112 Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive, 1113 RootIndex, 1114 KeyCell, 1115 NULL, 1116 0, 1117 &KeyName); 1118 if (!Kcb) 1119 { 1120 ObDereferenceObject(RootKey); 1121 return FALSE; 1122 } 1123 1124 /* Initialize the object */ 1125 RootKey->KeyControlBlock = Kcb; 1126 RootKey->Type = CM_KEY_BODY_TYPE; 1127 RootKey->NotifyBlock = NULL; 1128 RootKey->ProcessID = PsGetCurrentProcessId(); 1129 RootKey->KcbLocked = FALSE; 1130 1131 /* Link with KCB */ 1132 EnlistKeyBodyWithKCB(RootKey, 0); 1133 1134 /* Insert the key into the namespace */ 1135 Status = ObInsertObject(RootKey, 1136 NULL, 1137 KEY_ALL_ACCESS, 1138 0, 1139 NULL, 1140 &CmpRegistryRootHandle); 1141 if (!NT_SUCCESS(Status)) 1142 { 1143 ObDereferenceObject(RootKey); 1144 return FALSE; 1145 } 1146 1147 /* Reference the key again so that we never lose it */ 1148 Status = ObReferenceObjectByHandle(CmpRegistryRootHandle, 1149 KEY_READ, 1150 NULL, 1151 KernelMode, 1152 (PVOID*)&RootKey, 1153 NULL); 1154 if (!NT_SUCCESS(Status)) 1155 { 1156 ObDereferenceObject(RootKey); 1157 return FALSE; 1158 } 1159 1160 /* Completely sucessful */ 1161 return TRUE; 1162 } 1163 1164 static PCWSTR 1165 CmpGetRegistryPath(VOID) 1166 { 1167 PCWSTR ConfigPath; 1168 1169 /* Check if we are booted in setup */ 1170 if (!ExpInTextModeSetup) 1171 { 1172 ConfigPath = L"\\SystemRoot\\System32\\Config\\"; 1173 } 1174 else 1175 { 1176 ConfigPath = L"\\SystemRoot\\"; 1177 } 1178 1179 DPRINT1("CmpGetRegistryPath: ConfigPath = '%S'\n", ConfigPath); 1180 1181 return ConfigPath; 1182 } 1183 1184 _Function_class_(KSTART_ROUTINE) 1185 VOID 1186 NTAPI 1187 CmpLoadHiveThread(IN PVOID StartContext) 1188 { 1189 WCHAR FileBuffer[64], RegBuffer[64]; 1190 PCWSTR ConfigPath; 1191 UNICODE_STRING TempName, FileName, RegName; 1192 ULONG i, ErrorResponse, WorkerCount, Length; 1193 USHORT FileStart; 1194 ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize; 1195 PCMHIVE CmHive; 1196 HANDLE PrimaryHandle = NULL, LogHandle = NULL; 1197 NTSTATUS Status = STATUS_SUCCESS; 1198 PVOID ErrorParameters; 1199 PAGED_CODE(); 1200 1201 /* Get the hive index, make sure it makes sense */ 1202 i = PtrToUlong(StartContext); 1203 ASSERT(CmpMachineHiveList[i].Name != NULL); 1204 1205 /* We were started */ 1206 CmpMachineHiveList[i].ThreadStarted = TRUE; 1207 1208 /* Build the file name and registry name strings */ 1209 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer)); 1210 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer)); 1211 1212 /* Now build the system root path */ 1213 ConfigPath = CmpGetRegistryPath(); 1214 RtlInitUnicodeString(&TempName, ConfigPath); 1215 RtlAppendUnicodeStringToString(&FileName, &TempName); 1216 FileStart = FileName.Length; 1217 1218 /* And build the registry root path */ 1219 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); 1220 RtlAppendUnicodeStringToString(&RegName, &TempName); 1221 1222 /* Build the base name */ 1223 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); 1224 RtlAppendUnicodeStringToString(&RegName, &TempName); 1225 1226 /* Check if this is a child of the root */ 1227 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR) 1228 { 1229 /* Then setup the whole name */ 1230 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); 1231 RtlAppendUnicodeStringToString(&RegName, &TempName); 1232 } 1233 1234 /* Now add the rest of the file name */ 1235 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); 1236 FileName.Length = FileStart; 1237 RtlAppendUnicodeStringToString(&FileName, &TempName); 1238 if (!CmpMachineHiveList[i].CmHive) 1239 { 1240 /* We need to allocate a new hive structure */ 1241 CmpMachineHiveList[i].Allocate = TRUE; 1242 1243 /* Load the hive file */ 1244 Status = CmpInitHiveFromFile(&FileName, 1245 CmpMachineHiveList[i].HHiveFlags, 1246 &CmHive, 1247 &CmpMachineHiveList[i].Allocate, 1248 CM_CHECK_REGISTRY_PURGE_VOLATILES); 1249 if (!(NT_SUCCESS(Status)) || 1250 (!(CmpShareSystemHives) && !(CmHive->FileHandles[HFILE_TYPE_LOG]))) 1251 { 1252 /* 1253 * We failed, or could not get a log file (unless 1254 * the hive is shared), raise a hard error. 1255 */ 1256 ErrorParameters = &FileName; 1257 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE, 1258 1, 1259 1, 1260 (PULONG_PTR)&ErrorParameters, 1261 OptionOk, 1262 &ErrorResponse); 1263 } 1264 1265 /* Set the hive flags and newly allocated hive pointer */ 1266 CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags; 1267 CmpMachineHiveList[i].CmHive2 = CmHive; 1268 } 1269 else 1270 { 1271 /* We already have a hive, is it volatile? */ 1272 CmHive = CmpMachineHiveList[i].CmHive; 1273 if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) 1274 { 1275 /* It's now, open the hive file and log */ 1276 Status = CmpOpenHiveFiles(&FileName, 1277 L".LOG", 1278 &PrimaryHandle, 1279 &LogHandle, 1280 &PrimaryDisposition, 1281 &SecondaryDisposition, 1282 TRUE, 1283 TRUE, 1284 FALSE, 1285 &ClusterSize); 1286 if (!(NT_SUCCESS(Status)) || !(LogHandle)) 1287 { 1288 /* Couldn't open the hive or its log file, raise a hard error */ 1289 ErrorParameters = &FileName; 1290 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE, 1291 1, 1292 1, 1293 (PULONG_PTR)&ErrorParameters, 1294 OptionOk, 1295 &ErrorResponse); 1296 1297 /* And bugcheck for posterity's sake */ 1298 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status); 1299 } 1300 1301 /* Save the file handles. This should remove our sync hacks */ 1302 CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle; 1303 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle; 1304 1305 /* Allow lazy flushing since the handles are there -- remove sync hacks */ 1306 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH); 1307 CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH; 1308 1309 /* Get the real size of the hive */ 1310 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE; 1311 1312 /* Check if the cluster size doesn't match */ 1313 if (CmHive->Hive.Cluster != ClusterSize) 1314 { 1315 DPRINT1("FIXME: Support for CmHive->Hive.Cluster (%lu) != ClusterSize (%lu) is unimplemented!\n", 1316 CmHive->Hive.Cluster, ClusterSize); 1317 } 1318 1319 /* Set the file size */ 1320 DPRINT("FIXME: Should set file size: %lu\n", Length); 1321 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length)) 1322 //{ 1323 /* This shouldn't fail */ 1324 //ASSERT(FALSE); 1325 //} 1326 1327 /* Another thing we don't support is NTLDR-recovery */ 1328 if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE); 1329 1330 /* Finally, set our allocated hive to the same hive we've had */ 1331 CmpMachineHiveList[i].CmHive2 = CmHive; 1332 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2); 1333 } 1334 } 1335 1336 /* We're done */ 1337 CmpMachineHiveList[i].ThreadFinished = TRUE; 1338 1339 /* Check if we're the last worker */ 1340 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement); 1341 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES) 1342 { 1343 /* Signal the event */ 1344 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE); 1345 } 1346 1347 /* Kill the thread */ 1348 PsTerminateSystemThread(Status); 1349 } 1350 1351 VOID 1352 NTAPI 1353 CmpInitializeHiveList(VOID) 1354 { 1355 WCHAR FileBuffer[64], RegBuffer[64]; 1356 PCWSTR ConfigPath; 1357 UNICODE_STRING TempName, FileName, RegName; 1358 HANDLE Thread; 1359 NTSTATUS Status; 1360 ULONG i; 1361 USHORT RegStart; 1362 PSECURITY_DESCRIPTOR SecurityDescriptor; 1363 PAGED_CODE(); 1364 1365 /* Allow writing for now */ 1366 CmpNoWrite = FALSE; 1367 1368 /* Build the file name and registry name strings */ 1369 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer)); 1370 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer)); 1371 1372 /* Now build the system root path */ 1373 ConfigPath = CmpGetRegistryPath(); 1374 RtlInitUnicodeString(&TempName, ConfigPath); 1375 RtlAppendUnicodeStringToString(&FileName, &TempName); 1376 1377 /* And build the registry root path */ 1378 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\"); 1379 RtlAppendUnicodeStringToString(&RegName, &TempName); 1380 RegStart = RegName.Length; 1381 1382 /* Setup the event to synchronize workers */ 1383 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE); 1384 1385 /* Enter special boot condition */ 1386 CmpSpecialBootCondition = TRUE; 1387 1388 /* Create the SD for the root hives */ 1389 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1390 1391 /* Loop every hive we care about */ 1392 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) 1393 { 1394 /* Make sure the list is set up */ 1395 ASSERT(CmpMachineHiveList[i].Name != NULL); 1396 1397 /* Load the hive as volatile, if in LiveCD mode */ 1398 if (CmpShareSystemHives) 1399 CmpMachineHiveList[i].HHiveFlags |= HIVE_VOLATILE; 1400 1401 /* Create a thread to handle this hive */ 1402 Status = PsCreateSystemThread(&Thread, 1403 THREAD_ALL_ACCESS, 1404 NULL, 1405 0, 1406 NULL, 1407 CmpLoadHiveThread, 1408 UlongToPtr(i)); 1409 if (NT_SUCCESS(Status)) 1410 { 1411 /* We don't care about the handle -- the thread self-terminates */ 1412 ZwClose(Thread); 1413 } 1414 else 1415 { 1416 /* Can't imagine this happening */ 1417 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status); 1418 } 1419 } 1420 1421 /* Make sure we've reached the end of the list */ 1422 ASSERT(CmpMachineHiveList[i].Name == NULL); 1423 1424 /* Wait for hive loading to finish */ 1425 KeWaitForSingleObject(&CmpLoadWorkerEvent, 1426 Executive, 1427 KernelMode, 1428 FALSE, 1429 NULL); 1430 1431 /* Exit the special boot condition and make sure all workers completed */ 1432 CmpSpecialBootCondition = FALSE; 1433 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES); 1434 1435 /* Loop hives again */ 1436 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++) 1437 { 1438 /* Make sure the thread ran and finished */ 1439 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE); 1440 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE); 1441 1442 /* Check if this was a new hive */ 1443 if (!CmpMachineHiveList[i].CmHive) 1444 { 1445 /* Make sure we allocated something */ 1446 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL); 1447 1448 /* Build the base name */ 1449 RegName.Length = RegStart; 1450 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName); 1451 RtlAppendUnicodeStringToString(&RegName, &TempName); 1452 1453 /* Check if this is a child of the root */ 1454 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR) 1455 { 1456 /* Then setup the whole name */ 1457 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name); 1458 RtlAppendUnicodeStringToString(&RegName, &TempName); 1459 } 1460 1461 /* Now link the hive to its master */ 1462 Status = CmpLinkHiveToMaster(&RegName, 1463 NULL, 1464 CmpMachineHiveList[i].CmHive2, 1465 CmpMachineHiveList[i].Allocate, 1466 SecurityDescriptor); 1467 if (Status != STATUS_SUCCESS) 1468 { 1469 /* Linking needs to work */ 1470 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName); 1471 } 1472 1473 /* Check if we had to allocate a new hive */ 1474 if (CmpMachineHiveList[i].Allocate) 1475 { 1476 /* Sync the new hive */ 1477 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2)); 1478 } 1479 } 1480 1481 /* Check if we created a new hive */ 1482 if (CmpMachineHiveList[i].CmHive2) 1483 { 1484 /* Add to HiveList key */ 1485 CmpAddToHiveFileList(CmpMachineHiveList[i].CmHive2); 1486 } 1487 } 1488 1489 /* Get rid of the SD */ 1490 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1491 1492 /* Link SECURITY to SAM */ 1493 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM", 1494 L"\\Registry\\Machine\\SAM\\SAM"); 1495 1496 /* Link S-1-5-18 to .Default */ 1497 CmpNoVolatileCreates = FALSE; 1498 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18", 1499 L"\\Registry\\User\\.Default"); 1500 CmpNoVolatileCreates = TRUE; 1501 } 1502 1503 CODE_SEG("INIT") 1504 BOOLEAN 1505 NTAPI 1506 CmInitSystem1(VOID) 1507 { 1508 OBJECT_ATTRIBUTES ObjectAttributes; 1509 UNICODE_STRING KeyName; 1510 HANDLE KeyHandle; 1511 NTSTATUS Status; 1512 PCMHIVE HardwareHive; 1513 PSECURITY_DESCRIPTOR SecurityDescriptor; 1514 PAGED_CODE(); 1515 1516 /* Check if this is PE-boot */ 1517 if (InitIsWinPEMode) 1518 { 1519 /* Set registry to PE mode */ 1520 CmpMiniNTBoot = TRUE; 1521 CmpShareSystemHives = TRUE; 1522 } 1523 1524 /* Initialize the hive list and lock */ 1525 InitializeListHead(&CmpHiveListHead); 1526 ExInitializePushLock(&CmpHiveListHeadLock); 1527 ExInitializePushLock(&CmpLoadHiveLock); 1528 1529 /* Initialize registry lock */ 1530 ExInitializeResourceLite(&CmpRegistryLock); 1531 1532 /* Initialize the cache */ 1533 CmpInitializeCache(); 1534 1535 /* Initialize allocation and delayed dereferencing */ 1536 CmpInitCmPrivateAlloc(); 1537 CmpInitCmPrivateDelayAlloc(); 1538 CmpInitDelayDerefKCBEngine(); 1539 1540 /* Initialize callbacks */ 1541 CmpInitCallback(); 1542 1543 /* Initialize self healing */ 1544 KeInitializeGuardedMutex(&CmpSelfHealQueueLock); 1545 InitializeListHead(&CmpSelfHealQueueListHead); 1546 1547 /* Save the current process and lock the registry */ 1548 CmpSystemProcess = PsGetCurrentProcess(); 1549 1550 /* Create the key object types */ 1551 Status = CmpCreateObjectTypes(); 1552 if (!NT_SUCCESS(Status)) 1553 { 1554 /* Bugcheck */ 1555 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0); 1556 } 1557 1558 /* Build the master hive */ 1559 Status = CmpInitializeHive(&CmiVolatileHive, 1560 HINIT_CREATE, 1561 HIVE_VOLATILE, 1562 HFILE_TYPE_PRIMARY, 1563 NULL, 1564 NULL, 1565 NULL, 1566 NULL, 1567 NULL, 1568 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 1569 if (!NT_SUCCESS(Status)) 1570 { 1571 /* Bugcheck */ 1572 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0); 1573 } 1574 1575 /* Create the \REGISTRY key node */ 1576 if (!CmpCreateRegistryRoot()) 1577 { 1578 /* Bugcheck */ 1579 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0); 1580 } 1581 1582 /* Create the default security descriptor */ 1583 SecurityDescriptor = CmpHiveRootSecurityDescriptor(); 1584 1585 /* Create '\Registry\Machine' key */ 1586 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE"); 1587 InitializeObjectAttributes(&ObjectAttributes, 1588 &KeyName, 1589 OBJ_CASE_INSENSITIVE, 1590 NULL, 1591 SecurityDescriptor); 1592 Status = NtCreateKey(&KeyHandle, 1593 KEY_READ | KEY_WRITE, 1594 &ObjectAttributes, 1595 0, 1596 NULL, 1597 0, 1598 NULL); 1599 if (!NT_SUCCESS(Status)) 1600 { 1601 /* Bugcheck */ 1602 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0); 1603 } 1604 1605 /* Close the handle */ 1606 NtClose(KeyHandle); 1607 1608 /* Create '\Registry\User' key */ 1609 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER"); 1610 InitializeObjectAttributes(&ObjectAttributes, 1611 &KeyName, 1612 OBJ_CASE_INSENSITIVE, 1613 NULL, 1614 SecurityDescriptor); 1615 Status = NtCreateKey(&KeyHandle, 1616 KEY_READ | KEY_WRITE, 1617 &ObjectAttributes, 1618 0, 1619 NULL, 1620 0, 1621 NULL); 1622 if (!NT_SUCCESS(Status)) 1623 { 1624 /* Bugcheck */ 1625 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0); 1626 } 1627 1628 /* Close the handle */ 1629 NtClose(KeyHandle); 1630 1631 /* After this point, do not allow creating keys in the master hive */ 1632 CmpNoVolatileCreates = TRUE; 1633 1634 /* Initialize the system hive */ 1635 if (!CmpInitializeSystemHive(KeLoaderBlock)) 1636 { 1637 /* Bugcheck */ 1638 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0); 1639 } 1640 1641 /* Create the 'CurrentControlSet' link */ 1642 Status = CmpCreateControlSet(KeLoaderBlock); 1643 if (!NT_SUCCESS(Status)) 1644 { 1645 /* Bugcheck */ 1646 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0); 1647 } 1648 1649 /* Create the hardware hive */ 1650 Status = CmpInitializeHive(&HardwareHive, 1651 HINIT_CREATE, 1652 HIVE_VOLATILE, 1653 HFILE_TYPE_PRIMARY, 1654 NULL, 1655 NULL, 1656 NULL, 1657 NULL, 1658 NULL, 1659 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES); 1660 if (!NT_SUCCESS(Status)) 1661 { 1662 /* Bugcheck */ 1663 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0); 1664 } 1665 1666 /* Add the hive to the hive list */ 1667 CmpMachineHiveList[0].CmHive = HardwareHive; 1668 1669 /* Attach it to the machine key */ 1670 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE"); 1671 Status = CmpLinkHiveToMaster(&KeyName, 1672 NULL, 1673 HardwareHive, 1674 TRUE, 1675 SecurityDescriptor); 1676 if (!NT_SUCCESS(Status)) 1677 { 1678 /* Bugcheck */ 1679 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0); 1680 } 1681 1682 /* Add to HiveList key */ 1683 CmpAddToHiveFileList(HardwareHive); 1684 1685 /* Free the security descriptor */ 1686 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD); 1687 1688 /* Fill out the Hardware key with the ARC Data from the Loader */ 1689 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock); 1690 if (!NT_SUCCESS(Status)) 1691 { 1692 /* Bugcheck */ 1693 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0); 1694 } 1695 1696 /* Initialize machine-dependent information into the registry */ 1697 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock); 1698 if (!NT_SUCCESS(Status)) 1699 { 1700 /* Bugcheck */ 1701 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0); 1702 } 1703 1704 /* Initialize volatile registry settings */ 1705 Status = CmpSetSystemValues(KeLoaderBlock); 1706 if (!NT_SUCCESS(Status)) 1707 { 1708 /* Bugcheck */ 1709 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0); 1710 } 1711 1712 /* Free the load options */ 1713 ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM); 1714 1715 /* If we got here, all went well */ 1716 return TRUE; 1717 } 1718 1719 CODE_SEG("INIT") 1720 PUNICODE_STRING* 1721 NTAPI 1722 CmGetSystemDriverList(VOID) 1723 { 1724 LIST_ENTRY DriverList; 1725 OBJECT_ATTRIBUTES ObjectAttributes; 1726 NTSTATUS Status; 1727 PCM_KEY_BODY KeyBody; 1728 PHHIVE Hive; 1729 HCELL_INDEX RootCell, ControlCell; 1730 HANDLE KeyHandle; 1731 UNICODE_STRING KeyName; 1732 PLIST_ENTRY NextEntry; 1733 ULONG i; 1734 PUNICODE_STRING* ServicePath = NULL; 1735 BOOLEAN Success, AutoSelect; 1736 PBOOT_DRIVER_LIST_ENTRY DriverEntry; 1737 PAGED_CODE(); 1738 1739 /* Initialize the driver list */ 1740 InitializeListHead(&DriverList); 1741 1742 /* Open the system hive key */ 1743 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System"); 1744 InitializeObjectAttributes(&ObjectAttributes, 1745 &KeyName, 1746 OBJ_CASE_INSENSITIVE, 1747 NULL, 1748 NULL); 1749 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 1750 if (!NT_SUCCESS(Status)) return NULL; 1751 1752 /* Reference the key object to get the root hive/cell to access directly */ 1753 Status = ObReferenceObjectByHandle(KeyHandle, 1754 KEY_QUERY_VALUE, 1755 CmpKeyObjectType, 1756 KernelMode, 1757 (PVOID*)&KeyBody, 1758 NULL); 1759 if (!NT_SUCCESS(Status)) 1760 { 1761 /* Fail */ 1762 NtClose(KeyHandle); 1763 return NULL; 1764 } 1765 1766 /* Do all this under the registry lock */ 1767 CmpLockRegistryExclusive(); 1768 1769 /* Get the hive and key cell */ 1770 Hive = KeyBody->KeyControlBlock->KeyHive; 1771 RootCell = KeyBody->KeyControlBlock->KeyCell; 1772 1773 /* Open the current control set key */ 1774 RtlInitUnicodeString(&KeyName, L"Current"); 1775 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect); 1776 if (ControlCell == HCELL_NIL) goto EndPath; 1777 1778 /* Find all system drivers */ 1779 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList); 1780 if (!Success) goto EndPath; 1781 1782 /* Sort by group/tag */ 1783 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath; 1784 1785 /* Remove circular dependencies (cycles) and sort */ 1786 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath; 1787 1788 /* Loop the list to count drivers */ 1789 for (i = 0, NextEntry = DriverList.Flink; 1790 NextEntry != &DriverList; 1791 i++, NextEntry = NextEntry->Flink); 1792 1793 /* Allocate the array */ 1794 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING)); 1795 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1796 1797 /* Loop the driver list */ 1798 for (i = 0, NextEntry = DriverList.Flink; 1799 NextEntry != &DriverList; 1800 i++, NextEntry = NextEntry->Flink) 1801 { 1802 /* Get the entry */ 1803 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link); 1804 1805 /* Allocate the path for the caller */ 1806 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING)); 1807 if (!ServicePath[i]) 1808 { 1809 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1810 } 1811 1812 /* Duplicate the registry path */ 1813 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 1814 &DriverEntry->RegistryPath, 1815 ServicePath[i]); 1816 if (!NT_SUCCESS(Status)) 1817 { 1818 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1819 } 1820 } 1821 1822 /* Terminate the list */ 1823 ServicePath[i] = NULL; 1824 1825 EndPath: 1826 /* Free the driver list if we had one */ 1827 if (!IsListEmpty(&DriverList)) CmpFreeDriverList(Hive, &DriverList); 1828 1829 /* Unlock the registry */ 1830 CmpUnlockRegistry(); 1831 1832 /* Close the key handle and dereference the object, then return the path */ 1833 ObDereferenceObject(KeyBody); 1834 NtClose(KeyHandle); 1835 return ServicePath; 1836 } 1837 1838 VOID 1839 NTAPI 1840 CmpLockRegistryExclusive(VOID) 1841 { 1842 /* Enter a critical region and lock the registry */ 1843 KeEnterCriticalRegion(); 1844 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); 1845 1846 /* Sanity check */ 1847 ASSERT(CmpFlushStarveWriters == 0); 1848 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller); 1849 } 1850 1851 VOID 1852 NTAPI 1853 CmpLockRegistry(VOID) 1854 { 1855 /* Enter a critical region */ 1856 KeEnterCriticalRegion(); 1857 1858 /* Check if we have to starve writers */ 1859 if (CmpFlushStarveWriters) 1860 { 1861 /* Starve exlusive waiters */ 1862 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE); 1863 } 1864 else 1865 { 1866 /* Just grab the lock */ 1867 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE); 1868 } 1869 } 1870 1871 BOOLEAN 1872 NTAPI 1873 CmpTestRegistryLock(VOID) 1874 { 1875 /* Test the lock */ 1876 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE; 1877 } 1878 1879 BOOLEAN 1880 NTAPI 1881 CmpTestRegistryLockExclusive(VOID) 1882 { 1883 /* Test the lock */ 1884 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE; 1885 } 1886 1887 VOID 1888 NTAPI 1889 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive) 1890 { 1891 /* Lock the flusher. We should already be in a critical section */ 1892 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 1893 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 1894 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 1895 ExAcquireResourceExclusiveLite(Hive->FlusherLock, TRUE); 1896 } 1897 1898 VOID 1899 NTAPI 1900 CmpLockHiveFlusherShared(IN PCMHIVE Hive) 1901 { 1902 /* Lock the flusher. We should already be in a critical section */ 1903 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 1904 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 1905 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 1906 ExAcquireResourceSharedLite(Hive->FlusherLock, TRUE); 1907 } 1908 1909 VOID 1910 NTAPI 1911 CmpUnlockHiveFlusher(IN PCMHIVE Hive) 1912 { 1913 /* Sanity check */ 1914 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 1915 CMP_ASSERT_FLUSH_LOCK(Hive); 1916 1917 /* Release the lock */ 1918 ExReleaseResourceLite(Hive->FlusherLock); 1919 } 1920 1921 BOOLEAN 1922 NTAPI 1923 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive) 1924 { 1925 /* Test the lock */ 1926 return !ExIsResourceAcquiredSharedLite(Hive->FlusherLock) ? FALSE : TRUE; 1927 } 1928 1929 BOOLEAN 1930 NTAPI 1931 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive) 1932 { 1933 /* Test the lock */ 1934 return !ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) ? FALSE : TRUE; 1935 } 1936 1937 VOID 1938 NTAPI 1939 CmpUnlockRegistry(VOID) 1940 { 1941 /* Sanity check */ 1942 CMP_ASSERT_REGISTRY_LOCK(); 1943 1944 /* Check if we should flush the registry */ 1945 if (CmpFlushOnLockRelease) 1946 { 1947 /* The registry should be exclusively locked for this */ 1948 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK(); 1949 1950 /* Flush the registry */ 1951 CmpDoFlushAll(TRUE); 1952 CmpFlushOnLockRelease = FALSE; 1953 } 1954 1955 /* Release the lock and leave the critical region */ 1956 ExReleaseResourceLite(&CmpRegistryLock); 1957 KeLeaveCriticalRegion(); 1958 } 1959 1960 VOID 1961 NTAPI 1962 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1, 1963 IN ULONG ConvKey2) 1964 { 1965 ULONG Index1, Index2; 1966 1967 /* Sanity check */ 1968 CMP_ASSERT_REGISTRY_LOCK(); 1969 1970 /* Get hash indexes */ 1971 Index1 = GET_HASH_INDEX(ConvKey1); 1972 Index2 = GET_HASH_INDEX(ConvKey2); 1973 1974 /* See which one is highest */ 1975 if (Index1 < Index2) 1976 { 1977 /* Grab them in the proper order */ 1978 CmpAcquireKcbLockExclusiveByKey(ConvKey1); 1979 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 1980 } 1981 else 1982 { 1983 /* Grab the second one first, then the first */ 1984 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 1985 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1); 1986 } 1987 } 1988 1989 VOID 1990 NTAPI 1991 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1, 1992 IN ULONG ConvKey2) 1993 { 1994 ULONG Index1, Index2; 1995 1996 /* Sanity check */ 1997 CMP_ASSERT_REGISTRY_LOCK(); 1998 1999 /* Get hash indexes */ 2000 Index1 = GET_HASH_INDEX(ConvKey1); 2001 Index2 = GET_HASH_INDEX(ConvKey2); 2002 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2)->Owner == KeGetCurrentThread()) || 2003 (CmpTestRegistryLockExclusive())); 2004 2005 /* See which one is highest */ 2006 if (Index1 < Index2) 2007 { 2008 /* Grab them in the proper order */ 2009 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2010 (CmpTestRegistryLockExclusive())); 2011 CmpReleaseKcbLockByKey(ConvKey2); 2012 CmpReleaseKcbLockByKey(ConvKey1); 2013 } 2014 else 2015 { 2016 /* Release the first one first, then the second */ 2017 if (Index1 != Index2) 2018 { 2019 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2020 (CmpTestRegistryLockExclusive())); 2021 CmpReleaseKcbLockByKey(ConvKey1); 2022 } 2023 CmpReleaseKcbLockByKey(ConvKey2); 2024 } 2025 } 2026 2027 VOID 2028 NTAPI 2029 CmShutdownSystem(VOID) 2030 { 2031 PLIST_ENTRY ListEntry; 2032 PCMHIVE Hive; 2033 2034 /* Kill the workers */ 2035 if (!CmFirstTime) CmpShutdownWorkers(); 2036 2037 /* Flush all hives */ 2038 CmpLockRegistryExclusive(); 2039 CmpDoFlushAll(TRUE); 2040 2041 /* Close all hive files */ 2042 ListEntry = CmpHiveListHead.Flink; 2043 while (ListEntry != &CmpHiveListHead) 2044 { 2045 Hive = CONTAINING_RECORD(ListEntry, CMHIVE, HiveList); 2046 2047 CmpCloseHiveFiles(Hive); 2048 2049 ListEntry = ListEntry->Flink; 2050 } 2051 2052 /* 2053 * As we flushed all the hives on the disk, 2054 * tell the system we do not want any further 2055 * registry flushing or syncing at this point 2056 * since we are shutting down the registry anyway. 2057 */ 2058 HvShutdownComplete = TRUE; 2059 2060 CmpUnlockRegistry(); 2061 } 2062 2063 VOID 2064 NTAPI 2065 CmpSetVersionData(VOID) 2066 { 2067 NTSTATUS Status; 2068 OBJECT_ATTRIBUTES ObjectAttributes; 2069 UNICODE_STRING KeyName; 2070 UNICODE_STRING ValueName; 2071 UNICODE_STRING ValueData; 2072 ANSI_STRING TempString; 2073 HANDLE SoftwareKeyHandle = NULL; 2074 HANDLE MicrosoftKeyHandle = NULL; 2075 HANDLE WindowsNtKeyHandle = NULL; 2076 HANDLE CurrentVersionKeyHandle = NULL; 2077 WCHAR Buffer[128]; // Buffer large enough to contain a full ULONG in decimal 2078 // representation, and the full 'CurrentType' string. 2079 2080 /* 2081 * Open the 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' key 2082 * (create the intermediate subkeys if needed). 2083 */ 2084 2085 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SOFTWARE"); 2086 InitializeObjectAttributes(&ObjectAttributes, 2087 &KeyName, 2088 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2089 NULL, 2090 NULL); 2091 Status = NtCreateKey(&SoftwareKeyHandle, 2092 KEY_CREATE_SUB_KEY, 2093 &ObjectAttributes, 2094 0, 2095 NULL, 2096 0, 2097 NULL); 2098 if (!NT_SUCCESS(Status)) 2099 { 2100 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2101 return; 2102 } 2103 2104 RtlInitUnicodeString(&KeyName, L"Microsoft"); 2105 InitializeObjectAttributes(&ObjectAttributes, 2106 &KeyName, 2107 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2108 SoftwareKeyHandle, 2109 NULL); 2110 Status = NtCreateKey(&MicrosoftKeyHandle, 2111 KEY_CREATE_SUB_KEY, 2112 &ObjectAttributes, 2113 0, 2114 NULL, 2115 0, 2116 NULL); 2117 if (!NT_SUCCESS(Status)) 2118 { 2119 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2120 goto Quit; 2121 } 2122 2123 RtlInitUnicodeString(&KeyName, L"Windows NT"); 2124 InitializeObjectAttributes(&ObjectAttributes, 2125 &KeyName, 2126 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2127 MicrosoftKeyHandle, 2128 NULL); 2129 Status = NtCreateKey(&WindowsNtKeyHandle, 2130 KEY_CREATE_SUB_KEY, 2131 &ObjectAttributes, 2132 0, 2133 NULL, 2134 0, 2135 NULL); 2136 if (!NT_SUCCESS(Status)) 2137 { 2138 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2139 goto Quit; 2140 } 2141 2142 RtlInitUnicodeString(&KeyName, L"CurrentVersion"); 2143 InitializeObjectAttributes(&ObjectAttributes, 2144 &KeyName, 2145 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2146 WindowsNtKeyHandle, 2147 NULL); 2148 Status = NtCreateKey(&CurrentVersionKeyHandle, 2149 KEY_CREATE_SUB_KEY | KEY_SET_VALUE, 2150 &ObjectAttributes, 2151 0, 2152 NULL, 2153 0, 2154 NULL); 2155 if (!NT_SUCCESS(Status)) 2156 { 2157 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2158 goto Quit; 2159 } 2160 2161 /* Set the 'CurrentVersion' value */ 2162 RtlInitUnicodeString(&ValueName, L"CurrentVersion"); 2163 NtSetValueKey(CurrentVersionKeyHandle, 2164 &ValueName, 2165 0, 2166 REG_SZ, 2167 CmVersionString.Buffer, 2168 CmVersionString.Length + sizeof(WCHAR)); 2169 2170 /* Set the 'CurrentBuildNumber' value */ 2171 RtlInitUnicodeString(&ValueName, L"CurrentBuildNumber"); 2172 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2173 RtlIntegerToUnicodeString(NtBuildNumber & 0xFFFF, 10, &ValueData); 2174 NtSetValueKey(CurrentVersionKeyHandle, 2175 &ValueName, 2176 0, 2177 REG_SZ, 2178 ValueData.Buffer, 2179 ValueData.Length + sizeof(WCHAR)); 2180 2181 /* Set the 'BuildLab' value */ 2182 RtlInitUnicodeString(&ValueName, L"BuildLab"); 2183 RtlInitAnsiString(&TempString, NtBuildLab); 2184 Status = RtlAnsiStringToUnicodeString(&ValueData, &TempString, FALSE); 2185 if (NT_SUCCESS(Status)) 2186 { 2187 NtSetValueKey(CurrentVersionKeyHandle, 2188 &ValueName, 2189 0, 2190 REG_SZ, 2191 ValueData.Buffer, 2192 ValueData.Length + sizeof(WCHAR)); 2193 } 2194 2195 /* Set the 'CurrentType' value */ 2196 RtlInitUnicodeString(&ValueName, L"CurrentType"); 2197 RtlStringCbPrintfW(Buffer, sizeof(Buffer), 2198 L"%s %s", 2199 #ifdef CONFIG_SMP 2200 L"Multiprocessor" 2201 #else 2202 L"Uniprocessor" 2203 #endif 2204 , 2205 #if (DBG == 1) 2206 L"Checked" 2207 #else 2208 L"Free" 2209 #endif 2210 ); 2211 RtlInitUnicodeString(&ValueData, Buffer); 2212 NtSetValueKey(CurrentVersionKeyHandle, 2213 &ValueName, 2214 0, 2215 REG_SZ, 2216 ValueData.Buffer, 2217 ValueData.Length + sizeof(WCHAR)); 2218 2219 /* Set the 'CSDVersion' value */ 2220 RtlInitUnicodeString(&ValueName, L"CSDVersion"); 2221 if (CmCSDVersionString.Length != 0) 2222 { 2223 NtSetValueKey(CurrentVersionKeyHandle, 2224 &ValueName, 2225 0, 2226 REG_SZ, 2227 CmCSDVersionString.Buffer, 2228 CmCSDVersionString.Length + sizeof(WCHAR)); 2229 } 2230 else 2231 { 2232 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2233 } 2234 2235 /* Set the 'CSDBuildNumber' value */ 2236 RtlInitUnicodeString(&ValueName, L"CSDBuildNumber"); 2237 if (CmNtSpBuildNumber != 0) 2238 { 2239 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2240 RtlIntegerToUnicodeString(CmNtSpBuildNumber, 10, &ValueData); 2241 NtSetValueKey(CurrentVersionKeyHandle, 2242 &ValueName, 2243 0, 2244 REG_SZ, 2245 ValueData.Buffer, 2246 ValueData.Length + sizeof(WCHAR)); 2247 } 2248 else 2249 { 2250 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2251 } 2252 2253 /* Set the 'SystemRoot' value */ 2254 RtlInitUnicodeString(&ValueName, L"SystemRoot"); 2255 NtSetValueKey(CurrentVersionKeyHandle, 2256 &ValueName, 2257 0, 2258 REG_SZ, 2259 NtSystemRoot.Buffer, 2260 NtSystemRoot.Length + sizeof(WCHAR)); 2261 2262 Quit: 2263 /* Close the keys */ 2264 if (CurrentVersionKeyHandle != NULL) 2265 NtClose(CurrentVersionKeyHandle); 2266 2267 if (WindowsNtKeyHandle != NULL) 2268 NtClose(WindowsNtKeyHandle); 2269 2270 if (MicrosoftKeyHandle != NULL) 2271 NtClose(MicrosoftKeyHandle); 2272 2273 if (SoftwareKeyHandle != NULL) 2274 NtClose(SoftwareKeyHandle); 2275 } 2276 2277 /* EOF */ 2278