1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/config/ntapi.c 5 * PURPOSE: Configuration Manager - Internal Registry APIs 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Eric Kohl 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include "ntoskrnl.h" 13 #define NDEBUG 14 #include "debug.h" 15 16 BOOLEAN CmBootAcceptFirstTime = TRUE; 17 BOOLEAN CmFirstTime = TRUE; 18 extern ULONG InitSafeBootMode; 19 20 21 /* PRIVATE FUNCTIONS *********************************************************/ 22 23 /* 24 * Adapted from ntoskrnl/include/internal/ob_x.h:ObpReleaseObjectCreateInformation() 25 */ 26 VOID 27 ReleaseCapturedObjectAttributes( 28 _In_ POBJECT_ATTRIBUTES CapturedObjectAttributes, 29 _In_ KPROCESSOR_MODE AccessMode) 30 { 31 /* Check if we have a security descriptor */ 32 if (CapturedObjectAttributes->SecurityDescriptor) 33 { 34 /* Release it */ 35 SeReleaseSecurityDescriptor(CapturedObjectAttributes->SecurityDescriptor, 36 AccessMode, 37 TRUE); 38 CapturedObjectAttributes->SecurityDescriptor = NULL; 39 } 40 41 /* Check if we have an object name */ 42 if (CapturedObjectAttributes->ObjectName) 43 { 44 /* Release it */ 45 ReleaseCapturedUnicodeString(CapturedObjectAttributes->ObjectName, AccessMode); 46 } 47 } 48 49 /* 50 * Adapted from ntoskrnl/ob/oblife.c:ObpCaptureObjectCreateInformation() 51 */ 52 NTSTATUS 53 ProbeAndCaptureObjectAttributes( 54 _Out_ POBJECT_ATTRIBUTES CapturedObjectAttributes, 55 _Out_ PUNICODE_STRING ObjectName, 56 _In_ KPROCESSOR_MODE AccessMode, 57 _In_ POBJECT_ATTRIBUTES ObjectAttributes, 58 _In_ BOOLEAN CaptureSecurity) 59 { 60 NTSTATUS Status = STATUS_SUCCESS; 61 PSECURITY_DESCRIPTOR SecurityDescriptor; 62 // PSECURITY_QUALITY_OF_SERVICE SecurityQos; 63 PUNICODE_STRING LocalObjectName = NULL; 64 65 /* Zero out the Capture Data */ 66 RtlZeroMemory(CapturedObjectAttributes, sizeof(*CapturedObjectAttributes)); 67 68 /* SEH everything here for protection */ 69 _SEH2_TRY 70 { 71 /* Check if we got attributes */ 72 if (ObjectAttributes) 73 { 74 /* Check if we're in user mode */ 75 if (AccessMode != KernelMode) 76 { 77 /* Probe the attributes */ 78 ProbeForRead(ObjectAttributes, 79 sizeof(OBJECT_ATTRIBUTES), 80 sizeof(ULONG)); 81 } 82 83 /* Validate the Size and Attributes */ 84 if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) || 85 (ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES)) // Understood as all the possible valid attributes 86 { 87 /* Invalid combination, fail */ 88 _SEH2_YIELD(return STATUS_INVALID_PARAMETER); 89 } 90 91 /* Set some Create Info and do not allow user-mode kernel handles */ 92 CapturedObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES); 93 CapturedObjectAttributes->RootDirectory = ObjectAttributes->RootDirectory; 94 CapturedObjectAttributes->Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, AccessMode); 95 LocalObjectName = ObjectAttributes->ObjectName; 96 SecurityDescriptor = ObjectAttributes->SecurityDescriptor; 97 // SecurityQos = ObjectAttributes->SecurityQualityOfService; 98 99 /* Check if we have a security descriptor */ 100 if (CaptureSecurity && SecurityDescriptor) 101 { 102 /* 103 * Capture it. 104 * Note: This has an implicit memory barrier due 105 * to the function call, so cleanup is safe here. 106 */ 107 Status = SeCaptureSecurityDescriptor(SecurityDescriptor, 108 AccessMode, 109 NonPagedPool, 110 TRUE, 111 &CapturedObjectAttributes-> 112 SecurityDescriptor); 113 if (!NT_SUCCESS(Status)) 114 { 115 /* Capture failed, quit */ 116 CapturedObjectAttributes->SecurityDescriptor = NULL; 117 _SEH2_YIELD(return Status); 118 } 119 } 120 else 121 { 122 CapturedObjectAttributes->SecurityDescriptor = NULL; 123 } 124 125 #if 0 126 // We don't use the QoS! 127 128 /* Check if we have QoS */ 129 if (SecurityQos) 130 { 131 /* Check if we came from user mode */ 132 if (AccessMode != KernelMode) 133 { 134 /* Validate the QoS */ 135 ProbeForRead(SecurityQos, 136 sizeof(SECURITY_QUALITY_OF_SERVICE), 137 sizeof(ULONG)); 138 } 139 140 /* Save Info */ 141 CapturedObjectAttributes->SecurityQualityOfService = *SecurityQos; 142 CapturedObjectAttributes->SecurityQos = 143 &CapturedObjectAttributes->SecurityQualityOfService; 144 } 145 #else 146 CapturedObjectAttributes->SecurityQualityOfService = NULL; 147 #endif 148 } 149 else 150 { 151 /* We don't have a name */ 152 LocalObjectName = NULL; 153 } 154 } 155 _SEH2_EXCEPT(ExSystemExceptionFilter()) 156 { 157 /* Cleanup and return the exception code */ 158 ReleaseCapturedObjectAttributes(CapturedObjectAttributes, AccessMode); 159 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 160 } 161 _SEH2_END; 162 163 /* Now check if the Object Attributes had an Object Name */ 164 if (LocalObjectName) 165 { 166 Status = ProbeAndCaptureUnicodeString(ObjectName, AccessMode, LocalObjectName); 167 } 168 else 169 { 170 /* Clear the string */ 171 RtlInitEmptyUnicodeString(ObjectName, NULL, 0); 172 173 /* It cannot have specified a Root Directory */ 174 if (CapturedObjectAttributes->RootDirectory) 175 { 176 Status = STATUS_OBJECT_NAME_INVALID; 177 } 178 } 179 180 /* Set the caputured object attributes name pointer to the one the user gave to us */ 181 CapturedObjectAttributes->ObjectName = ObjectName; 182 183 /* Cleanup if we failed */ 184 if (!NT_SUCCESS(Status)) 185 { 186 ReleaseCapturedObjectAttributes(CapturedObjectAttributes, AccessMode); 187 } 188 189 /* Return status to caller */ 190 return Status; 191 } 192 193 static 194 NTSTATUS 195 CmpConvertHandleToKernelHandle( 196 _In_ HANDLE SourceHandle, 197 _In_opt_ POBJECT_TYPE ObjectType, 198 _In_ ACCESS_MASK DesiredAccess, 199 _In_ KPROCESSOR_MODE AccessMode, 200 _Out_ PHANDLE KernelHandle) 201 { 202 NTSTATUS Status; 203 PVOID Object; 204 205 *KernelHandle = NULL; 206 207 /* NULL handle is valid */ 208 if (SourceHandle == NULL) 209 return STATUS_SUCCESS; 210 211 /* Get the object pointer */ 212 Status = ObReferenceObjectByHandle(SourceHandle, 213 DesiredAccess, 214 ObjectType, 215 AccessMode, 216 &Object, 217 NULL); 218 if (!NT_SUCCESS(Status)) 219 return Status; 220 221 /* Create a kernel handle from the pointer */ 222 Status = ObOpenObjectByPointer(Object, 223 OBJ_KERNEL_HANDLE, 224 NULL, 225 DesiredAccess, 226 ObjectType, 227 KernelMode, 228 KernelHandle); 229 230 /* Dereference the object */ 231 ObDereferenceObject(Object); 232 return Status; 233 } 234 235 236 /* FUNCTIONS *****************************************************************/ 237 238 NTSTATUS 239 NTAPI 240 NtCreateKey(OUT PHANDLE KeyHandle, 241 IN ACCESS_MASK DesiredAccess, 242 IN POBJECT_ATTRIBUTES ObjectAttributes, 243 IN ULONG TitleIndex, 244 IN PUNICODE_STRING Class OPTIONAL, 245 IN ULONG CreateOptions, 246 OUT PULONG Disposition OPTIONAL) 247 { 248 NTSTATUS Status; 249 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 250 CM_PARSE_CONTEXT ParseContext = {0}; 251 HANDLE Handle; 252 PAGED_CODE(); 253 254 DPRINT("NtCreateKey(Path: %wZ, Root %x, Access: %x, CreateOptions %x)\n", 255 ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory, 256 DesiredAccess, CreateOptions); 257 258 /* Ignore the WOW64 flag, it's not valid in the kernel */ 259 DesiredAccess &= ~KEY_WOW64_RES; 260 261 /* Check for user-mode caller */ 262 if (PreviousMode != KernelMode) 263 { 264 /* Prepare to probe parameters */ 265 _SEH2_TRY 266 { 267 /* Check if we have a class */ 268 if (Class) 269 { 270 /* Probe it */ 271 ParseContext.Class = ProbeForReadUnicodeString(Class); 272 ProbeForRead(ParseContext.Class.Buffer, 273 ParseContext.Class.Length, 274 sizeof(WCHAR)); 275 } 276 277 /* Probe the key handle */ 278 ProbeForWriteHandle(KeyHandle); 279 *KeyHandle = NULL; 280 281 /* Probe object attributes */ 282 ProbeForRead(ObjectAttributes, 283 sizeof(OBJECT_ATTRIBUTES), 284 sizeof(ULONG)); 285 286 if (Disposition) 287 ProbeForWriteUlong(Disposition); 288 } 289 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 290 { 291 /* Return the exception code */ 292 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 293 } 294 _SEH2_END; 295 } 296 else 297 { 298 /* Save the class directly */ 299 if (Class) ParseContext.Class = *Class; 300 } 301 302 /* Setup the parse context */ 303 ParseContext.CreateOperation = TRUE; 304 ParseContext.CreateOptions = CreateOptions; 305 306 /* Do the create */ 307 Status = ObOpenObjectByName(ObjectAttributes, 308 CmpKeyObjectType, 309 PreviousMode, 310 NULL, 311 DesiredAccess, 312 &ParseContext, 313 &Handle); 314 315 _SEH2_TRY 316 { 317 /* Return data to user */ 318 if (NT_SUCCESS(Status)) *KeyHandle = Handle; 319 if (Disposition) *Disposition = ParseContext.Disposition; 320 } 321 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 322 { 323 /* Get the status */ 324 Status = _SEH2_GetExceptionCode(); 325 } 326 _SEH2_END; 327 328 DPRINT("Returning handle %x, Status %x.\n", Handle, Status); 329 330 /* Return status */ 331 return Status; 332 } 333 334 NTSTATUS 335 NTAPI 336 NtOpenKey(OUT PHANDLE KeyHandle, 337 IN ACCESS_MASK DesiredAccess, 338 IN POBJECT_ATTRIBUTES ObjectAttributes) 339 { 340 CM_PARSE_CONTEXT ParseContext = {0}; 341 HANDLE Handle; 342 NTSTATUS Status; 343 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 344 PAGED_CODE(); 345 DPRINT("NtOpenKey(Path: %wZ, Root %x, Access: %x)\n", 346 ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory, DesiredAccess); 347 348 /* Ignore the WOW64 flag, it's not valid in the kernel */ 349 DesiredAccess &= ~KEY_WOW64_RES; 350 351 /* Check for user-mode caller */ 352 if (PreviousMode != KernelMode) 353 { 354 /* Prepare to probe parameters */ 355 _SEH2_TRY 356 { 357 /* Probe the key handle */ 358 ProbeForWriteHandle(KeyHandle); 359 *KeyHandle = NULL; 360 361 /* Probe object attributes */ 362 ProbeForRead(ObjectAttributes, 363 sizeof(OBJECT_ATTRIBUTES), 364 sizeof(ULONG)); 365 } 366 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 367 { 368 /* Return the exception code */ 369 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 370 } 371 _SEH2_END; 372 } 373 374 /* Just let the object manager handle this */ 375 Status = ObOpenObjectByName(ObjectAttributes, 376 CmpKeyObjectType, 377 PreviousMode, 378 NULL, 379 DesiredAccess, 380 &ParseContext, 381 &Handle); 382 383 /* Only do this if we succeeded */ 384 if (NT_SUCCESS(Status)) 385 { 386 _SEH2_TRY 387 { 388 /* Return the handle to caller */ 389 *KeyHandle = Handle; 390 } 391 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 392 { 393 /* Get the status */ 394 Status = _SEH2_GetExceptionCode(); 395 } 396 _SEH2_END; 397 } 398 399 DPRINT("Returning handle %x, Status %x.\n", Handle, Status); 400 401 /* Return status */ 402 return Status; 403 } 404 405 406 NTSTATUS 407 NTAPI 408 NtDeleteKey(IN HANDLE KeyHandle) 409 { 410 PCM_KEY_BODY KeyObject; 411 NTSTATUS Status; 412 REG_DELETE_KEY_INFORMATION DeleteKeyInfo; 413 REG_POST_OPERATION_INFORMATION PostOperationInfo; 414 PAGED_CODE(); 415 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle); 416 417 /* Verify that the handle is valid and is a registry key */ 418 Status = ObReferenceObjectByHandle(KeyHandle, 419 DELETE, 420 CmpKeyObjectType, 421 ExGetPreviousMode(), 422 (PVOID*)&KeyObject, 423 NULL); 424 if (!NT_SUCCESS(Status)) return Status; 425 426 /* Setup the callback */ 427 PostOperationInfo.Object = (PVOID)KeyObject; 428 DeleteKeyInfo.Object = (PVOID)KeyObject; 429 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteKey, &DeleteKeyInfo); 430 if (NT_SUCCESS(Status)) 431 { 432 /* Check if we are read-only */ 433 if ((KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) || 434 (KeyObject->KeyControlBlock->ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY)) 435 { 436 /* Fail */ 437 Status = STATUS_ACCESS_DENIED; 438 } 439 else 440 { 441 /* Call the internal API */ 442 Status = CmDeleteKey(KeyObject); 443 } 444 445 /* Do post callback */ 446 PostOperationInfo.Status = Status; 447 CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo); 448 } 449 450 /* Dereference and return status */ 451 ObDereferenceObject(KeyObject); 452 return Status; 453 } 454 455 NTSTATUS 456 NTAPI 457 NtEnumerateKey(IN HANDLE KeyHandle, 458 IN ULONG Index, 459 IN KEY_INFORMATION_CLASS KeyInformationClass, 460 OUT PVOID KeyInformation, 461 IN ULONG Length, 462 OUT PULONG ResultLength) 463 { 464 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 465 NTSTATUS Status; 466 PCM_KEY_BODY KeyObject; 467 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo; 468 REG_POST_OPERATION_INFORMATION PostOperationInfo; 469 PAGED_CODE(); 470 DPRINT("NtEnumerateKey() KH 0x%p, Index 0x%x, KIC %d, Length %lu\n", 471 KeyHandle, Index, KeyInformationClass, Length); 472 473 /* Reject classes we don't know about */ 474 if ((KeyInformationClass != KeyBasicInformation) && 475 (KeyInformationClass != KeyNodeInformation) && 476 (KeyInformationClass != KeyFullInformation)) 477 { 478 /* Fail */ 479 return STATUS_INVALID_PARAMETER; 480 } 481 482 /* Verify that the handle is valid and is a registry key */ 483 Status = ObReferenceObjectByHandle(KeyHandle, 484 KEY_ENUMERATE_SUB_KEYS, 485 CmpKeyObjectType, 486 PreviousMode, 487 (PVOID*)&KeyObject, 488 NULL); 489 if (!NT_SUCCESS(Status)) return Status; 490 491 if (PreviousMode != KernelMode) 492 { 493 _SEH2_TRY 494 { 495 ProbeForWriteUlong(ResultLength); 496 ProbeForWrite(KeyInformation, 497 Length, 498 sizeof(ULONG)); 499 } 500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 501 { 502 /* Dereference and return status */ 503 ObDereferenceObject(KeyObject); 504 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 505 } 506 _SEH2_END; 507 } 508 509 /* Setup the callback */ 510 PostOperationInfo.Object = (PVOID)KeyObject; 511 EnumerateKeyInfo.Object = (PVOID)KeyObject; 512 EnumerateKeyInfo.Index = Index; 513 EnumerateKeyInfo.KeyInformationClass = KeyInformationClass; 514 EnumerateKeyInfo.Length = Length; 515 EnumerateKeyInfo.ResultLength = ResultLength; 516 517 /* Do the callback */ 518 Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateKey, &EnumerateKeyInfo); 519 if (NT_SUCCESS(Status)) 520 { 521 /* Call the internal API */ 522 Status = CmEnumerateKey(KeyObject->KeyControlBlock, 523 Index, 524 KeyInformationClass, 525 KeyInformation, 526 Length, 527 ResultLength); 528 529 /* Do the post callback */ 530 PostOperationInfo.Status = Status; 531 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo); 532 } 533 534 /* Dereference and return status */ 535 ObDereferenceObject(KeyObject); 536 DPRINT("Returning status %x.\n", Status); 537 return Status; 538 } 539 540 NTSTATUS 541 NTAPI 542 NtEnumerateValueKey(IN HANDLE KeyHandle, 543 IN ULONG Index, 544 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 545 OUT PVOID KeyValueInformation, 546 IN ULONG Length, 547 OUT PULONG ResultLength) 548 { 549 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 550 NTSTATUS Status; 551 PCM_KEY_BODY KeyObject; 552 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo; 553 REG_POST_OPERATION_INFORMATION PostOperationInfo; 554 555 PAGED_CODE(); 556 557 DPRINT("NtEnumerateValueKey() KH 0x%p, Index 0x%x, KVIC %d, Length %lu\n", 558 KeyHandle, Index, KeyValueInformationClass, Length); 559 560 /* Reject classes we don't know about */ 561 if ((KeyValueInformationClass != KeyValueBasicInformation) && 562 (KeyValueInformationClass != KeyValueFullInformation) && 563 (KeyValueInformationClass != KeyValuePartialInformation) && 564 (KeyValueInformationClass != KeyValueFullInformationAlign64) && 565 (KeyValueInformationClass != KeyValuePartialInformationAlign64)) 566 { 567 /* Fail */ 568 return STATUS_INVALID_PARAMETER; 569 } 570 571 /* Verify that the handle is valid and is a registry key */ 572 Status = ObReferenceObjectByHandle(KeyHandle, 573 KEY_QUERY_VALUE, 574 CmpKeyObjectType, 575 PreviousMode, 576 (PVOID*)&KeyObject, 577 NULL); 578 if (!NT_SUCCESS(Status)) return Status; 579 580 if (PreviousMode != KernelMode) 581 { 582 _SEH2_TRY 583 { 584 ProbeForWriteUlong(ResultLength); 585 ProbeForWrite(KeyValueInformation, 586 Length, 587 sizeof(ULONG)); 588 } 589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 590 { 591 /* Dereference and return status */ 592 ObDereferenceObject(KeyObject); 593 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 594 } 595 _SEH2_END; 596 } 597 598 /* Setup the callback */ 599 PostOperationInfo.Object = (PVOID)KeyObject; 600 EnumerateValueKeyInfo.Object = (PVOID)KeyObject; 601 EnumerateValueKeyInfo.Index = Index; 602 EnumerateValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass; 603 EnumerateValueKeyInfo.KeyValueInformation = KeyValueInformation; 604 EnumerateValueKeyInfo.Length = Length; 605 EnumerateValueKeyInfo.ResultLength = ResultLength; 606 607 /* Do the callback */ 608 Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey, 609 &EnumerateValueKeyInfo); 610 if (NT_SUCCESS(Status)) 611 { 612 /* Call the internal API */ 613 Status = CmEnumerateValueKey(KeyObject->KeyControlBlock, 614 Index, 615 KeyValueInformationClass, 616 KeyValueInformation, 617 Length, 618 ResultLength); 619 620 /* Do the post callback */ 621 PostOperationInfo.Status = Status; 622 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo); 623 } 624 625 /* Dereference and return status */ 626 ObDereferenceObject(KeyObject); 627 return Status; 628 } 629 630 NTSTATUS 631 NTAPI 632 NtQueryKey(IN HANDLE KeyHandle, 633 IN KEY_INFORMATION_CLASS KeyInformationClass, 634 OUT PVOID KeyInformation, 635 IN ULONG Length, 636 OUT PULONG ResultLength) 637 { 638 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 639 NTSTATUS Status; 640 PCM_KEY_BODY KeyObject; 641 REG_QUERY_KEY_INFORMATION QueryKeyInfo; 642 REG_POST_OPERATION_INFORMATION PostOperationInfo; 643 OBJECT_HANDLE_INFORMATION HandleInfo; 644 PAGED_CODE(); 645 DPRINT("NtQueryKey() KH 0x%p, KIC %d, Length %lu\n", 646 KeyHandle, KeyInformationClass, Length); 647 648 /* Reject invalid classes */ 649 if ((KeyInformationClass != KeyBasicInformation) && 650 (KeyInformationClass != KeyNodeInformation) && 651 (KeyInformationClass != KeyFullInformation) && 652 (KeyInformationClass != KeyNameInformation) && 653 (KeyInformationClass != KeyCachedInformation) && 654 (KeyInformationClass != KeyFlagsInformation)) 655 { 656 /* Fail */ 657 return STATUS_INVALID_PARAMETER; 658 } 659 660 /* Check if just the name is required */ 661 if (KeyInformationClass == KeyNameInformation) 662 { 663 /* Ignore access level */ 664 Status = ObReferenceObjectByHandle(KeyHandle, 665 0, 666 CmpKeyObjectType, 667 PreviousMode, 668 (PVOID*)&KeyObject, 669 &HandleInfo); 670 if (NT_SUCCESS(Status)) 671 { 672 /* At least a single bit of access is required */ 673 if (!HandleInfo.GrantedAccess) 674 { 675 /* No such luck */ 676 ObDereferenceObject(KeyObject); 677 Status = STATUS_ACCESS_DENIED; 678 } 679 } 680 } 681 else 682 { 683 /* Get a reference */ 684 Status = ObReferenceObjectByHandle(KeyHandle, 685 KEY_QUERY_VALUE, 686 CmpKeyObjectType, 687 PreviousMode, 688 (PVOID*)&KeyObject, 689 NULL); 690 } 691 692 /* Quit on failure */ 693 if (!NT_SUCCESS(Status)) return Status; 694 695 if (PreviousMode != KernelMode) 696 { 697 _SEH2_TRY 698 { 699 ProbeForWriteUlong(ResultLength); 700 ProbeForWrite(KeyInformation, 701 Length, 702 sizeof(ULONG)); 703 } 704 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 705 { 706 /* Dereference and return status */ 707 ObDereferenceObject(KeyObject); 708 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 709 } 710 _SEH2_END; 711 } 712 713 /* Setup the callback */ 714 PostOperationInfo.Object = (PVOID)KeyObject; 715 QueryKeyInfo.Object = (PVOID)KeyObject; 716 QueryKeyInfo.KeyInformationClass = KeyInformationClass; 717 QueryKeyInfo.KeyInformation = KeyInformation; 718 QueryKeyInfo.Length = Length; 719 QueryKeyInfo.ResultLength = ResultLength; 720 721 /* Do the callback */ 722 Status = CmiCallRegisteredCallbacks(RegNtPreQueryKey, &QueryKeyInfo); 723 if (NT_SUCCESS(Status)) 724 { 725 /* Call the internal API */ 726 Status = CmQueryKey(KeyObject->KeyControlBlock, 727 KeyInformationClass, 728 KeyInformation, 729 Length, 730 ResultLength); 731 732 /* Do the post callback */ 733 PostOperationInfo.Status = Status; 734 CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo); 735 } 736 737 /* Dereference and return status */ 738 ObDereferenceObject(KeyObject); 739 return Status; 740 } 741 742 NTSTATUS 743 NTAPI 744 NtQueryValueKey(IN HANDLE KeyHandle, 745 IN PUNICODE_STRING ValueName, 746 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 747 OUT PVOID KeyValueInformation, 748 IN ULONG Length, 749 OUT PULONG ResultLength) 750 { 751 NTSTATUS Status; 752 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 753 PCM_KEY_BODY KeyObject; 754 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo; 755 REG_POST_OPERATION_INFORMATION PostOperationInfo; 756 UNICODE_STRING ValueNameCopy; 757 758 PAGED_CODE(); 759 760 DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n", 761 KeyHandle, ValueName, KeyValueInformationClass, Length); 762 763 /* Reject classes we don't know about */ 764 if ((KeyValueInformationClass != KeyValueBasicInformation) && 765 (KeyValueInformationClass != KeyValueFullInformation) && 766 (KeyValueInformationClass != KeyValuePartialInformation) && 767 (KeyValueInformationClass != KeyValueFullInformationAlign64) && 768 (KeyValueInformationClass != KeyValuePartialInformationAlign64)) 769 { 770 /* Fail */ 771 return STATUS_INVALID_PARAMETER; 772 } 773 774 /* Verify that the handle is valid and is a registry key */ 775 Status = ObReferenceObjectByHandle(KeyHandle, 776 KEY_QUERY_VALUE, 777 CmpKeyObjectType, 778 PreviousMode, 779 (PVOID*)&KeyObject, 780 NULL); 781 if (!NT_SUCCESS(Status)) 782 return Status; 783 784 if (PreviousMode != KernelMode) 785 { 786 _SEH2_TRY 787 { 788 ProbeForWriteUlong(ResultLength); 789 ProbeForWrite(KeyValueInformation, 790 Length, 791 sizeof(ULONG)); 792 } 793 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 794 { 795 /* Dereference and return status */ 796 ObDereferenceObject(KeyObject); 797 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 798 } 799 _SEH2_END; 800 } 801 802 /* Capture the string */ 803 Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName); 804 if (!NT_SUCCESS(Status)) 805 goto Quit; 806 807 /* Make sure the name is aligned properly */ 808 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) 809 { 810 /* It isn't, so we'll fail */ 811 Status = STATUS_INVALID_PARAMETER; 812 goto Quit; 813 } 814 815 /* Ignore any null characters at the end */ 816 while ((ValueNameCopy.Length) && 817 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1])) 818 { 819 /* Skip it */ 820 ValueNameCopy.Length -= sizeof(WCHAR); 821 } 822 823 /* Setup the callback */ 824 PostOperationInfo.Object = (PVOID)KeyObject; 825 QueryValueKeyInfo.Object = (PVOID)KeyObject; 826 QueryValueKeyInfo.ValueName = &ValueNameCopy; 827 QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass; 828 QueryValueKeyInfo.Length = Length; 829 QueryValueKeyInfo.ResultLength = ResultLength; 830 831 /* Do the callback */ 832 Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo); 833 if (NT_SUCCESS(Status)) 834 { 835 /* Call the internal API */ 836 Status = CmQueryValueKey(KeyObject->KeyControlBlock, 837 ValueNameCopy, 838 KeyValueInformationClass, 839 KeyValueInformation, 840 Length, 841 ResultLength); 842 843 /* Do the post callback */ 844 PostOperationInfo.Status = Status; 845 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo); 846 } 847 848 Quit: 849 if (ValueNameCopy.Buffer) 850 ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode); 851 852 /* Dereference and return status */ 853 ObDereferenceObject(KeyObject); 854 return Status; 855 } 856 857 NTSTATUS 858 NTAPI 859 NtSetValueKey(IN HANDLE KeyHandle, 860 IN PUNICODE_STRING ValueName, 861 IN ULONG TitleIndex, 862 IN ULONG Type, 863 IN PVOID Data, 864 IN ULONG DataSize) 865 { 866 NTSTATUS Status = STATUS_SUCCESS; 867 KPROCESSOR_MODE PreviousMode; 868 PCM_KEY_BODY KeyObject; 869 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo; 870 REG_POST_OPERATION_INFORMATION PostOperationInfo; 871 UNICODE_STRING ValueNameCopy; 872 873 PAGED_CODE(); 874 875 PreviousMode = ExGetPreviousMode(); 876 877 /* Verify that the handle is valid and is a registry key */ 878 Status = ObReferenceObjectByHandle(KeyHandle, 879 KEY_SET_VALUE, 880 CmpKeyObjectType, 881 PreviousMode, 882 (PVOID*)&KeyObject, 883 NULL); 884 if (!NT_SUCCESS(Status)) 885 return Status; 886 887 if (!DataSize) 888 Data = NULL; 889 890 /* Probe and copy the data */ 891 if ((PreviousMode != KernelMode) && (DataSize != 0)) 892 { 893 PVOID DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM); 894 if (!DataCopy) 895 { 896 /* Dereference and return status */ 897 ObDereferenceObject(KeyObject); 898 return STATUS_INSUFFICIENT_RESOURCES; 899 } 900 _SEH2_TRY 901 { 902 ProbeForRead(Data, DataSize, 1); 903 RtlCopyMemory(DataCopy, Data, DataSize); 904 } 905 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 906 { 907 Status = _SEH2_GetExceptionCode(); 908 } 909 _SEH2_END; 910 911 if (!NT_SUCCESS(Status)) 912 { 913 /* Dereference and return status */ 914 ExFreePoolWithTag(DataCopy, TAG_CM); 915 ObDereferenceObject(KeyObject); 916 return Status; 917 } 918 Data = DataCopy; 919 } 920 921 /* Capture the string */ 922 Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName); 923 if (!NT_SUCCESS(Status)) 924 goto Quit; 925 926 DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n", 927 KeyHandle, &ValueNameCopy, TitleIndex, Type, DataSize); 928 929 /* Make sure the name is aligned, not too long, and the data under 4GB */ 930 if ( (ValueNameCopy.Length > 32767) || 931 ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) || 932 (DataSize > 0x80000000)) 933 { 934 /* Fail */ 935 Status = STATUS_INVALID_PARAMETER; 936 goto Quit; 937 } 938 939 /* Ignore any null characters at the end */ 940 while ((ValueNameCopy.Length) && 941 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1])) 942 { 943 /* Skip it */ 944 ValueNameCopy.Length -= sizeof(WCHAR); 945 } 946 947 /* Don't touch read-only keys */ 948 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) 949 { 950 /* Fail */ 951 Status = STATUS_ACCESS_DENIED; 952 goto Quit; 953 } 954 955 /* Setup callback */ 956 PostOperationInfo.Object = (PVOID)KeyObject; 957 SetValueKeyInfo.Object = (PVOID)KeyObject; 958 SetValueKeyInfo.ValueName = &ValueNameCopy; 959 SetValueKeyInfo.TitleIndex = TitleIndex; 960 SetValueKeyInfo.Type = Type; 961 SetValueKeyInfo.Data = Data; 962 SetValueKeyInfo.DataSize = DataSize; 963 964 /* Do the callback */ 965 Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo); 966 if (NT_SUCCESS(Status)) 967 { 968 /* Call the internal API */ 969 Status = CmSetValueKey(KeyObject->KeyControlBlock, 970 &ValueNameCopy, 971 Type, 972 Data, 973 DataSize); 974 975 /* Do the post-callback */ 976 PostOperationInfo.Status = Status; 977 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo); 978 } 979 980 Quit: 981 if (ValueNameCopy.Buffer) 982 ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode); 983 984 if ((PreviousMode != KernelMode) && Data) 985 ExFreePoolWithTag(Data, TAG_CM); 986 987 /* Dereference and return status */ 988 ObDereferenceObject(KeyObject); 989 return Status; 990 } 991 992 NTSTATUS 993 NTAPI 994 NtDeleteValueKey(IN HANDLE KeyHandle, 995 IN PUNICODE_STRING ValueName) 996 { 997 NTSTATUS Status; 998 PCM_KEY_BODY KeyObject; 999 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo; 1000 REG_POST_OPERATION_INFORMATION PostOperationInfo; 1001 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1002 UNICODE_STRING ValueNameCopy; 1003 1004 PAGED_CODE(); 1005 1006 /* Verify that the handle is valid and is a registry key */ 1007 Status = ObReferenceObjectByHandle(KeyHandle, 1008 KEY_SET_VALUE, 1009 CmpKeyObjectType, 1010 PreviousMode, 1011 (PVOID*)&KeyObject, 1012 NULL); 1013 if (!NT_SUCCESS(Status)) 1014 return Status; 1015 1016 /* Capture the string */ 1017 Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName); 1018 if (!NT_SUCCESS(Status)) 1019 goto Quit; 1020 1021 /* Make sure the name is aligned properly */ 1022 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) 1023 { 1024 /* It isn't, so we'll fail */ 1025 Status = STATUS_INVALID_PARAMETER; 1026 goto Quit; 1027 } 1028 1029 /* Don't touch read-only keys */ 1030 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) 1031 { 1032 /* Fail */ 1033 Status = STATUS_ACCESS_DENIED; 1034 goto Quit; 1035 } 1036 1037 /* Do the callback */ 1038 DeleteValueKeyInfo.Object = (PVOID)KeyObject; 1039 DeleteValueKeyInfo.ValueName = ValueName; 1040 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey, 1041 &DeleteValueKeyInfo); 1042 if (NT_SUCCESS(Status)) 1043 { 1044 /* Call the internal API */ 1045 Status = CmDeleteValueKey(KeyObject->KeyControlBlock, ValueNameCopy); 1046 1047 /* Do the post callback */ 1048 PostOperationInfo.Object = (PVOID)KeyObject; 1049 PostOperationInfo.Status = Status; 1050 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey, 1051 &PostOperationInfo); 1052 } 1053 1054 Quit: 1055 if (ValueNameCopy.Buffer) 1056 ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode); 1057 1058 /* Dereference and return status */ 1059 ObDereferenceObject(KeyObject); 1060 return Status; 1061 } 1062 1063 NTSTATUS 1064 NTAPI 1065 NtFlushKey(IN HANDLE KeyHandle) 1066 { 1067 NTSTATUS Status; 1068 PCM_KEY_BODY KeyObject; 1069 PAGED_CODE(); 1070 1071 /* Get the key object */ 1072 Status = ObReferenceObjectByHandle(KeyHandle, 1073 0, 1074 CmpKeyObjectType, 1075 ExGetPreviousMode(), 1076 (PVOID*)&KeyObject, 1077 NULL); 1078 if (!NT_SUCCESS(Status)) return Status; 1079 1080 /* Lock the registry */ 1081 CmpLockRegistry(); 1082 1083 /* Lock the KCB */ 1084 CmpAcquireKcbLockShared(KeyObject->KeyControlBlock); 1085 1086 /* Make sure KCB isn't deleted */ 1087 if (KeyObject->KeyControlBlock->Delete) 1088 { 1089 /* Fail */ 1090 Status = STATUS_KEY_DELETED; 1091 } 1092 else 1093 { 1094 /* Call the internal API */ 1095 Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE); 1096 } 1097 1098 /* Release the locks */ 1099 CmpReleaseKcbLock(KeyObject->KeyControlBlock); 1100 CmpUnlockRegistry(); 1101 1102 /* Dereference the object and return status */ 1103 ObDereferenceObject(KeyObject); 1104 return Status; 1105 } 1106 1107 NTSTATUS 1108 NTAPI 1109 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes, 1110 IN POBJECT_ATTRIBUTES FileObjectAttributes) 1111 { 1112 /* Call the newer API */ 1113 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, 0, NULL); 1114 } 1115 1116 NTSTATUS 1117 NTAPI 1118 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes, 1119 IN POBJECT_ATTRIBUTES FileObjectAttributes, 1120 IN ULONG Flags) 1121 { 1122 /* Call the newer API */ 1123 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL); 1124 } 1125 1126 NTSTATUS 1127 NTAPI 1128 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey, 1129 IN POBJECT_ATTRIBUTES SourceFile, 1130 IN ULONG Flags, 1131 IN HANDLE TrustClassKey) 1132 { 1133 NTSTATUS Status; 1134 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1135 OBJECT_ATTRIBUTES CapturedTargetKey; 1136 OBJECT_ATTRIBUTES CapturedSourceFile; 1137 UNICODE_STRING TargetKeyName, SourceFileName; 1138 HANDLE KmTargetKeyRootDir = NULL, KmSourceFileRootDir = NULL; 1139 PCM_KEY_BODY KeyBody = NULL; 1140 1141 PAGED_CODE(); 1142 1143 /* Validate flags */ 1144 if (Flags & ~REG_NO_LAZY_FLUSH) 1145 return STATUS_INVALID_PARAMETER; 1146 1147 /* Validate privilege */ 1148 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode)) 1149 { 1150 DPRINT1("Restore Privilege missing!\n"); 1151 return STATUS_PRIVILEGE_NOT_HELD; 1152 } 1153 1154 /* Block APCs */ 1155 KeEnterCriticalRegion(); 1156 1157 /* Check for user-mode caller */ 1158 if (PreviousMode != KernelMode) 1159 { 1160 /* Prepare to probe parameters */ 1161 _SEH2_TRY 1162 { 1163 /* Probe target key */ 1164 ProbeForRead(TargetKey, 1165 sizeof(OBJECT_ATTRIBUTES), 1166 sizeof(ULONG)); 1167 1168 /* Probe source file */ 1169 ProbeForRead(SourceFile, 1170 sizeof(OBJECT_ATTRIBUTES), 1171 sizeof(ULONG)); 1172 } 1173 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1174 { 1175 /* Return the exception code */ 1176 Status = _SEH2_GetExceptionCode(); 1177 _SEH2_YIELD(goto Quit); 1178 } 1179 _SEH2_END; 1180 } 1181 1182 /* Probe and capture the target key attributes, including the security */ 1183 Status = ProbeAndCaptureObjectAttributes(&CapturedTargetKey, 1184 &TargetKeyName, 1185 PreviousMode, 1186 TargetKey, 1187 TRUE); 1188 if (!NT_SUCCESS(Status)) 1189 goto Quit; 1190 1191 /* 1192 * Probe and capture the source file attributes, but not the security. 1193 * A proper security context is built by CmLoadKey(). 1194 */ 1195 Status = ProbeAndCaptureObjectAttributes(&CapturedSourceFile, 1196 &SourceFileName, 1197 PreviousMode, 1198 SourceFile, 1199 FALSE); 1200 if (!NT_SUCCESS(Status)) 1201 { 1202 ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode); 1203 goto Quit; 1204 } 1205 1206 /* Make sure the target key root directory handle is a kernel handle */ 1207 Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory, 1208 CmpKeyObjectType, 1209 KEY_READ, 1210 PreviousMode, 1211 &KmTargetKeyRootDir); 1212 if (!NT_SUCCESS(Status)) 1213 goto Cleanup; 1214 CapturedTargetKey.RootDirectory = KmTargetKeyRootDir; 1215 CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE; 1216 1217 /* Make sure the source file root directory handle is a kernel handle */ 1218 Status = CmpConvertHandleToKernelHandle(CapturedSourceFile.RootDirectory, 1219 IoFileObjectType, 1220 FILE_TRAVERSE, 1221 PreviousMode, 1222 &KmSourceFileRootDir); 1223 if (!NT_SUCCESS(Status)) 1224 goto Cleanup; 1225 CapturedSourceFile.RootDirectory = KmSourceFileRootDir; 1226 CapturedSourceFile.Attributes |= OBJ_KERNEL_HANDLE; 1227 1228 /* Check if we have a trust class */ 1229 if (TrustClassKey) 1230 { 1231 /* Reference it */ 1232 Status = ObReferenceObjectByHandle(TrustClassKey, 1233 0, 1234 CmpKeyObjectType, 1235 PreviousMode, 1236 (PVOID*)&KeyBody, 1237 NULL); 1238 } 1239 1240 /* Call the internal API */ 1241 Status = CmLoadKey(&CapturedTargetKey, 1242 &CapturedSourceFile, 1243 Flags, 1244 KeyBody); 1245 1246 /* Dereference the trust key, if any */ 1247 if (KeyBody) ObDereferenceObject(KeyBody); 1248 1249 Cleanup: 1250 /* Close the local kernel handles */ 1251 if (KmSourceFileRootDir) 1252 ObCloseHandle(KmSourceFileRootDir, KernelMode); 1253 if (KmTargetKeyRootDir) 1254 ObCloseHandle(KmTargetKeyRootDir, KernelMode); 1255 1256 /* Release the captured object attributes */ 1257 ReleaseCapturedObjectAttributes(&CapturedSourceFile, PreviousMode); 1258 ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode); 1259 1260 Quit: 1261 /* Bring back APCs */ 1262 KeLeaveCriticalRegion(); 1263 1264 /* Return status */ 1265 return Status; 1266 } 1267 1268 NTSTATUS 1269 NTAPI 1270 NtNotifyChangeKey(IN HANDLE KeyHandle, 1271 IN HANDLE Event, 1272 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1273 IN PVOID ApcContext OPTIONAL, 1274 OUT PIO_STATUS_BLOCK IoStatusBlock, 1275 IN ULONG CompletionFilter, 1276 IN BOOLEAN WatchTree, 1277 OUT PVOID Buffer, 1278 IN ULONG Length, 1279 IN BOOLEAN Asynchronous) 1280 { 1281 /* Call the newer API */ 1282 return NtNotifyChangeMultipleKeys(KeyHandle, 1283 0, 1284 NULL, 1285 Event, 1286 ApcRoutine, 1287 ApcContext, 1288 IoStatusBlock, 1289 CompletionFilter, 1290 WatchTree, 1291 Buffer, 1292 Length, 1293 Asynchronous); 1294 } 1295 1296 NTSTATUS 1297 NTAPI 1298 NtInitializeRegistry(IN USHORT Flag) 1299 { 1300 BOOLEAN SetupBoot; 1301 NTSTATUS Status = STATUS_SUCCESS; 1302 PAGED_CODE(); 1303 1304 /* Always do this as kernel mode */ 1305 if (KeGetPreviousMode() == UserMode) 1306 return ZwInitializeRegistry(Flag); 1307 1308 /* Enough of the system has booted by now */ 1309 Ki386PerfEnd(); 1310 1311 /* Validate flag */ 1312 if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER; 1313 1314 /* Check if boot was accepted */ 1315 if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX)) 1316 { 1317 /* Only allow once */ 1318 if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED; 1319 CmBootAcceptFirstTime = FALSE; 1320 1321 /* Get the control set accepted */ 1322 Flag -= CM_BOOT_FLAG_ACCEPTED; 1323 if (Flag) 1324 { 1325 /* Save the last known good boot */ 1326 Status = CmpSaveBootControlSet(Flag); 1327 1328 /* Notify HAL */ 1329 HalEndOfBoot(); 1330 1331 /* Enable lazy flush */ 1332 CmpHoldLazyFlush = FALSE; 1333 CmpLazyFlush(); 1334 return Status; 1335 } 1336 1337 /* Otherwise, invalid boot */ 1338 return STATUS_INVALID_PARAMETER; 1339 } 1340 1341 /* Check if this was a setup boot */ 1342 SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE); 1343 1344 /* Make sure we're only called once */ 1345 if (!CmFirstTime) return STATUS_ACCESS_DENIED; 1346 CmFirstTime = FALSE; 1347 1348 /* Lock the registry exclusively */ 1349 CmpLockRegistryExclusive(); 1350 1351 /* Initialize the hives and lazy flusher */ 1352 CmpCmdInit(SetupBoot); 1353 1354 /* Save version data */ 1355 CmpSetVersionData(); 1356 1357 /* Release the registry lock */ 1358 CmpUnlockRegistry(); 1359 return STATUS_SUCCESS; 1360 } 1361 1362 NTSTATUS 1363 NTAPI 1364 NtCompactKeys(IN ULONG Count, 1365 IN PHANDLE KeyArray) 1366 { 1367 UNIMPLEMENTED; 1368 return STATUS_NOT_IMPLEMENTED; 1369 } 1370 1371 NTSTATUS 1372 NTAPI 1373 NtCompressKey(IN HANDLE Key) 1374 { 1375 UNIMPLEMENTED; 1376 return STATUS_NOT_IMPLEMENTED; 1377 } 1378 1379 // FIXME: different for different windows versions! 1380 #define PRODUCT_ACTIVATION_VERSION 7749 1381 1382 NTSTATUS 1383 NTAPI 1384 NtLockProductActivationKeys(IN PULONG pPrivateVer, 1385 IN PULONG pSafeMode) 1386 { 1387 KPROCESSOR_MODE PreviousMode; 1388 1389 PreviousMode = ExGetPreviousMode(); 1390 _SEH2_TRY 1391 { 1392 /* Check if the caller asked for the version */ 1393 if (pPrivateVer != NULL) 1394 { 1395 /* For user mode, probe it */ 1396 if (PreviousMode != KernelMode) 1397 { 1398 ProbeForWriteUlong(pPrivateVer); 1399 } 1400 1401 /* Return the expected version */ 1402 *pPrivateVer = PRODUCT_ACTIVATION_VERSION; 1403 } 1404 1405 /* Check if the caller asked for safe mode mode state */ 1406 if (pSafeMode != NULL) 1407 { 1408 /* For user mode, probe it */ 1409 if (PreviousMode != KernelMode) 1410 { 1411 ProbeForWriteUlong(pSafeMode); 1412 } 1413 1414 /* Return the safe boot mode state */ 1415 *pSafeMode = InitSafeBootMode; 1416 } 1417 } 1418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1419 { 1420 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1421 } 1422 _SEH2_END; 1423 1424 return STATUS_SUCCESS; 1425 } 1426 1427 NTSTATUS 1428 NTAPI 1429 NtLockRegistryKey(IN HANDLE KeyHandle) 1430 { 1431 UNIMPLEMENTED; 1432 return STATUS_NOT_IMPLEMENTED; 1433 } 1434 1435 NTSTATUS 1436 NTAPI 1437 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle, 1438 IN ULONG Count, 1439 IN POBJECT_ATTRIBUTES SlaveObjects, 1440 IN HANDLE Event, 1441 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1442 IN PVOID ApcContext OPTIONAL, 1443 OUT PIO_STATUS_BLOCK IoStatusBlock, 1444 IN ULONG CompletionFilter, 1445 IN BOOLEAN WatchTree, 1446 OUT PVOID Buffer, 1447 IN ULONG Length, 1448 IN BOOLEAN Asynchronous) 1449 { 1450 UNIMPLEMENTED_ONCE; 1451 return STATUS_NOT_IMPLEMENTED; 1452 } 1453 1454 NTSTATUS 1455 NTAPI 1456 NtQueryMultipleValueKey(IN HANDLE KeyHandle, 1457 IN OUT PKEY_VALUE_ENTRY ValueList, 1458 IN ULONG NumberOfValues, 1459 OUT PVOID Buffer, 1460 IN OUT PULONG Length, 1461 OUT PULONG ReturnLength) 1462 { 1463 UNIMPLEMENTED; 1464 return STATUS_NOT_IMPLEMENTED; 1465 } 1466 1467 NTSTATUS 1468 NTAPI 1469 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey, 1470 OUT PULONG HandleCount) 1471 { 1472 KPROCESSOR_MODE PreviousMode; 1473 PCM_KEY_BODY KeyBody = NULL; 1474 HANDLE KeyHandle; 1475 NTSTATUS Status; 1476 ULONG SubKeys; 1477 1478 DPRINT("NtQueryOpenSubKeys()\n"); 1479 1480 PAGED_CODE(); 1481 1482 /* Get the processor mode */ 1483 PreviousMode = KeGetPreviousMode(); 1484 1485 /* Check for user-mode caller */ 1486 if (PreviousMode != KernelMode) 1487 { 1488 /* Prepare to probe parameters */ 1489 _SEH2_TRY 1490 { 1491 /* Probe target key */ 1492 ProbeForRead(TargetKey, 1493 sizeof(OBJECT_ATTRIBUTES), 1494 sizeof(ULONG)); 1495 1496 /* Probe handle count */ 1497 ProbeForWriteUlong(HandleCount); 1498 } 1499 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1500 { 1501 /* Return the exception code */ 1502 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1503 } 1504 _SEH2_END; 1505 } 1506 1507 /* Open a handle to the key */ 1508 Status = ObOpenObjectByName(TargetKey, 1509 CmpKeyObjectType, 1510 PreviousMode, 1511 NULL, 1512 KEY_READ, 1513 NULL, 1514 &KeyHandle); 1515 if (NT_SUCCESS(Status)) 1516 { 1517 /* Reference the key object */ 1518 Status = ObReferenceObjectByHandle(KeyHandle, 1519 KEY_READ, 1520 CmpKeyObjectType, 1521 PreviousMode, 1522 (PVOID*)&KeyBody, 1523 NULL); 1524 1525 /* Close the handle */ 1526 NtClose(KeyHandle); 1527 } 1528 1529 /* Fail, if the key object could not be referenced */ 1530 if (!NT_SUCCESS(Status)) 1531 return Status; 1532 1533 /* Lock the registry exclusively */ 1534 CmpLockRegistryExclusive(); 1535 1536 /* Fail, if we did not open a hive root key */ 1537 if (KeyBody->KeyControlBlock->KeyCell != 1538 KeyBody->KeyControlBlock->KeyHive->BaseBlock->RootCell) 1539 { 1540 DPRINT("Error: Key is not a hive root key!\n"); 1541 CmpUnlockRegistry(); 1542 ObDereferenceObject(KeyBody); 1543 return STATUS_INVALID_PARAMETER; 1544 } 1545 1546 /* Call the internal API */ 1547 SubKeys = CmpEnumerateOpenSubKeys(KeyBody->KeyControlBlock, 1548 FALSE, FALSE); 1549 1550 /* Unlock the registry */ 1551 CmpUnlockRegistry(); 1552 1553 /* Dereference the key object */ 1554 ObDereferenceObject(KeyBody); 1555 1556 /* Write back the result */ 1557 _SEH2_TRY 1558 { 1559 *HandleCount = SubKeys; 1560 } 1561 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1562 { 1563 Status = _SEH2_GetExceptionCode(); 1564 } 1565 _SEH2_END; 1566 1567 DPRINT("Done.\n"); 1568 1569 return Status; 1570 } 1571 1572 NTSTATUS 1573 NTAPI 1574 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey, 1575 IN ULONG BufferLength, 1576 IN PVOID Buffer, 1577 IN PULONG RequiredSize) 1578 { 1579 UNIMPLEMENTED; 1580 return STATUS_NOT_IMPLEMENTED; 1581 } 1582 1583 NTSTATUS 1584 NTAPI 1585 NtRenameKey(IN HANDLE KeyHandle, 1586 IN PUNICODE_STRING ReplacementName) 1587 { 1588 UNIMPLEMENTED; 1589 return STATUS_NOT_IMPLEMENTED; 1590 } 1591 1592 NTSTATUS 1593 NTAPI 1594 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes, 1595 IN HANDLE Key, 1596 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes) 1597 { 1598 UNIMPLEMENTED; 1599 return STATUS_NOT_IMPLEMENTED; 1600 } 1601 1602 NTSTATUS 1603 NTAPI 1604 NtRestoreKey(IN HANDLE KeyHandle, 1605 IN HANDLE FileHandle, 1606 IN ULONG RestoreFlags) 1607 { 1608 UNIMPLEMENTED; 1609 return STATUS_NOT_IMPLEMENTED; 1610 } 1611 1612 NTSTATUS 1613 NTAPI 1614 NtSaveKey(IN HANDLE KeyHandle, 1615 IN HANDLE FileHandle) 1616 { 1617 /* Call the extended API */ 1618 return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT); 1619 } 1620 1621 NTSTATUS 1622 NTAPI 1623 NtSaveKeyEx(IN HANDLE KeyHandle, 1624 IN HANDLE FileHandle, 1625 IN ULONG Flags) 1626 { 1627 NTSTATUS Status; 1628 HANDLE KmFileHandle = NULL; 1629 PCM_KEY_BODY KeyObject; 1630 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1631 1632 PAGED_CODE(); 1633 1634 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle, FileHandle, Flags); 1635 1636 /* Verify the flags */ 1637 if ((Flags != REG_STANDARD_FORMAT) 1638 && (Flags != REG_LATEST_FORMAT) 1639 && (Flags != REG_NO_COMPRESSION)) 1640 { 1641 /* Only one of these values can be specified */ 1642 return STATUS_INVALID_PARAMETER; 1643 } 1644 1645 /* Validate privilege */ 1646 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode)) 1647 { 1648 return STATUS_PRIVILEGE_NOT_HELD; 1649 } 1650 1651 /* Make sure the target file handle is a kernel handle */ 1652 Status = CmpConvertHandleToKernelHandle(FileHandle, 1653 IoFileObjectType, 1654 FILE_WRITE_DATA, 1655 PreviousMode, 1656 &KmFileHandle); 1657 if (!NT_SUCCESS(Status)) 1658 goto Quit; 1659 1660 /* Verify that the handle is valid and is a registry key */ 1661 Status = ObReferenceObjectByHandle(KeyHandle, 1662 KEY_READ, 1663 CmpKeyObjectType, 1664 PreviousMode, 1665 (PVOID*)&KeyObject, 1666 NULL); 1667 if (!NT_SUCCESS(Status)) 1668 goto Quit; 1669 1670 /* Call the internal API */ 1671 Status = CmSaveKey(KeyObject->KeyControlBlock, KmFileHandle, Flags); 1672 1673 /* Dereference the registry key */ 1674 ObDereferenceObject(KeyObject); 1675 1676 Quit: 1677 /* Close the local kernel handle */ 1678 if (KmFileHandle) 1679 ObCloseHandle(KmFileHandle, KernelMode); 1680 1681 return Status; 1682 } 1683 1684 NTSTATUS 1685 NTAPI 1686 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle, 1687 IN HANDLE LowPrecedenceKeyHandle, 1688 IN HANDLE FileHandle) 1689 { 1690 NTSTATUS Status; 1691 KPROCESSOR_MODE PreviousMode; 1692 HANDLE KmFileHandle = NULL; 1693 PCM_KEY_BODY HighPrecedenceKeyObject = NULL; 1694 PCM_KEY_BODY LowPrecedenceKeyObject = NULL; 1695 1696 PAGED_CODE(); 1697 1698 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n", 1699 HighPrecedenceKeyHandle, LowPrecedenceKeyHandle, FileHandle); 1700 1701 PreviousMode = ExGetPreviousMode(); 1702 1703 /* Validate privilege */ 1704 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode)) 1705 { 1706 return STATUS_PRIVILEGE_NOT_HELD; 1707 } 1708 1709 /* Make sure the target file handle is a kernel handle */ 1710 Status = CmpConvertHandleToKernelHandle(FileHandle, 1711 IoFileObjectType, 1712 FILE_WRITE_DATA, 1713 PreviousMode, 1714 &KmFileHandle); 1715 if (!NT_SUCCESS(Status)) 1716 goto Quit; 1717 1718 /* Verify that the handles are valid and are registry keys */ 1719 Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle, 1720 KEY_READ, 1721 CmpKeyObjectType, 1722 PreviousMode, 1723 (PVOID*)&HighPrecedenceKeyObject, 1724 NULL); 1725 if (!NT_SUCCESS(Status)) 1726 goto Quit; 1727 1728 Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle, 1729 KEY_READ, 1730 CmpKeyObjectType, 1731 PreviousMode, 1732 (PVOID*)&LowPrecedenceKeyObject, 1733 NULL); 1734 if (!NT_SUCCESS(Status)) 1735 goto Quit; 1736 1737 /* Call the internal API */ 1738 Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock, 1739 LowPrecedenceKeyObject->KeyControlBlock, 1740 KmFileHandle); 1741 1742 Quit: 1743 /* Dereference the opened key objects */ 1744 if (LowPrecedenceKeyObject) 1745 ObDereferenceObject(LowPrecedenceKeyObject); 1746 if (HighPrecedenceKeyObject) 1747 ObDereferenceObject(HighPrecedenceKeyObject); 1748 1749 /* Close the local kernel handle */ 1750 if (KmFileHandle) 1751 ObCloseHandle(KmFileHandle, KernelMode); 1752 1753 return Status; 1754 } 1755 1756 NTSTATUS 1757 NTAPI 1758 NtSetInformationKey(IN HANDLE KeyHandle, 1759 IN KEY_SET_INFORMATION_CLASS KeyInformationClass, 1760 IN PVOID KeyInformation, 1761 IN ULONG KeyInformationLength) 1762 { 1763 UNIMPLEMENTED; 1764 return STATUS_NOT_IMPLEMENTED; 1765 } 1766 1767 NTSTATUS 1768 NTAPI 1769 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes) 1770 { 1771 return NtUnloadKey2(KeyObjectAttributes, 0); 1772 } 1773 1774 NTSTATUS 1775 NTAPI 1776 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey, 1777 IN ULONG Flags) 1778 { 1779 NTSTATUS Status; 1780 OBJECT_ATTRIBUTES CapturedTargetKey; 1781 UNICODE_STRING ObjectName; 1782 HANDLE KmTargetKeyRootDir = NULL; 1783 CM_PARSE_CONTEXT ParseContext = {0}; 1784 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1785 PCM_KEY_BODY KeyBody = NULL; 1786 ULONG ParentConv = 0, ChildConv = 0; 1787 HANDLE Handle; 1788 1789 PAGED_CODE(); 1790 1791 /* Validate privilege */ 1792 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode)) 1793 { 1794 DPRINT1("Restore Privilege missing!\n"); 1795 return STATUS_PRIVILEGE_NOT_HELD; 1796 } 1797 1798 /* Check for user-mode caller */ 1799 if (PreviousMode != KernelMode) 1800 { 1801 /* Prepare to probe parameters */ 1802 _SEH2_TRY 1803 { 1804 /* Probe object attributes */ 1805 ProbeForRead(TargetKey, 1806 sizeof(OBJECT_ATTRIBUTES), 1807 sizeof(ULONG)); 1808 1809 CapturedTargetKey = *TargetKey; 1810 1811 /* Probe the string */ 1812 ObjectName = ProbeForReadUnicodeString(CapturedTargetKey.ObjectName); 1813 ProbeForRead(ObjectName.Buffer, 1814 ObjectName.Length, 1815 sizeof(WCHAR)); 1816 1817 CapturedTargetKey.ObjectName = &ObjectName; 1818 } 1819 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1820 { 1821 /* Return the exception code */ 1822 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1823 } 1824 _SEH2_END; 1825 } 1826 else 1827 { 1828 /* Save the target attributes directly */ 1829 CapturedTargetKey = *TargetKey; 1830 } 1831 1832 /* Make sure the target key root directory handle is a kernel handle */ 1833 Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory, 1834 CmpKeyObjectType, 1835 KEY_WRITE, 1836 PreviousMode, 1837 &KmTargetKeyRootDir); 1838 if (!NT_SUCCESS(Status)) 1839 return Status; 1840 CapturedTargetKey.RootDirectory = KmTargetKeyRootDir; 1841 CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE; 1842 1843 /* Setup the parse context */ 1844 ParseContext.CreateOperation = TRUE; 1845 ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE; 1846 1847 /* Do the create */ 1848 /* Open a local handle to the key */ 1849 Status = ObOpenObjectByName(&CapturedTargetKey, 1850 CmpKeyObjectType, 1851 KernelMode, 1852 NULL, 1853 KEY_WRITE, 1854 &ParseContext, 1855 &Handle); 1856 if (NT_SUCCESS(Status)) 1857 { 1858 /* Reference the key object */ 1859 Status = ObReferenceObjectByHandle(Handle, 1860 KEY_WRITE, 1861 CmpKeyObjectType, 1862 KernelMode, 1863 (PVOID*)&KeyBody, 1864 NULL); 1865 1866 /* Close the handle */ 1867 ObCloseHandle(Handle, KernelMode); 1868 } 1869 1870 /* Close the local kernel handle */ 1871 if (KmTargetKeyRootDir) 1872 ObCloseHandle(KmTargetKeyRootDir, KernelMode); 1873 1874 /* Return if a failure was encountered */ 1875 if (!NT_SUCCESS(Status)) 1876 return Status; 1877 1878 /* Acquire the lock depending on flags */ 1879 if (Flags == REG_FORCE_UNLOAD) 1880 { 1881 /* Lock registry exclusively */ 1882 CmpLockRegistryExclusive(); 1883 } 1884 else 1885 { 1886 /* Lock registry */ 1887 CmpLockRegistry(); 1888 1889 /* Acquire the hive loading lock */ 1890 ExAcquirePushLockExclusive(&CmpLoadHiveLock); 1891 1892 /* Lock parent and child */ 1893 if (KeyBody->KeyControlBlock->ParentKcb) 1894 ParentConv = KeyBody->KeyControlBlock->ParentKcb->ConvKey; 1895 else 1896 ParentConv = KeyBody->KeyControlBlock->ConvKey; 1897 1898 ChildConv = KeyBody->KeyControlBlock->ConvKey; 1899 1900 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv, ParentConv); 1901 } 1902 1903 /* Check if it's being deleted already */ 1904 if (KeyBody->KeyControlBlock->Delete) 1905 { 1906 /* Return appropriate status */ 1907 Status = STATUS_KEY_DELETED; 1908 goto Quit; 1909 } 1910 1911 /* Check if it's a read-only key */ 1912 if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) 1913 { 1914 /* Return appropriate status */ 1915 Status = STATUS_ACCESS_DENIED; 1916 goto Quit; 1917 } 1918 1919 /* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */ 1920 Status = CmUnloadKey(KeyBody->KeyControlBlock, Flags); 1921 1922 /* Check if we failed, but really need to succeed */ 1923 if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD)) 1924 { 1925 /* TODO: We should perform another attempt here */ 1926 _SEH2_TRY 1927 { 1928 DPRINT1("NtUnloadKey2(%wZ): We want to force-unload the hive but couldn't unload it: Retrying is UNIMPLEMENTED!\n", TargetKey->ObjectName); 1929 } 1930 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1931 { 1932 } 1933 _SEH2_END; 1934 } 1935 1936 /* If CmUnloadKey() failed we need to unlock registry ourselves */ 1937 if (!NT_SUCCESS(Status)) 1938 { 1939 if (Flags != REG_FORCE_UNLOAD) 1940 { 1941 /* Release the KCB locks */ 1942 CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv); 1943 1944 /* Release the hive loading lock */ 1945 ExReleasePushLockExclusive(&CmpLoadHiveLock); 1946 } 1947 1948 /* Unlock the registry */ 1949 CmpUnlockRegistry(); 1950 } 1951 1952 Quit: 1953 /* Dereference the key */ 1954 ObDereferenceObject(KeyBody); 1955 1956 /* Return status */ 1957 return Status; 1958 } 1959 1960 NTSTATUS 1961 NTAPI 1962 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey, 1963 IN HANDLE Event) 1964 { 1965 UNIMPLEMENTED; 1966 return STATUS_NOT_IMPLEMENTED; 1967 } 1968 1969 /* EOF */ 1970