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 INIT_FUNCTION 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 INIT_FUNCTION 450 static 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 INIT_FUNCTION 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 INIT_FUNCTION 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 INIT_FUNCTION 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 INIT_FUNCTION 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 INIT_FUNCTION 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 INIT_FUNCTION 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 INIT_FUNCTION 1725 VOID 1726 NTAPI 1727 CmpFreeDriverList(IN PHHIVE Hive, 1728 IN PLIST_ENTRY DriverList) 1729 { 1730 PLIST_ENTRY NextEntry, OldEntry; 1731 PBOOT_DRIVER_NODE DriverNode; 1732 PAGED_CODE(); 1733 1734 /* Parse the current list */ 1735 NextEntry = DriverList->Flink; 1736 while (NextEntry != DriverList) 1737 { 1738 /* Get the driver node */ 1739 DriverNode = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_NODE, ListEntry.Link); 1740 1741 /* Get the next entry now, since we're going to free it later */ 1742 OldEntry = NextEntry; 1743 NextEntry = NextEntry->Flink; 1744 1745 /* Was there a name? */ 1746 if (DriverNode->Name.Buffer) 1747 { 1748 /* Free it */ 1749 CmpFree(DriverNode->Name.Buffer, DriverNode->Name.Length); 1750 } 1751 1752 /* Was there a registry path? */ 1753 if (DriverNode->ListEntry.RegistryPath.Buffer) 1754 { 1755 /* Free it */ 1756 CmpFree(DriverNode->ListEntry.RegistryPath.Buffer, 1757 DriverNode->ListEntry.RegistryPath.MaximumLength); 1758 } 1759 1760 /* Was there a file path? */ 1761 if (DriverNode->ListEntry.FilePath.Buffer) 1762 { 1763 /* Free it */ 1764 CmpFree(DriverNode->ListEntry.FilePath.Buffer, 1765 DriverNode->ListEntry.FilePath.MaximumLength); 1766 } 1767 1768 /* Now free the node, and move on */ 1769 CmpFree(OldEntry, sizeof(BOOT_DRIVER_NODE)); 1770 } 1771 } 1772 1773 INIT_FUNCTION 1774 PUNICODE_STRING* 1775 NTAPI 1776 CmGetSystemDriverList(VOID) 1777 { 1778 LIST_ENTRY DriverList; 1779 OBJECT_ATTRIBUTES ObjectAttributes; 1780 NTSTATUS Status; 1781 PCM_KEY_BODY KeyBody; 1782 PHHIVE Hive; 1783 HCELL_INDEX RootCell, ControlCell; 1784 HANDLE KeyHandle; 1785 UNICODE_STRING KeyName; 1786 PLIST_ENTRY NextEntry; 1787 ULONG i; 1788 PUNICODE_STRING* ServicePath = NULL; 1789 BOOLEAN Success, AutoSelect; 1790 PBOOT_DRIVER_LIST_ENTRY DriverEntry; 1791 PAGED_CODE(); 1792 1793 /* Initialize the driver list */ 1794 InitializeListHead(&DriverList); 1795 1796 /* Open the system hive key */ 1797 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System"); 1798 InitializeObjectAttributes(&ObjectAttributes, 1799 &KeyName, 1800 OBJ_CASE_INSENSITIVE, 1801 NULL, 1802 NULL); 1803 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 1804 if (!NT_SUCCESS(Status)) return NULL; 1805 1806 /* Reference the key object to get the root hive/cell to access directly */ 1807 Status = ObReferenceObjectByHandle(KeyHandle, 1808 KEY_QUERY_VALUE, 1809 CmpKeyObjectType, 1810 KernelMode, 1811 (PVOID*)&KeyBody, 1812 NULL); 1813 if (!NT_SUCCESS(Status)) 1814 { 1815 /* Fail */ 1816 NtClose(KeyHandle); 1817 return NULL; 1818 } 1819 1820 /* Do all this under the registry lock */ 1821 CmpLockRegistryExclusive(); 1822 1823 /* Get the hive and key cell */ 1824 Hive = KeyBody->KeyControlBlock->KeyHive; 1825 RootCell = KeyBody->KeyControlBlock->KeyCell; 1826 1827 /* Open the current control set key */ 1828 RtlInitUnicodeString(&KeyName, L"Current"); 1829 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect); 1830 if (ControlCell == HCELL_NIL) goto EndPath; 1831 1832 /* Find all system drivers */ 1833 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList); 1834 if (!Success) goto EndPath; 1835 1836 /* Sort by group/tag */ 1837 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath; 1838 1839 /* Remove circular dependencies (cycles) and sort */ 1840 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath; 1841 1842 /* Loop the list to count drivers */ 1843 for (i = 0, NextEntry = DriverList.Flink; 1844 NextEntry != &DriverList; 1845 i++, NextEntry = NextEntry->Flink); 1846 1847 /* Allocate the array */ 1848 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING)); 1849 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1850 1851 /* Loop the driver list */ 1852 for (i = 0, NextEntry = DriverList.Flink; 1853 NextEntry != &DriverList; 1854 i++, NextEntry = NextEntry->Flink) 1855 { 1856 /* Get the entry */ 1857 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link); 1858 1859 /* Allocate the path for the caller */ 1860 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING)); 1861 if (!ServicePath[i]) 1862 { 1863 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1864 } 1865 1866 /* Duplicate the registry path */ 1867 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 1868 &DriverEntry->RegistryPath, 1869 ServicePath[i]); 1870 if (!NT_SUCCESS(Status)) 1871 { 1872 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0); 1873 } 1874 } 1875 1876 /* Terminate the list */ 1877 ServicePath[i] = NULL; 1878 1879 EndPath: 1880 /* Free the driver list if we had one */ 1881 if (!IsListEmpty(&DriverList)) CmpFreeDriverList(Hive, &DriverList); 1882 1883 /* Unlock the registry */ 1884 CmpUnlockRegistry(); 1885 1886 /* Close the key handle and dereference the object, then return the path */ 1887 ObDereferenceObject(KeyBody); 1888 NtClose(KeyHandle); 1889 return ServicePath; 1890 } 1891 1892 VOID 1893 NTAPI 1894 CmpLockRegistryExclusive(VOID) 1895 { 1896 /* Enter a critical region and lock the registry */ 1897 KeEnterCriticalRegion(); 1898 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE); 1899 1900 /* Sanity check */ 1901 ASSERT(CmpFlushStarveWriters == 0); 1902 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller); 1903 } 1904 1905 VOID 1906 NTAPI 1907 CmpLockRegistry(VOID) 1908 { 1909 /* Enter a critical region */ 1910 KeEnterCriticalRegion(); 1911 1912 /* Check if we have to starve writers */ 1913 if (CmpFlushStarveWriters) 1914 { 1915 /* Starve exlusive waiters */ 1916 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE); 1917 } 1918 else 1919 { 1920 /* Just grab the lock */ 1921 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE); 1922 } 1923 } 1924 1925 BOOLEAN 1926 NTAPI 1927 CmpTestRegistryLock(VOID) 1928 { 1929 /* Test the lock */ 1930 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE; 1931 } 1932 1933 BOOLEAN 1934 NTAPI 1935 CmpTestRegistryLockExclusive(VOID) 1936 { 1937 /* Test the lock */ 1938 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE; 1939 } 1940 1941 VOID 1942 NTAPI 1943 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive) 1944 { 1945 /* Lock the flusher. We should already be in a critical section */ 1946 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 1947 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 1948 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 1949 ExAcquireResourceExclusiveLite(Hive->FlusherLock, TRUE); 1950 } 1951 1952 VOID 1953 NTAPI 1954 CmpLockHiveFlusherShared(IN PCMHIVE Hive) 1955 { 1956 /* Lock the flusher. We should already be in a critical section */ 1957 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 1958 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) && 1959 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0)); 1960 ExAcquireResourceSharedLite(Hive->FlusherLock, TRUE); 1961 } 1962 1963 VOID 1964 NTAPI 1965 CmpUnlockHiveFlusher(IN PCMHIVE Hive) 1966 { 1967 /* Sanity check */ 1968 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive); 1969 CMP_ASSERT_FLUSH_LOCK(Hive); 1970 1971 /* Release the lock */ 1972 ExReleaseResourceLite(Hive->FlusherLock); 1973 } 1974 1975 BOOLEAN 1976 NTAPI 1977 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive) 1978 { 1979 /* Test the lock */ 1980 return !ExIsResourceAcquiredSharedLite(Hive->FlusherLock) ? FALSE : TRUE; 1981 } 1982 1983 BOOLEAN 1984 NTAPI 1985 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive) 1986 { 1987 /* Test the lock */ 1988 return !ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) ? FALSE : TRUE; 1989 } 1990 1991 VOID 1992 NTAPI 1993 CmpUnlockRegistry(VOID) 1994 { 1995 /* Sanity check */ 1996 CMP_ASSERT_REGISTRY_LOCK(); 1997 1998 /* Check if we should flush the registry */ 1999 if (CmpFlushOnLockRelease) 2000 { 2001 /* The registry should be exclusively locked for this */ 2002 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK(); 2003 2004 /* Flush the registry */ 2005 CmpDoFlushAll(TRUE); 2006 CmpFlushOnLockRelease = FALSE; 2007 } 2008 else 2009 { 2010 /* Lazy flush the registry */ 2011 CmpLazyFlush(); 2012 } 2013 2014 /* Release the lock and leave the critical region */ 2015 ExReleaseResourceLite(&CmpRegistryLock); 2016 KeLeaveCriticalRegion(); 2017 } 2018 2019 VOID 2020 NTAPI 2021 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1, 2022 IN ULONG ConvKey2) 2023 { 2024 ULONG Index1, Index2; 2025 2026 /* Sanity check */ 2027 CMP_ASSERT_REGISTRY_LOCK(); 2028 2029 /* Get hash indexes */ 2030 Index1 = GET_HASH_INDEX(ConvKey1); 2031 Index2 = GET_HASH_INDEX(ConvKey2); 2032 2033 /* See which one is highest */ 2034 if (Index1 < Index2) 2035 { 2036 /* Grab them in the proper order */ 2037 CmpAcquireKcbLockExclusiveByKey(ConvKey1); 2038 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 2039 } 2040 else 2041 { 2042 /* Grab the second one first, then the first */ 2043 CmpAcquireKcbLockExclusiveByKey(ConvKey2); 2044 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1); 2045 } 2046 } 2047 2048 VOID 2049 NTAPI 2050 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1, 2051 IN ULONG ConvKey2) 2052 { 2053 ULONG Index1, Index2; 2054 2055 /* Sanity check */ 2056 CMP_ASSERT_REGISTRY_LOCK(); 2057 2058 /* Get hash indexes */ 2059 Index1 = GET_HASH_INDEX(ConvKey1); 2060 Index2 = GET_HASH_INDEX(ConvKey2); 2061 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2)->Owner == KeGetCurrentThread()) || 2062 (CmpTestRegistryLockExclusive())); 2063 2064 /* See which one is highest */ 2065 if (Index1 < Index2) 2066 { 2067 /* Grab them in the proper order */ 2068 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2069 (CmpTestRegistryLockExclusive())); 2070 CmpReleaseKcbLockByKey(ConvKey2); 2071 CmpReleaseKcbLockByKey(ConvKey1); 2072 } 2073 else 2074 { 2075 /* Release the first one first, then the second */ 2076 if (Index1 != Index2) 2077 { 2078 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) || 2079 (CmpTestRegistryLockExclusive())); 2080 CmpReleaseKcbLockByKey(ConvKey1); 2081 } 2082 CmpReleaseKcbLockByKey(ConvKey2); 2083 } 2084 } 2085 2086 VOID 2087 NTAPI 2088 CmShutdownSystem(VOID) 2089 { 2090 PLIST_ENTRY ListEntry; 2091 PCMHIVE Hive; 2092 2093 /* Kill the workers */ 2094 if (!CmFirstTime) CmpShutdownWorkers(); 2095 2096 /* Flush all hives */ 2097 CmpLockRegistryExclusive(); 2098 CmpDoFlushAll(TRUE); 2099 2100 /* Close all hive files */ 2101 ListEntry = CmpHiveListHead.Flink; 2102 while (ListEntry != &CmpHiveListHead) 2103 { 2104 Hive = CONTAINING_RECORD(ListEntry, CMHIVE, HiveList); 2105 2106 CmpCloseHiveFiles(Hive); 2107 2108 ListEntry = ListEntry->Flink; 2109 } 2110 2111 CmpUnlockRegistry(); 2112 } 2113 2114 VOID 2115 NTAPI 2116 CmpSetVersionData(VOID) 2117 { 2118 NTSTATUS Status; 2119 OBJECT_ATTRIBUTES ObjectAttributes; 2120 UNICODE_STRING KeyName; 2121 UNICODE_STRING ValueName; 2122 UNICODE_STRING ValueData; 2123 ANSI_STRING TempString; 2124 HANDLE SoftwareKeyHandle = NULL; 2125 HANDLE MicrosoftKeyHandle = NULL; 2126 HANDLE WindowsNtKeyHandle = NULL; 2127 HANDLE CurrentVersionKeyHandle = NULL; 2128 WCHAR Buffer[128]; // Buffer large enough to contain a full ULONG in decimal 2129 // representation, and the full 'CurrentType' string. 2130 2131 /* 2132 * Open the 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' key 2133 * (create the intermediate subkeys if needed). 2134 */ 2135 2136 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SOFTWARE"); 2137 InitializeObjectAttributes(&ObjectAttributes, 2138 &KeyName, 2139 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2140 NULL, 2141 NULL); 2142 Status = NtCreateKey(&SoftwareKeyHandle, 2143 KEY_CREATE_SUB_KEY, 2144 &ObjectAttributes, 2145 0, 2146 NULL, 2147 0, 2148 NULL); 2149 if (!NT_SUCCESS(Status)) 2150 { 2151 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2152 return; 2153 } 2154 2155 RtlInitUnicodeString(&KeyName, L"Microsoft"); 2156 InitializeObjectAttributes(&ObjectAttributes, 2157 &KeyName, 2158 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2159 SoftwareKeyHandle, 2160 NULL); 2161 Status = NtCreateKey(&MicrosoftKeyHandle, 2162 KEY_CREATE_SUB_KEY, 2163 &ObjectAttributes, 2164 0, 2165 NULL, 2166 0, 2167 NULL); 2168 if (!NT_SUCCESS(Status)) 2169 { 2170 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2171 goto Quit; 2172 } 2173 2174 RtlInitUnicodeString(&KeyName, L"Windows NT"); 2175 InitializeObjectAttributes(&ObjectAttributes, 2176 &KeyName, 2177 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2178 MicrosoftKeyHandle, 2179 NULL); 2180 Status = NtCreateKey(&WindowsNtKeyHandle, 2181 KEY_CREATE_SUB_KEY, 2182 &ObjectAttributes, 2183 0, 2184 NULL, 2185 0, 2186 NULL); 2187 if (!NT_SUCCESS(Status)) 2188 { 2189 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2190 goto Quit; 2191 } 2192 2193 RtlInitUnicodeString(&KeyName, L"CurrentVersion"); 2194 InitializeObjectAttributes(&ObjectAttributes, 2195 &KeyName, 2196 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 2197 WindowsNtKeyHandle, 2198 NULL); 2199 Status = NtCreateKey(&CurrentVersionKeyHandle, 2200 KEY_CREATE_SUB_KEY | KEY_SET_VALUE, 2201 &ObjectAttributes, 2202 0, 2203 NULL, 2204 0, 2205 NULL); 2206 if (!NT_SUCCESS(Status)) 2207 { 2208 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status); 2209 goto Quit; 2210 } 2211 2212 /* Set the 'CurrentVersion' value */ 2213 RtlInitUnicodeString(&ValueName, L"CurrentVersion"); 2214 NtSetValueKey(CurrentVersionKeyHandle, 2215 &ValueName, 2216 0, 2217 REG_SZ, 2218 CmVersionString.Buffer, 2219 CmVersionString.Length + sizeof(WCHAR)); 2220 2221 /* Set the 'CurrentBuildNumber' value */ 2222 RtlInitUnicodeString(&ValueName, L"CurrentBuildNumber"); 2223 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2224 RtlIntegerToUnicodeString(NtBuildNumber & 0xFFFF, 10, &ValueData); 2225 NtSetValueKey(CurrentVersionKeyHandle, 2226 &ValueName, 2227 0, 2228 REG_SZ, 2229 ValueData.Buffer, 2230 ValueData.Length + sizeof(WCHAR)); 2231 2232 /* Set the 'BuildLab' value */ 2233 RtlInitUnicodeString(&ValueName, L"BuildLab"); 2234 RtlInitAnsiString(&TempString, NtBuildLab); 2235 Status = RtlAnsiStringToUnicodeString(&ValueData, &TempString, FALSE); 2236 if (NT_SUCCESS(Status)) 2237 { 2238 NtSetValueKey(CurrentVersionKeyHandle, 2239 &ValueName, 2240 0, 2241 REG_SZ, 2242 ValueData.Buffer, 2243 ValueData.Length + sizeof(WCHAR)); 2244 } 2245 2246 /* Set the 'CurrentType' value */ 2247 RtlInitUnicodeString(&ValueName, L"CurrentType"); 2248 RtlStringCbPrintfW(Buffer, sizeof(Buffer), 2249 L"%s %s", 2250 #ifdef CONFIG_SMP 2251 L"Multiprocessor" 2252 #else 2253 L"Uniprocessor" 2254 #endif 2255 , 2256 #if (DBG == 1) 2257 L"Checked" 2258 #else 2259 L"Free" 2260 #endif 2261 ); 2262 RtlInitUnicodeString(&ValueData, Buffer); 2263 NtSetValueKey(CurrentVersionKeyHandle, 2264 &ValueName, 2265 0, 2266 REG_SZ, 2267 ValueData.Buffer, 2268 ValueData.Length + sizeof(WCHAR)); 2269 2270 /* Set the 'CSDVersion' value */ 2271 RtlInitUnicodeString(&ValueName, L"CSDVersion"); 2272 if (CmCSDVersionString.Length != 0) 2273 { 2274 NtSetValueKey(CurrentVersionKeyHandle, 2275 &ValueName, 2276 0, 2277 REG_SZ, 2278 CmCSDVersionString.Buffer, 2279 CmCSDVersionString.Length + sizeof(WCHAR)); 2280 } 2281 else 2282 { 2283 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2284 } 2285 2286 /* Set the 'CSDBuildNumber' value */ 2287 RtlInitUnicodeString(&ValueName, L"CSDBuildNumber"); 2288 if (CmNtSpBuildNumber != 0) 2289 { 2290 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer)); 2291 RtlIntegerToUnicodeString(CmNtSpBuildNumber, 10, &ValueData); 2292 NtSetValueKey(CurrentVersionKeyHandle, 2293 &ValueName, 2294 0, 2295 REG_SZ, 2296 ValueData.Buffer, 2297 ValueData.Length + sizeof(WCHAR)); 2298 } 2299 else 2300 { 2301 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName); 2302 } 2303 2304 /* Set the 'SystemRoot' value */ 2305 RtlInitUnicodeString(&ValueName, L"SystemRoot"); 2306 NtSetValueKey(CurrentVersionKeyHandle, 2307 &ValueName, 2308 0, 2309 REG_SZ, 2310 NtSystemRoot.Buffer, 2311 NtSystemRoot.Length + sizeof(WCHAR)); 2312 2313 Quit: 2314 /* Close the keys */ 2315 if (CurrentVersionKeyHandle != NULL) 2316 NtClose(CurrentVersionKeyHandle); 2317 2318 if (WindowsNtKeyHandle != NULL) 2319 NtClose(WindowsNtKeyHandle); 2320 2321 if (MicrosoftKeyHandle != NULL) 2322 NtClose(MicrosoftKeyHandle); 2323 2324 if (SoftwareKeyHandle != NULL) 2325 NtClose(SoftwareKeyHandle); 2326 } 2327 2328 /* EOF */ 2329