2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmapi.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
;
19 /* FUNCTIONS *****************************************************************/
23 NtCreateKey(OUT PHANDLE KeyHandle
,
24 IN ACCESS_MASK DesiredAccess
,
25 IN POBJECT_ATTRIBUTES ObjectAttributes
,
27 IN PUNICODE_STRING Class OPTIONAL
,
28 IN ULONG CreateOptions
,
29 OUT PULONG Disposition OPTIONAL
)
32 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
33 CM_PARSE_CONTEXT ParseContext
= {0};
36 DPRINT("NtCreateKey(OB name %wZ)\n", ObjectAttributes
->ObjectName
);
38 /* Check for user-mode caller */
39 if (PreviousMode
!= KernelMode
)
41 /* Prepare to probe parameters */
44 /* Check if we have a class */
48 ParseContext
.Class
= ProbeForReadUnicodeString(Class
);
49 ProbeForRead(ParseContext
.Class
.Buffer
,
50 ParseContext
.Class
.Length
,
54 /* Probe the key handle */
55 ProbeForWriteHandle(KeyHandle
);
58 /* Probe object attributes */
59 ProbeForRead(ObjectAttributes
,
60 sizeof(OBJECT_ATTRIBUTES
),
63 if (Disposition
) ProbeForWriteUlong(Disposition
);
65 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
67 /* Return the exception code */
68 _SEH2_YIELD(return _SEH2_GetExceptionCode());
74 /* Save the class directly */
75 if (Class
) ParseContext
.Class
= *Class
;
78 /* Setup the parse context */
79 ParseContext
.CreateOperation
= TRUE
;
80 ParseContext
.CreateOptions
= CreateOptions
;
83 Status
= ObOpenObjectByName(ObjectAttributes
,
93 /* Return data to user */
94 if (NT_SUCCESS(Status
)) *KeyHandle
= Handle
;
95 if (Disposition
) *Disposition
= ParseContext
.Disposition
;
97 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
100 Status
= _SEH2_GetExceptionCode();
110 NtOpenKey(OUT PHANDLE KeyHandle
,
111 IN ACCESS_MASK DesiredAccess
,
112 IN POBJECT_ATTRIBUTES ObjectAttributes
)
114 CM_PARSE_CONTEXT ParseContext
= {0};
117 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
119 DPRINT("NtOpenKey(OB 0x%wZ)\n", ObjectAttributes
->ObjectName
);
121 /* Check for user-mode caller */
122 if (PreviousMode
!= KernelMode
)
124 /* Prepare to probe parameters */
127 /* Probe the key handle */
128 ProbeForWriteHandle(KeyHandle
);
131 /* Probe object attributes */
132 ProbeForRead(ObjectAttributes
,
133 sizeof(OBJECT_ATTRIBUTES
),
136 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
138 /* Return the exception code */
139 _SEH2_YIELD(return _SEH2_GetExceptionCode());
144 /* Just let the object manager handle this */
145 Status
= ObOpenObjectByName(ObjectAttributes
,
153 /* Only do this if we succeeded */
154 if (NT_SUCCESS(Status
))
158 /* Return the handle to caller */
161 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
164 Status
= _SEH2_GetExceptionCode();
176 NtDeleteKey(IN HANDLE KeyHandle
)
178 PCM_KEY_BODY KeyObject
;
180 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
181 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
183 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle
);
185 /* Verify that the handle is valid and is a registry key */
186 Status
= ObReferenceObjectByHandle(KeyHandle
,
192 if (!NT_SUCCESS(Status
)) return Status
;
194 /* Setup the callback */
195 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
196 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
197 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteKey
, &DeleteKeyInfo
);
198 if (NT_SUCCESS(Status
))
200 /* Check if we are read-only */
201 if ((KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
) ||
202 (KeyObject
->KeyControlBlock
->ParentKcb
->ExtFlags
& CM_KCB_READ_ONLY_KEY
))
205 Status
= STATUS_ACCESS_DENIED
;
209 /* Call the internal API */
210 Status
= CmDeleteKey(KeyObject
);
213 /* Do post callback */
214 PostOperationInfo
.Status
= Status
;
215 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
218 /* Dereference the object */
219 ObDereferenceObject(KeyObject
);
225 NtEnumerateKey(IN HANDLE KeyHandle
,
227 IN KEY_INFORMATION_CLASS KeyInformationClass
,
228 OUT PVOID KeyInformation
,
230 OUT PULONG ResultLength
)
232 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
234 PCM_KEY_BODY KeyObject
;
235 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
236 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
238 DPRINT("NtEnumerateKey() KH 0x%x, Index 0x%x, KIC %d, Length %d\n",
239 KeyHandle
, Index
, KeyInformationClass
, Length
);
241 /* Reject classes we don't know about */
242 if ((KeyInformationClass
!= KeyBasicInformation
) &&
243 (KeyInformationClass
!= KeyNodeInformation
) &&
244 (KeyInformationClass
!= KeyFullInformation
))
247 return STATUS_INVALID_PARAMETER
;
250 /* Verify that the handle is valid and is a registry key */
251 Status
= ObReferenceObjectByHandle(KeyHandle
,
252 KEY_ENUMERATE_SUB_KEYS
,
257 if (!NT_SUCCESS(Status
)) return Status
;
259 if (PreviousMode
!= KernelMode
)
263 ProbeForWriteUlong(ResultLength
);
264 ProbeForWrite(KeyInformation
,
268 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
270 /* Dereference and return status */
271 ObDereferenceObject(KeyObject
);
272 _SEH2_YIELD(return _SEH2_GetExceptionCode());
277 /* Setup the callback */
278 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
279 EnumerateKeyInfo
.Object
= (PVOID
)KeyObject
;
280 EnumerateKeyInfo
.Index
= Index
;
281 EnumerateKeyInfo
.KeyInformationClass
= KeyInformationClass
;
282 EnumerateKeyInfo
.Length
= Length
;
283 EnumerateKeyInfo
.ResultLength
= ResultLength
;
285 /* Do the callback */
286 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateKey
, &EnumerateKeyInfo
);
287 if (NT_SUCCESS(Status
))
289 /* Call the internal API */
290 Status
= CmEnumerateKey(KeyObject
->KeyControlBlock
,
297 /* Do the post callback */
298 PostOperationInfo
.Status
= Status
;
299 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
302 /* Dereference and return status */
303 ObDereferenceObject(KeyObject
);
309 NtEnumerateValueKey(IN HANDLE KeyHandle
,
311 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
312 OUT PVOID KeyValueInformation
,
314 OUT PULONG ResultLength
)
316 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
318 PCM_KEY_BODY KeyObject
;
319 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo
;
320 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
322 DPRINT("NtEnumerateValueKey() KH 0x%x, Index 0x%x, KVIC %d, Length %d\n",
323 KeyHandle
, Index
, KeyValueInformationClass
, Length
);
325 /* Reject classes we don't know about */
326 if ((KeyValueInformationClass
!= KeyValueBasicInformation
) &&
327 (KeyValueInformationClass
!= KeyValueFullInformation
) &&
328 (KeyValueInformationClass
!= KeyValuePartialInformation
))
331 return STATUS_INVALID_PARAMETER
;
334 /* Verify that the handle is valid and is a registry key */
335 Status
= ObReferenceObjectByHandle(KeyHandle
,
341 if (!NT_SUCCESS(Status
)) return Status
;
343 if (PreviousMode
!= KernelMode
)
347 ProbeForWriteUlong(ResultLength
);
348 ProbeForWrite(KeyValueInformation
,
352 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
354 /* Dereference and return status */
355 ObDereferenceObject(KeyObject
);
356 _SEH2_YIELD(return _SEH2_GetExceptionCode());
361 /* Setup the callback */
362 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
363 EnumerateValueKeyInfo
.Object
= (PVOID
)KeyObject
;
364 EnumerateValueKeyInfo
.Index
= Index
;
365 EnumerateValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
366 EnumerateValueKeyInfo
.KeyValueInformation
= KeyValueInformation
;
367 EnumerateValueKeyInfo
.Length
= Length
;
368 EnumerateValueKeyInfo
.ResultLength
= ResultLength
;
370 /* Do the callback */
371 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey
,
372 &EnumerateValueKeyInfo
);
373 if (NT_SUCCESS(Status
))
375 /* Call the internal API */
376 Status
= CmEnumerateValueKey(KeyObject
->KeyControlBlock
,
378 KeyValueInformationClass
,
383 /* Do the post callback */
384 PostOperationInfo
.Status
= Status
;
385 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey
, &PostOperationInfo
);
388 ObDereferenceObject(KeyObject
);
394 NtQueryKey(IN HANDLE KeyHandle
,
395 IN KEY_INFORMATION_CLASS KeyInformationClass
,
396 OUT PVOID KeyInformation
,
398 OUT PULONG ResultLength
)
400 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
402 PCM_KEY_BODY KeyObject
;
403 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
404 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
405 OBJECT_HANDLE_INFORMATION HandleInfo
;
407 DPRINT("NtQueryKey() KH 0x%x, KIC %d, Length %d\n",
408 KeyHandle
, KeyInformationClass
, Length
);
410 /* Reject invalid classes */
411 if ((KeyInformationClass
!= KeyBasicInformation
) &&
412 (KeyInformationClass
!= KeyNodeInformation
) &&
413 (KeyInformationClass
!= KeyFullInformation
) &&
414 (KeyInformationClass
!= KeyNameInformation
) &&
415 (KeyInformationClass
!= KeyCachedInformation
) &&
416 (KeyInformationClass
!= KeyFlagsInformation
))
419 return STATUS_INVALID_PARAMETER
;
422 /* Check if just the name is required */
423 if (KeyInformationClass
== KeyNameInformation
)
425 /* Ignore access level */
426 Status
= ObReferenceObjectByHandle(KeyHandle
,
432 if (NT_SUCCESS(Status
))
434 /* At least a single bit of access is required */
435 if (!HandleInfo
.GrantedAccess
)
438 ObDereferenceObject(KeyObject
);
439 Status
= STATUS_ACCESS_DENIED
;
445 /* Get a reference */
446 Status
= ObReferenceObjectByHandle(KeyHandle
,
454 /* Quit on failure */
455 if (!NT_SUCCESS(Status
)) return Status
;
457 if (PreviousMode
!= KernelMode
)
461 ProbeForWriteUlong(ResultLength
);
462 ProbeForWrite(KeyInformation
,
466 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
468 /* Dereference and return status */
469 ObDereferenceObject(KeyObject
);
470 _SEH2_YIELD(return _SEH2_GetExceptionCode());
475 /* Setup the callback */
476 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
477 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
478 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
479 QueryKeyInfo
.KeyInformation
= KeyInformation
;
480 QueryKeyInfo
.Length
= Length
;
481 QueryKeyInfo
.ResultLength
= ResultLength
;
483 /* Do the callback */
484 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryKey
, &QueryKeyInfo
);
485 if (NT_SUCCESS(Status
))
487 /* Call the internal API */
488 Status
= CmQueryKey(KeyObject
->KeyControlBlock
,
494 /* Do the post callback */
495 PostOperationInfo
.Status
= Status
;
496 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
499 /* Dereference and return status */
500 ObDereferenceObject(KeyObject
);
506 NtQueryValueKey(IN HANDLE KeyHandle
,
507 IN PUNICODE_STRING ValueName
,
508 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
509 OUT PVOID KeyValueInformation
,
511 OUT PULONG ResultLength
)
513 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
515 PCM_KEY_BODY KeyObject
;
516 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
517 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
518 UNICODE_STRING ValueNameCopy
= *ValueName
;
520 DPRINT("NtQueryValueKey() KH 0x%x, VN '%wZ', KVIC %d, Length %d\n",
521 KeyHandle
, ValueName
, KeyValueInformationClass
, Length
);
523 /* Verify that the handle is valid and is a registry key */
524 Status
= ObReferenceObjectByHandle(KeyHandle
,
530 if (!NT_SUCCESS(Status
)) return Status
;
532 if (PreviousMode
!= KernelMode
)
536 ProbeForWriteUlong(ResultLength
);
537 ProbeForWrite(KeyValueInformation
,
541 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
543 /* Dereference and return status */
544 ObDereferenceObject(KeyObject
);
545 _SEH2_YIELD(return _SEH2_GetExceptionCode());
550 /* Make sure the name is aligned properly */
551 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
553 /* It isn't, so we'll fail */
554 ObDereferenceObject(KeyObject
);
555 return STATUS_INVALID_PARAMETER
;
559 /* Ignore any null characters at the end */
560 while ((ValueNameCopy
.Length
) &&
561 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
564 ValueNameCopy
.Length
-= sizeof(WCHAR
);
568 /* Setup the callback */
569 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
570 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
571 QueryValueKeyInfo
.ValueName
= &ValueNameCopy
;
572 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
573 QueryValueKeyInfo
.Length
= Length
;
574 QueryValueKeyInfo
.ResultLength
= ResultLength
;
576 /* Do the callback */
577 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
578 if (NT_SUCCESS(Status
))
580 /* Call the internal API */
581 Status
= CmQueryValueKey(KeyObject
->KeyControlBlock
,
583 KeyValueInformationClass
,
588 /* Do the post callback */
589 PostOperationInfo
.Status
= Status
;
590 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
593 /* Dereference and return status */
594 ObDereferenceObject(KeyObject
);
600 NtSetValueKey(IN HANDLE KeyHandle
,
601 IN PUNICODE_STRING ValueName
,
608 PCM_KEY_BODY KeyObject
;
609 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
610 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
611 UNICODE_STRING ValueNameCopy
= *ValueName
;
613 DPRINT("NtSetValueKey() KH 0x%x, VN '%wZ', TI %x, T %d, DS %d\n",
614 KeyHandle
, ValueName
, TitleIndex
, Type
, DataSize
);
616 /* Verify that the handle is valid and is a registry key */
617 Status
= ObReferenceObjectByHandle(KeyHandle
,
623 if (!NT_SUCCESS(Status
)) return Status
;
625 /* Make sure the name is aligned, not too long, and the data under 4GB */
626 if ( (ValueNameCopy
.Length
> 32767) ||
627 ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1))) ||
628 (DataSize
> 0x80000000))
631 ObDereferenceObject(KeyObject
);
632 return STATUS_INVALID_PARAMETER
;
635 /* Ignore any null characters at the end */
636 while ((ValueNameCopy
.Length
) &&
637 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
640 ValueNameCopy
.Length
-= sizeof(WCHAR
);
643 /* Don't touch read-only keys */
644 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
647 ObDereferenceObject(KeyObject
);
648 return STATUS_ACCESS_DENIED
;
652 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
653 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
654 SetValueKeyInfo
.ValueName
= ValueName
;
655 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
656 SetValueKeyInfo
.Type
= Type
;
657 SetValueKeyInfo
.Data
= Data
;
658 SetValueKeyInfo
.DataSize
= DataSize
;
660 /* Do the callback */
661 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
662 if (NT_SUCCESS(Status
))
664 /* Call the internal API */
665 Status
= CmSetValueKey(KeyObject
->KeyControlBlock
,
672 /* Do the post-callback */
673 PostOperationInfo
.Status
= Status
;
674 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
676 /* Dereference and return status */
677 ObDereferenceObject(KeyObject
);
683 NtDeleteValueKey(IN HANDLE KeyHandle
,
684 IN PUNICODE_STRING ValueName
)
686 PCM_KEY_BODY KeyObject
;
688 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
689 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
690 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
691 UNICODE_STRING ValueNameCopy
= *ValueName
;
694 /* Verify that the handle is valid and is a registry key */
695 Status
= ObReferenceObjectByHandle(KeyHandle
,
701 if (!NT_SUCCESS(Status
)) return Status
;
703 /* Don't touch read-only keys */
704 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
707 ObDereferenceObject(KeyObject
);
708 return STATUS_ACCESS_DENIED
;
711 /* Make sure the name is aligned properly */
712 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
714 /* It isn't, so we'll fail */
715 ObDereferenceObject(KeyObject
);
716 return STATUS_INVALID_PARAMETER
;
719 /* Do the callback */
720 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
721 DeleteValueKeyInfo
.ValueName
= ValueName
;
722 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
,
723 &DeleteValueKeyInfo
);
724 if (NT_SUCCESS(Status
))
726 /* Call the internal API */
727 Status
= CmDeleteValueKey(KeyObject
->KeyControlBlock
, ValueNameCopy
);
729 /* Do the post callback */
730 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
731 PostOperationInfo
.Status
= Status
;
732 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
,
736 /* Dereference the key body */
737 ObDereferenceObject(KeyObject
);
743 NtFlushKey(IN HANDLE KeyHandle
)
746 PCM_KEY_BODY KeyObject
;
749 /* Get the key object */
750 Status
= ObReferenceObjectByHandle(KeyHandle
,
756 if (!NT_SUCCESS(Status
)) return Status
;
758 /* Lock the registry */
762 CmpAcquireKcbLockShared(KeyObject
->KeyControlBlock
);
764 /* Make sure KCB isn't deleted */
765 if (KeyObject
->KeyControlBlock
->Delete
)
768 Status
= STATUS_KEY_DELETED
;
772 /* Call the internal API */
773 Status
= CmFlushKey(KeyObject
->KeyControlBlock
, FALSE
);
776 /* Release the locks */
777 CmpReleaseKcbLock(KeyObject
->KeyControlBlock
);
780 /* Dereference the object and return status */
781 ObDereferenceObject(KeyObject
);
787 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
788 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
790 /* Call the newer API */
791 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, 0, NULL
);
796 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
797 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
800 /* Call the newer API */
801 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, Flags
, NULL
);
806 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
807 IN POBJECT_ATTRIBUTES SourceFile
,
809 IN HANDLE TrustClassKey
)
812 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
813 PCM_KEY_BODY KeyBody
= NULL
;
817 if (Flags
& ~REG_NO_LAZY_FLUSH
) return STATUS_INVALID_PARAMETER
;
819 /* Validate privilege */
820 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
823 DPRINT1("Restore Privilege missing!\n");
824 return STATUS_PRIVILEGE_NOT_HELD
;
828 KeEnterCriticalRegion();
830 /* Check if we have a trust class */
834 Status
= ObReferenceObjectByHandle(TrustClassKey
,
842 /* Call the internal API */
843 Status
= CmLoadKey(TargetKey
, SourceFile
, Flags
, KeyBody
);
845 /* Dereference the trust key, if any */
846 if (KeyBody
) ObDereferenceObject(KeyBody
);
848 /* Bring back APCs */
849 KeLeaveCriticalRegion();
857 NtNotifyChangeKey(IN HANDLE KeyHandle
,
859 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
860 IN PVOID ApcContext OPTIONAL
,
861 OUT PIO_STATUS_BLOCK IoStatusBlock
,
862 IN ULONG CompletionFilter
,
863 IN BOOLEAN WatchTree
,
866 IN BOOLEAN Asynchronous
)
868 /* Call the newer API */
869 return NtNotifyChangeMultipleKeys(KeyHandle
,
885 NtInitializeRegistry(IN USHORT Flag
)
888 NTSTATUS Status
= STATUS_SUCCESS
;
891 /* Always do this as kernel mode */
892 if (KeGetPreviousMode() == UserMode
) return ZwInitializeRegistry(Flag
);
894 /* Enough of the system has booted by now */
898 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
900 /* Check if boot was accepted */
901 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
903 /* Only allow once */
904 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
905 CmBootAcceptFirstTime
= FALSE
;
907 /* Get the control set accepted */
908 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
911 /* FIXME: Save the last known good boot */
912 //Status = CmpSaveBootControlSet(Flag);
917 /* Enable lazy flush */
918 CmpHoldLazyFlush
= FALSE
;
923 /* Otherwise, invalid boot */
924 return STATUS_INVALID_PARAMETER
;
927 /* Check if this was a setup boot */
928 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
930 /* Make sure we're only called once */
931 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
934 /* Acquire registry lock */
935 //CmpLockRegistryExclusive();
937 /* Initialize the hives and lazy flusher */
938 CmpCmdInit(SetupBoot
);
940 /* Save version data */
943 /* Release the registry lock */
944 //CmpUnlockRegistry();
945 return STATUS_SUCCESS
;
950 NtCompactKeys(IN ULONG Count
,
954 return STATUS_NOT_IMPLEMENTED
;
959 NtCompressKey(IN HANDLE Key
)
962 return STATUS_NOT_IMPLEMENTED
;
967 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
971 return STATUS_NOT_IMPLEMENTED
;
976 NtLockRegistryKey(IN HANDLE KeyHandle
)
979 return STATUS_NOT_IMPLEMENTED
;
984 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
986 IN POBJECT_ATTRIBUTES SlaveObjects
,
988 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
989 IN PVOID ApcContext OPTIONAL
,
990 OUT PIO_STATUS_BLOCK IoStatusBlock
,
991 IN ULONG CompletionFilter
,
992 IN BOOLEAN WatchTree
,
995 IN BOOLEAN Asynchronous
)
998 return STATUS_NOT_IMPLEMENTED
;
1003 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1004 IN OUT PKEY_VALUE_ENTRY ValueList
,
1005 IN ULONG NumberOfValues
,
1007 IN OUT PULONG Length
,
1008 OUT PULONG ReturnLength
)
1011 return STATUS_NOT_IMPLEMENTED
;
1016 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1017 OUT PULONG HandleCount
)
1019 KPROCESSOR_MODE PreviousMode
;
1020 PCM_KEY_BODY KeyBody
= NULL
;
1024 DPRINT("NtQueryOpenSubKeys()\n");
1028 /* Get the processor mode */
1029 PreviousMode
= KeGetPreviousMode();
1031 if (PreviousMode
!= KernelMode
)
1033 /* Prepare to probe parameters */
1036 /* Probe target key */
1037 ProbeForRead(TargetKey
,
1038 sizeof(OBJECT_ATTRIBUTES
),
1041 /* Probe handle count */
1042 ProbeForWriteUlong(HandleCount
);
1044 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1046 /* Return the exception code */
1047 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1052 /* Open a handle to the key */
1053 Status
= ObOpenObjectByName(TargetKey
,
1060 if (NT_SUCCESS(Status
))
1062 /* Reference the key object */
1063 Status
= ObReferenceObjectByHandle(KeyHandle
,
1070 /* Close the handle */
1074 /* Fail, if the key object could not be referenced */
1075 if (!NT_SUCCESS(Status
))
1078 /* Lock the registry exclusively */
1079 CmpLockRegistryExclusive();
1081 /* Fail, if we did not open a hive root key */
1082 if (KeyBody
->KeyControlBlock
->KeyCell
!=
1083 KeyBody
->KeyControlBlock
->KeyHive
->BaseBlock
->RootCell
)
1085 DPRINT("Error: Key is not a hive root key!\n");
1086 CmpUnlockRegistry();
1087 ObDereferenceObject(KeyBody
);
1088 return STATUS_INVALID_PARAMETER
;
1091 /* Call the internal API */
1092 *HandleCount
= CmCountOpenSubKeys(KeyBody
->KeyControlBlock
,
1095 /* Unlock the registry */
1096 CmpUnlockRegistry();
1098 /* Dereference the key object */
1099 ObDereferenceObject(KeyBody
);
1108 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey
,
1109 IN ULONG BufferLength
,
1111 IN PULONG RequiredSize
)
1114 return STATUS_NOT_IMPLEMENTED
;
1119 NtRenameKey(IN HANDLE KeyHandle
,
1120 IN PUNICODE_STRING ReplacementName
)
1123 return STATUS_NOT_IMPLEMENTED
;
1128 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1130 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1133 return STATUS_NOT_IMPLEMENTED
;
1138 NtRestoreKey(IN HANDLE KeyHandle
,
1139 IN HANDLE FileHandle
,
1140 IN ULONG RestoreFlags
)
1143 return STATUS_NOT_IMPLEMENTED
;
1148 NtSaveKey(IN HANDLE KeyHandle
,
1149 IN HANDLE FileHandle
)
1152 return STATUS_NOT_IMPLEMENTED
;
1157 NtSaveKeyEx(IN HANDLE KeyHandle
,
1158 IN HANDLE FileHandle
,
1162 return STATUS_NOT_IMPLEMENTED
;
1167 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle
,
1168 IN HANDLE LowPrecedenceKeyHandle
,
1169 IN HANDLE FileHandle
)
1172 return STATUS_NOT_IMPLEMENTED
;
1177 NtSetInformationKey(IN HANDLE KeyHandle
,
1178 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
1179 IN PVOID KeyInformation
,
1180 IN ULONG KeyInformationLength
)
1183 return STATUS_NOT_IMPLEMENTED
;
1188 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
1190 return NtUnloadKey2(KeyObjectAttributes
, 0);
1195 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey
,
1200 OBJECT_ATTRIBUTES ObjectAttributes
;
1201 UNICODE_STRING ObjectName
;
1202 CM_PARSE_CONTEXT ParseContext
= {0};
1203 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1204 PCM_KEY_BODY KeyBody
= NULL
;
1205 ULONG ParentConv
= 0, ChildConv
= 0;
1209 /* Validate privilege */
1210 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1213 DPRINT1("Restore Privilege missing!\n");
1214 return STATUS_PRIVILEGE_NOT_HELD
;
1217 /* Check for user-mode caller */
1218 if (PreviousMode
!= KernelMode
)
1220 /* Prepare to probe parameters */
1223 /* Probe object attributes */
1224 ProbeForRead(TargetKey
,
1225 sizeof(OBJECT_ATTRIBUTES
),
1228 ObjectAttributes
= *TargetKey
;
1230 /* Probe the string */
1231 ProbeForReadUnicodeString(&TargetKey
->ObjectName
);
1233 ObjectName
= *TargetKey
->ObjectName
;
1235 ProbeForRead(ObjectName
.Buffer
,
1239 ObjectAttributes
.ObjectName
= &ObjectName
;
1241 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1243 /* Return the exception code */
1244 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1250 /* Save the target attributes directly */
1251 ObjectAttributes
= *TargetKey
;
1254 /* Setup the parse context */
1255 ParseContext
.CreateOperation
= TRUE
;
1256 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1259 Status
= ObOpenObjectByName(&ObjectAttributes
,
1267 /* Return if failure encountered */
1268 if (!NT_SUCCESS(Status
)) return Status
;
1271 Status
= ObReferenceObjectByHandle(Handle
,
1278 /* Close the handle */
1281 /* Return if failure encountered */
1282 if (!NT_SUCCESS(Status
)) return Status
;
1284 /* Acquire the lock depending on flags */
1285 if (Flags
== REG_FORCE_UNLOAD
)
1287 /* Lock registry exclusively */
1288 CmpLockRegistryExclusive();
1295 /* Acquire the hive loading lock */
1296 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1298 /* Lock parent and child */
1299 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1300 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1302 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1304 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1306 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1309 /* Check if it's being deleted already */
1310 if (KeyBody
->KeyControlBlock
->Delete
)
1312 /* Return appropriate status */
1313 Status
= STATUS_KEY_DELETED
;
1317 /* Check if it's a readonly key */
1318 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1320 /* Return appropriate status */
1321 Status
= STATUS_ACCESS_DENIED
;
1325 /* Call the internal API */
1326 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
,
1329 /* Check if we failed, but really need to succeed */
1330 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1332 /* TODO: We should perform another attempt here */
1336 /* If CmUnloadKey failed we need to unlock registry ourselves */
1337 if (!NT_SUCCESS(Status
))
1339 if (Flags
!= REG_FORCE_UNLOAD
)
1341 /* Release the hive loading lock */
1342 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1344 /* Release two KCBs lock */
1345 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1348 /* Unlock the registry */
1349 CmpUnlockRegistry();
1353 /* Dereference the key */
1354 ObDereferenceObject(KeyBody
);
1360 return STATUS_NOT_IMPLEMENTED
;
1366 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1370 return STATUS_NOT_IMPLEMENTED
;