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 ProbeForRead(pPrivateVer, sizeof(ULONG), sizeof(ULONG)); 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 ProbeForRead(pSafeMode, sizeof(ULONG), sizeof(ULONG)); 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 1477 DPRINT("NtQueryOpenSubKeys()\n"); 1478 1479 PAGED_CODE(); 1480 1481 /* Get the processor mode */ 1482 PreviousMode = KeGetPreviousMode(); 1483 1484 /* Check for user-mode caller */ 1485 if (PreviousMode != KernelMode) 1486 { 1487 /* Prepare to probe parameters */ 1488 _SEH2_TRY 1489 { 1490 /* Probe target key */ 1491 ProbeForRead(TargetKey, 1492 sizeof(OBJECT_ATTRIBUTES), 1493 sizeof(ULONG)); 1494 1495 /* Probe handle count */ 1496 ProbeForWriteUlong(HandleCount); 1497 } 1498 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1499 { 1500 /* Return the exception code */ 1501 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1502 } 1503 _SEH2_END; 1504 } 1505 1506 /* Open a handle to the key */ 1507 Status = ObOpenObjectByName(TargetKey, 1508 CmpKeyObjectType, 1509 PreviousMode, 1510 NULL, 1511 KEY_READ, 1512 NULL, 1513 &KeyHandle); 1514 if (NT_SUCCESS(Status)) 1515 { 1516 /* Reference the key object */ 1517 Status = ObReferenceObjectByHandle(KeyHandle, 1518 KEY_READ, 1519 CmpKeyObjectType, 1520 PreviousMode, 1521 (PVOID*)&KeyBody, 1522 NULL); 1523 1524 /* Close the handle */ 1525 NtClose(KeyHandle); 1526 } 1527 1528 /* Fail, if the key object could not be referenced */ 1529 if (!NT_SUCCESS(Status)) 1530 return Status; 1531 1532 /* Lock the registry exclusively */ 1533 CmpLockRegistryExclusive(); 1534 1535 /* Fail, if we did not open a hive root key */ 1536 if (KeyBody->KeyControlBlock->KeyCell != 1537 KeyBody->KeyControlBlock->KeyHive->BaseBlock->RootCell) 1538 { 1539 DPRINT("Error: Key is not a hive root key!\n"); 1540 CmpUnlockRegistry(); 1541 ObDereferenceObject(KeyBody); 1542 return STATUS_INVALID_PARAMETER; 1543 } 1544 1545 /* Call the internal API */ 1546 *HandleCount = CmpEnumerateOpenSubKeys(KeyBody->KeyControlBlock, 1547 FALSE, FALSE); 1548 1549 /* Unlock the registry */ 1550 CmpUnlockRegistry(); 1551 1552 /* Dereference the key object */ 1553 ObDereferenceObject(KeyBody); 1554 1555 DPRINT("Done.\n"); 1556 1557 return Status; 1558 } 1559 1560 NTSTATUS 1561 NTAPI 1562 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey, 1563 IN ULONG BufferLength, 1564 IN PVOID Buffer, 1565 IN PULONG RequiredSize) 1566 { 1567 UNIMPLEMENTED; 1568 return STATUS_NOT_IMPLEMENTED; 1569 } 1570 1571 NTSTATUS 1572 NTAPI 1573 NtRenameKey(IN HANDLE KeyHandle, 1574 IN PUNICODE_STRING ReplacementName) 1575 { 1576 UNIMPLEMENTED; 1577 return STATUS_NOT_IMPLEMENTED; 1578 } 1579 1580 NTSTATUS 1581 NTAPI 1582 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes, 1583 IN HANDLE Key, 1584 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes) 1585 { 1586 UNIMPLEMENTED; 1587 return STATUS_NOT_IMPLEMENTED; 1588 } 1589 1590 NTSTATUS 1591 NTAPI 1592 NtRestoreKey(IN HANDLE KeyHandle, 1593 IN HANDLE FileHandle, 1594 IN ULONG RestoreFlags) 1595 { 1596 UNIMPLEMENTED; 1597 return STATUS_NOT_IMPLEMENTED; 1598 } 1599 1600 NTSTATUS 1601 NTAPI 1602 NtSaveKey(IN HANDLE KeyHandle, 1603 IN HANDLE FileHandle) 1604 { 1605 /* Call the extended API */ 1606 return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT); 1607 } 1608 1609 NTSTATUS 1610 NTAPI 1611 NtSaveKeyEx(IN HANDLE KeyHandle, 1612 IN HANDLE FileHandle, 1613 IN ULONG Flags) 1614 { 1615 NTSTATUS Status; 1616 HANDLE KmFileHandle = NULL; 1617 PCM_KEY_BODY KeyObject; 1618 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1619 1620 PAGED_CODE(); 1621 1622 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle, FileHandle, Flags); 1623 1624 /* Verify the flags */ 1625 if ((Flags != REG_STANDARD_FORMAT) 1626 && (Flags != REG_LATEST_FORMAT) 1627 && (Flags != REG_NO_COMPRESSION)) 1628 { 1629 /* Only one of these values can be specified */ 1630 return STATUS_INVALID_PARAMETER; 1631 } 1632 1633 /* Validate privilege */ 1634 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode)) 1635 { 1636 return STATUS_PRIVILEGE_NOT_HELD; 1637 } 1638 1639 /* Make sure the target file handle is a kernel handle */ 1640 Status = CmpConvertHandleToKernelHandle(FileHandle, 1641 IoFileObjectType, 1642 FILE_WRITE_DATA, 1643 PreviousMode, 1644 &KmFileHandle); 1645 if (!NT_SUCCESS(Status)) 1646 goto Quit; 1647 1648 /* Verify that the handle is valid and is a registry key */ 1649 Status = ObReferenceObjectByHandle(KeyHandle, 1650 KEY_READ, 1651 CmpKeyObjectType, 1652 PreviousMode, 1653 (PVOID*)&KeyObject, 1654 NULL); 1655 if (!NT_SUCCESS(Status)) 1656 goto Quit; 1657 1658 /* Call the internal API */ 1659 Status = CmSaveKey(KeyObject->KeyControlBlock, KmFileHandle, Flags); 1660 1661 /* Dereference the registry key */ 1662 ObDereferenceObject(KeyObject); 1663 1664 Quit: 1665 /* Close the local kernel handle */ 1666 if (KmFileHandle) 1667 ObCloseHandle(KmFileHandle, KernelMode); 1668 1669 return Status; 1670 } 1671 1672 NTSTATUS 1673 NTAPI 1674 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle, 1675 IN HANDLE LowPrecedenceKeyHandle, 1676 IN HANDLE FileHandle) 1677 { 1678 NTSTATUS Status; 1679 KPROCESSOR_MODE PreviousMode; 1680 HANDLE KmFileHandle = NULL; 1681 PCM_KEY_BODY HighPrecedenceKeyObject = NULL; 1682 PCM_KEY_BODY LowPrecedenceKeyObject = NULL; 1683 1684 PAGED_CODE(); 1685 1686 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n", 1687 HighPrecedenceKeyHandle, LowPrecedenceKeyHandle, FileHandle); 1688 1689 PreviousMode = ExGetPreviousMode(); 1690 1691 /* Validate privilege */ 1692 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode)) 1693 { 1694 return STATUS_PRIVILEGE_NOT_HELD; 1695 } 1696 1697 /* Make sure the target file handle is a kernel handle */ 1698 Status = CmpConvertHandleToKernelHandle(FileHandle, 1699 IoFileObjectType, 1700 FILE_WRITE_DATA, 1701 PreviousMode, 1702 &KmFileHandle); 1703 if (!NT_SUCCESS(Status)) 1704 goto Quit; 1705 1706 /* Verify that the handles are valid and are registry keys */ 1707 Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle, 1708 KEY_READ, 1709 CmpKeyObjectType, 1710 PreviousMode, 1711 (PVOID*)&HighPrecedenceKeyObject, 1712 NULL); 1713 if (!NT_SUCCESS(Status)) 1714 goto Quit; 1715 1716 Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle, 1717 KEY_READ, 1718 CmpKeyObjectType, 1719 PreviousMode, 1720 (PVOID*)&LowPrecedenceKeyObject, 1721 NULL); 1722 if (!NT_SUCCESS(Status)) 1723 goto Quit; 1724 1725 /* Call the internal API */ 1726 Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock, 1727 LowPrecedenceKeyObject->KeyControlBlock, 1728 KmFileHandle); 1729 1730 Quit: 1731 /* Dereference the opened key objects */ 1732 if (LowPrecedenceKeyObject) 1733 ObDereferenceObject(LowPrecedenceKeyObject); 1734 if (HighPrecedenceKeyObject) 1735 ObDereferenceObject(HighPrecedenceKeyObject); 1736 1737 /* Close the local kernel handle */ 1738 if (KmFileHandle) 1739 ObCloseHandle(KmFileHandle, KernelMode); 1740 1741 return Status; 1742 } 1743 1744 NTSTATUS 1745 NTAPI 1746 NtSetInformationKey(IN HANDLE KeyHandle, 1747 IN KEY_SET_INFORMATION_CLASS KeyInformationClass, 1748 IN PVOID KeyInformation, 1749 IN ULONG KeyInformationLength) 1750 { 1751 UNIMPLEMENTED; 1752 return STATUS_NOT_IMPLEMENTED; 1753 } 1754 1755 NTSTATUS 1756 NTAPI 1757 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes) 1758 { 1759 return NtUnloadKey2(KeyObjectAttributes, 0); 1760 } 1761 1762 NTSTATUS 1763 NTAPI 1764 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey, 1765 IN ULONG Flags) 1766 { 1767 NTSTATUS Status; 1768 OBJECT_ATTRIBUTES CapturedTargetKey; 1769 UNICODE_STRING ObjectName; 1770 HANDLE KmTargetKeyRootDir = NULL; 1771 CM_PARSE_CONTEXT ParseContext = {0}; 1772 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1773 PCM_KEY_BODY KeyBody = NULL; 1774 ULONG ParentConv = 0, ChildConv = 0; 1775 HANDLE Handle; 1776 1777 PAGED_CODE(); 1778 1779 /* Validate privilege */ 1780 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode)) 1781 { 1782 DPRINT1("Restore Privilege missing!\n"); 1783 return STATUS_PRIVILEGE_NOT_HELD; 1784 } 1785 1786 /* Check for user-mode caller */ 1787 if (PreviousMode != KernelMode) 1788 { 1789 /* Prepare to probe parameters */ 1790 _SEH2_TRY 1791 { 1792 /* Probe object attributes */ 1793 ProbeForRead(TargetKey, 1794 sizeof(OBJECT_ATTRIBUTES), 1795 sizeof(ULONG)); 1796 1797 CapturedTargetKey = *TargetKey; 1798 1799 /* Probe the string */ 1800 ObjectName = ProbeForReadUnicodeString(CapturedTargetKey.ObjectName); 1801 ProbeForRead(ObjectName.Buffer, 1802 ObjectName.Length, 1803 sizeof(WCHAR)); 1804 1805 CapturedTargetKey.ObjectName = &ObjectName; 1806 } 1807 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1808 { 1809 /* Return the exception code */ 1810 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1811 } 1812 _SEH2_END; 1813 } 1814 else 1815 { 1816 /* Save the target attributes directly */ 1817 CapturedTargetKey = *TargetKey; 1818 } 1819 1820 /* Make sure the target key root directory handle is a kernel handle */ 1821 Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory, 1822 CmpKeyObjectType, 1823 KEY_WRITE, 1824 PreviousMode, 1825 &KmTargetKeyRootDir); 1826 if (!NT_SUCCESS(Status)) 1827 return Status; 1828 CapturedTargetKey.RootDirectory = KmTargetKeyRootDir; 1829 CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE; 1830 1831 /* Setup the parse context */ 1832 ParseContext.CreateOperation = TRUE; 1833 ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE; 1834 1835 /* Do the create */ 1836 /* Open a local handle to the key */ 1837 Status = ObOpenObjectByName(&CapturedTargetKey, 1838 CmpKeyObjectType, 1839 KernelMode, 1840 NULL, 1841 KEY_WRITE, 1842 &ParseContext, 1843 &Handle); 1844 if (NT_SUCCESS(Status)) 1845 { 1846 /* Reference the key object */ 1847 Status = ObReferenceObjectByHandle(Handle, 1848 KEY_WRITE, 1849 CmpKeyObjectType, 1850 KernelMode, 1851 (PVOID*)&KeyBody, 1852 NULL); 1853 1854 /* Close the handle */ 1855 ObCloseHandle(Handle, KernelMode); 1856 } 1857 1858 /* Close the local kernel handle */ 1859 if (KmTargetKeyRootDir) 1860 ObCloseHandle(KmTargetKeyRootDir, KernelMode); 1861 1862 /* Return if a failure was encountered */ 1863 if (!NT_SUCCESS(Status)) 1864 return Status; 1865 1866 /* Acquire the lock depending on flags */ 1867 if (Flags == REG_FORCE_UNLOAD) 1868 { 1869 /* Lock registry exclusively */ 1870 CmpLockRegistryExclusive(); 1871 } 1872 else 1873 { 1874 /* Lock registry */ 1875 CmpLockRegistry(); 1876 1877 /* Acquire the hive loading lock */ 1878 ExAcquirePushLockExclusive(&CmpLoadHiveLock); 1879 1880 /* Lock parent and child */ 1881 if (KeyBody->KeyControlBlock->ParentKcb) 1882 ParentConv = KeyBody->KeyControlBlock->ParentKcb->ConvKey; 1883 else 1884 ParentConv = KeyBody->KeyControlBlock->ConvKey; 1885 1886 ChildConv = KeyBody->KeyControlBlock->ConvKey; 1887 1888 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv, ParentConv); 1889 } 1890 1891 /* Check if it's being deleted already */ 1892 if (KeyBody->KeyControlBlock->Delete) 1893 { 1894 /* Return appropriate status */ 1895 Status = STATUS_KEY_DELETED; 1896 goto Quit; 1897 } 1898 1899 /* Check if it's a read-only key */ 1900 if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) 1901 { 1902 /* Return appropriate status */ 1903 Status = STATUS_ACCESS_DENIED; 1904 goto Quit; 1905 } 1906 1907 /* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */ 1908 Status = CmUnloadKey(KeyBody->KeyControlBlock, Flags); 1909 1910 /* Check if we failed, but really need to succeed */ 1911 if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD)) 1912 { 1913 /* TODO: We should perform another attempt here */ 1914 _SEH2_TRY 1915 { 1916 DPRINT1("NtUnloadKey2(%wZ): We want to force-unload the hive but couldn't unload it: Retrying is UNIMPLEMENTED!\n", TargetKey->ObjectName); 1917 } 1918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1919 { 1920 } 1921 _SEH2_END; 1922 } 1923 1924 /* If CmUnloadKey() failed we need to unlock registry ourselves */ 1925 if (!NT_SUCCESS(Status)) 1926 { 1927 if (Flags != REG_FORCE_UNLOAD) 1928 { 1929 /* Release the KCB locks */ 1930 CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv); 1931 1932 /* Release the hive loading lock */ 1933 ExReleasePushLockExclusive(&CmpLoadHiveLock); 1934 } 1935 1936 /* Unlock the registry */ 1937 CmpUnlockRegistry(); 1938 } 1939 1940 Quit: 1941 /* Dereference the key */ 1942 ObDereferenceObject(KeyBody); 1943 1944 /* Return status */ 1945 return Status; 1946 } 1947 1948 NTSTATUS 1949 NTAPI 1950 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey, 1951 IN HANDLE Event) 1952 { 1953 UNIMPLEMENTED; 1954 return STATUS_NOT_IMPLEMENTED; 1955 } 1956 1957 /* EOF */ 1958