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