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