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 /* FUNCTIONS *****************************************************************/ 21 22 NTSTATUS 23 NTAPI 24 NtCreateKey(OUT PHANDLE KeyHandle, 25 IN ACCESS_MASK DesiredAccess, 26 IN POBJECT_ATTRIBUTES ObjectAttributes, 27 IN ULONG TitleIndex, 28 IN PUNICODE_STRING Class OPTIONAL, 29 IN ULONG CreateOptions, 30 OUT PULONG Disposition OPTIONAL) 31 { 32 NTSTATUS Status; 33 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 34 CM_PARSE_CONTEXT ParseContext = {0}; 35 HANDLE Handle; 36 PAGED_CODE(); 37 38 DPRINT("NtCreateKey(Path: %wZ, Root %x, Access: %x, CreateOptions %x)\n", 39 ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory, 40 DesiredAccess, CreateOptions); 41 42 /* Ignore the WOW64 flag, it's not valid in the kernel */ 43 DesiredAccess &= ~KEY_WOW64_RES; 44 45 /* Check for user-mode caller */ 46 if (PreviousMode != KernelMode) 47 { 48 /* Prepare to probe parameters */ 49 _SEH2_TRY 50 { 51 /* Check if we have a class */ 52 if (Class) 53 { 54 /* Probe it */ 55 ParseContext.Class = ProbeForReadUnicodeString(Class); 56 ProbeForRead(ParseContext.Class.Buffer, 57 ParseContext.Class.Length, 58 sizeof(WCHAR)); 59 } 60 61 /* Probe the key handle */ 62 ProbeForWriteHandle(KeyHandle); 63 *KeyHandle = NULL; 64 65 /* Probe object attributes */ 66 ProbeForRead(ObjectAttributes, 67 sizeof(OBJECT_ATTRIBUTES), 68 sizeof(ULONG)); 69 70 if (Disposition) 71 ProbeForWriteUlong(Disposition); 72 } 73 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 74 { 75 /* Return the exception code */ 76 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 77 } 78 _SEH2_END; 79 } 80 else 81 { 82 /* Save the class directly */ 83 if (Class) ParseContext.Class = *Class; 84 } 85 86 /* Setup the parse context */ 87 ParseContext.CreateOperation = TRUE; 88 ParseContext.CreateOptions = CreateOptions; 89 90 /* Do the create */ 91 Status = ObOpenObjectByName(ObjectAttributes, 92 CmpKeyObjectType, 93 PreviousMode, 94 NULL, 95 DesiredAccess, 96 &ParseContext, 97 &Handle); 98 99 _SEH2_TRY 100 { 101 /* Return data to user */ 102 if (NT_SUCCESS(Status)) *KeyHandle = Handle; 103 if (Disposition) *Disposition = ParseContext.Disposition; 104 } 105 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 106 { 107 /* Get the status */ 108 Status = _SEH2_GetExceptionCode(); 109 } 110 _SEH2_END; 111 112 DPRINT("Returning handle %x, Status %x.\n", Handle, Status); 113 114 /* Return status */ 115 return Status; 116 } 117 118 NTSTATUS 119 NTAPI 120 NtOpenKey(OUT PHANDLE KeyHandle, 121 IN ACCESS_MASK DesiredAccess, 122 IN POBJECT_ATTRIBUTES ObjectAttributes) 123 { 124 CM_PARSE_CONTEXT ParseContext = {0}; 125 HANDLE Handle; 126 NTSTATUS Status; 127 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 128 PAGED_CODE(); 129 DPRINT("NtOpenKey(Path: %wZ, Root %x, Access: %x)\n", 130 ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory, DesiredAccess); 131 132 /* Ignore the WOW64 flag, it's not valid in the kernel */ 133 DesiredAccess &= ~KEY_WOW64_RES; 134 135 /* Check for user-mode caller */ 136 if (PreviousMode != KernelMode) 137 { 138 /* Prepare to probe parameters */ 139 _SEH2_TRY 140 { 141 /* Probe the key handle */ 142 ProbeForWriteHandle(KeyHandle); 143 *KeyHandle = NULL; 144 145 /* Probe object attributes */ 146 ProbeForRead(ObjectAttributes, 147 sizeof(OBJECT_ATTRIBUTES), 148 sizeof(ULONG)); 149 } 150 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 151 { 152 /* Return the exception code */ 153 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 154 } 155 _SEH2_END; 156 } 157 158 /* Just let the object manager handle this */ 159 Status = ObOpenObjectByName(ObjectAttributes, 160 CmpKeyObjectType, 161 ExGetPreviousMode(), 162 NULL, 163 DesiredAccess, 164 &ParseContext, 165 &Handle); 166 167 /* Only do this if we succeeded */ 168 if (NT_SUCCESS(Status)) 169 { 170 _SEH2_TRY 171 { 172 /* Return the handle to caller */ 173 *KeyHandle = Handle; 174 } 175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 176 { 177 /* Get the status */ 178 Status = _SEH2_GetExceptionCode(); 179 } 180 _SEH2_END; 181 } 182 183 DPRINT("Returning handle %x, Status %x.\n", Handle, Status); 184 185 /* Return status */ 186 return Status; 187 } 188 189 190 NTSTATUS 191 NTAPI 192 NtDeleteKey(IN HANDLE KeyHandle) 193 { 194 PCM_KEY_BODY KeyObject; 195 NTSTATUS Status; 196 REG_DELETE_KEY_INFORMATION DeleteKeyInfo; 197 REG_POST_OPERATION_INFORMATION PostOperationInfo; 198 PAGED_CODE(); 199 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle); 200 201 /* Verify that the handle is valid and is a registry key */ 202 Status = ObReferenceObjectByHandle(KeyHandle, 203 DELETE, 204 CmpKeyObjectType, 205 ExGetPreviousMode(), 206 (PVOID*)&KeyObject, 207 NULL); 208 if (!NT_SUCCESS(Status)) return Status; 209 210 /* Setup the callback */ 211 PostOperationInfo.Object = (PVOID)KeyObject; 212 DeleteKeyInfo.Object = (PVOID)KeyObject; 213 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteKey, &DeleteKeyInfo); 214 if (NT_SUCCESS(Status)) 215 { 216 /* Check if we are read-only */ 217 if ((KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) || 218 (KeyObject->KeyControlBlock->ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY)) 219 { 220 /* Fail */ 221 Status = STATUS_ACCESS_DENIED; 222 } 223 else 224 { 225 /* Call the internal API */ 226 Status = CmDeleteKey(KeyObject); 227 } 228 229 /* Do post callback */ 230 PostOperationInfo.Status = Status; 231 CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo); 232 } 233 234 /* Dereference the object */ 235 ObDereferenceObject(KeyObject); 236 return Status; 237 } 238 239 NTSTATUS 240 NTAPI 241 NtEnumerateKey(IN HANDLE KeyHandle, 242 IN ULONG Index, 243 IN KEY_INFORMATION_CLASS KeyInformationClass, 244 OUT PVOID KeyInformation, 245 IN ULONG Length, 246 OUT PULONG ResultLength) 247 { 248 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 249 NTSTATUS Status; 250 PCM_KEY_BODY KeyObject; 251 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo; 252 REG_POST_OPERATION_INFORMATION PostOperationInfo; 253 PAGED_CODE(); 254 DPRINT("NtEnumerateKey() KH 0x%p, Index 0x%x, KIC %d, Length %lu\n", 255 KeyHandle, Index, KeyInformationClass, Length); 256 257 /* Reject classes we don't know about */ 258 if ((KeyInformationClass != KeyBasicInformation) && 259 (KeyInformationClass != KeyNodeInformation) && 260 (KeyInformationClass != KeyFullInformation)) 261 { 262 /* Fail */ 263 return STATUS_INVALID_PARAMETER; 264 } 265 266 /* Verify that the handle is valid and is a registry key */ 267 Status = ObReferenceObjectByHandle(KeyHandle, 268 KEY_ENUMERATE_SUB_KEYS, 269 CmpKeyObjectType, 270 ExGetPreviousMode(), 271 (PVOID*)&KeyObject, 272 NULL); 273 if (!NT_SUCCESS(Status)) return Status; 274 275 if (PreviousMode != KernelMode) 276 { 277 _SEH2_TRY 278 { 279 ProbeForWriteUlong(ResultLength); 280 ProbeForWrite(KeyInformation, 281 Length, 282 sizeof(ULONG)); 283 } 284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 285 { 286 /* Dereference and return status */ 287 ObDereferenceObject(KeyObject); 288 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 289 } 290 _SEH2_END; 291 } 292 293 /* Setup the callback */ 294 PostOperationInfo.Object = (PVOID)KeyObject; 295 EnumerateKeyInfo.Object = (PVOID)KeyObject; 296 EnumerateKeyInfo.Index = Index; 297 EnumerateKeyInfo.KeyInformationClass = KeyInformationClass; 298 EnumerateKeyInfo.Length = Length; 299 EnumerateKeyInfo.ResultLength = ResultLength; 300 301 /* Do the callback */ 302 Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateKey, &EnumerateKeyInfo); 303 if (NT_SUCCESS(Status)) 304 { 305 /* Call the internal API */ 306 Status = CmEnumerateKey(KeyObject->KeyControlBlock, 307 Index, 308 KeyInformationClass, 309 KeyInformation, 310 Length, 311 ResultLength); 312 313 /* Do the post callback */ 314 PostOperationInfo.Status = Status; 315 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey, &PostOperationInfo); 316 } 317 318 /* Dereference and return status */ 319 ObDereferenceObject(KeyObject); 320 DPRINT("Returning status %x.\n", Status); 321 return Status; 322 } 323 324 NTSTATUS 325 NTAPI 326 NtEnumerateValueKey(IN HANDLE KeyHandle, 327 IN ULONG Index, 328 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 329 OUT PVOID KeyValueInformation, 330 IN ULONG Length, 331 OUT PULONG ResultLength) 332 { 333 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 334 NTSTATUS Status; 335 PCM_KEY_BODY KeyObject; 336 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo; 337 REG_POST_OPERATION_INFORMATION PostOperationInfo; 338 PAGED_CODE(); 339 DPRINT("NtEnumerateValueKey() KH 0x%p, Index 0x%x, KVIC %d, Length %lu\n", 340 KeyHandle, Index, KeyValueInformationClass, Length); 341 342 /* Reject classes we don't know about */ 343 if ((KeyValueInformationClass != KeyValueBasicInformation) && 344 (KeyValueInformationClass != KeyValueFullInformation) && 345 (KeyValueInformationClass != KeyValuePartialInformation)) 346 { 347 /* Fail */ 348 return STATUS_INVALID_PARAMETER; 349 } 350 351 /* Verify that the handle is valid and is a registry key */ 352 Status = ObReferenceObjectByHandle(KeyHandle, 353 KEY_QUERY_VALUE, 354 CmpKeyObjectType, 355 ExGetPreviousMode(), 356 (PVOID*)&KeyObject, 357 NULL); 358 if (!NT_SUCCESS(Status)) return Status; 359 360 if (PreviousMode != KernelMode) 361 { 362 _SEH2_TRY 363 { 364 ProbeForWriteUlong(ResultLength); 365 ProbeForWrite(KeyValueInformation, 366 Length, 367 sizeof(ULONG)); 368 } 369 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 370 { 371 /* Dereference and return status */ 372 ObDereferenceObject(KeyObject); 373 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 374 } 375 _SEH2_END; 376 } 377 378 /* Setup the callback */ 379 PostOperationInfo.Object = (PVOID)KeyObject; 380 EnumerateValueKeyInfo.Object = (PVOID)KeyObject; 381 EnumerateValueKeyInfo.Index = Index; 382 EnumerateValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass; 383 EnumerateValueKeyInfo.KeyValueInformation = KeyValueInformation; 384 EnumerateValueKeyInfo.Length = Length; 385 EnumerateValueKeyInfo.ResultLength = ResultLength; 386 387 /* Do the callback */ 388 Status = CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey, 389 &EnumerateValueKeyInfo); 390 if (NT_SUCCESS(Status)) 391 { 392 /* Call the internal API */ 393 Status = CmEnumerateValueKey(KeyObject->KeyControlBlock, 394 Index, 395 KeyValueInformationClass, 396 KeyValueInformation, 397 Length, 398 ResultLength); 399 400 /* Do the post callback */ 401 PostOperationInfo.Status = Status; 402 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo); 403 } 404 405 ObDereferenceObject(KeyObject); 406 return Status; 407 } 408 409 NTSTATUS 410 NTAPI 411 NtQueryKey(IN HANDLE KeyHandle, 412 IN KEY_INFORMATION_CLASS KeyInformationClass, 413 OUT PVOID KeyInformation, 414 IN ULONG Length, 415 OUT PULONG ResultLength) 416 { 417 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 418 NTSTATUS Status; 419 PCM_KEY_BODY KeyObject; 420 REG_QUERY_KEY_INFORMATION QueryKeyInfo; 421 REG_POST_OPERATION_INFORMATION PostOperationInfo; 422 OBJECT_HANDLE_INFORMATION HandleInfo; 423 PAGED_CODE(); 424 DPRINT("NtQueryKey() KH 0x%p, KIC %d, Length %lu\n", 425 KeyHandle, KeyInformationClass, Length); 426 427 /* Reject invalid classes */ 428 if ((KeyInformationClass != KeyBasicInformation) && 429 (KeyInformationClass != KeyNodeInformation) && 430 (KeyInformationClass != KeyFullInformation) && 431 (KeyInformationClass != KeyNameInformation) && 432 (KeyInformationClass != KeyCachedInformation) && 433 (KeyInformationClass != KeyFlagsInformation)) 434 { 435 /* Fail */ 436 return STATUS_INVALID_PARAMETER; 437 } 438 439 /* Check if just the name is required */ 440 if (KeyInformationClass == KeyNameInformation) 441 { 442 /* Ignore access level */ 443 Status = ObReferenceObjectByHandle(KeyHandle, 444 0, 445 CmpKeyObjectType, 446 ExGetPreviousMode(), 447 (PVOID*)&KeyObject, 448 &HandleInfo); 449 if (NT_SUCCESS(Status)) 450 { 451 /* At least a single bit of access is required */ 452 if (!HandleInfo.GrantedAccess) 453 { 454 /* No such luck */ 455 ObDereferenceObject(KeyObject); 456 Status = STATUS_ACCESS_DENIED; 457 } 458 } 459 } 460 else 461 { 462 /* Get a reference */ 463 Status = ObReferenceObjectByHandle(KeyHandle, 464 KEY_QUERY_VALUE, 465 CmpKeyObjectType, 466 ExGetPreviousMode(), 467 (PVOID*)&KeyObject, 468 NULL); 469 } 470 471 /* Quit on failure */ 472 if (!NT_SUCCESS(Status)) return Status; 473 474 if (PreviousMode != KernelMode) 475 { 476 _SEH2_TRY 477 { 478 ProbeForWriteUlong(ResultLength); 479 ProbeForWrite(KeyInformation, 480 Length, 481 sizeof(ULONG)); 482 } 483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 484 { 485 /* Dereference and return status */ 486 ObDereferenceObject(KeyObject); 487 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 488 } 489 _SEH2_END; 490 } 491 492 /* Setup the callback */ 493 PostOperationInfo.Object = (PVOID)KeyObject; 494 QueryKeyInfo.Object = (PVOID)KeyObject; 495 QueryKeyInfo.KeyInformationClass = KeyInformationClass; 496 QueryKeyInfo.KeyInformation = KeyInformation; 497 QueryKeyInfo.Length = Length; 498 QueryKeyInfo.ResultLength = ResultLength; 499 500 /* Do the callback */ 501 Status = CmiCallRegisteredCallbacks(RegNtPreQueryKey, &QueryKeyInfo); 502 if (NT_SUCCESS(Status)) 503 { 504 /* Call the internal API */ 505 Status = CmQueryKey(KeyObject->KeyControlBlock, 506 KeyInformationClass, 507 KeyInformation, 508 Length, 509 ResultLength); 510 511 /* Do the post callback */ 512 PostOperationInfo.Status = Status; 513 CmiCallRegisteredCallbacks(RegNtPostQueryKey, &PostOperationInfo); 514 } 515 516 /* Dereference and return status */ 517 ObDereferenceObject(KeyObject); 518 return Status; 519 } 520 521 NTSTATUS 522 NTAPI 523 NtQueryValueKey(IN HANDLE KeyHandle, 524 IN PUNICODE_STRING ValueName, 525 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 526 OUT PVOID KeyValueInformation, 527 IN ULONG Length, 528 OUT PULONG ResultLength) 529 { 530 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 531 NTSTATUS Status; 532 PCM_KEY_BODY KeyObject; 533 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo; 534 REG_POST_OPERATION_INFORMATION PostOperationInfo; 535 UNICODE_STRING ValueNameCopy = *ValueName; 536 PAGED_CODE(); 537 DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n", 538 KeyHandle, ValueName, KeyValueInformationClass, Length); 539 540 /* Verify that the handle is valid and is a registry key */ 541 Status = ObReferenceObjectByHandle(KeyHandle, 542 KEY_QUERY_VALUE, 543 CmpKeyObjectType, 544 ExGetPreviousMode(), 545 (PVOID*)&KeyObject, 546 NULL); 547 if (!NT_SUCCESS(Status)) return Status; 548 549 if (PreviousMode != KernelMode) 550 { 551 _SEH2_TRY 552 { 553 ProbeForWriteUlong(ResultLength); 554 ProbeForWrite(KeyValueInformation, 555 Length, 556 sizeof(ULONG)); 557 } 558 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 559 { 560 /* Dereference and return status */ 561 ObDereferenceObject(KeyObject); 562 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 563 } 564 _SEH2_END; 565 } 566 567 /* Make sure the name is aligned properly */ 568 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) 569 { 570 /* It isn't, so we'll fail */ 571 ObDereferenceObject(KeyObject); 572 return STATUS_INVALID_PARAMETER; 573 } 574 else 575 { 576 /* Ignore any null characters at the end */ 577 while ((ValueNameCopy.Length) && 578 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1])) 579 { 580 /* Skip it */ 581 ValueNameCopy.Length -= sizeof(WCHAR); 582 } 583 } 584 585 /* Setup the callback */ 586 PostOperationInfo.Object = (PVOID)KeyObject; 587 QueryValueKeyInfo.Object = (PVOID)KeyObject; 588 QueryValueKeyInfo.ValueName = &ValueNameCopy; 589 QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass; 590 QueryValueKeyInfo.Length = Length; 591 QueryValueKeyInfo.ResultLength = ResultLength; 592 593 /* Do the callback */ 594 Status = CmiCallRegisteredCallbacks(RegNtPreQueryValueKey, &QueryValueKeyInfo); 595 if (NT_SUCCESS(Status)) 596 { 597 /* Call the internal API */ 598 Status = CmQueryValueKey(KeyObject->KeyControlBlock, 599 ValueNameCopy, 600 KeyValueInformationClass, 601 KeyValueInformation, 602 Length, 603 ResultLength); 604 605 /* Do the post callback */ 606 PostOperationInfo.Status = Status; 607 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo); 608 } 609 610 /* Dereference and return status */ 611 ObDereferenceObject(KeyObject); 612 return Status; 613 } 614 615 NTSTATUS 616 NTAPI 617 NtSetValueKey(IN HANDLE KeyHandle, 618 IN PUNICODE_STRING ValueName, 619 IN ULONG TitleIndex, 620 IN ULONG Type, 621 IN PVOID Data, 622 IN ULONG DataSize) 623 { 624 NTSTATUS Status = STATUS_SUCCESS; 625 PCM_KEY_BODY KeyObject = NULL; 626 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo; 627 REG_POST_OPERATION_INFORMATION PostOperationInfo; 628 UNICODE_STRING ValueNameCopy; 629 KPROCESSOR_MODE PreviousMode; 630 631 PAGED_CODE(); 632 633 PreviousMode = ExGetPreviousMode(); 634 635 if (!DataSize) 636 Data = NULL; 637 638 /* Probe and copy the data */ 639 if ((PreviousMode != KernelMode) && (DataSize != 0)) 640 { 641 PVOID DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM); 642 if (!DataCopy) 643 return STATUS_INSUFFICIENT_RESOURCES; 644 _SEH2_TRY 645 { 646 ProbeForRead(Data, DataSize, 1); 647 RtlCopyMemory(DataCopy, Data, DataSize); 648 } 649 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 650 { 651 Status = _SEH2_GetExceptionCode(); 652 } 653 _SEH2_END; 654 655 if (!NT_SUCCESS(Status)) 656 { 657 ExFreePoolWithTag(DataCopy, TAG_CM); 658 return Status; 659 } 660 Data = DataCopy; 661 } 662 663 /* Capture the string */ 664 Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName); 665 if (!NT_SUCCESS(Status)) 666 goto end; 667 668 DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n", 669 KeyHandle, &ValueNameCopy, TitleIndex, Type, DataSize); 670 671 /* Verify that the handle is valid and is a registry key */ 672 Status = ObReferenceObjectByHandle(KeyHandle, 673 KEY_SET_VALUE, 674 CmpKeyObjectType, 675 ExGetPreviousMode(), 676 (PVOID*)&KeyObject, 677 NULL); 678 if (!NT_SUCCESS(Status)) 679 goto end; 680 681 /* Make sure the name is aligned, not too long, and the data under 4GB */ 682 if ( (ValueNameCopy.Length > 32767) || 683 ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) || 684 (DataSize > 0x80000000)) 685 { 686 /* Fail */ 687 Status = STATUS_INVALID_PARAMETER; 688 goto end; 689 } 690 691 /* Ignore any null characters at the end */ 692 while ((ValueNameCopy.Length) && 693 !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1])) 694 { 695 /* Skip it */ 696 ValueNameCopy.Length -= sizeof(WCHAR); 697 } 698 699 /* Don't touch read-only keys */ 700 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) 701 { 702 /* Fail */ 703 Status = STATUS_ACCESS_DENIED; 704 goto end; 705 } 706 707 /* Setup callback */ 708 PostOperationInfo.Object = (PVOID)KeyObject; 709 SetValueKeyInfo.Object = (PVOID)KeyObject; 710 SetValueKeyInfo.ValueName = &ValueNameCopy; 711 SetValueKeyInfo.TitleIndex = TitleIndex; 712 SetValueKeyInfo.Type = Type; 713 SetValueKeyInfo.Data = Data; 714 SetValueKeyInfo.DataSize = DataSize; 715 716 /* Do the callback */ 717 Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo); 718 if (NT_SUCCESS(Status)) 719 { 720 /* Call the internal API */ 721 Status = CmSetValueKey(KeyObject->KeyControlBlock, 722 &ValueNameCopy, 723 Type, 724 Data, 725 DataSize); 726 } 727 728 /* Do the post-callback */ 729 PostOperationInfo.Status = Status; 730 CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo); 731 732 end: 733 /* Dereference and return status */ 734 if (KeyObject) 735 ObDereferenceObject(KeyObject); 736 ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode); 737 if ((PreviousMode != KernelMode) && Data) 738 ExFreePoolWithTag(Data, TAG_CM); 739 return Status; 740 } 741 742 NTSTATUS 743 NTAPI 744 NtDeleteValueKey(IN HANDLE KeyHandle, 745 IN PUNICODE_STRING ValueName) 746 { 747 PCM_KEY_BODY KeyObject; 748 NTSTATUS Status; 749 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo; 750 REG_POST_OPERATION_INFORMATION PostOperationInfo; 751 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 752 UNICODE_STRING ValueNameCopy = *ValueName; 753 PAGED_CODE(); 754 755 /* Verify that the handle is valid and is a registry key */ 756 Status = ObReferenceObjectByHandle(KeyHandle, 757 KEY_SET_VALUE, 758 CmpKeyObjectType, 759 PreviousMode, 760 (PVOID *)&KeyObject, 761 NULL); 762 if (!NT_SUCCESS(Status)) return Status; 763 764 /* Don't touch read-only keys */ 765 if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) 766 { 767 /* Fail */ 768 ObDereferenceObject(KeyObject); 769 return STATUS_ACCESS_DENIED; 770 } 771 772 /* Make sure the name is aligned properly */ 773 if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) 774 { 775 /* It isn't, so we'll fail */ 776 ObDereferenceObject(KeyObject); 777 return STATUS_INVALID_PARAMETER; 778 } 779 780 /* Do the callback */ 781 DeleteValueKeyInfo.Object = (PVOID)KeyObject; 782 DeleteValueKeyInfo.ValueName = ValueName; 783 Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey, 784 &DeleteValueKeyInfo); 785 if (NT_SUCCESS(Status)) 786 { 787 /* Call the internal API */ 788 Status = CmDeleteValueKey(KeyObject->KeyControlBlock, ValueNameCopy); 789 790 /* Do the post callback */ 791 PostOperationInfo.Object = (PVOID)KeyObject; 792 PostOperationInfo.Status = Status; 793 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey, 794 &PostOperationInfo); 795 } 796 797 /* Dereference the key body */ 798 ObDereferenceObject(KeyObject); 799 return Status; 800 } 801 802 NTSTATUS 803 NTAPI 804 NtFlushKey(IN HANDLE KeyHandle) 805 { 806 NTSTATUS Status; 807 PCM_KEY_BODY KeyObject; 808 PAGED_CODE(); 809 810 /* Get the key object */ 811 Status = ObReferenceObjectByHandle(KeyHandle, 812 0, 813 CmpKeyObjectType, 814 ExGetPreviousMode(), 815 (PVOID*)&KeyObject, 816 NULL); 817 if (!NT_SUCCESS(Status)) return Status; 818 819 /* Lock the registry */ 820 CmpLockRegistry(); 821 822 /* Lock the KCB */ 823 CmpAcquireKcbLockShared(KeyObject->KeyControlBlock); 824 825 /* Make sure KCB isn't deleted */ 826 if (KeyObject->KeyControlBlock->Delete) 827 { 828 /* Fail */ 829 Status = STATUS_KEY_DELETED; 830 } 831 else 832 { 833 /* Call the internal API */ 834 Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE); 835 } 836 837 /* Release the locks */ 838 CmpReleaseKcbLock(KeyObject->KeyControlBlock); 839 CmpUnlockRegistry(); 840 841 /* Dereference the object and return status */ 842 ObDereferenceObject(KeyObject); 843 return Status; 844 } 845 846 NTSTATUS 847 NTAPI 848 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes, 849 IN POBJECT_ATTRIBUTES FileObjectAttributes) 850 { 851 /* Call the newer API */ 852 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, 0, NULL); 853 } 854 855 NTSTATUS 856 NTAPI 857 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes, 858 IN POBJECT_ATTRIBUTES FileObjectAttributes, 859 IN ULONG Flags) 860 { 861 /* Call the newer API */ 862 return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL); 863 } 864 865 NTSTATUS 866 NTAPI 867 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey, 868 IN POBJECT_ATTRIBUTES SourceFile, 869 IN ULONG Flags, 870 IN HANDLE TrustClassKey) 871 { 872 NTSTATUS Status; 873 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 874 PCM_KEY_BODY KeyBody = NULL; 875 PAGED_CODE(); 876 877 /* Validate flags */ 878 if (Flags & ~REG_NO_LAZY_FLUSH) return STATUS_INVALID_PARAMETER; 879 880 /* Validate privilege */ 881 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode)) 882 { 883 /* Fail */ 884 DPRINT1("Restore Privilege missing!\n"); 885 return STATUS_PRIVILEGE_NOT_HELD; 886 } 887 888 /* Block APCs */ 889 KeEnterCriticalRegion(); 890 891 /* Check if we have a trust class */ 892 if (TrustClassKey) 893 { 894 /* Reference it */ 895 Status = ObReferenceObjectByHandle(TrustClassKey, 896 0, 897 CmpKeyObjectType, 898 PreviousMode, 899 (PVOID *)&KeyBody, 900 NULL); 901 } 902 903 /* Call the internal API */ 904 Status = CmLoadKey(TargetKey, SourceFile, Flags, KeyBody); 905 906 /* Dereference the trust key, if any */ 907 if (KeyBody) ObDereferenceObject(KeyBody); 908 909 /* Bring back APCs */ 910 KeLeaveCriticalRegion(); 911 912 /* Return status */ 913 return Status; 914 } 915 916 NTSTATUS 917 NTAPI 918 NtNotifyChangeKey(IN HANDLE KeyHandle, 919 IN HANDLE Event, 920 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 921 IN PVOID ApcContext OPTIONAL, 922 OUT PIO_STATUS_BLOCK IoStatusBlock, 923 IN ULONG CompletionFilter, 924 IN BOOLEAN WatchTree, 925 OUT PVOID Buffer, 926 IN ULONG Length, 927 IN BOOLEAN Asynchronous) 928 { 929 /* Call the newer API */ 930 return NtNotifyChangeMultipleKeys(KeyHandle, 931 0, 932 NULL, 933 Event, 934 ApcRoutine, 935 ApcContext, 936 IoStatusBlock, 937 CompletionFilter, 938 WatchTree, 939 Buffer, 940 Length, 941 Asynchronous); 942 } 943 944 NTSTATUS 945 NTAPI 946 NtInitializeRegistry(IN USHORT Flag) 947 { 948 BOOLEAN SetupBoot; 949 NTSTATUS Status = STATUS_SUCCESS; 950 PAGED_CODE(); 951 952 /* Always do this as kernel mode */ 953 if (KeGetPreviousMode() == UserMode) return ZwInitializeRegistry(Flag); 954 955 /* Enough of the system has booted by now */ 956 Ki386PerfEnd(); 957 958 /* Validate flag */ 959 if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER; 960 961 /* Check if boot was accepted */ 962 if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX)) 963 { 964 /* Only allow once */ 965 if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED; 966 CmBootAcceptFirstTime = FALSE; 967 968 /* Get the control set accepted */ 969 Flag -= CM_BOOT_FLAG_ACCEPTED; 970 if (Flag) 971 { 972 /* FIXME: Save the last known good boot */ 973 //Status = CmpSaveBootControlSet(Flag); 974 975 /* Notify HAL */ 976 HalEndOfBoot(); 977 978 /* Enable lazy flush */ 979 CmpHoldLazyFlush = FALSE; 980 CmpLazyFlush(); 981 return Status; 982 } 983 984 /* Otherwise, invalid boot */ 985 return STATUS_INVALID_PARAMETER; 986 } 987 988 /* Check if this was a setup boot */ 989 SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE); 990 991 /* Make sure we're only called once */ 992 if (!CmFirstTime) return STATUS_ACCESS_DENIED; 993 CmFirstTime = FALSE; 994 995 /* Acquire registry lock */ 996 //CmpLockRegistryExclusive(); 997 998 /* Initialize the hives and lazy flusher */ 999 CmpCmdInit(SetupBoot); 1000 1001 /* Save version data */ 1002 CmpSetVersionData(); 1003 1004 /* Release the registry lock */ 1005 //CmpUnlockRegistry(); 1006 return STATUS_SUCCESS; 1007 } 1008 1009 NTSTATUS 1010 NTAPI 1011 NtCompactKeys(IN ULONG Count, 1012 IN PHANDLE KeyArray) 1013 { 1014 UNIMPLEMENTED; 1015 return STATUS_NOT_IMPLEMENTED; 1016 } 1017 1018 NTSTATUS 1019 NTAPI 1020 NtCompressKey(IN HANDLE Key) 1021 { 1022 UNIMPLEMENTED; 1023 return STATUS_NOT_IMPLEMENTED; 1024 } 1025 1026 // FIXME: different for different windows versions! 1027 #define PRODUCT_ACTIVATION_VERSION 7749 1028 1029 NTSTATUS 1030 NTAPI 1031 NtLockProductActivationKeys(IN PULONG pPrivateVer, 1032 IN PULONG pSafeMode) 1033 { 1034 KPROCESSOR_MODE PreviousMode; 1035 1036 PreviousMode = ExGetPreviousMode(); 1037 _SEH2_TRY 1038 { 1039 /* Check if the caller asked for the version */ 1040 if (pPrivateVer != NULL) 1041 { 1042 /* For user mode, probe it */ 1043 if (PreviousMode != KernelMode) 1044 { 1045 ProbeForRead(pPrivateVer, sizeof(ULONG), sizeof(ULONG)); 1046 } 1047 1048 /* Return the expected version */ 1049 *pPrivateVer = PRODUCT_ACTIVATION_VERSION; 1050 } 1051 1052 /* Check if the caller asked for safe mode mode state */ 1053 if (pSafeMode != NULL) 1054 { 1055 /* For user mode, probe it */ 1056 if (PreviousMode != KernelMode) 1057 { 1058 ProbeForRead(pSafeMode, sizeof(ULONG), sizeof(ULONG)); 1059 } 1060 1061 /* Return the safe boot mode state */ 1062 *pSafeMode = InitSafeBootMode; 1063 } 1064 } 1065 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1066 { 1067 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1068 } 1069 _SEH2_END; 1070 1071 return STATUS_SUCCESS; 1072 } 1073 1074 NTSTATUS 1075 NTAPI 1076 NtLockRegistryKey(IN HANDLE KeyHandle) 1077 { 1078 UNIMPLEMENTED; 1079 return STATUS_NOT_IMPLEMENTED; 1080 } 1081 1082 NTSTATUS 1083 NTAPI 1084 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle, 1085 IN ULONG Count, 1086 IN POBJECT_ATTRIBUTES SlaveObjects, 1087 IN HANDLE Event, 1088 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 1089 IN PVOID ApcContext OPTIONAL, 1090 OUT PIO_STATUS_BLOCK IoStatusBlock, 1091 IN ULONG CompletionFilter, 1092 IN BOOLEAN WatchTree, 1093 OUT PVOID Buffer, 1094 IN ULONG Length, 1095 IN BOOLEAN Asynchronous) 1096 { 1097 UNIMPLEMENTED; 1098 return STATUS_NOT_IMPLEMENTED; 1099 } 1100 1101 NTSTATUS 1102 NTAPI 1103 NtQueryMultipleValueKey(IN HANDLE KeyHandle, 1104 IN OUT PKEY_VALUE_ENTRY ValueList, 1105 IN ULONG NumberOfValues, 1106 OUT PVOID Buffer, 1107 IN OUT PULONG Length, 1108 OUT PULONG ReturnLength) 1109 { 1110 UNIMPLEMENTED; 1111 return STATUS_NOT_IMPLEMENTED; 1112 } 1113 1114 NTSTATUS 1115 NTAPI 1116 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey, 1117 OUT PULONG HandleCount) 1118 { 1119 KPROCESSOR_MODE PreviousMode; 1120 PCM_KEY_BODY KeyBody = NULL; 1121 HANDLE KeyHandle; 1122 NTSTATUS Status; 1123 1124 DPRINT("NtQueryOpenSubKeys()\n"); 1125 1126 PAGED_CODE(); 1127 1128 /* Get the processor mode */ 1129 PreviousMode = KeGetPreviousMode(); 1130 1131 if (PreviousMode != KernelMode) 1132 { 1133 /* Prepare to probe parameters */ 1134 _SEH2_TRY 1135 { 1136 /* Probe target key */ 1137 ProbeForRead(TargetKey, 1138 sizeof(OBJECT_ATTRIBUTES), 1139 sizeof(ULONG)); 1140 1141 /* Probe handle count */ 1142 ProbeForWriteUlong(HandleCount); 1143 } 1144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1145 { 1146 /* Return the exception code */ 1147 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1148 } 1149 _SEH2_END; 1150 } 1151 1152 /* Open a handle to the key */ 1153 Status = ObOpenObjectByName(TargetKey, 1154 CmpKeyObjectType, 1155 PreviousMode, 1156 NULL, 1157 KEY_READ, 1158 NULL, 1159 &KeyHandle); 1160 if (NT_SUCCESS(Status)) 1161 { 1162 /* Reference the key object */ 1163 Status = ObReferenceObjectByHandle(KeyHandle, 1164 KEY_READ, 1165 CmpKeyObjectType, 1166 PreviousMode, 1167 (PVOID *)&KeyBody, 1168 NULL); 1169 1170 /* Close the handle */ 1171 NtClose(KeyHandle); 1172 } 1173 1174 /* Fail, if the key object could not be referenced */ 1175 if (!NT_SUCCESS(Status)) 1176 return Status; 1177 1178 /* Lock the registry exclusively */ 1179 CmpLockRegistryExclusive(); 1180 1181 /* Fail, if we did not open a hive root key */ 1182 if (KeyBody->KeyControlBlock->KeyCell != 1183 KeyBody->KeyControlBlock->KeyHive->BaseBlock->RootCell) 1184 { 1185 DPRINT("Error: Key is not a hive root key!\n"); 1186 CmpUnlockRegistry(); 1187 ObDereferenceObject(KeyBody); 1188 return STATUS_INVALID_PARAMETER; 1189 } 1190 1191 /* Call the internal API */ 1192 *HandleCount = CmCountOpenSubKeys(KeyBody->KeyControlBlock, 1193 FALSE); 1194 1195 /* Unlock the registry */ 1196 CmpUnlockRegistry(); 1197 1198 /* Dereference the key object */ 1199 ObDereferenceObject(KeyBody); 1200 1201 DPRINT("Done.\n"); 1202 1203 return Status; 1204 } 1205 1206 NTSTATUS 1207 NTAPI 1208 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey, 1209 IN ULONG BufferLength, 1210 IN PVOID Buffer, 1211 IN PULONG RequiredSize) 1212 { 1213 UNIMPLEMENTED; 1214 return STATUS_NOT_IMPLEMENTED; 1215 } 1216 1217 NTSTATUS 1218 NTAPI 1219 NtRenameKey(IN HANDLE KeyHandle, 1220 IN PUNICODE_STRING ReplacementName) 1221 { 1222 UNIMPLEMENTED; 1223 return STATUS_NOT_IMPLEMENTED; 1224 } 1225 1226 NTSTATUS 1227 NTAPI 1228 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes, 1229 IN HANDLE Key, 1230 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes) 1231 { 1232 UNIMPLEMENTED; 1233 return STATUS_NOT_IMPLEMENTED; 1234 } 1235 1236 NTSTATUS 1237 NTAPI 1238 NtRestoreKey(IN HANDLE KeyHandle, 1239 IN HANDLE FileHandle, 1240 IN ULONG RestoreFlags) 1241 { 1242 UNIMPLEMENTED; 1243 return STATUS_NOT_IMPLEMENTED; 1244 } 1245 1246 NTSTATUS 1247 NTAPI 1248 NtSaveKey(IN HANDLE KeyHandle, 1249 IN HANDLE FileHandle) 1250 { 1251 /* Call the extended API */ 1252 return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT); 1253 } 1254 1255 NTSTATUS 1256 NTAPI 1257 NtSaveKeyEx(IN HANDLE KeyHandle, 1258 IN HANDLE FileHandle, 1259 IN ULONG Flags) 1260 { 1261 NTSTATUS Status; 1262 PCM_KEY_BODY KeyObject; 1263 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1264 1265 PAGED_CODE(); 1266 1267 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle, FileHandle, Flags); 1268 1269 /* Verify the flags */ 1270 if ((Flags != REG_STANDARD_FORMAT) 1271 && (Flags != REG_LATEST_FORMAT) 1272 && (Flags != REG_NO_COMPRESSION)) 1273 { 1274 /* Only one of these values can be specified */ 1275 return STATUS_INVALID_PARAMETER; 1276 } 1277 1278 /* Check for the SeBackupPrivilege */ 1279 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode)) 1280 { 1281 return STATUS_PRIVILEGE_NOT_HELD; 1282 } 1283 1284 /* Verify that the handle is valid and is a registry key */ 1285 Status = ObReferenceObjectByHandle(KeyHandle, 1286 KEY_READ, 1287 CmpKeyObjectType, 1288 PreviousMode, 1289 (PVOID*)&KeyObject, 1290 NULL); 1291 if (!NT_SUCCESS(Status)) return Status; 1292 1293 /* Call the internal API */ 1294 Status = CmSaveKey(KeyObject->KeyControlBlock, FileHandle, Flags); 1295 1296 ObDereferenceObject(KeyObject); 1297 return Status; 1298 } 1299 1300 NTSTATUS 1301 NTAPI 1302 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle, 1303 IN HANDLE LowPrecedenceKeyHandle, 1304 IN HANDLE FileHandle) 1305 { 1306 KPROCESSOR_MODE PreviousMode; 1307 PCM_KEY_BODY HighPrecedenceKeyObject = NULL; 1308 PCM_KEY_BODY LowPrecedenceKeyObject = NULL; 1309 NTSTATUS Status; 1310 1311 PAGED_CODE(); 1312 1313 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n", 1314 HighPrecedenceKeyHandle, LowPrecedenceKeyHandle, FileHandle); 1315 1316 PreviousMode = ExGetPreviousMode(); 1317 1318 /* Check for the SeBackupPrivilege */ 1319 if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode)) 1320 { 1321 return STATUS_PRIVILEGE_NOT_HELD; 1322 } 1323 1324 /* Verify that the handles are valid and are registry keys */ 1325 Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle, 1326 KEY_READ, 1327 CmpKeyObjectType, 1328 PreviousMode, 1329 (PVOID*)&HighPrecedenceKeyObject, 1330 NULL); 1331 if (!NT_SUCCESS(Status)) 1332 goto done; 1333 1334 Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle, 1335 KEY_READ, 1336 CmpKeyObjectType, 1337 PreviousMode, 1338 (PVOID*)&LowPrecedenceKeyObject, 1339 NULL); 1340 if (!NT_SUCCESS(Status)) 1341 goto done; 1342 1343 /* Call the internal API */ 1344 Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock, 1345 LowPrecedenceKeyObject->KeyControlBlock, 1346 FileHandle); 1347 1348 done: 1349 if (LowPrecedenceKeyObject) 1350 ObDereferenceObject(LowPrecedenceKeyObject); 1351 1352 if (HighPrecedenceKeyObject) 1353 ObDereferenceObject(HighPrecedenceKeyObject); 1354 1355 return Status; 1356 } 1357 1358 NTSTATUS 1359 NTAPI 1360 NtSetInformationKey(IN HANDLE KeyHandle, 1361 IN KEY_SET_INFORMATION_CLASS KeyInformationClass, 1362 IN PVOID KeyInformation, 1363 IN ULONG KeyInformationLength) 1364 { 1365 UNIMPLEMENTED; 1366 return STATUS_NOT_IMPLEMENTED; 1367 } 1368 1369 NTSTATUS 1370 NTAPI 1371 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes) 1372 { 1373 return NtUnloadKey2(KeyObjectAttributes, 0); 1374 } 1375 1376 NTSTATUS 1377 NTAPI 1378 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey, 1379 IN ULONG Flags) 1380 { 1381 NTSTATUS Status; 1382 OBJECT_ATTRIBUTES ObjectAttributes; 1383 UNICODE_STRING ObjectName; 1384 CM_PARSE_CONTEXT ParseContext = {0}; 1385 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1386 PCM_KEY_BODY KeyBody = NULL; 1387 ULONG ParentConv = 0, ChildConv = 0; 1388 HANDLE Handle; 1389 1390 PAGED_CODE(); 1391 1392 /* Validate privilege */ 1393 if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode)) 1394 { 1395 /* Fail */ 1396 DPRINT1("Restore Privilege missing!\n"); 1397 return STATUS_PRIVILEGE_NOT_HELD; 1398 } 1399 1400 /* Check for user-mode caller */ 1401 if (PreviousMode != KernelMode) 1402 { 1403 /* Prepare to probe parameters */ 1404 _SEH2_TRY 1405 { 1406 /* Probe object attributes */ 1407 ProbeForRead(TargetKey, 1408 sizeof(OBJECT_ATTRIBUTES), 1409 sizeof(ULONG)); 1410 1411 ObjectAttributes = *TargetKey; 1412 1413 /* Probe the string */ 1414 ProbeForReadUnicodeString(&TargetKey->ObjectName); 1415 1416 ObjectName = *TargetKey->ObjectName; 1417 1418 ProbeForRead(ObjectName.Buffer, 1419 ObjectName.Length, 1420 sizeof(WCHAR)); 1421 1422 ObjectAttributes.ObjectName = &ObjectName; 1423 } 1424 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1425 { 1426 /* Return the exception code */ 1427 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1428 } 1429 _SEH2_END; 1430 } 1431 else 1432 { 1433 /* Save the target attributes directly */ 1434 ObjectAttributes = *TargetKey; 1435 } 1436 1437 /* Setup the parse context */ 1438 ParseContext.CreateOperation = TRUE; 1439 ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE; 1440 1441 /* Do the create */ 1442 Status = ObOpenObjectByName(&ObjectAttributes, 1443 CmpKeyObjectType, 1444 KernelMode, 1445 NULL, 1446 KEY_WRITE, 1447 &ParseContext, 1448 &Handle); 1449 1450 /* Return if failure encountered */ 1451 if (!NT_SUCCESS(Status)) return Status; 1452 1453 /* Reference it */ 1454 Status = ObReferenceObjectByHandle(Handle, 1455 KEY_WRITE, 1456 CmpKeyObjectType, 1457 KernelMode, 1458 (PVOID *)&KeyBody, 1459 NULL); 1460 1461 /* Close the handle */ 1462 ZwClose(Handle); 1463 1464 /* Return if failure encountered */ 1465 if (!NT_SUCCESS(Status)) return Status; 1466 1467 /* Acquire the lock depending on flags */ 1468 if (Flags == REG_FORCE_UNLOAD) 1469 { 1470 /* Lock registry exclusively */ 1471 CmpLockRegistryExclusive(); 1472 } 1473 else 1474 { 1475 /* Lock registry */ 1476 CmpLockRegistry(); 1477 1478 /* Acquire the hive loading lock */ 1479 ExAcquirePushLockExclusive(&CmpLoadHiveLock); 1480 1481 /* Lock parent and child */ 1482 if (KeyBody->KeyControlBlock->ParentKcb) 1483 ParentConv = KeyBody->KeyControlBlock->ParentKcb->ConvKey; 1484 else 1485 ParentConv = KeyBody->KeyControlBlock->ConvKey; 1486 1487 ChildConv = KeyBody->KeyControlBlock->ConvKey; 1488 1489 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv, ParentConv); 1490 } 1491 1492 /* Check if it's being deleted already */ 1493 if (KeyBody->KeyControlBlock->Delete) 1494 { 1495 /* Return appropriate status */ 1496 Status = STATUS_KEY_DELETED; 1497 goto Quickie; 1498 } 1499 1500 /* Check if it's a readonly key */ 1501 if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) 1502 { 1503 /* Return appropriate status */ 1504 Status = STATUS_ACCESS_DENIED; 1505 goto Quickie; 1506 } 1507 1508 /* Call the internal API */ 1509 Status = CmUnloadKey(KeyBody->KeyControlBlock, 1510 Flags); 1511 1512 /* Check if we failed, but really need to succeed */ 1513 if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD)) 1514 { 1515 /* TODO: We should perform another attempt here */ 1516 ASSERT(FALSE); 1517 } 1518 1519 /* If CmUnloadKey failed we need to unlock registry ourselves */ 1520 if (!NT_SUCCESS(Status)) 1521 { 1522 if (Flags != REG_FORCE_UNLOAD) 1523 { 1524 /* Release the KCB locks */ 1525 CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv); 1526 1527 /* Release the hive loading lock */ 1528 ExReleasePushLockExclusive(&CmpLoadHiveLock); 1529 } 1530 1531 /* Unlock the registry */ 1532 CmpUnlockRegistry(); 1533 } 1534 1535 Quickie: 1536 /* Dereference the key */ 1537 ObDereferenceObject(KeyBody); 1538 1539 /* Return status */ 1540 return Status; 1541 } 1542 1543 NTSTATUS 1544 NTAPI 1545 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey, 1546 IN HANDLE Event) 1547 { 1548 UNIMPLEMENTED; 1549 return STATUS_NOT_IMPLEMENTED; 1550 } 1551 1552 /* EOF */ 1553