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
)
1306 return ZwInitializeRegistry(Flag
);
1308 /* Enough of the system has booted by now */
1312 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
1314 /* Check if boot was accepted */
1315 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
1317 /* Only allow once */
1318 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
1319 CmBootAcceptFirstTime
= FALSE
;
1321 /* Get the control set accepted */
1322 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
1325 /* Save the last known good boot */
1326 Status
= CmpSaveBootControlSet(Flag
);
1331 /* Enable lazy flush */
1332 CmpHoldLazyFlush
= FALSE
;
1337 /* Otherwise, invalid boot */
1338 return STATUS_INVALID_PARAMETER
;
1341 /* Check if this was a setup boot */
1342 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
1344 /* Make sure we're only called once */
1345 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
1346 CmFirstTime
= FALSE
;
1348 /* Lock the registry exclusively */
1349 CmpLockRegistryExclusive();
1351 /* Initialize the hives and lazy flusher */
1352 CmpCmdInit(SetupBoot
);
1354 /* Save version data */
1355 CmpSetVersionData();
1357 /* Release the registry lock */
1358 CmpUnlockRegistry();
1359 return STATUS_SUCCESS
;
1364 NtCompactKeys(IN ULONG Count
,
1365 IN PHANDLE KeyArray
)
1368 return STATUS_NOT_IMPLEMENTED
;
1373 NtCompressKey(IN HANDLE Key
)
1376 return STATUS_NOT_IMPLEMENTED
;
1379 // FIXME: different for different windows versions!
1380 #define PRODUCT_ACTIVATION_VERSION 7749
1384 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
1385 IN PULONG pSafeMode
)
1387 KPROCESSOR_MODE PreviousMode
;
1389 PreviousMode
= ExGetPreviousMode();
1392 /* Check if the caller asked for the version */
1393 if (pPrivateVer
!= NULL
)
1395 /* For user mode, probe it */
1396 if (PreviousMode
!= KernelMode
)
1398 ProbeForRead(pPrivateVer
, sizeof(ULONG
), sizeof(ULONG
));
1401 /* Return the expected version */
1402 *pPrivateVer
= PRODUCT_ACTIVATION_VERSION
;
1405 /* Check if the caller asked for safe mode mode state */
1406 if (pSafeMode
!= NULL
)
1408 /* For user mode, probe it */
1409 if (PreviousMode
!= KernelMode
)
1411 ProbeForRead(pSafeMode
, sizeof(ULONG
), sizeof(ULONG
));
1414 /* Return the safe boot mode state */
1415 *pSafeMode
= InitSafeBootMode
;
1418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1420 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1424 return STATUS_SUCCESS
;
1429 NtLockRegistryKey(IN HANDLE KeyHandle
)
1432 return STATUS_NOT_IMPLEMENTED
;
1437 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
1439 IN POBJECT_ATTRIBUTES SlaveObjects
,
1441 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1442 IN PVOID ApcContext OPTIONAL
,
1443 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1444 IN ULONG CompletionFilter
,
1445 IN BOOLEAN WatchTree
,
1448 IN BOOLEAN Asynchronous
)
1451 return STATUS_NOT_IMPLEMENTED
;
1456 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1457 IN OUT PKEY_VALUE_ENTRY ValueList
,
1458 IN ULONG NumberOfValues
,
1460 IN OUT PULONG Length
,
1461 OUT PULONG ReturnLength
)
1464 return STATUS_NOT_IMPLEMENTED
;
1469 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1470 OUT PULONG HandleCount
)
1472 KPROCESSOR_MODE PreviousMode
;
1473 PCM_KEY_BODY KeyBody
= NULL
;
1477 DPRINT("NtQueryOpenSubKeys()\n");
1481 /* Get the processor mode */
1482 PreviousMode
= KeGetPreviousMode();
1484 /* Check for user-mode caller */
1485 if (PreviousMode
!= KernelMode
)
1487 /* Prepare to probe parameters */
1490 /* Probe target key */
1491 ProbeForRead(TargetKey
,
1492 sizeof(OBJECT_ATTRIBUTES
),
1495 /* Probe handle count */
1496 ProbeForWriteUlong(HandleCount
);
1498 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1500 /* Return the exception code */
1501 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1506 /* Open a handle to the key */
1507 Status
= ObOpenObjectByName(TargetKey
,
1514 if (NT_SUCCESS(Status
))
1516 /* Reference the key object */
1517 Status
= ObReferenceObjectByHandle(KeyHandle
,
1524 /* Close the handle */
1528 /* Fail, if the key object could not be referenced */
1529 if (!NT_SUCCESS(Status
))
1532 /* Lock the registry exclusively */
1533 CmpLockRegistryExclusive();
1535 /* Fail, if we did not open a hive root key */
1536 if (KeyBody
->KeyControlBlock
->KeyCell
!=
1537 KeyBody
->KeyControlBlock
->KeyHive
->BaseBlock
->RootCell
)
1539 DPRINT("Error: Key is not a hive root key!\n");
1540 CmpUnlockRegistry();
1541 ObDereferenceObject(KeyBody
);
1542 return STATUS_INVALID_PARAMETER
;
1545 /* Call the internal API */
1546 *HandleCount
= CmpEnumerateOpenSubKeys(KeyBody
->KeyControlBlock
,
1549 /* Unlock the registry */
1550 CmpUnlockRegistry();
1552 /* Dereference the key object */
1553 ObDereferenceObject(KeyBody
);
1562 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey
,
1563 IN ULONG BufferLength
,
1565 IN PULONG RequiredSize
)
1568 return STATUS_NOT_IMPLEMENTED
;
1573 NtRenameKey(IN HANDLE KeyHandle
,
1574 IN PUNICODE_STRING ReplacementName
)
1577 return STATUS_NOT_IMPLEMENTED
;
1582 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1584 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1587 return STATUS_NOT_IMPLEMENTED
;
1592 NtRestoreKey(IN HANDLE KeyHandle
,
1593 IN HANDLE FileHandle
,
1594 IN ULONG RestoreFlags
)
1597 return STATUS_NOT_IMPLEMENTED
;
1602 NtSaveKey(IN HANDLE KeyHandle
,
1603 IN HANDLE FileHandle
)
1605 /* Call the extended API */
1606 return NtSaveKeyEx(KeyHandle
, FileHandle
, REG_STANDARD_FORMAT
);
1611 NtSaveKeyEx(IN HANDLE KeyHandle
,
1612 IN HANDLE FileHandle
,
1616 HANDLE KmFileHandle
= NULL
;
1617 PCM_KEY_BODY KeyObject
;
1618 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1622 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle
, FileHandle
, Flags
);
1624 /* Verify the flags */
1625 if ((Flags
!= REG_STANDARD_FORMAT
)
1626 && (Flags
!= REG_LATEST_FORMAT
)
1627 && (Flags
!= REG_NO_COMPRESSION
))
1629 /* Only one of these values can be specified */
1630 return STATUS_INVALID_PARAMETER
;
1633 /* Validate privilege */
1634 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1636 return STATUS_PRIVILEGE_NOT_HELD
;
1639 /* Make sure the target file handle is a kernel handle */
1640 Status
= CmpConvertHandleToKernelHandle(FileHandle
,
1645 if (!NT_SUCCESS(Status
))
1648 /* Verify that the handle is valid and is a registry key */
1649 Status
= ObReferenceObjectByHandle(KeyHandle
,
1655 if (!NT_SUCCESS(Status
))
1658 /* Call the internal API */
1659 Status
= CmSaveKey(KeyObject
->KeyControlBlock
, KmFileHandle
, Flags
);
1661 /* Dereference the registry key */
1662 ObDereferenceObject(KeyObject
);
1665 /* Close the local kernel handle */
1667 ObCloseHandle(KmFileHandle
, KernelMode
);
1674 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle
,
1675 IN HANDLE LowPrecedenceKeyHandle
,
1676 IN HANDLE FileHandle
)
1679 KPROCESSOR_MODE PreviousMode
;
1680 HANDLE KmFileHandle
= NULL
;
1681 PCM_KEY_BODY HighPrecedenceKeyObject
= NULL
;
1682 PCM_KEY_BODY LowPrecedenceKeyObject
= NULL
;
1686 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n",
1687 HighPrecedenceKeyHandle
, LowPrecedenceKeyHandle
, FileHandle
);
1689 PreviousMode
= ExGetPreviousMode();
1691 /* Validate privilege */
1692 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1694 return STATUS_PRIVILEGE_NOT_HELD
;
1697 /* Make sure the target file handle is a kernel handle */
1698 Status
= CmpConvertHandleToKernelHandle(FileHandle
,
1703 if (!NT_SUCCESS(Status
))
1706 /* Verify that the handles are valid and are registry keys */
1707 Status
= ObReferenceObjectByHandle(HighPrecedenceKeyHandle
,
1711 (PVOID
*)&HighPrecedenceKeyObject
,
1713 if (!NT_SUCCESS(Status
))
1716 Status
= ObReferenceObjectByHandle(LowPrecedenceKeyHandle
,
1720 (PVOID
*)&LowPrecedenceKeyObject
,
1722 if (!NT_SUCCESS(Status
))
1725 /* Call the internal API */
1726 Status
= CmSaveMergedKeys(HighPrecedenceKeyObject
->KeyControlBlock
,
1727 LowPrecedenceKeyObject
->KeyControlBlock
,
1731 /* Dereference the opened key objects */
1732 if (LowPrecedenceKeyObject
)
1733 ObDereferenceObject(LowPrecedenceKeyObject
);
1734 if (HighPrecedenceKeyObject
)
1735 ObDereferenceObject(HighPrecedenceKeyObject
);
1737 /* Close the local kernel handle */
1739 ObCloseHandle(KmFileHandle
, KernelMode
);
1746 NtSetInformationKey(IN HANDLE KeyHandle
,
1747 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
1748 IN PVOID KeyInformation
,
1749 IN ULONG KeyInformationLength
)
1752 return STATUS_NOT_IMPLEMENTED
;
1757 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
1759 return NtUnloadKey2(KeyObjectAttributes
, 0);
1764 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey
,
1768 OBJECT_ATTRIBUTES CapturedTargetKey
;
1769 UNICODE_STRING ObjectName
;
1770 HANDLE KmTargetKeyRootDir
= NULL
;
1771 CM_PARSE_CONTEXT ParseContext
= {0};
1772 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1773 PCM_KEY_BODY KeyBody
= NULL
;
1774 ULONG ParentConv
= 0, ChildConv
= 0;
1779 /* Validate privilege */
1780 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1782 DPRINT1("Restore Privilege missing!\n");
1783 return STATUS_PRIVILEGE_NOT_HELD
;
1786 /* Check for user-mode caller */
1787 if (PreviousMode
!= KernelMode
)
1789 /* Prepare to probe parameters */
1792 /* Probe object attributes */
1793 ProbeForRead(TargetKey
,
1794 sizeof(OBJECT_ATTRIBUTES
),
1797 CapturedTargetKey
= *TargetKey
;
1799 /* Probe the string */
1800 ObjectName
= ProbeForReadUnicodeString(CapturedTargetKey
.ObjectName
);
1801 ProbeForRead(ObjectName
.Buffer
,
1805 CapturedTargetKey
.ObjectName
= &ObjectName
;
1807 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1809 /* Return the exception code */
1810 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1816 /* Save the target attributes directly */
1817 CapturedTargetKey
= *TargetKey
;
1820 /* Make sure the target key root directory handle is a kernel handle */
1821 Status
= CmpConvertHandleToKernelHandle(CapturedTargetKey
.RootDirectory
,
1825 &KmTargetKeyRootDir
);
1826 if (!NT_SUCCESS(Status
))
1828 CapturedTargetKey
.RootDirectory
= KmTargetKeyRootDir
;
1829 CapturedTargetKey
.Attributes
|= OBJ_KERNEL_HANDLE
;
1831 /* Setup the parse context */
1832 ParseContext
.CreateOperation
= TRUE
;
1833 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1836 /* Open a local handle to the key */
1837 Status
= ObOpenObjectByName(&CapturedTargetKey
,
1844 if (NT_SUCCESS(Status
))
1846 /* Reference the key object */
1847 Status
= ObReferenceObjectByHandle(Handle
,
1854 /* Close the handle */
1855 ObCloseHandle(Handle
, KernelMode
);
1858 /* Close the local kernel handle */
1859 if (KmTargetKeyRootDir
)
1860 ObCloseHandle(KmTargetKeyRootDir
, KernelMode
);
1862 /* Return if a failure was encountered */
1863 if (!NT_SUCCESS(Status
))
1866 /* Acquire the lock depending on flags */
1867 if (Flags
== REG_FORCE_UNLOAD
)
1869 /* Lock registry exclusively */
1870 CmpLockRegistryExclusive();
1877 /* Acquire the hive loading lock */
1878 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1880 /* Lock parent and child */
1881 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1882 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1884 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1886 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1888 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1891 /* Check if it's being deleted already */
1892 if (KeyBody
->KeyControlBlock
->Delete
)
1894 /* Return appropriate status */
1895 Status
= STATUS_KEY_DELETED
;
1899 /* Check if it's a read-only key */
1900 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1902 /* Return appropriate status */
1903 Status
= STATUS_ACCESS_DENIED
;
1907 /* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */
1908 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
, Flags
);
1910 /* Check if we failed, but really need to succeed */
1911 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1913 /* TODO: We should perform another attempt here */
1916 DPRINT1("NtUnloadKey2(%wZ): We want to force-unload the hive but couldn't unload it: Retrying is UNIMPLEMENTED!\n", TargetKey
->ObjectName
);
1918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1924 /* If CmUnloadKey() failed we need to unlock registry ourselves */
1925 if (!NT_SUCCESS(Status
))
1927 if (Flags
!= REG_FORCE_UNLOAD
)
1929 /* Release the KCB locks */
1930 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1932 /* Release the hive loading lock */
1933 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1936 /* Unlock the registry */
1937 CmpUnlockRegistry();
1941 /* Dereference the key */
1942 ObDereferenceObject(KeyBody
);
1950 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1954 return STATUS_NOT_IMPLEMENTED
;