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
);
893 /* Enough of the system has booted by now */
897 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
899 /* Check if boot was accepted */
900 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
902 /* Only allow once */
903 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
904 CmBootAcceptFirstTime
= FALSE
;
906 /* Get the control set accepted */
907 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
910 /* FIXME: Save the last known good boot */
911 //Status = CmpSaveBootControlSet(Flag);
916 /* Enable lazy flush */
917 CmpHoldLazyFlush
= FALSE
;
922 /* Otherwise, invalid boot */
923 return STATUS_INVALID_PARAMETER
;
926 /* Check if this was a setup boot */
927 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
929 /* Make sure we're only called once */
930 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
933 /* Acquire registry lock */
934 //CmpLockRegistryExclusive();
936 /* Initialize the hives and lazy flusher */
937 CmpCmdInit(SetupBoot
);
939 /* FIXME: Save version data */
940 //CmpSetVersionData();
942 /* Release the registry lock */
943 //CmpUnlockRegistry();
944 return STATUS_SUCCESS
;
949 NtCompactKeys(IN ULONG Count
,
953 return STATUS_NOT_IMPLEMENTED
;
958 NtCompressKey(IN HANDLE Key
)
961 return STATUS_NOT_IMPLEMENTED
;
966 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
970 return STATUS_NOT_IMPLEMENTED
;
975 NtLockRegistryKey(IN HANDLE KeyHandle
)
978 return STATUS_NOT_IMPLEMENTED
;
983 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
985 IN POBJECT_ATTRIBUTES SlaveObjects
,
987 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
988 IN PVOID ApcContext OPTIONAL
,
989 OUT PIO_STATUS_BLOCK IoStatusBlock
,
990 IN ULONG CompletionFilter
,
991 IN BOOLEAN WatchTree
,
994 IN BOOLEAN Asynchronous
)
997 return STATUS_NOT_IMPLEMENTED
;
1002 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1003 IN OUT PKEY_VALUE_ENTRY ValueList
,
1004 IN ULONG NumberOfValues
,
1006 IN OUT PULONG Length
,
1007 OUT PULONG ReturnLength
)
1010 return STATUS_NOT_IMPLEMENTED
;
1015 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1016 OUT PULONG HandleCount
)
1019 return STATUS_NOT_IMPLEMENTED
;
1024 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey
,
1025 IN ULONG BufferLength
,
1027 IN PULONG RequiredSize
)
1030 return STATUS_NOT_IMPLEMENTED
;
1035 NtRenameKey(IN HANDLE KeyHandle
,
1036 IN PUNICODE_STRING ReplacementName
)
1039 return STATUS_NOT_IMPLEMENTED
;
1044 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1046 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1049 return STATUS_NOT_IMPLEMENTED
;
1054 NtRestoreKey(IN HANDLE KeyHandle
,
1055 IN HANDLE FileHandle
,
1056 IN ULONG RestoreFlags
)
1059 return STATUS_NOT_IMPLEMENTED
;
1064 NtSaveKey(IN HANDLE KeyHandle
,
1065 IN HANDLE FileHandle
)
1068 return STATUS_NOT_IMPLEMENTED
;
1073 NtSaveKeyEx(IN HANDLE KeyHandle
,
1074 IN HANDLE FileHandle
,
1078 return STATUS_NOT_IMPLEMENTED
;
1083 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle
,
1084 IN HANDLE LowPrecedenceKeyHandle
,
1085 IN HANDLE FileHandle
)
1088 return STATUS_NOT_IMPLEMENTED
;
1093 NtSetInformationKey(IN HANDLE KeyHandle
,
1094 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
1095 IN PVOID KeyInformation
,
1096 IN ULONG KeyInformationLength
)
1099 return STATUS_NOT_IMPLEMENTED
;
1104 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
1106 return NtUnloadKey2(KeyObjectAttributes
, 0);
1111 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey
,
1116 OBJECT_ATTRIBUTES ObjectAttributes
;
1117 UNICODE_STRING ObjectName
;
1118 CM_PARSE_CONTEXT ParseContext
= {0};
1119 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1120 PCM_KEY_BODY KeyBody
= NULL
;
1121 ULONG ParentConv
= 0, ChildConv
= 0;
1125 /* Validate privilege */
1126 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1129 DPRINT1("Restore Privilege missing!\n");
1130 return STATUS_PRIVILEGE_NOT_HELD
;
1133 /* Check for user-mode caller */
1134 if (PreviousMode
!= KernelMode
)
1136 /* Prepare to probe parameters */
1139 /* Probe object attributes */
1140 ProbeForRead(TargetKey
,
1141 sizeof(OBJECT_ATTRIBUTES
),
1144 ObjectAttributes
= *TargetKey
;
1146 /* Probe the string */
1147 ProbeForReadUnicodeString(&TargetKey
->ObjectName
);
1149 ObjectName
= *TargetKey
->ObjectName
;
1151 ProbeForRead(ObjectName
.Buffer
,
1155 ObjectAttributes
.ObjectName
= &ObjectName
;
1157 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1159 /* Return the exception code */
1160 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1166 /* Save the target attributes directly */
1167 ObjectAttributes
= *TargetKey
;
1170 /* Setup the parse context */
1171 ParseContext
.CreateOperation
= TRUE
;
1172 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1175 Status
= ObOpenObjectByName(&ObjectAttributes
,
1183 /* Return if failure encountered */
1184 if (!NT_SUCCESS(Status
)) return Status
;
1187 Status
= ObReferenceObjectByHandle(Handle
,
1194 /* Close the handle */
1197 /* Return if failure encountered */
1198 if (!NT_SUCCESS(Status
)) return Status
;
1200 /* Acquire the lock depending on flags */
1201 if (Flags
== REG_FORCE_UNLOAD
)
1203 /* Lock registry exclusively */
1204 CmpLockRegistryExclusive();
1211 /* Acquire the hive loading lock */
1212 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1214 /* Lock parent and child */
1215 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1216 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1218 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1220 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1222 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1225 /* Check if it's being deleted already */
1226 if (KeyBody
->KeyControlBlock
->Delete
)
1228 /* Return appropriate status */
1229 Status
= STATUS_KEY_DELETED
;
1233 /* Check if it's a readonly key */
1234 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1236 /* Return appropriate status */
1237 Status
= STATUS_ACCESS_DENIED
;
1241 /* Call the internal API */
1242 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
,
1245 /* Check if we failed, but really need to succeed */
1246 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1248 /* TODO: We should perform another attempt here */
1252 /* If CmUnloadKey failed we need to unlock registry ourselves */
1253 if (!NT_SUCCESS(Status
))
1255 if (Flags
!= REG_FORCE_UNLOAD
)
1257 /* Release the hive loading lock */
1258 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1260 /* Release two KCBs lock */
1261 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1264 /* Unlock the registry */
1265 CmpUnlockRegistry();
1269 /* Dereference the key */
1270 ObDereferenceObject(KeyBody
);
1276 return STATUS_NOT_IMPLEMENTED
;
1282 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1286 return STATUS_NOT_IMPLEMENTED
;