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)
9 /* INCLUDES ******************************************************************/
15 BOOLEAN CmBootAcceptFirstTime
= TRUE
;
16 BOOLEAN CmFirstTime
= TRUE
;
18 /* FUNCTIONS *****************************************************************/
22 NtCreateKey(OUT PHANDLE KeyHandle
,
23 IN ACCESS_MASK DesiredAccess
,
24 IN POBJECT_ATTRIBUTES ObjectAttributes
,
26 IN PUNICODE_STRING Class OPTIONAL
,
27 IN ULONG CreateOptions
,
28 OUT PULONG Disposition OPTIONAL
)
31 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
32 CM_PARSE_CONTEXT ParseContext
= {0};
35 DPRINT("NtCreateKey(OB name %wZ)\n", ObjectAttributes
->ObjectName
);
37 /* Check for user-mode caller */
38 if (PreviousMode
!= KernelMode
)
40 /* Prepare to probe parameters */
43 /* Check if we have a class */
47 ParseContext
.Class
= ProbeForReadUnicodeString(Class
);
48 ProbeForRead(ParseContext
.Class
.Buffer
,
49 ParseContext
.Class
.Length
,
53 /* Probe the key handle */
54 ProbeForWriteHandle(KeyHandle
);
57 /* Probe object attributes */
58 ProbeForRead(ObjectAttributes
,
59 sizeof(OBJECT_ATTRIBUTES
),
62 if (Disposition
) ProbeForWriteUlong(Disposition
);
64 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
66 /* Return the exception code */
67 _SEH2_YIELD(return _SEH2_GetExceptionCode());
73 /* Save the class directly */
74 if (Class
) ParseContext
.Class
= *Class
;
77 /* Setup the parse context */
78 ParseContext
.CreateOperation
= TRUE
;
79 ParseContext
.CreateOptions
= CreateOptions
;
82 Status
= ObOpenObjectByName(ObjectAttributes
,
92 /* Return data to user */
93 if (NT_SUCCESS(Status
)) *KeyHandle
= Handle
;
94 if (Disposition
) *Disposition
= ParseContext
.Disposition
;
96 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
99 Status
= _SEH2_GetExceptionCode();
109 NtOpenKey(OUT PHANDLE KeyHandle
,
110 IN ACCESS_MASK DesiredAccess
,
111 IN POBJECT_ATTRIBUTES ObjectAttributes
)
113 CM_PARSE_CONTEXT ParseContext
= {0};
116 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
118 DPRINT("NtOpenKey(OB 0x%wZ)\n", ObjectAttributes
->ObjectName
);
120 /* Check for user-mode caller */
121 if (PreviousMode
!= KernelMode
)
123 /* Prepare to probe parameters */
126 /* Probe the key handle */
127 ProbeForWriteHandle(KeyHandle
);
130 /* Probe object attributes */
131 ProbeForRead(ObjectAttributes
,
132 sizeof(OBJECT_ATTRIBUTES
),
135 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
137 /* Return the exception code */
138 _SEH2_YIELD(return _SEH2_GetExceptionCode());
143 /* Just let the object manager handle this */
144 Status
= ObOpenObjectByName(ObjectAttributes
,
152 /* Only do this if we succeeded */
153 if (NT_SUCCESS(Status
))
157 /* Return the handle to caller */
160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
163 Status
= _SEH2_GetExceptionCode();
175 NtDeleteKey(IN HANDLE KeyHandle
)
177 PCM_KEY_BODY KeyObject
;
179 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
180 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
182 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle
);
184 /* Verify that the handle is valid and is a registry key */
185 Status
= ObReferenceObjectByHandle(KeyHandle
,
191 if (!NT_SUCCESS(Status
)) return Status
;
193 /* Setup the callback */
194 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
195 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
196 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteKey
, &DeleteKeyInfo
);
197 if (NT_SUCCESS(Status
))
199 /* Check if we are read-only */
200 if ((KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
) ||
201 (KeyObject
->KeyControlBlock
->ParentKcb
->ExtFlags
& CM_KCB_READ_ONLY_KEY
))
204 Status
= STATUS_ACCESS_DENIED
;
208 /* Call the internal API */
209 Status
= CmDeleteKey(KeyObject
);
212 /* Do post callback */
213 PostOperationInfo
.Status
= Status
;
214 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
217 /* Dereference the object */
218 ObDereferenceObject(KeyObject
);
224 NtEnumerateKey(IN HANDLE KeyHandle
,
226 IN KEY_INFORMATION_CLASS KeyInformationClass
,
227 OUT PVOID KeyInformation
,
229 OUT PULONG ResultLength
)
231 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
233 PCM_KEY_BODY KeyObject
;
234 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
235 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
237 DPRINT("NtEnumerateKey() KH 0x%x, Index 0x%x, KIC %d, Length %d\n",
238 KeyHandle
, Index
, KeyInformationClass
, Length
);
240 /* Reject classes we don't know about */
241 if ((KeyInformationClass
!= KeyBasicInformation
) &&
242 (KeyInformationClass
!= KeyNodeInformation
) &&
243 (KeyInformationClass
!= KeyFullInformation
))
246 return STATUS_INVALID_PARAMETER
;
249 /* Verify that the handle is valid and is a registry key */
250 Status
= ObReferenceObjectByHandle(KeyHandle
,
251 KEY_ENUMERATE_SUB_KEYS
,
256 if (!NT_SUCCESS(Status
)) return Status
;
258 if (PreviousMode
!= KernelMode
)
262 ProbeForWriteUlong(ResultLength
);
263 ProbeForWrite(KeyInformation
,
267 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
269 /* Dereference and return status */
270 ObDereferenceObject(KeyObject
);
271 _SEH2_YIELD(return _SEH2_GetExceptionCode());
276 /* Setup the callback */
277 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
278 EnumerateKeyInfo
.Object
= (PVOID
)KeyObject
;
279 EnumerateKeyInfo
.Index
= Index
;
280 EnumerateKeyInfo
.KeyInformationClass
= KeyInformationClass
;
281 EnumerateKeyInfo
.Length
= Length
;
282 EnumerateKeyInfo
.ResultLength
= ResultLength
;
284 /* Do the callback */
285 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateKey
, &EnumerateKeyInfo
);
286 if (NT_SUCCESS(Status
))
288 /* Call the internal API */
289 Status
= CmEnumerateKey(KeyObject
->KeyControlBlock
,
296 /* Do the post callback */
297 PostOperationInfo
.Status
= Status
;
298 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
301 /* Dereference and return status */
302 ObDereferenceObject(KeyObject
);
308 NtEnumerateValueKey(IN HANDLE KeyHandle
,
310 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
311 OUT PVOID KeyValueInformation
,
313 OUT PULONG ResultLength
)
315 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
317 PCM_KEY_BODY KeyObject
;
318 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo
;
319 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
321 DPRINT("NtEnumerateValueKey() KH 0x%x, Index 0x%x, KVIC %d, Length %d\n",
322 KeyHandle
, Index
, KeyValueInformationClass
, Length
);
324 /* Reject classes we don't know about */
325 if ((KeyValueInformationClass
!= KeyValueBasicInformation
) &&
326 (KeyValueInformationClass
!= KeyValueFullInformation
) &&
327 (KeyValueInformationClass
!= KeyValuePartialInformation
))
330 return STATUS_INVALID_PARAMETER
;
333 /* Verify that the handle is valid and is a registry key */
334 Status
= ObReferenceObjectByHandle(KeyHandle
,
340 if (!NT_SUCCESS(Status
)) return Status
;
342 if (PreviousMode
!= KernelMode
)
346 ProbeForWriteUlong(ResultLength
);
347 ProbeForWrite(KeyValueInformation
,
351 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
353 /* Dereference and return status */
354 ObDereferenceObject(KeyObject
);
355 _SEH2_YIELD(return _SEH2_GetExceptionCode());
360 /* Setup the callback */
361 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
362 EnumerateValueKeyInfo
.Object
= (PVOID
)KeyObject
;
363 EnumerateValueKeyInfo
.Index
= Index
;
364 EnumerateValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
365 EnumerateValueKeyInfo
.KeyValueInformation
= KeyValueInformation
;
366 EnumerateValueKeyInfo
.Length
= Length
;
367 EnumerateValueKeyInfo
.ResultLength
= ResultLength
;
369 /* Do the callback */
370 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey
,
371 &EnumerateValueKeyInfo
);
372 if (NT_SUCCESS(Status
))
374 /* Call the internal API */
375 Status
= CmEnumerateValueKey(KeyObject
->KeyControlBlock
,
377 KeyValueInformationClass
,
382 /* Do the post callback */
383 PostOperationInfo
.Status
= Status
;
384 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey
, &PostOperationInfo
);
387 ObDereferenceObject(KeyObject
);
393 NtQueryKey(IN HANDLE KeyHandle
,
394 IN KEY_INFORMATION_CLASS KeyInformationClass
,
395 OUT PVOID KeyInformation
,
397 OUT PULONG ResultLength
)
399 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
401 PCM_KEY_BODY KeyObject
;
402 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
403 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
404 OBJECT_HANDLE_INFORMATION HandleInfo
;
406 DPRINT("NtQueryKey() KH 0x%x, KIC %d, Length %d\n",
407 KeyHandle
, KeyInformationClass
, Length
);
409 /* Reject invalid classes */
410 if ((KeyInformationClass
!= KeyBasicInformation
) &&
411 (KeyInformationClass
!= KeyNodeInformation
) &&
412 (KeyInformationClass
!= KeyFullInformation
) &&
413 (KeyInformationClass
!= KeyNameInformation
) &&
414 (KeyInformationClass
!= KeyCachedInformation
) &&
415 (KeyInformationClass
!= KeyFlagsInformation
))
418 return STATUS_INVALID_PARAMETER
;
421 /* Check if just the name is required */
422 if (KeyInformationClass
== KeyNameInformation
)
424 /* Ignore access level */
425 Status
= ObReferenceObjectByHandle(KeyHandle
,
431 if (NT_SUCCESS(Status
))
433 /* At least a single bit of access is required */
434 if (!HandleInfo
.GrantedAccess
)
437 ObDereferenceObject(KeyObject
);
438 Status
= STATUS_ACCESS_DENIED
;
444 /* Get a reference */
445 Status
= ObReferenceObjectByHandle(KeyHandle
,
453 /* Quit on failure */
454 if (!NT_SUCCESS(Status
)) return Status
;
456 if (PreviousMode
!= KernelMode
)
460 ProbeForWriteUlong(ResultLength
);
461 ProbeForWrite(KeyInformation
,
465 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
467 /* Dereference and return status */
468 ObDereferenceObject(KeyObject
);
469 _SEH2_YIELD(return _SEH2_GetExceptionCode());
474 /* Setup the callback */
475 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
476 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
477 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
478 QueryKeyInfo
.KeyInformation
= KeyInformation
;
479 QueryKeyInfo
.Length
= Length
;
480 QueryKeyInfo
.ResultLength
= ResultLength
;
482 /* Do the callback */
483 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryKey
, &QueryKeyInfo
);
484 if (NT_SUCCESS(Status
))
486 /* Call the internal API */
487 Status
= CmQueryKey(KeyObject
->KeyControlBlock
,
493 /* Do the post callback */
494 PostOperationInfo
.Status
= Status
;
495 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
498 /* Dereference and return status */
499 ObDereferenceObject(KeyObject
);
505 NtQueryValueKey(IN HANDLE KeyHandle
,
506 IN PUNICODE_STRING ValueName
,
507 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
508 OUT PVOID KeyValueInformation
,
510 OUT PULONG ResultLength
)
512 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
514 PCM_KEY_BODY KeyObject
;
515 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
516 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
517 UNICODE_STRING ValueNameCopy
= *ValueName
;
519 DPRINT("NtQueryValueKey() KH 0x%x, VN '%wZ', KVIC %d, Length %d\n",
520 KeyHandle
, ValueName
, KeyValueInformationClass
, Length
);
522 /* Verify that the handle is valid and is a registry key */
523 Status
= ObReferenceObjectByHandle(KeyHandle
,
529 if (!NT_SUCCESS(Status
)) return Status
;
531 if (PreviousMode
!= KernelMode
)
535 ProbeForWriteUlong(ResultLength
);
536 ProbeForWrite(KeyValueInformation
,
540 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
542 /* Dereference and return status */
543 ObDereferenceObject(KeyObject
);
544 _SEH2_YIELD(return _SEH2_GetExceptionCode());
549 /* Make sure the name is aligned properly */
550 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
552 /* It isn't, so we'll fail */
553 ObDereferenceObject(KeyObject
);
554 return STATUS_INVALID_PARAMETER
;
558 /* Ignore any null characters at the end */
559 while ((ValueNameCopy
.Length
) &&
560 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
563 ValueNameCopy
.Length
-= sizeof(WCHAR
);
567 /* Setup the callback */
568 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
569 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
570 QueryValueKeyInfo
.ValueName
= &ValueNameCopy
;
571 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
572 QueryValueKeyInfo
.Length
= Length
;
573 QueryValueKeyInfo
.ResultLength
= ResultLength
;
575 /* Do the callback */
576 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
577 if (NT_SUCCESS(Status
))
579 /* Call the internal API */
580 Status
= CmQueryValueKey(KeyObject
->KeyControlBlock
,
582 KeyValueInformationClass
,
587 /* Do the post callback */
588 PostOperationInfo
.Status
= Status
;
589 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
592 /* Dereference and return status */
593 ObDereferenceObject(KeyObject
);
599 NtSetValueKey(IN HANDLE KeyHandle
,
600 IN PUNICODE_STRING ValueName
,
607 PCM_KEY_BODY KeyObject
;
608 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
609 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
610 UNICODE_STRING ValueNameCopy
= *ValueName
;
612 DPRINT("NtSetValueKey() KH 0x%x, VN '%wZ', TI %x, T %d, DS %d\n",
613 KeyHandle
, ValueName
, TitleIndex
, Type
, DataSize
);
615 /* Verify that the handle is valid and is a registry key */
616 Status
= ObReferenceObjectByHandle(KeyHandle
,
622 if (!NT_SUCCESS(Status
)) return Status
;
624 /* Make sure the name is aligned, not too long, and the data under 4GB */
625 if ( (ValueNameCopy
.Length
> 32767) ||
626 ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1))) ||
627 (DataSize
> 0x80000000))
630 ObDereferenceObject(KeyObject
);
631 return STATUS_INVALID_PARAMETER
;
634 /* Ignore any null characters at the end */
635 while ((ValueNameCopy
.Length
) &&
636 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
639 ValueNameCopy
.Length
-= sizeof(WCHAR
);
642 /* Don't touch read-only keys */
643 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
646 ObDereferenceObject(KeyObject
);
647 return STATUS_ACCESS_DENIED
;
651 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
652 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
653 SetValueKeyInfo
.ValueName
= ValueName
;
654 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
655 SetValueKeyInfo
.Type
= Type
;
656 SetValueKeyInfo
.Data
= Data
;
657 SetValueKeyInfo
.DataSize
= DataSize
;
659 /* Do the callback */
660 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
661 if (NT_SUCCESS(Status
))
663 /* Call the internal API */
664 Status
= CmSetValueKey(KeyObject
->KeyControlBlock
,
671 /* Do the post-callback */
672 PostOperationInfo
.Status
= Status
;
673 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
675 /* Dereference and return status */
676 ObDereferenceObject(KeyObject
);
682 NtDeleteValueKey(IN HANDLE KeyHandle
,
683 IN PUNICODE_STRING ValueName
)
685 PCM_KEY_BODY KeyObject
;
687 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
688 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
689 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
690 UNICODE_STRING ValueNameCopy
= *ValueName
;
693 /* Verify that the handle is valid and is a registry key */
694 Status
= ObReferenceObjectByHandle(KeyHandle
,
700 if (!NT_SUCCESS(Status
)) return Status
;
702 /* Don't touch read-only keys */
703 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
706 ObDereferenceObject(KeyObject
);
707 return STATUS_ACCESS_DENIED
;
710 /* Make sure the name is aligned properly */
711 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
713 /* It isn't, so we'll fail */
714 ObDereferenceObject(KeyObject
);
715 return STATUS_INVALID_PARAMETER
;
718 /* Do the callback */
719 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
720 DeleteValueKeyInfo
.ValueName
= ValueName
;
721 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
,
722 &DeleteValueKeyInfo
);
723 if (NT_SUCCESS(Status
))
725 /* Call the internal API */
726 Status
= CmDeleteValueKey(KeyObject
->KeyControlBlock
, ValueNameCopy
);
728 /* Do the post callback */
729 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
730 PostOperationInfo
.Status
= Status
;
731 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
,
735 /* Dereference the key body */
736 ObDereferenceObject(KeyObject
);
742 NtFlushKey(IN HANDLE KeyHandle
)
745 PCM_KEY_BODY KeyObject
;
748 /* Get the key object */
749 Status
= ObReferenceObjectByHandle(KeyHandle
,
755 if (!NT_SUCCESS(Status
)) return Status
;
757 /* Lock the registry */
761 CmpAcquireKcbLockShared(KeyObject
->KeyControlBlock
);
763 /* Make sure KCB isn't deleted */
764 if (KeyObject
->KeyControlBlock
->Delete
)
767 Status
= STATUS_KEY_DELETED
;
771 /* Call the internal API */
772 Status
= CmFlushKey(KeyObject
->KeyControlBlock
, FALSE
);
775 /* Release the locks */
776 CmpReleaseKcbLock(KeyObject
->KeyControlBlock
);
779 /* Dereference the object and return status */
780 ObDereferenceObject(KeyObject
);
786 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
787 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
789 /* Call the newer API */
790 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, 0, NULL
);
795 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
796 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
799 /* Call the newer API */
800 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, Flags
, NULL
);
805 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
806 IN POBJECT_ATTRIBUTES SourceFile
,
808 IN HANDLE TrustClassKey
)
811 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
812 PCM_KEY_BODY KeyBody
= NULL
;
816 if (Flags
& ~REG_NO_LAZY_FLUSH
) return STATUS_INVALID_PARAMETER
;
818 /* Validate privilege */
819 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
822 DPRINT1("Restore Privilege missing!\n");
823 return STATUS_PRIVILEGE_NOT_HELD
;
827 KeEnterCriticalRegion();
829 /* Check if we have a trust class */
833 Status
= ObReferenceObjectByHandle(TrustClassKey
,
841 /* Call the internal API */
842 Status
= CmLoadKey(TargetKey
, SourceFile
, Flags
, KeyBody
);
844 /* Dereference the trust key, if any */
845 if (KeyBody
) ObDereferenceObject(KeyBody
);
847 /* Bring back APCs */
848 KeLeaveCriticalRegion();
856 NtNotifyChangeKey(IN HANDLE KeyHandle
,
858 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
859 IN PVOID ApcContext OPTIONAL
,
860 OUT PIO_STATUS_BLOCK IoStatusBlock
,
861 IN ULONG CompletionFilter
,
862 IN BOOLEAN WatchTree
,
865 IN BOOLEAN Asynchronous
)
867 /* Call the newer API */
868 return NtNotifyChangeMultipleKeys(KeyHandle
,
884 NtInitializeRegistry(IN USHORT Flag
)
887 NTSTATUS Status
= STATUS_SUCCESS
;
890 /* Always do this as kernel mode */
891 if (KeGetPreviousMode() == UserMode
) return ZwInitializeRegistry(Flag
);
894 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
896 /* Check if boot was accepted */
897 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
899 /* Only allow once */
900 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
901 CmBootAcceptFirstTime
= FALSE
;
903 /* Get the control set accepted */
904 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
907 /* FIXME: Save the last known good boot */
908 //Status = CmpSaveBootControlSet(Flag);
913 /* Enable lazy flush */
914 CmpHoldLazyFlush
= FALSE
;
919 /* Otherwise, invalid boot */
920 return STATUS_INVALID_PARAMETER
;
923 /* Check if this was a setup boot */
924 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
926 /* Make sure we're only called once */
927 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
930 /* Acquire registry lock */
931 //CmpLockRegistryExclusive();
933 /* Initialize the hives and lazy flusher */
934 CmpCmdInit(SetupBoot
);
936 /* FIXME: Save version data */
937 //CmpSetVersionData();
939 /* Release the registry lock */
940 //CmpUnlockRegistry();
941 return STATUS_SUCCESS
;
946 NtCompactKeys(IN ULONG Count
,
950 return STATUS_NOT_IMPLEMENTED
;
955 NtCompressKey(IN HANDLE Key
)
958 return STATUS_NOT_IMPLEMENTED
;
963 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
967 return STATUS_NOT_IMPLEMENTED
;
972 NtLockRegistryKey(IN HANDLE KeyHandle
)
975 return STATUS_NOT_IMPLEMENTED
;
980 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
982 IN POBJECT_ATTRIBUTES SlaveObjects
,
984 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
985 IN PVOID ApcContext OPTIONAL
,
986 OUT PIO_STATUS_BLOCK IoStatusBlock
,
987 IN ULONG CompletionFilter
,
988 IN BOOLEAN WatchTree
,
991 IN BOOLEAN Asynchronous
)
994 return STATUS_NOT_IMPLEMENTED
;
999 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1000 IN OUT PKEY_VALUE_ENTRY ValueList
,
1001 IN ULONG NumberOfValues
,
1003 IN OUT PULONG Length
,
1004 OUT PULONG ReturnLength
)
1007 return STATUS_NOT_IMPLEMENTED
;
1012 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1013 OUT PULONG HandleCount
)
1016 return STATUS_NOT_IMPLEMENTED
;
1021 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey
,
1022 IN ULONG BufferLength
,
1024 IN PULONG RequiredSize
)
1027 return STATUS_NOT_IMPLEMENTED
;
1032 NtRenameKey(IN HANDLE KeyHandle
,
1033 IN PUNICODE_STRING ReplacementName
)
1036 return STATUS_NOT_IMPLEMENTED
;
1041 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1043 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1046 return STATUS_NOT_IMPLEMENTED
;
1051 NtRestoreKey(IN HANDLE KeyHandle
,
1052 IN HANDLE FileHandle
,
1053 IN ULONG RestoreFlags
)
1056 return STATUS_NOT_IMPLEMENTED
;
1061 NtSaveKey(IN HANDLE KeyHandle
,
1062 IN HANDLE FileHandle
)
1065 return STATUS_NOT_IMPLEMENTED
;
1070 NtSaveKeyEx(IN HANDLE KeyHandle
,
1071 IN HANDLE FileHandle
,
1075 return STATUS_NOT_IMPLEMENTED
;
1080 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle
,
1081 IN HANDLE LowPrecedenceKeyHandle
,
1082 IN HANDLE FileHandle
)
1085 return STATUS_NOT_IMPLEMENTED
;
1090 NtSetInformationKey(IN HANDLE KeyHandle
,
1091 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
1092 IN PVOID KeyInformation
,
1093 IN ULONG KeyInformationLength
)
1096 return STATUS_NOT_IMPLEMENTED
;
1101 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
1103 return NtUnloadKey2(KeyObjectAttributes
, 0);
1108 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey
,
1113 OBJECT_ATTRIBUTES ObjectAttributes
;
1114 UNICODE_STRING ObjectName
;
1115 CM_PARSE_CONTEXT ParseContext
= {0};
1116 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1117 PCM_KEY_BODY KeyBody
= NULL
;
1118 ULONG ParentConv
= 0, ChildConv
= 0;
1122 /* Validate privilege */
1123 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1126 DPRINT1("Restore Privilege missing!\n");
1127 return STATUS_PRIVILEGE_NOT_HELD
;
1130 /* Check for user-mode caller */
1131 if (PreviousMode
!= KernelMode
)
1133 /* Prepare to probe parameters */
1136 /* Probe object attributes */
1137 ProbeForRead(TargetKey
,
1138 sizeof(OBJECT_ATTRIBUTES
),
1141 ObjectAttributes
= *TargetKey
;
1143 /* Probe the string */
1144 ProbeForReadUnicodeString(&TargetKey
->ObjectName
);
1146 ObjectName
= *TargetKey
->ObjectName
;
1148 ProbeForRead(ObjectName
.Buffer
,
1152 ObjectAttributes
.ObjectName
= &ObjectName
;
1154 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1156 /* Return the exception code */
1157 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1163 /* Save the target attributes directly */
1164 ObjectAttributes
= *TargetKey
;
1167 /* Setup the parse context */
1168 ParseContext
.CreateOperation
= TRUE
;
1169 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1172 Status
= ObOpenObjectByName(&ObjectAttributes
,
1180 /* Return if failure encountered */
1181 if (!NT_SUCCESS(Status
)) return Status
;
1184 Status
= ObReferenceObjectByHandle(Handle
,
1191 /* Close the handle */
1194 /* Return if failure encountered */
1195 if (!NT_SUCCESS(Status
)) return Status
;
1197 /* Acquire the lock depending on flags */
1198 if (Flags
== REG_FORCE_UNLOAD
)
1200 /* Lock registry exclusively */
1201 CmpLockRegistryExclusive();
1208 /* Acquire the hive loading lock */
1209 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1211 /* Lock parent and child */
1212 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1213 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1215 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1217 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1219 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1222 /* Check if it's being deleted already */
1223 if (KeyBody
->KeyControlBlock
->Delete
)
1225 /* Return appropriate status */
1226 Status
= STATUS_KEY_DELETED
;
1230 /* Check if it's a readonly key */
1231 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1233 /* Return appropriate status */
1234 Status
= STATUS_ACCESS_DENIED
;
1238 /* Call the internal API */
1239 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
,
1242 /* Check if we failed, but really need to succeed */
1243 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1245 /* TODO: We should perform another attempt here */
1249 /* If CmUnloadKey failed we need to unlock registry ourselves */
1250 if (!NT_SUCCESS(Status
))
1252 if (Flags
!= REG_FORCE_UNLOAD
)
1254 /* Release the hive loading lock */
1255 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1257 /* Release two KCBs lock */
1258 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1261 /* Unlock the registry */
1262 CmpUnlockRegistry();
1266 /* Dereference the key */
1267 ObDereferenceObject(KeyBody
);
1273 return STATUS_NOT_IMPLEMENTED
;
1279 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1283 return STATUS_NOT_IMPLEMENTED
;