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)
10 /* INCLUDES ******************************************************************/
16 BOOLEAN CmBootAcceptFirstTime
= TRUE
;
17 BOOLEAN CmFirstTime
= TRUE
;
18 extern ULONG InitSafeBootMode
;
21 /* PRIVATE FUNCTIONS *********************************************************/
24 * Adapted from ntoskrnl/include/internal/ob_x.h:ObpReleaseObjectCreateInformation()
27 ReleaseCapturedObjectAttributes(
28 _In_ POBJECT_ATTRIBUTES CapturedObjectAttributes
,
29 _In_ KPROCESSOR_MODE AccessMode
)
31 /* Check if we have a security descriptor */
32 if (CapturedObjectAttributes
->SecurityDescriptor
)
35 SeReleaseSecurityDescriptor(CapturedObjectAttributes
->SecurityDescriptor
,
38 CapturedObjectAttributes
->SecurityDescriptor
= NULL
;
41 /* Check if we have an object name */
42 if (CapturedObjectAttributes
->ObjectName
)
45 ReleaseCapturedUnicodeString(CapturedObjectAttributes
->ObjectName
, AccessMode
);
50 * Adapted from ntoskrnl/ob/oblife.c:ObpCaptureObjectCreateInformation()
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
)
60 NTSTATUS Status
= STATUS_SUCCESS
;
61 PSECURITY_DESCRIPTOR SecurityDescriptor
;
62 // PSECURITY_QUALITY_OF_SERVICE SecurityQos;
63 PUNICODE_STRING LocalObjectName
= NULL
;
65 /* Zero out the Capture Data */
66 RtlZeroMemory(CapturedObjectAttributes
, sizeof(*CapturedObjectAttributes
));
68 /* SEH everything here for protection */
71 /* Check if we got attributes */
74 /* Check if we're in user mode */
75 if (AccessMode
!= KernelMode
)
77 /* Probe the attributes */
78 ProbeForRead(ObjectAttributes
,
79 sizeof(OBJECT_ATTRIBUTES
),
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
87 /* Invalid combination, fail */
88 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
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;
99 /* Check if we have a security descriptor */
100 if (CaptureSecurity
&& SecurityDescriptor
)
104 * Note: This has an implicit memory barrier due
105 * to the function call, so cleanup is safe here.
107 Status
= SeCaptureSecurityDescriptor(SecurityDescriptor
,
111 &CapturedObjectAttributes
->
113 if (!NT_SUCCESS(Status
))
115 /* Capture failed, quit */
116 CapturedObjectAttributes
->SecurityDescriptor
= NULL
;
117 _SEH2_YIELD(return Status
);
122 CapturedObjectAttributes
->SecurityDescriptor
= NULL
;
126 // We don't use the QoS!
128 /* Check if we have QoS */
131 /* Check if we came from user mode */
132 if (AccessMode
!= KernelMode
)
134 /* Validate the QoS */
135 ProbeForRead(SecurityQos
,
136 sizeof(SECURITY_QUALITY_OF_SERVICE
),
141 CapturedObjectAttributes
->SecurityQualityOfService
= *SecurityQos
;
142 CapturedObjectAttributes
->SecurityQos
=
143 &CapturedObjectAttributes
->SecurityQualityOfService
;
146 CapturedObjectAttributes
->SecurityQualityOfService
= NULL
;
151 /* We don't have a name */
152 LocalObjectName
= NULL
;
155 _SEH2_EXCEPT(ExSystemExceptionFilter())
157 /* Cleanup and return the exception code */
158 ReleaseCapturedObjectAttributes(CapturedObjectAttributes
, AccessMode
);
159 _SEH2_YIELD(return _SEH2_GetExceptionCode());
163 /* Now check if the Object Attributes had an Object Name */
166 Status
= ProbeAndCaptureUnicodeString(ObjectName
, AccessMode
, LocalObjectName
);
170 /* Clear the string */
171 RtlInitEmptyUnicodeString(ObjectName
, NULL
, 0);
173 /* It cannot have specified a Root Directory */
174 if (CapturedObjectAttributes
->RootDirectory
)
176 Status
= STATUS_OBJECT_NAME_INVALID
;
180 /* Set the caputured object attributes name pointer to the one the user gave to us */
181 CapturedObjectAttributes
->ObjectName
= ObjectName
;
183 /* Cleanup if we failed */
184 if (!NT_SUCCESS(Status
))
186 ReleaseCapturedObjectAttributes(CapturedObjectAttributes
, AccessMode
);
189 /* Return status to caller */
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
)
205 *KernelHandle
= NULL
;
207 /* NULL handle is valid */
208 if (SourceHandle
== NULL
)
209 return STATUS_SUCCESS
;
211 /* Get the object pointer */
212 Status
= ObReferenceObjectByHandle(SourceHandle
,
218 if (!NT_SUCCESS(Status
))
221 /* Create a kernel handle from the pointer */
222 Status
= ObOpenObjectByPointer(Object
,
230 /* Dereference the object */
231 ObDereferenceObject(Object
);
236 /* FUNCTIONS *****************************************************************/
240 NtCreateKey(OUT PHANDLE KeyHandle
,
241 IN ACCESS_MASK DesiredAccess
,
242 IN POBJECT_ATTRIBUTES ObjectAttributes
,
244 IN PUNICODE_STRING Class OPTIONAL
,
245 IN ULONG CreateOptions
,
246 OUT PULONG Disposition OPTIONAL
)
249 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
250 CM_PARSE_CONTEXT ParseContext
= {0};
254 DPRINT("NtCreateKey(Path: %wZ, Root %x, Access: %x, CreateOptions %x)\n",
255 ObjectAttributes
->ObjectName
, ObjectAttributes
->RootDirectory
,
256 DesiredAccess
, CreateOptions
);
258 /* Ignore the WOW64 flag, it's not valid in the kernel */
259 DesiredAccess
&= ~KEY_WOW64_RES
;
261 /* Check for user-mode caller */
262 if (PreviousMode
!= KernelMode
)
264 /* Prepare to probe parameters */
267 /* Check if we have a class */
271 ParseContext
.Class
= ProbeForReadUnicodeString(Class
);
272 ProbeForRead(ParseContext
.Class
.Buffer
,
273 ParseContext
.Class
.Length
,
277 /* Probe the key handle */
278 ProbeForWriteHandle(KeyHandle
);
281 /* Probe object attributes */
282 ProbeForRead(ObjectAttributes
,
283 sizeof(OBJECT_ATTRIBUTES
),
287 ProbeForWriteUlong(Disposition
);
289 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
291 /* Return the exception code */
292 _SEH2_YIELD(return _SEH2_GetExceptionCode());
298 /* Save the class directly */
299 if (Class
) ParseContext
.Class
= *Class
;
302 /* Setup the parse context */
303 ParseContext
.CreateOperation
= TRUE
;
304 ParseContext
.CreateOptions
= CreateOptions
;
307 Status
= ObOpenObjectByName(ObjectAttributes
,
317 /* Return data to user */
318 if (NT_SUCCESS(Status
)) *KeyHandle
= Handle
;
319 if (Disposition
) *Disposition
= ParseContext
.Disposition
;
321 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
324 Status
= _SEH2_GetExceptionCode();
328 DPRINT("Returning handle %x, Status %x.\n", Handle
, Status
);
336 NtOpenKey(OUT PHANDLE KeyHandle
,
337 IN ACCESS_MASK DesiredAccess
,
338 IN POBJECT_ATTRIBUTES ObjectAttributes
)
340 CM_PARSE_CONTEXT ParseContext
= {0};
343 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
345 DPRINT("NtOpenKey(Path: %wZ, Root %x, Access: %x)\n",
346 ObjectAttributes
->ObjectName
, ObjectAttributes
->RootDirectory
, DesiredAccess
);
348 /* Ignore the WOW64 flag, it's not valid in the kernel */
349 DesiredAccess
&= ~KEY_WOW64_RES
;
351 /* Check for user-mode caller */
352 if (PreviousMode
!= KernelMode
)
354 /* Prepare to probe parameters */
357 /* Probe the key handle */
358 ProbeForWriteHandle(KeyHandle
);
361 /* Probe object attributes */
362 ProbeForRead(ObjectAttributes
,
363 sizeof(OBJECT_ATTRIBUTES
),
366 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
368 /* Return the exception code */
369 _SEH2_YIELD(return _SEH2_GetExceptionCode());
374 /* Just let the object manager handle this */
375 Status
= ObOpenObjectByName(ObjectAttributes
,
383 /* Only do this if we succeeded */
384 if (NT_SUCCESS(Status
))
388 /* Return the handle to caller */
391 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
394 Status
= _SEH2_GetExceptionCode();
399 DPRINT("Returning handle %x, Status %x.\n", Handle
, Status
);
408 NtDeleteKey(IN HANDLE KeyHandle
)
410 PCM_KEY_BODY KeyObject
;
412 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
413 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
415 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle
);
417 /* Verify that the handle is valid and is a registry key */
418 Status
= ObReferenceObjectByHandle(KeyHandle
,
424 if (!NT_SUCCESS(Status
)) return Status
;
426 /* Setup the callback */
427 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
428 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
429 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteKey
, &DeleteKeyInfo
);
430 if (NT_SUCCESS(Status
))
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
))
437 Status
= STATUS_ACCESS_DENIED
;
441 /* Call the internal API */
442 Status
= CmDeleteKey(KeyObject
);
445 /* Do post callback */
446 PostOperationInfo
.Status
= Status
;
447 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
450 /* Dereference and return status */
451 ObDereferenceObject(KeyObject
);
457 NtEnumerateKey(IN HANDLE KeyHandle
,
459 IN KEY_INFORMATION_CLASS KeyInformationClass
,
460 OUT PVOID KeyInformation
,
462 OUT PULONG ResultLength
)
464 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
466 PCM_KEY_BODY KeyObject
;
467 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
468 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
470 DPRINT("NtEnumerateKey() KH 0x%p, Index 0x%x, KIC %d, Length %lu\n",
471 KeyHandle
, Index
, KeyInformationClass
, Length
);
473 /* Reject classes we don't know about */
474 if ((KeyInformationClass
!= KeyBasicInformation
) &&
475 (KeyInformationClass
!= KeyNodeInformation
) &&
476 (KeyInformationClass
!= KeyFullInformation
))
479 return STATUS_INVALID_PARAMETER
;
482 /* Verify that the handle is valid and is a registry key */
483 Status
= ObReferenceObjectByHandle(KeyHandle
,
484 KEY_ENUMERATE_SUB_KEYS
,
489 if (!NT_SUCCESS(Status
)) return Status
;
491 if (PreviousMode
!= KernelMode
)
495 ProbeForWriteUlong(ResultLength
);
496 ProbeForWrite(KeyInformation
,
500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
502 /* Dereference and return status */
503 ObDereferenceObject(KeyObject
);
504 _SEH2_YIELD(return _SEH2_GetExceptionCode());
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
;
517 /* Do the callback */
518 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateKey
, &EnumerateKeyInfo
);
519 if (NT_SUCCESS(Status
))
521 /* Call the internal API */
522 Status
= CmEnumerateKey(KeyObject
->KeyControlBlock
,
529 /* Do the post callback */
530 PostOperationInfo
.Status
= Status
;
531 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
534 /* Dereference and return status */
535 ObDereferenceObject(KeyObject
);
536 DPRINT("Returning status %x.\n", Status
);
542 NtEnumerateValueKey(IN HANDLE KeyHandle
,
544 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
545 OUT PVOID KeyValueInformation
,
547 OUT PULONG ResultLength
)
549 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
551 PCM_KEY_BODY KeyObject
;
552 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo
;
553 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
557 DPRINT("NtEnumerateValueKey() KH 0x%p, Index 0x%x, KVIC %d, Length %lu\n",
558 KeyHandle
, Index
, KeyValueInformationClass
, Length
);
560 /* Reject classes we don't know about */
561 if ((KeyValueInformationClass
!= KeyValueBasicInformation
) &&
562 (KeyValueInformationClass
!= KeyValueFullInformation
) &&
563 (KeyValueInformationClass
!= KeyValuePartialInformation
) &&
564 (KeyValueInformationClass
!= KeyValueFullInformationAlign64
) &&
565 (KeyValueInformationClass
!= KeyValuePartialInformationAlign64
))
568 return STATUS_INVALID_PARAMETER
;
571 /* Verify that the handle is valid and is a registry key */
572 Status
= ObReferenceObjectByHandle(KeyHandle
,
578 if (!NT_SUCCESS(Status
)) return Status
;
580 if (PreviousMode
!= KernelMode
)
584 ProbeForWriteUlong(ResultLength
);
585 ProbeForWrite(KeyValueInformation
,
589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
591 /* Dereference and return status */
592 ObDereferenceObject(KeyObject
);
593 _SEH2_YIELD(return _SEH2_GetExceptionCode());
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
;
607 /* Do the callback */
608 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey
,
609 &EnumerateValueKeyInfo
);
610 if (NT_SUCCESS(Status
))
612 /* Call the internal API */
613 Status
= CmEnumerateValueKey(KeyObject
->KeyControlBlock
,
615 KeyValueInformationClass
,
620 /* Do the post callback */
621 PostOperationInfo
.Status
= Status
;
622 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey
, &PostOperationInfo
);
625 /* Dereference and return status */
626 ObDereferenceObject(KeyObject
);
632 NtQueryKey(IN HANDLE KeyHandle
,
633 IN KEY_INFORMATION_CLASS KeyInformationClass
,
634 OUT PVOID KeyInformation
,
636 OUT PULONG ResultLength
)
638 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
640 PCM_KEY_BODY KeyObject
;
641 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
642 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
643 OBJECT_HANDLE_INFORMATION HandleInfo
;
645 DPRINT("NtQueryKey() KH 0x%p, KIC %d, Length %lu\n",
646 KeyHandle
, KeyInformationClass
, Length
);
648 /* Reject invalid classes */
649 if ((KeyInformationClass
!= KeyBasicInformation
) &&
650 (KeyInformationClass
!= KeyNodeInformation
) &&
651 (KeyInformationClass
!= KeyFullInformation
) &&
652 (KeyInformationClass
!= KeyNameInformation
) &&
653 (KeyInformationClass
!= KeyCachedInformation
) &&
654 (KeyInformationClass
!= KeyFlagsInformation
))
657 return STATUS_INVALID_PARAMETER
;
660 /* Check if just the name is required */
661 if (KeyInformationClass
== KeyNameInformation
)
663 /* Ignore access level */
664 Status
= ObReferenceObjectByHandle(KeyHandle
,
670 if (NT_SUCCESS(Status
))
672 /* At least a single bit of access is required */
673 if (!HandleInfo
.GrantedAccess
)
676 ObDereferenceObject(KeyObject
);
677 Status
= STATUS_ACCESS_DENIED
;
683 /* Get a reference */
684 Status
= ObReferenceObjectByHandle(KeyHandle
,
692 /* Quit on failure */
693 if (!NT_SUCCESS(Status
)) return Status
;
695 if (PreviousMode
!= KernelMode
)
699 ProbeForWriteUlong(ResultLength
);
700 ProbeForWrite(KeyInformation
,
704 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
706 /* Dereference and return status */
707 ObDereferenceObject(KeyObject
);
708 _SEH2_YIELD(return _SEH2_GetExceptionCode());
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
;
721 /* Do the callback */
722 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryKey
, &QueryKeyInfo
);
723 if (NT_SUCCESS(Status
))
725 /* Call the internal API */
726 Status
= CmQueryKey(KeyObject
->KeyControlBlock
,
732 /* Do the post callback */
733 PostOperationInfo
.Status
= Status
;
734 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
737 /* Dereference and return status */
738 ObDereferenceObject(KeyObject
);
744 NtQueryValueKey(IN HANDLE KeyHandle
,
745 IN PUNICODE_STRING ValueName
,
746 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
747 OUT PVOID KeyValueInformation
,
749 OUT PULONG ResultLength
)
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
;
760 DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n",
761 KeyHandle
, ValueName
, KeyValueInformationClass
, Length
);
763 /* Reject classes we don't know about */
764 if ((KeyValueInformationClass
!= KeyValueBasicInformation
) &&
765 (KeyValueInformationClass
!= KeyValueFullInformation
) &&
766 (KeyValueInformationClass
!= KeyValuePartialInformation
) &&
767 (KeyValueInformationClass
!= KeyValueFullInformationAlign64
) &&
768 (KeyValueInformationClass
!= KeyValuePartialInformationAlign64
))
771 return STATUS_INVALID_PARAMETER
;
774 /* Verify that the handle is valid and is a registry key */
775 Status
= ObReferenceObjectByHandle(KeyHandle
,
781 if (!NT_SUCCESS(Status
))
784 if (PreviousMode
!= KernelMode
)
788 ProbeForWriteUlong(ResultLength
);
789 ProbeForWrite(KeyValueInformation
,
793 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
795 /* Dereference and return status */
796 ObDereferenceObject(KeyObject
);
797 _SEH2_YIELD(return _SEH2_GetExceptionCode());
802 /* Capture the string */
803 Status
= ProbeAndCaptureUnicodeString(&ValueNameCopy
, PreviousMode
, ValueName
);
804 if (!NT_SUCCESS(Status
))
807 /* Make sure the name is aligned properly */
808 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
810 /* It isn't, so we'll fail */
811 Status
= STATUS_INVALID_PARAMETER
;
815 /* Ignore any null characters at the end */
816 while ((ValueNameCopy
.Length
) &&
817 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
820 ValueNameCopy
.Length
-= sizeof(WCHAR
);
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
;
831 /* Do the callback */
832 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
833 if (NT_SUCCESS(Status
))
835 /* Call the internal API */
836 Status
= CmQueryValueKey(KeyObject
->KeyControlBlock
,
838 KeyValueInformationClass
,
843 /* Do the post callback */
844 PostOperationInfo
.Status
= Status
;
845 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
849 if (ValueNameCopy
.Buffer
)
850 ReleaseCapturedUnicodeString(&ValueNameCopy
, PreviousMode
);
852 /* Dereference and return status */
853 ObDereferenceObject(KeyObject
);
859 NtSetValueKey(IN HANDLE KeyHandle
,
860 IN PUNICODE_STRING ValueName
,
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
;
875 PreviousMode
= ExGetPreviousMode();
877 /* Verify that the handle is valid and is a registry key */
878 Status
= ObReferenceObjectByHandle(KeyHandle
,
884 if (!NT_SUCCESS(Status
))
890 /* Probe and copy the data */
891 if ((PreviousMode
!= KernelMode
) && (DataSize
!= 0))
893 PVOID DataCopy
= ExAllocatePoolWithTag(PagedPool
, DataSize
, TAG_CM
);
896 /* Dereference and return status */
897 ObDereferenceObject(KeyObject
);
898 return STATUS_INSUFFICIENT_RESOURCES
;
902 ProbeForRead(Data
, DataSize
, 1);
903 RtlCopyMemory(DataCopy
, Data
, DataSize
);
905 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
907 Status
= _SEH2_GetExceptionCode();
911 if (!NT_SUCCESS(Status
))
913 /* Dereference and return status */
914 ExFreePoolWithTag(DataCopy
, TAG_CM
);
915 ObDereferenceObject(KeyObject
);
921 /* Capture the string */
922 Status
= ProbeAndCaptureUnicodeString(&ValueNameCopy
, PreviousMode
, ValueName
);
923 if (!NT_SUCCESS(Status
))
926 DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
927 KeyHandle
, &ValueNameCopy
, TitleIndex
, Type
, DataSize
);
929 /* Make sure the name is aligned, not too long, and the data under 4GB */
930 if ( (ValueNameCopy
.Length
> 32767) ||
931 ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1))) ||
932 (DataSize
> 0x80000000))
935 Status
= STATUS_INVALID_PARAMETER
;
939 /* Ignore any null characters at the end */
940 while ((ValueNameCopy
.Length
) &&
941 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
944 ValueNameCopy
.Length
-= sizeof(WCHAR
);
947 /* Don't touch read-only keys */
948 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
951 Status
= STATUS_ACCESS_DENIED
;
956 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
957 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
958 SetValueKeyInfo
.ValueName
= &ValueNameCopy
;
959 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
960 SetValueKeyInfo
.Type
= Type
;
961 SetValueKeyInfo
.Data
= Data
;
962 SetValueKeyInfo
.DataSize
= DataSize
;
964 /* Do the callback */
965 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
966 if (NT_SUCCESS(Status
))
968 /* Call the internal API */
969 Status
= CmSetValueKey(KeyObject
->KeyControlBlock
,
975 /* Do the post-callback */
976 PostOperationInfo
.Status
= Status
;
977 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
981 if (ValueNameCopy
.Buffer
)
982 ReleaseCapturedUnicodeString(&ValueNameCopy
, PreviousMode
);
984 if ((PreviousMode
!= KernelMode
) && Data
)
985 ExFreePoolWithTag(Data
, TAG_CM
);
987 /* Dereference and return status */
988 ObDereferenceObject(KeyObject
);
994 NtDeleteValueKey(IN HANDLE KeyHandle
,
995 IN PUNICODE_STRING ValueName
)
998 PCM_KEY_BODY KeyObject
;
999 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
1000 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
1001 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1002 UNICODE_STRING ValueNameCopy
;
1006 /* Verify that the handle is valid and is a registry key */
1007 Status
= ObReferenceObjectByHandle(KeyHandle
,
1013 if (!NT_SUCCESS(Status
))
1016 /* Capture the string */
1017 Status
= ProbeAndCaptureUnicodeString(&ValueNameCopy
, PreviousMode
, ValueName
);
1018 if (!NT_SUCCESS(Status
))
1021 /* Make sure the name is aligned properly */
1022 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
1024 /* It isn't, so we'll fail */
1025 Status
= STATUS_INVALID_PARAMETER
;
1029 /* Don't touch read-only keys */
1030 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1033 Status
= STATUS_ACCESS_DENIED
;
1037 /* Do the callback */
1038 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
1039 DeleteValueKeyInfo
.ValueName
= ValueName
;
1040 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
,
1041 &DeleteValueKeyInfo
);
1042 if (NT_SUCCESS(Status
))
1044 /* Call the internal API */
1045 Status
= CmDeleteValueKey(KeyObject
->KeyControlBlock
, ValueNameCopy
);
1047 /* Do the post callback */
1048 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
1049 PostOperationInfo
.Status
= Status
;
1050 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
,
1051 &PostOperationInfo
);
1055 if (ValueNameCopy
.Buffer
)
1056 ReleaseCapturedUnicodeString(&ValueNameCopy
, PreviousMode
);
1058 /* Dereference and return status */
1059 ObDereferenceObject(KeyObject
);
1065 NtFlushKey(IN HANDLE KeyHandle
)
1068 PCM_KEY_BODY KeyObject
;
1071 /* Get the key object */
1072 Status
= ObReferenceObjectByHandle(KeyHandle
,
1075 ExGetPreviousMode(),
1078 if (!NT_SUCCESS(Status
)) return Status
;
1080 /* Lock the registry */
1084 CmpAcquireKcbLockShared(KeyObject
->KeyControlBlock
);
1086 /* Make sure KCB isn't deleted */
1087 if (KeyObject
->KeyControlBlock
->Delete
)
1090 Status
= STATUS_KEY_DELETED
;
1094 /* Call the internal API */
1095 Status
= CmFlushKey(KeyObject
->KeyControlBlock
, FALSE
);
1098 /* Release the locks */
1099 CmpReleaseKcbLock(KeyObject
->KeyControlBlock
);
1100 CmpUnlockRegistry();
1102 /* Dereference the object and return status */
1103 ObDereferenceObject(KeyObject
);
1109 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1110 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
1112 /* Call the newer API */
1113 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, 0, NULL
);
1118 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
1119 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
1122 /* Call the newer API */
1123 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, Flags
, NULL
);
1128 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1129 IN POBJECT_ATTRIBUTES SourceFile
,
1131 IN HANDLE TrustClassKey
)
1134 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1135 OBJECT_ATTRIBUTES CapturedTargetKey
;
1136 OBJECT_ATTRIBUTES CapturedSourceFile
;
1137 UNICODE_STRING TargetKeyName
, SourceFileName
;
1138 HANDLE KmTargetKeyRootDir
= NULL
, KmSourceFileRootDir
= NULL
;
1139 PCM_KEY_BODY KeyBody
= NULL
;
1143 /* Validate flags */
1144 if (Flags
& ~REG_NO_LAZY_FLUSH
)
1145 return STATUS_INVALID_PARAMETER
;
1147 /* Validate privilege */
1148 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1150 DPRINT1("Restore Privilege missing!\n");
1151 return STATUS_PRIVILEGE_NOT_HELD
;
1155 KeEnterCriticalRegion();
1157 /* Check for user-mode caller */
1158 if (PreviousMode
!= KernelMode
)
1160 /* Prepare to probe parameters */
1163 /* Probe target key */
1164 ProbeForRead(TargetKey
,
1165 sizeof(OBJECT_ATTRIBUTES
),
1168 /* Probe source file */
1169 ProbeForRead(SourceFile
,
1170 sizeof(OBJECT_ATTRIBUTES
),
1173 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1175 /* Return the exception code */
1176 Status
= _SEH2_GetExceptionCode();
1177 _SEH2_YIELD(goto Quit
);
1182 /* Probe and capture the target key attributes, including the security */
1183 Status
= ProbeAndCaptureObjectAttributes(&CapturedTargetKey
,
1188 if (!NT_SUCCESS(Status
))
1192 * Probe and capture the source file attributes, but not the security.
1193 * A proper security context is built by CmLoadKey().
1195 Status
= ProbeAndCaptureObjectAttributes(&CapturedSourceFile
,
1200 if (!NT_SUCCESS(Status
))
1202 ReleaseCapturedObjectAttributes(&CapturedTargetKey
, PreviousMode
);
1206 /* Make sure the target key root directory handle is a kernel handle */
1207 Status
= CmpConvertHandleToKernelHandle(CapturedTargetKey
.RootDirectory
,
1211 &KmTargetKeyRootDir
);
1212 if (!NT_SUCCESS(Status
))
1214 CapturedTargetKey
.RootDirectory
= KmTargetKeyRootDir
;
1215 CapturedTargetKey
.Attributes
|= OBJ_KERNEL_HANDLE
;
1217 /* Make sure the source file root directory handle is a kernel handle */
1218 Status
= CmpConvertHandleToKernelHandle(CapturedSourceFile
.RootDirectory
,
1222 &KmSourceFileRootDir
);
1223 if (!NT_SUCCESS(Status
))
1225 CapturedSourceFile
.RootDirectory
= KmSourceFileRootDir
;
1226 CapturedSourceFile
.Attributes
|= OBJ_KERNEL_HANDLE
;
1228 /* Check if we have a trust class */
1232 Status
= ObReferenceObjectByHandle(TrustClassKey
,
1240 /* Call the internal API */
1241 Status
= CmLoadKey(&CapturedTargetKey
,
1242 &CapturedSourceFile
,
1246 /* Dereference the trust key, if any */
1247 if (KeyBody
) ObDereferenceObject(KeyBody
);
1250 /* Close the local kernel handles */
1251 if (KmSourceFileRootDir
)
1252 ObCloseHandle(KmSourceFileRootDir
, KernelMode
);
1253 if (KmTargetKeyRootDir
)
1254 ObCloseHandle(KmTargetKeyRootDir
, KernelMode
);
1256 /* Release the captured object attributes */
1257 ReleaseCapturedObjectAttributes(&CapturedSourceFile
, PreviousMode
);
1258 ReleaseCapturedObjectAttributes(&CapturedTargetKey
, PreviousMode
);
1261 /* Bring back APCs */
1262 KeLeaveCriticalRegion();
1270 NtNotifyChangeKey(IN HANDLE KeyHandle
,
1272 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1273 IN PVOID ApcContext OPTIONAL
,
1274 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1275 IN ULONG CompletionFilter
,
1276 IN BOOLEAN WatchTree
,
1279 IN BOOLEAN Asynchronous
)
1281 /* Call the newer API */
1282 return NtNotifyChangeMultipleKeys(KeyHandle
,
1298 NtInitializeRegistry(IN USHORT Flag
)
1301 NTSTATUS Status
= STATUS_SUCCESS
;
1304 /* Always do this as kernel mode */
1305 if (KeGetPreviousMode() == UserMode
) return ZwInitializeRegistry(Flag
);
1307 /* Enough of the system has booted by now */
1311 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
1313 /* Check if boot was accepted */
1314 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
1316 /* Only allow once */
1317 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
1318 CmBootAcceptFirstTime
= FALSE
;
1320 /* Get the control set accepted */
1321 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
1324 /* FIXME: Save the last known good boot */
1325 //Status = CmpSaveBootControlSet(Flag);
1330 /* Enable lazy flush */
1331 CmpHoldLazyFlush
= FALSE
;
1336 /* Otherwise, invalid boot */
1337 return STATUS_INVALID_PARAMETER
;
1340 /* Check if this was a setup boot */
1341 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
1343 /* Make sure we're only called once */
1344 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
1345 CmFirstTime
= FALSE
;
1347 /* Acquire registry lock */
1348 //CmpLockRegistryExclusive();
1350 /* Initialize the hives and lazy flusher */
1351 CmpCmdInit(SetupBoot
);
1353 /* Save version data */
1354 CmpSetVersionData();
1356 /* Release the registry lock */
1357 //CmpUnlockRegistry();
1358 return STATUS_SUCCESS
;
1363 NtCompactKeys(IN ULONG Count
,
1364 IN PHANDLE KeyArray
)
1367 return STATUS_NOT_IMPLEMENTED
;
1372 NtCompressKey(IN HANDLE Key
)
1375 return STATUS_NOT_IMPLEMENTED
;
1378 // FIXME: different for different windows versions!
1379 #define PRODUCT_ACTIVATION_VERSION 7749
1383 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
1384 IN PULONG pSafeMode
)
1386 KPROCESSOR_MODE PreviousMode
;
1388 PreviousMode
= ExGetPreviousMode();
1391 /* Check if the caller asked for the version */
1392 if (pPrivateVer
!= NULL
)
1394 /* For user mode, probe it */
1395 if (PreviousMode
!= KernelMode
)
1397 ProbeForRead(pPrivateVer
, sizeof(ULONG
), sizeof(ULONG
));
1400 /* Return the expected version */
1401 *pPrivateVer
= PRODUCT_ACTIVATION_VERSION
;
1404 /* Check if the caller asked for safe mode mode state */
1405 if (pSafeMode
!= NULL
)
1407 /* For user mode, probe it */
1408 if (PreviousMode
!= KernelMode
)
1410 ProbeForRead(pSafeMode
, sizeof(ULONG
), sizeof(ULONG
));
1413 /* Return the safe boot mode state */
1414 *pSafeMode
= InitSafeBootMode
;
1417 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1419 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1423 return STATUS_SUCCESS
;
1428 NtLockRegistryKey(IN HANDLE KeyHandle
)
1431 return STATUS_NOT_IMPLEMENTED
;
1436 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
1438 IN POBJECT_ATTRIBUTES SlaveObjects
,
1440 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1441 IN PVOID ApcContext OPTIONAL
,
1442 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1443 IN ULONG CompletionFilter
,
1444 IN BOOLEAN WatchTree
,
1447 IN BOOLEAN Asynchronous
)
1450 return STATUS_NOT_IMPLEMENTED
;
1455 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1456 IN OUT PKEY_VALUE_ENTRY ValueList
,
1457 IN ULONG NumberOfValues
,
1459 IN OUT PULONG Length
,
1460 OUT PULONG ReturnLength
)
1463 return STATUS_NOT_IMPLEMENTED
;
1468 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1469 OUT PULONG HandleCount
)
1471 KPROCESSOR_MODE PreviousMode
;
1472 PCM_KEY_BODY KeyBody
= NULL
;
1476 DPRINT("NtQueryOpenSubKeys()\n");
1480 /* Get the processor mode */
1481 PreviousMode
= KeGetPreviousMode();
1483 /* Check for user-mode caller */
1484 if (PreviousMode
!= KernelMode
)
1486 /* Prepare to probe parameters */
1489 /* Probe target key */
1490 ProbeForRead(TargetKey
,
1491 sizeof(OBJECT_ATTRIBUTES
),
1494 /* Probe handle count */
1495 ProbeForWriteUlong(HandleCount
);
1497 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1499 /* Return the exception code */
1500 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1505 /* Open a handle to the key */
1506 Status
= ObOpenObjectByName(TargetKey
,
1513 if (NT_SUCCESS(Status
))
1515 /* Reference the key object */
1516 Status
= ObReferenceObjectByHandle(KeyHandle
,
1523 /* Close the handle */
1527 /* Fail, if the key object could not be referenced */
1528 if (!NT_SUCCESS(Status
))
1531 /* Lock the registry exclusively */
1532 CmpLockRegistryExclusive();
1534 /* Fail, if we did not open a hive root key */
1535 if (KeyBody
->KeyControlBlock
->KeyCell
!=
1536 KeyBody
->KeyControlBlock
->KeyHive
->BaseBlock
->RootCell
)
1538 DPRINT("Error: Key is not a hive root key!\n");
1539 CmpUnlockRegistry();
1540 ObDereferenceObject(KeyBody
);
1541 return STATUS_INVALID_PARAMETER
;
1544 /* Call the internal API */
1545 *HandleCount
= CmCountOpenSubKeys(KeyBody
->KeyControlBlock
,
1548 /* Unlock the registry */
1549 CmpUnlockRegistry();
1551 /* Dereference the key object */
1552 ObDereferenceObject(KeyBody
);
1561 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey
,
1562 IN ULONG BufferLength
,
1564 IN PULONG RequiredSize
)
1567 return STATUS_NOT_IMPLEMENTED
;
1572 NtRenameKey(IN HANDLE KeyHandle
,
1573 IN PUNICODE_STRING ReplacementName
)
1576 return STATUS_NOT_IMPLEMENTED
;
1581 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1583 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1586 return STATUS_NOT_IMPLEMENTED
;
1591 NtRestoreKey(IN HANDLE KeyHandle
,
1592 IN HANDLE FileHandle
,
1593 IN ULONG RestoreFlags
)
1596 return STATUS_NOT_IMPLEMENTED
;
1601 NtSaveKey(IN HANDLE KeyHandle
,
1602 IN HANDLE FileHandle
)
1604 /* Call the extended API */
1605 return NtSaveKeyEx(KeyHandle
, FileHandle
, REG_STANDARD_FORMAT
);
1610 NtSaveKeyEx(IN HANDLE KeyHandle
,
1611 IN HANDLE FileHandle
,
1615 HANDLE KmFileHandle
= NULL
;
1616 PCM_KEY_BODY KeyObject
;
1617 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1621 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle
, FileHandle
, Flags
);
1623 /* Verify the flags */
1624 if ((Flags
!= REG_STANDARD_FORMAT
)
1625 && (Flags
!= REG_LATEST_FORMAT
)
1626 && (Flags
!= REG_NO_COMPRESSION
))
1628 /* Only one of these values can be specified */
1629 return STATUS_INVALID_PARAMETER
;
1632 /* Validate privilege */
1633 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1635 return STATUS_PRIVILEGE_NOT_HELD
;
1638 /* Make sure the target file handle is a kernel handle */
1639 Status
= CmpConvertHandleToKernelHandle(FileHandle
,
1644 if (!NT_SUCCESS(Status
))
1647 /* Verify that the handle is valid and is a registry key */
1648 Status
= ObReferenceObjectByHandle(KeyHandle
,
1654 if (!NT_SUCCESS(Status
))
1657 /* Call the internal API */
1658 Status
= CmSaveKey(KeyObject
->KeyControlBlock
, KmFileHandle
, Flags
);
1660 /* Dereference the registry key */
1661 ObDereferenceObject(KeyObject
);
1664 /* Close the local kernel handle */
1666 ObCloseHandle(KmFileHandle
, KernelMode
);
1673 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle
,
1674 IN HANDLE LowPrecedenceKeyHandle
,
1675 IN HANDLE FileHandle
)
1678 KPROCESSOR_MODE PreviousMode
;
1679 HANDLE KmFileHandle
= NULL
;
1680 PCM_KEY_BODY HighPrecedenceKeyObject
= NULL
;
1681 PCM_KEY_BODY LowPrecedenceKeyObject
= NULL
;
1685 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n",
1686 HighPrecedenceKeyHandle
, LowPrecedenceKeyHandle
, FileHandle
);
1688 PreviousMode
= ExGetPreviousMode();
1690 /* Validate privilege */
1691 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1693 return STATUS_PRIVILEGE_NOT_HELD
;
1696 /* Make sure the target file handle is a kernel handle */
1697 Status
= CmpConvertHandleToKernelHandle(FileHandle
,
1702 if (!NT_SUCCESS(Status
))
1705 /* Verify that the handles are valid and are registry keys */
1706 Status
= ObReferenceObjectByHandle(HighPrecedenceKeyHandle
,
1710 (PVOID
*)&HighPrecedenceKeyObject
,
1712 if (!NT_SUCCESS(Status
))
1715 Status
= ObReferenceObjectByHandle(LowPrecedenceKeyHandle
,
1719 (PVOID
*)&LowPrecedenceKeyObject
,
1721 if (!NT_SUCCESS(Status
))
1724 /* Call the internal API */
1725 Status
= CmSaveMergedKeys(HighPrecedenceKeyObject
->KeyControlBlock
,
1726 LowPrecedenceKeyObject
->KeyControlBlock
,
1730 /* Dereference the opened key objects */
1731 if (LowPrecedenceKeyObject
)
1732 ObDereferenceObject(LowPrecedenceKeyObject
);
1733 if (HighPrecedenceKeyObject
)
1734 ObDereferenceObject(HighPrecedenceKeyObject
);
1736 /* Close the local kernel handle */
1738 ObCloseHandle(KmFileHandle
, KernelMode
);
1745 NtSetInformationKey(IN HANDLE KeyHandle
,
1746 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
1747 IN PVOID KeyInformation
,
1748 IN ULONG KeyInformationLength
)
1751 return STATUS_NOT_IMPLEMENTED
;
1756 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
1758 return NtUnloadKey2(KeyObjectAttributes
, 0);
1763 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey
,
1767 OBJECT_ATTRIBUTES CapturedTargetKey
;
1768 UNICODE_STRING ObjectName
;
1769 HANDLE KmTargetKeyRootDir
= NULL
;
1770 CM_PARSE_CONTEXT ParseContext
= {0};
1771 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1772 PCM_KEY_BODY KeyBody
= NULL
;
1773 ULONG ParentConv
= 0, ChildConv
= 0;
1778 /* Validate privilege */
1779 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1781 DPRINT1("Restore Privilege missing!\n");
1782 return STATUS_PRIVILEGE_NOT_HELD
;
1785 /* Check for user-mode caller */
1786 if (PreviousMode
!= KernelMode
)
1788 /* Prepare to probe parameters */
1791 /* Probe object attributes */
1792 ProbeForRead(TargetKey
,
1793 sizeof(OBJECT_ATTRIBUTES
),
1796 CapturedTargetKey
= *TargetKey
;
1798 /* Probe the string */
1799 ObjectName
= ProbeForReadUnicodeString(CapturedTargetKey
.ObjectName
);
1800 ProbeForRead(ObjectName
.Buffer
,
1804 CapturedTargetKey
.ObjectName
= &ObjectName
;
1806 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1808 /* Return the exception code */
1809 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1815 /* Save the target attributes directly */
1816 CapturedTargetKey
= *TargetKey
;
1819 /* Make sure the target key root directory handle is a kernel handle */
1820 Status
= CmpConvertHandleToKernelHandle(CapturedTargetKey
.RootDirectory
,
1824 &KmTargetKeyRootDir
);
1825 if (!NT_SUCCESS(Status
))
1827 CapturedTargetKey
.RootDirectory
= KmTargetKeyRootDir
;
1828 CapturedTargetKey
.Attributes
|= OBJ_KERNEL_HANDLE
;
1830 /* Setup the parse context */
1831 ParseContext
.CreateOperation
= TRUE
;
1832 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1835 /* Open a local handle to the key */
1836 Status
= ObOpenObjectByName(&CapturedTargetKey
,
1843 if (NT_SUCCESS(Status
))
1845 /* Reference the key object */
1846 Status
= ObReferenceObjectByHandle(Handle
,
1853 /* Close the handle */
1854 ObCloseHandle(Handle
, KernelMode
);
1857 /* Close the local kernel handle */
1858 if (KmTargetKeyRootDir
)
1859 ObCloseHandle(KmTargetKeyRootDir
, KernelMode
);
1861 /* Return if a failure was encountered */
1862 if (!NT_SUCCESS(Status
))
1865 /* Acquire the lock depending on flags */
1866 if (Flags
== REG_FORCE_UNLOAD
)
1868 /* Lock registry exclusively */
1869 CmpLockRegistryExclusive();
1876 /* Acquire the hive loading lock */
1877 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1879 /* Lock parent and child */
1880 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1881 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1883 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1885 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1887 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1890 /* Check if it's being deleted already */
1891 if (KeyBody
->KeyControlBlock
->Delete
)
1893 /* Return appropriate status */
1894 Status
= STATUS_KEY_DELETED
;
1898 /* Check if it's a read-only key */
1899 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1901 /* Return appropriate status */
1902 Status
= STATUS_ACCESS_DENIED
;
1906 /* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */
1907 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
, Flags
);
1909 /* Check if we failed, but really need to succeed */
1910 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1912 /* TODO: We should perform another attempt here */
1915 DPRINT1("NtUnloadKey2(%wZ): We want to force-unload the hive but couldn't unload it: Retrying is UNIMPLEMENTED!\n", TargetKey
->ObjectName
);
1917 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1923 /* If CmUnloadKey() failed we need to unlock registry ourselves */
1924 if (!NT_SUCCESS(Status
))
1926 if (Flags
!= REG_FORCE_UNLOAD
)
1928 /* Release the KCB locks */
1929 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1931 /* Release the hive loading lock */
1932 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1935 /* Unlock the registry */
1936 CmpUnlockRegistry();
1940 /* Dereference the key */
1941 ObDereferenceObject(KeyBody
);
1949 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1953 return STATUS_NOT_IMPLEMENTED
;