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 = NULL; 894 895 _SEH2_TRY 896 { 897 ProbeForRead(Data, DataSize, 1); 898 } 899 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 900 { 901 Status = _SEH2_GetExceptionCode(); 902 } 903 _SEH2_END; 904 905 if (!NT_SUCCESS(Status)) 906 { 907 /* Dereference and return status */ 908 ObDereferenceObject(KeyObject); 909 return Status; 910 } 911 912 DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM); 913 if (!DataCopy) 914 { 915 /* Dereference and return status */ 916 ObDereferenceObject(KeyObject); 917 return STATUS_INSUFFICIENT_RESOURCES; 918 } 919 920 _SEH2_TRY 921 { 922 RtlCopyMemory(DataCopy, Data, DataSize); 923 } 924 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 925 { 926 Status = _SEH2_GetExceptionCode(); 927 } 928 _SEH2_END; 929 930 if (!NT_SUCCESS(Status)) 931 { 932 /* Dereference and return status */ 933 ExFreePoolWithTag(DataCopy, TAG_CM); 934 ObDereferenceObject(KeyObject); 935 return Status; 936 } 937 938 Data = DataCopy; 939 } 940 941 /* Capture the string */ 942 Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName); 943 if (!NT_SUCCESS(Status)) 944 goto Quit; 945 946 DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n", 947 KeyHandle, &ValueNameCopy, TitleIndex, Type, DataSize); 948 949 /* Make sure the name is aligned, not too long, and the data under 4GB */ 950 if ( (ValueNameCopy.Length > 32767) || 951 ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) || 952 (DataSize > 0x80000000)) 953 { 954 /* Fail */ 955 Status = STATUS_INVALID_PARAMETER; 956 goto Quit; 957 } 958 959 /* Ignore any null characters at the end */ 960 while ((ValueNameCopy.Length) && 961 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1])) 962 { 963 /* Skip it */ 964 ValueNameCopy.Length -= sizeof(WCHAR); 965 } 966 967 /* Don't touch read-only keys */ 968 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) 969 { 970 /* Fail */ 971 Status = STATUS_ACCESS_DENIED; 972 goto Quit; 973 } 974 975 /* Setup callback */ 976 PostOperationInfo.Object = (PVOID)KeyObject; 977 SetValueKeyInfo.Object = (PVOID)KeyObject; 978 SetValueKeyInfo.ValueName = &ValueNameCopy; 979 SetValueKeyInfo.TitleIndex = TitleIndex; 980 SetValueKeyInfo.Type = Type; 981 SetValueKeyInfo.Data = Data; 982 SetValueKeyInfo.DataSize = DataSize; 983 984 /* Do the callback */ 985 Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo); 986 if (NT_SUCCESS(Status)) 987 { 988 /* Call the internal API */ 989 Status = CmSetValueKey(KeyObject->KeyControlBlock, 990 &ValueNameCopy, 991 Type, 992 Data, 993 DataSize); 994 995 /* Do the post-callback */ 996 PostOperationInfo.Status = Status; 997 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo); 998 } 999 1000 Quit: 1001 if (ValueNameCopy.Buffer) 1002 ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode); 1003 1004 if ((PreviousMode != KernelMode) && Data) 1005 ExFreePoolWithTag(Data, TAG_CM); 1006 1007 /* Dereference and return status */ 1008 ObDereferenceObject(KeyObject); 1009 return Status; 1010 } 1011 1012 NTSTATUS 1013 NTAPI 1014 NtDeleteValueKey(IN HANDLE KeyHandle, 1015 IN PUNICODE_STRING ValueName) 1016 { 1017 NTSTATUS Status; 1018 PCM_KEY_BODY KeyObject; 1019 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo; 1020 REG_POST_OPERATION_INFORMATION PostOperationInfo; 1021 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1022 UNICODE_STRING ValueNameCopy; 1023 1024 PAGED_CODE(); 1025 1026 /* Verify that the handle is valid and is a registry key */ 1027 Status = ObReferenceObjectByHandle(KeyHandle, 1028 KEY_SET_VALUE, 1029 CmpKeyObjectType, 1030 PreviousMode, 1031 (PVOID*)&KeyObject, 1032 NULL); 1033 if (!NT_SUCCESS(Status)) 1034 return Status; 1035 1036 /* Capture the string */ 1037 Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName); 1038 if (!NT_SUCCESS(Status)) 1039 goto Quit; 1040 1041 /* Make sure the name is aligned properly */ 1042 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) 1043 { 1044 /* It isn't, so we'll fail */ 1045 Status = STATUS_INVALID_PARAMETER; 1046 goto Quit; 1047 } 1048 1049 /* Don't touch read-only keys */ 1050 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) 1051 { 1052 /* Fail */ 1053 Status = STATUS_ACCESS_DENIED; 1054 goto Quit; 1055 } 1056 1057 /* Do the callback */ 1058 DeleteValueKeyInfo.Object = (PVOID)KeyObject; 1059 DeleteValueKeyInfo.ValueName = ValueName; 1060 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey, 1061 &DeleteValueKeyInfo); 1062 if (NT_SUCCESS(Status)) 1063 { 1064 /* Call the internal API */ 1065 Status = CmDeleteValueKey(KeyObject->KeyControlBlock, ValueNameCopy); 1066 1067 /* Do the post callback */ 1068 PostOperationInfo.Object = (PVOID)KeyObject; 1069 PostOperationInfo.Status = Status; 1070 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey, 1071 &PostOperationInfo); 1072 } 1073 1074 Quit: 1075 if (ValueNameCopy.Buffer) 1076 ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode); 1077 1078 /* Dereference and return status */ 1079 ObDereferenceObject(KeyObject); 1080 return Status; 1081 } 1082 1083 NTSTATUS 1084 NTAPI 1085 NtFlushKey(IN HANDLE KeyHandle) 1086 { 1087 NTSTATUS Status; 1088 PCM_KEY_BODY KeyObject; 1089 PAGED_CODE(); 1090 1091 /* Get the key object */ 1092 Status = ObReferenceObjectByHandle(KeyHandle, 1093 0, 1094 CmpKeyObjectType, 1095 ExGetPreviousMode(), 1096 (PVOID*)&KeyObject, 1097 NULL); 1098 if (!NT_SUCCESS(Status)) return Status; 1099 1100 /* Lock the registry */ 1101 CmpLockRegistry(); 1102 1103 /* Lock the KCB */ 1104 CmpAcquireKcbLockShared(KeyObject->KeyControlBlock); 1105 1106 /* Make sure KCB isn't deleted */ 1107 if (KeyObject->KeyControlBlock->Delete) 1108 { 1109 /* Fail */ 1110 Status = STATUS_KEY_DELETED; 1111 } 1112 else 1113 { 1114 /* Call the internal API */ 1115 Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE); 1116 } 1117 1118 /* Release the locks */ 1119 CmpReleaseKcbLock(KeyObject->KeyControlBlock); 1120 CmpUnlockRegistry(); 1121 1122 /* Dereference the object and return status */ 1123 ObDereferenceObject(KeyObject); 1124 return Status; 1125 } 1126 1127 NTSTATUS 1128 NTAPI 1129 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes, 1130 IN POBJECT_ATTRIBUTES FileObjectAttributes) 1131 { 1132 /* Call the newer API */ 1133 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, 0, NULL); 1134 } 1135 1136 NTSTATUS 1137 NTAPI 1138 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes, 1139 IN POBJECT_ATTRIBUTES FileObjectAttributes, 1140 IN ULONG Flags) 1141 { 1142 /* Call the newer API */ 1143 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL); 1144 } 1145 1146 NTSTATUS 1147 NTAPI 1148 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey, 1149 IN POBJECT_ATTRIBUTES SourceFile, 1150 IN ULONG Flags, 1151 IN HANDLE TrustClassKey) 1152 { 1153 NTSTATUS Status; 1154 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1155 OBJECT_ATTRIBUTES CapturedTargetKey; 1156 OBJECT_ATTRIBUTES CapturedSourceFile; 1157 UNICODE_STRING TargetKeyName, SourceFileName; 1158 HANDLE KmTargetKeyRootDir = NULL, KmSourceFileRootDir = NULL; 1159 PCM_KEY_BODY KeyBody = NULL; 1160 1161 PAGED_CODE(); 1162 1163 /* Validate flags */ 1164 if (Flags & ~REG_NO_LAZY_FLUSH) 1165 return STATUS_INVALID_PARAMETER; 1166 1167 /* Validate privilege */ 1168 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode)) 1169 { 1170 DPRINT1("Restore Privilege missing!\n"); 1171 return STATUS_PRIVILEGE_NOT_HELD; 1172 } 1173 1174 /* Block APCs */ 1175 KeEnterCriticalRegion(); 1176 1177 /* Check for user-mode caller */ 1178 if (PreviousMode != KernelMode) 1179 { 1180 /* Prepare to probe parameters */ 1181 _SEH2_TRY 1182 { 1183 /* Probe target key */ 1184 ProbeForRead(TargetKey, 1185 sizeof(OBJECT_ATTRIBUTES), 1186 sizeof(ULONG)); 1187 1188 /* Probe source file */ 1189 ProbeForRead(SourceFile, 1190 sizeof(OBJECT_ATTRIBUTES), 1191 sizeof(ULONG)); 1192 } 1193 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1194 { 1195 /* Return the exception code */ 1196 Status = _SEH2_GetExceptionCode(); 1197 _SEH2_YIELD(goto Quit); 1198 } 1199 _SEH2_END; 1200 } 1201 1202 /* Probe and capture the target key attributes, including the security */ 1203 Status = ProbeAndCaptureObjectAttributes(&CapturedTargetKey, 1204 &TargetKeyName, 1205 PreviousMode, 1206 TargetKey, 1207 TRUE); 1208 if (!NT_SUCCESS(Status)) 1209 goto Quit; 1210 1211 /* 1212 * Probe and capture the source file attributes, but not the security. 1213 * A proper security context is built by CmLoadKey(). 1214 */ 1215 Status = ProbeAndCaptureObjectAttributes(&CapturedSourceFile, 1216 &SourceFileName, 1217 PreviousMode, 1218 SourceFile, 1219 FALSE); 1220 if (!NT_SUCCESS(Status)) 1221 { 1222 ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode); 1223 goto Quit; 1224 } 1225 1226 /* Make sure the target key root directory handle is a kernel handle */ 1227 Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory, 1228 CmpKeyObjectType, 1229 KEY_READ, 1230 PreviousMode, 1231 &KmTargetKeyRootDir); 1232 if (!NT_SUCCESS(Status)) 1233 goto Cleanup; 1234 CapturedTargetKey.RootDirectory = KmTargetKeyRootDir; 1235 CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE; 1236 1237 /* Make sure the source file root directory handle is a kernel handle */ 1238 Status = CmpConvertHandleToKernelHandle(CapturedSourceFile.RootDirectory, 1239 IoFileObjectType, 1240 FILE_TRAVERSE, 1241 PreviousMode, 1242 &KmSourceFileRootDir); 1243 if (!NT_SUCCESS(Status)) 1244 goto Cleanup; 1245 CapturedSourceFile.RootDirectory = KmSourceFileRootDir; 1246 CapturedSourceFile.Attributes |= OBJ_KERNEL_HANDLE; 1247 1248 /* Check if we have a trust class */ 1249 if (TrustClassKey) 1250 { 1251 /* Reference it */ 1252 Status = ObReferenceObjectByHandle(TrustClassKey, 1253 0, 1254 CmpKeyObjectType, 1255 PreviousMode, 1256 (PVOID*)&KeyBody, 1257 NULL); 1258 } 1259 1260 /* Call the internal API */ 1261 Status = CmLoadKey(&CapturedTargetKey, 1262 &CapturedSourceFile, 1263 Flags, 1264 KeyBody); 1265 1266 /* Dereference the trust key, if any */ 1267 if (KeyBody) ObDereferenceObject(KeyBody); 1268 1269 Cleanup: 1270 /* Close the local kernel handles */ 1271 if (KmSourceFileRootDir) 1272 ObCloseHandle(KmSourceFileRootDir, KernelMode); 1273 if (KmTargetKeyRootDir) 1274 ObCloseHandle(KmTargetKeyRootDir, KernelMode); 1275 1276 /* Release the captured object attributes */ 1277 ReleaseCapturedObjectAttributes(&CapturedSourceFile, PreviousMode); 1278 ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode); 1279 1280 Quit: 1281 /* Bring back APCs */ 1282 KeLeaveCriticalRegion(); 1283 1284 /* Return status */ 1285 return Status; 1286 } 1287 1288 NTSTATUS 1289 NTAPI 1290 NtNotifyChangeKey(IN HANDLE KeyHandle, 1291 IN HANDLE Event, 1292 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1293 IN PVOID ApcContext OPTIONAL, 1294 OUT PIO_STATUS_BLOCK IoStatusBlock, 1295 IN ULONG CompletionFilter, 1296 IN BOOLEAN WatchTree, 1297 OUT PVOID Buffer, 1298 IN ULONG Length, 1299 IN BOOLEAN Asynchronous) 1300 { 1301 /* Call the newer API */ 1302 return NtNotifyChangeMultipleKeys(KeyHandle, 1303 0, 1304 NULL, 1305 Event, 1306 ApcRoutine, 1307 ApcContext, 1308 IoStatusBlock, 1309 CompletionFilter, 1310 WatchTree, 1311 Buffer, 1312 Length, 1313 Asynchronous); 1314 } 1315 1316 NTSTATUS 1317 NTAPI 1318 NtInitializeRegistry(IN USHORT Flag) 1319 { 1320 BOOLEAN SetupBoot; 1321 NTSTATUS Status = STATUS_SUCCESS; 1322 PAGED_CODE(); 1323 1324 /* Always do this as kernel mode */ 1325 if (KeGetPreviousMode() == UserMode) 1326 return ZwInitializeRegistry(Flag); 1327 1328 /* Enough of the system has booted by now */ 1329 Ki386PerfEnd(); 1330 1331 /* Validate flag */ 1332 if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER; 1333 1334 /* Check if boot was accepted */ 1335 if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX)) 1336 { 1337 /* Only allow once */ 1338 if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED; 1339 CmBootAcceptFirstTime = FALSE; 1340 1341 /* Get the control set accepted */ 1342 Flag -= CM_BOOT_FLAG_ACCEPTED; 1343 if (Flag) 1344 { 1345 /* Save the last known good boot */ 1346 Status = CmpSaveBootControlSet(Flag); 1347 1348 /* Notify HAL */ 1349 HalEndOfBoot(); 1350 1351 /* Enable lazy flush */ 1352 CmpHoldLazyFlush = FALSE; 1353 CmpLazyFlush(); 1354 return Status; 1355 } 1356 1357 /* Otherwise, invalid boot */ 1358 return STATUS_INVALID_PARAMETER; 1359 } 1360 1361 /* Check if this was a setup boot */ 1362 SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE); 1363 1364 /* Make sure we're only called once */ 1365 if (!CmFirstTime) return STATUS_ACCESS_DENIED; 1366 CmFirstTime = FALSE; 1367 1368 /* Lock the registry exclusively */ 1369 CmpLockRegistryExclusive(); 1370 1371 /* Initialize the hives and lazy flusher */ 1372 CmpCmdInit(SetupBoot); 1373 1374 /* Save version data */ 1375 CmpSetVersionData(); 1376 1377 /* Release the registry lock */ 1378 CmpUnlockRegistry(); 1379 return STATUS_SUCCESS; 1380 } 1381 1382 NTSTATUS 1383 NTAPI 1384 NtCompactKeys(IN ULONG Count, 1385 IN PHANDLE KeyArray) 1386 { 1387 UNIMPLEMENTED; 1388 return STATUS_NOT_IMPLEMENTED; 1389 } 1390 1391 NTSTATUS 1392 NTAPI 1393 NtCompressKey(IN HANDLE Key) 1394 { 1395 UNIMPLEMENTED; 1396 return STATUS_NOT_IMPLEMENTED; 1397 } 1398 1399 // FIXME: different for different windows versions! 1400 #define PRODUCT_ACTIVATION_VERSION 7749 1401 1402 NTSTATUS 1403 NTAPI 1404 NtLockProductActivationKeys(IN PULONG pPrivateVer, 1405 IN PULONG pSafeMode) 1406 { 1407 KPROCESSOR_MODE PreviousMode; 1408 1409 PreviousMode = ExGetPreviousMode(); 1410 _SEH2_TRY 1411 { 1412 /* Check if the caller asked for the version */ 1413 if (pPrivateVer != NULL) 1414 { 1415 /* For user mode, probe it */ 1416 if (PreviousMode != KernelMode) 1417 { 1418 ProbeForWriteUlong(pPrivateVer); 1419 } 1420 1421 /* Return the expected version */ 1422 *pPrivateVer = PRODUCT_ACTIVATION_VERSION; 1423 } 1424 1425 /* Check if the caller asked for safe mode mode state */ 1426 if (pSafeMode != NULL) 1427 { 1428 /* For user mode, probe it */ 1429 if (PreviousMode != KernelMode) 1430 { 1431 ProbeForWriteUlong(pSafeMode); 1432 } 1433 1434 /* Return the safe boot mode state */ 1435 *pSafeMode = InitSafeBootMode; 1436 } 1437 } 1438 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1439 { 1440 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1441 } 1442 _SEH2_END; 1443 1444 return STATUS_SUCCESS; 1445 } 1446 1447 NTSTATUS 1448 NTAPI 1449 NtLockRegistryKey(IN HANDLE KeyHandle) 1450 { 1451 UNIMPLEMENTED; 1452 return STATUS_NOT_IMPLEMENTED; 1453 } 1454 1455 NTSTATUS 1456 NTAPI 1457 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle, 1458 IN ULONG Count, 1459 IN POBJECT_ATTRIBUTES SlaveObjects, 1460 IN HANDLE Event, 1461 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1462 IN PVOID ApcContext OPTIONAL, 1463 OUT PIO_STATUS_BLOCK IoStatusBlock, 1464 IN ULONG CompletionFilter, 1465 IN BOOLEAN WatchTree, 1466 OUT PVOID Buffer, 1467 IN ULONG Length, 1468 IN BOOLEAN Asynchronous) 1469 { 1470 UNIMPLEMENTED_ONCE; 1471 return STATUS_NOT_IMPLEMENTED; 1472 } 1473 1474 NTSTATUS 1475 NTAPI 1476 NtQueryMultipleValueKey(IN HANDLE KeyHandle, 1477 IN OUT PKEY_VALUE_ENTRY ValueList, 1478 IN ULONG NumberOfValues, 1479 OUT PVOID Buffer, 1480 IN OUT PULONG Length, 1481 OUT PULONG ReturnLength) 1482 { 1483 UNIMPLEMENTED; 1484 return STATUS_NOT_IMPLEMENTED; 1485 } 1486 1487 NTSTATUS 1488 NTAPI 1489 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey, 1490 OUT PULONG HandleCount) 1491 { 1492 KPROCESSOR_MODE PreviousMode; 1493 PCM_KEY_BODY KeyBody = NULL; 1494 HANDLE KeyHandle; 1495 NTSTATUS Status; 1496 ULONG SubKeys; 1497 1498 DPRINT("NtQueryOpenSubKeys()\n"); 1499 1500 PAGED_CODE(); 1501 1502 /* Get the processor mode */ 1503 PreviousMode = KeGetPreviousMode(); 1504 1505 /* Check for user-mode caller */ 1506 if (PreviousMode != KernelMode) 1507 { 1508 /* Prepare to probe parameters */ 1509 _SEH2_TRY 1510 { 1511 /* Probe target key */ 1512 ProbeForRead(TargetKey, 1513 sizeof(OBJECT_ATTRIBUTES), 1514 sizeof(ULONG)); 1515 1516 /* Probe handle count */ 1517 ProbeForWriteUlong(HandleCount); 1518 } 1519 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1520 { 1521 /* Return the exception code */ 1522 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1523 } 1524 _SEH2_END; 1525 } 1526 1527 /* Open a handle to the key */ 1528 Status = ObOpenObjectByName(TargetKey, 1529 CmpKeyObjectType, 1530 PreviousMode, 1531 NULL, 1532 KEY_READ, 1533 NULL, 1534 &KeyHandle); 1535 if (NT_SUCCESS(Status)) 1536 { 1537 /* Reference the key object */ 1538 Status = ObReferenceObjectByHandle(KeyHandle, 1539 KEY_READ, 1540 CmpKeyObjectType, 1541 PreviousMode, 1542 (PVOID*)&KeyBody, 1543 NULL); 1544 1545 /* Close the handle */ 1546 NtClose(KeyHandle); 1547 } 1548 1549 /* Fail, if the key object could not be referenced */ 1550 if (!NT_SUCCESS(Status)) 1551 return Status; 1552 1553 /* Lock the registry exclusively */ 1554 CmpLockRegistryExclusive(); 1555 1556 /* Fail, if we did not open a hive root key */ 1557 if (KeyBody->KeyControlBlock->KeyCell != 1558 KeyBody->KeyControlBlock->KeyHive->BaseBlock->RootCell) 1559 { 1560 DPRINT("Error: Key is not a hive root key!\n"); 1561 CmpUnlockRegistry(); 1562 ObDereferenceObject(KeyBody); 1563 return STATUS_INVALID_PARAMETER; 1564 } 1565 1566 /* Call the internal API */ 1567 SubKeys = CmpEnumerateOpenSubKeys(KeyBody->KeyControlBlock, 1568 FALSE, FALSE); 1569 1570 /* Unlock the registry */ 1571 CmpUnlockRegistry(); 1572 1573 /* Dereference the key object */ 1574 ObDereferenceObject(KeyBody); 1575 1576 /* Write back the result */ 1577 _SEH2_TRY 1578 { 1579 *HandleCount = SubKeys; 1580 } 1581 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1582 { 1583 Status = _SEH2_GetExceptionCode(); 1584 } 1585 _SEH2_END; 1586 1587 DPRINT("Done.\n"); 1588 1589 return Status; 1590 } 1591 1592 NTSTATUS 1593 NTAPI 1594 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey, 1595 IN ULONG BufferLength, 1596 IN PVOID Buffer, 1597 IN PULONG RequiredSize) 1598 { 1599 UNIMPLEMENTED; 1600 return STATUS_NOT_IMPLEMENTED; 1601 } 1602 1603 NTSTATUS 1604 NTAPI 1605 NtRenameKey(IN HANDLE KeyHandle, 1606 IN PUNICODE_STRING ReplacementName) 1607 { 1608 UNIMPLEMENTED; 1609 return STATUS_NOT_IMPLEMENTED; 1610 } 1611 1612 NTSTATUS 1613 NTAPI 1614 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes, 1615 IN HANDLE Key, 1616 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes) 1617 { 1618 UNIMPLEMENTED; 1619 return STATUS_NOT_IMPLEMENTED; 1620 } 1621 1622 NTSTATUS 1623 NTAPI 1624 NtRestoreKey(IN HANDLE KeyHandle, 1625 IN HANDLE FileHandle, 1626 IN ULONG RestoreFlags) 1627 { 1628 UNIMPLEMENTED; 1629 return STATUS_NOT_IMPLEMENTED; 1630 } 1631 1632 NTSTATUS 1633 NTAPI 1634 NtSaveKey(IN HANDLE KeyHandle, 1635 IN HANDLE FileHandle) 1636 { 1637 /* Call the extended API */ 1638 return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT); 1639 } 1640 1641 NTSTATUS 1642 NTAPI 1643 NtSaveKeyEx(IN HANDLE KeyHandle, 1644 IN HANDLE FileHandle, 1645 IN ULONG Flags) 1646 { 1647 NTSTATUS Status; 1648 HANDLE KmFileHandle = NULL; 1649 PCM_KEY_BODY KeyObject; 1650 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1651 1652 PAGED_CODE(); 1653 1654 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle, FileHandle, Flags); 1655 1656 /* Verify the flags */ 1657 if ((Flags != REG_STANDARD_FORMAT) 1658 && (Flags != REG_LATEST_FORMAT) 1659 && (Flags != REG_NO_COMPRESSION)) 1660 { 1661 /* Only one of these values can be specified */ 1662 return STATUS_INVALID_PARAMETER; 1663 } 1664 1665 /* Validate privilege */ 1666 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode)) 1667 { 1668 return STATUS_PRIVILEGE_NOT_HELD; 1669 } 1670 1671 /* Make sure the target file handle is a kernel handle */ 1672 Status = CmpConvertHandleToKernelHandle(FileHandle, 1673 IoFileObjectType, 1674 FILE_WRITE_DATA, 1675 PreviousMode, 1676 &KmFileHandle); 1677 if (!NT_SUCCESS(Status)) 1678 goto Quit; 1679 1680 /* Verify that the handle is valid and is a registry key */ 1681 Status = ObReferenceObjectByHandle(KeyHandle, 1682 KEY_READ, 1683 CmpKeyObjectType, 1684 PreviousMode, 1685 (PVOID*)&KeyObject, 1686 NULL); 1687 if (!NT_SUCCESS(Status)) 1688 goto Quit; 1689 1690 /* Call the internal API */ 1691 Status = CmSaveKey(KeyObject->KeyControlBlock, KmFileHandle, Flags); 1692 1693 /* Dereference the registry key */ 1694 ObDereferenceObject(KeyObject); 1695 1696 Quit: 1697 /* Close the local kernel handle */ 1698 if (KmFileHandle) 1699 ObCloseHandle(KmFileHandle, KernelMode); 1700 1701 return Status; 1702 } 1703 1704 NTSTATUS 1705 NTAPI 1706 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle, 1707 IN HANDLE LowPrecedenceKeyHandle, 1708 IN HANDLE FileHandle) 1709 { 1710 NTSTATUS Status; 1711 KPROCESSOR_MODE PreviousMode; 1712 HANDLE KmFileHandle = NULL; 1713 PCM_KEY_BODY HighPrecedenceKeyObject = NULL; 1714 PCM_KEY_BODY LowPrecedenceKeyObject = NULL; 1715 1716 PAGED_CODE(); 1717 1718 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n", 1719 HighPrecedenceKeyHandle, LowPrecedenceKeyHandle, FileHandle); 1720 1721 PreviousMode = ExGetPreviousMode(); 1722 1723 /* Validate privilege */ 1724 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode)) 1725 { 1726 return STATUS_PRIVILEGE_NOT_HELD; 1727 } 1728 1729 /* Make sure the target file handle is a kernel handle */ 1730 Status = CmpConvertHandleToKernelHandle(FileHandle, 1731 IoFileObjectType, 1732 FILE_WRITE_DATA, 1733 PreviousMode, 1734 &KmFileHandle); 1735 if (!NT_SUCCESS(Status)) 1736 goto Quit; 1737 1738 /* Verify that the handles are valid and are registry keys */ 1739 Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle, 1740 KEY_READ, 1741 CmpKeyObjectType, 1742 PreviousMode, 1743 (PVOID*)&HighPrecedenceKeyObject, 1744 NULL); 1745 if (!NT_SUCCESS(Status)) 1746 goto Quit; 1747 1748 Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle, 1749 KEY_READ, 1750 CmpKeyObjectType, 1751 PreviousMode, 1752 (PVOID*)&LowPrecedenceKeyObject, 1753 NULL); 1754 if (!NT_SUCCESS(Status)) 1755 goto Quit; 1756 1757 /* Call the internal API */ 1758 Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock, 1759 LowPrecedenceKeyObject->KeyControlBlock, 1760 KmFileHandle); 1761 1762 Quit: 1763 /* Dereference the opened key objects */ 1764 if (LowPrecedenceKeyObject) 1765 ObDereferenceObject(LowPrecedenceKeyObject); 1766 if (HighPrecedenceKeyObject) 1767 ObDereferenceObject(HighPrecedenceKeyObject); 1768 1769 /* Close the local kernel handle */ 1770 if (KmFileHandle) 1771 ObCloseHandle(KmFileHandle, KernelMode); 1772 1773 return Status; 1774 } 1775 1776 NTSTATUS 1777 NTAPI 1778 NtSetInformationKey(IN HANDLE KeyHandle, 1779 IN KEY_SET_INFORMATION_CLASS KeyInformationClass, 1780 IN PVOID KeyInformation, 1781 IN ULONG KeyInformationLength) 1782 { 1783 UNIMPLEMENTED; 1784 return STATUS_NOT_IMPLEMENTED; 1785 } 1786 1787 NTSTATUS 1788 NTAPI 1789 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes) 1790 { 1791 return NtUnloadKey2(KeyObjectAttributes, 0); 1792 } 1793 1794 NTSTATUS 1795 NTAPI 1796 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey, 1797 IN ULONG Flags) 1798 { 1799 NTSTATUS Status; 1800 OBJECT_ATTRIBUTES CapturedTargetKey; 1801 UNICODE_STRING ObjectName; 1802 HANDLE KmTargetKeyRootDir = NULL; 1803 CM_PARSE_CONTEXT ParseContext = {0}; 1804 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1805 PCM_KEY_BODY KeyBody = NULL; 1806 ULONG ParentConv = 0, ChildConv = 0; 1807 HANDLE Handle; 1808 1809 PAGED_CODE(); 1810 1811 /* Validate privilege */ 1812 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode)) 1813 { 1814 DPRINT1("Restore Privilege missing!\n"); 1815 return STATUS_PRIVILEGE_NOT_HELD; 1816 } 1817 1818 /* Check for user-mode caller */ 1819 if (PreviousMode != KernelMode) 1820 { 1821 /* Prepare to probe parameters */ 1822 _SEH2_TRY 1823 { 1824 /* Probe object attributes */ 1825 ProbeForRead(TargetKey, 1826 sizeof(OBJECT_ATTRIBUTES), 1827 sizeof(ULONG)); 1828 1829 CapturedTargetKey = *TargetKey; 1830 1831 /* Probe the string */ 1832 ObjectName = ProbeForReadUnicodeString(CapturedTargetKey.ObjectName); 1833 ProbeForRead(ObjectName.Buffer, 1834 ObjectName.Length, 1835 sizeof(WCHAR)); 1836 1837 CapturedTargetKey.ObjectName = &ObjectName; 1838 } 1839 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1840 { 1841 /* Return the exception code */ 1842 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1843 } 1844 _SEH2_END; 1845 } 1846 else 1847 { 1848 /* Save the target attributes directly */ 1849 CapturedTargetKey = *TargetKey; 1850 } 1851 1852 /* Make sure the target key root directory handle is a kernel handle */ 1853 Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory, 1854 CmpKeyObjectType, 1855 KEY_WRITE, 1856 PreviousMode, 1857 &KmTargetKeyRootDir); 1858 if (!NT_SUCCESS(Status)) 1859 return Status; 1860 CapturedTargetKey.RootDirectory = KmTargetKeyRootDir; 1861 CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE; 1862 1863 /* Setup the parse context */ 1864 ParseContext.CreateOperation = TRUE; 1865 ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE; 1866 1867 /* Do the create */ 1868 /* Open a local handle to the key */ 1869 Status = ObOpenObjectByName(&CapturedTargetKey, 1870 CmpKeyObjectType, 1871 KernelMode, 1872 NULL, 1873 KEY_WRITE, 1874 &ParseContext, 1875 &Handle); 1876 if (NT_SUCCESS(Status)) 1877 { 1878 /* Reference the key object */ 1879 Status = ObReferenceObjectByHandle(Handle, 1880 KEY_WRITE, 1881 CmpKeyObjectType, 1882 KernelMode, 1883 (PVOID*)&KeyBody, 1884 NULL); 1885 1886 /* Close the handle */ 1887 ObCloseHandle(Handle, KernelMode); 1888 } 1889 1890 /* Close the local kernel handle */ 1891 if (KmTargetKeyRootDir) 1892 ObCloseHandle(KmTargetKeyRootDir, KernelMode); 1893 1894 /* Return if a failure was encountered */ 1895 if (!NT_SUCCESS(Status)) 1896 return Status; 1897 1898 /* Acquire the lock depending on flags */ 1899 if (Flags == REG_FORCE_UNLOAD) 1900 { 1901 /* Lock registry exclusively */ 1902 CmpLockRegistryExclusive(); 1903 } 1904 else 1905 { 1906 /* Lock registry */ 1907 CmpLockRegistry(); 1908 1909 /* Acquire the hive loading lock */ 1910 ExAcquirePushLockExclusive(&CmpLoadHiveLock); 1911 1912 /* Lock parent and child */ 1913 if (KeyBody->KeyControlBlock->ParentKcb) 1914 ParentConv = KeyBody->KeyControlBlock->ParentKcb->ConvKey; 1915 else 1916 ParentConv = KeyBody->KeyControlBlock->ConvKey; 1917 1918 ChildConv = KeyBody->KeyControlBlock->ConvKey; 1919 1920 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv, ParentConv); 1921 } 1922 1923 /* Check if it's being deleted already */ 1924 if (KeyBody->KeyControlBlock->Delete) 1925 { 1926 /* Return appropriate status */ 1927 Status = STATUS_KEY_DELETED; 1928 goto Quit; 1929 } 1930 1931 /* Check if it's a read-only key */ 1932 if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) 1933 { 1934 /* Return appropriate status */ 1935 Status = STATUS_ACCESS_DENIED; 1936 goto Quit; 1937 } 1938 1939 /* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */ 1940 Status = CmUnloadKey(KeyBody->KeyControlBlock, Flags); 1941 1942 /* Check if we failed, but really need to succeed */ 1943 if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD)) 1944 { 1945 /* TODO: We should perform another attempt here */ 1946 _SEH2_TRY 1947 { 1948 DPRINT1("NtUnloadKey2(%wZ): We want to force-unload the hive but couldn't unload it: Retrying is UNIMPLEMENTED!\n", TargetKey->ObjectName); 1949 } 1950 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1951 { 1952 } 1953 _SEH2_END; 1954 } 1955 1956 /* If CmUnloadKey() failed we need to unlock registry ourselves */ 1957 if (!NT_SUCCESS(Status)) 1958 { 1959 if (Flags != REG_FORCE_UNLOAD) 1960 { 1961 /* Release the KCB locks */ 1962 CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv); 1963 1964 /* Release the hive loading lock */ 1965 ExReleasePushLockExclusive(&CmpLoadHiveLock); 1966 } 1967 1968 /* Unlock the registry */ 1969 CmpUnlockRegistry(); 1970 } 1971 1972 Quit: 1973 /* Dereference the key */ 1974 ObDereferenceObject(KeyBody); 1975 1976 /* Return status */ 1977 return Status; 1978 } 1979 1980 NTSTATUS 1981 NTAPI 1982 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey, 1983 IN HANDLE Event) 1984 { 1985 UNIMPLEMENTED; 1986 return STATUS_NOT_IMPLEMENTED; 1987 } 1988 1989 /* EOF */ 1990