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
)
30 NTSTATUS Status
= STATUS_SUCCESS
;
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 /* Get the error code */
67 Status
= _SEH2_GetExceptionCode();
70 if(!NT_SUCCESS(Status
)) return Status
;
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};
116 NTSTATUS Status
= STATUS_SUCCESS
;
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
)
139 Status
= _SEH2_GetExceptionCode();
142 if(!NT_SUCCESS(Status
)) return Status
;
145 /* Just let the object manager handle this */
146 Status
= ObOpenObjectByName(ObjectAttributes
,
154 /* Only do this if we succeeded */
155 if (NT_SUCCESS(Status
))
159 /* Return the handle to caller */
162 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
165 Status
= _SEH2_GetExceptionCode();
177 NtDeleteKey(IN HANDLE KeyHandle
)
179 PCM_KEY_BODY KeyObject
;
181 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
182 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
184 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle
);
186 /* Verify that the handle is valid and is a registry key */
187 Status
= ObReferenceObjectByHandle(KeyHandle
,
193 if (!NT_SUCCESS(Status
)) return Status
;
195 /* Setup the callback */
196 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
197 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
198 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteKey
, &DeleteKeyInfo
);
199 if (NT_SUCCESS(Status
))
201 /* Check if we are read-only */
202 if ((KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
) ||
203 (KeyObject
->KeyControlBlock
->ParentKcb
->ExtFlags
& CM_KCB_READ_ONLY_KEY
))
206 Status
= STATUS_ACCESS_DENIED
;
210 /* Call the internal API */
211 Status
= CmDeleteKey(KeyObject
);
214 /* Do post callback */
215 PostOperationInfo
.Status
= Status
;
216 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
219 /* Dereference the object */
220 ObDereferenceObject(KeyObject
);
226 NtEnumerateKey(IN HANDLE KeyHandle
,
228 IN KEY_INFORMATION_CLASS KeyInformationClass
,
229 OUT PVOID KeyInformation
,
231 OUT PULONG ResultLength
)
233 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
235 PCM_KEY_BODY KeyObject
;
236 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
237 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
239 DPRINT("NtEnumerateKey() KH 0x%x, Index 0x%x, KIC %d, Length %d\n",
240 KeyHandle
, Index
, KeyInformationClass
, Length
);
242 /* Reject classes we don't know about */
243 if ((KeyInformationClass
!= KeyBasicInformation
) &&
244 (KeyInformationClass
!= KeyNodeInformation
) &&
245 (KeyInformationClass
!= KeyFullInformation
))
248 return STATUS_INVALID_PARAMETER
;
251 /* Verify that the handle is valid and is a registry key */
252 Status
= ObReferenceObjectByHandle(KeyHandle
,
253 KEY_ENUMERATE_SUB_KEYS
,
258 if (!NT_SUCCESS(Status
)) return Status
;
260 if (PreviousMode
!= KernelMode
)
264 ProbeForWriteUlong(ResultLength
);
265 ProbeForWrite(KeyInformation
,
269 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
271 Status
= _SEH2_GetExceptionCode();
275 if (!NT_SUCCESS(Status
))
277 /* Dereference and return status */
278 ObDereferenceObject(KeyObject
);
283 /* Setup the callback */
284 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
285 EnumerateKeyInfo
.Object
= (PVOID
)KeyObject
;
286 EnumerateKeyInfo
.Index
= Index
;
287 EnumerateKeyInfo
.KeyInformationClass
= KeyInformationClass
;
288 EnumerateKeyInfo
.Length
= Length
;
289 EnumerateKeyInfo
.ResultLength
= ResultLength
;
291 /* Do the callback */
292 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateKey
, &EnumerateKeyInfo
);
293 if (NT_SUCCESS(Status
))
295 /* Call the internal API */
296 Status
= CmEnumerateKey(KeyObject
->KeyControlBlock
,
303 /* Do the post callback */
304 PostOperationInfo
.Status
= Status
;
305 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
308 /* Dereference and return status */
309 ObDereferenceObject(KeyObject
);
315 NtEnumerateValueKey(IN HANDLE KeyHandle
,
317 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
318 OUT PVOID KeyValueInformation
,
320 OUT PULONG ResultLength
)
322 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
324 PCM_KEY_BODY KeyObject
;
325 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo
;
326 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
328 DPRINT("NtEnumerateValueKey() KH 0x%x, Index 0x%x, KVIC %d, Length %d\n",
329 KeyHandle
, Index
, KeyValueInformationClass
, Length
);
331 /* Reject classes we don't know about */
332 if ((KeyValueInformationClass
!= KeyValueBasicInformation
) &&
333 (KeyValueInformationClass
!= KeyValueFullInformation
) &&
334 (KeyValueInformationClass
!= KeyValuePartialInformation
))
337 return STATUS_INVALID_PARAMETER
;
340 /* Verify that the handle is valid and is a registry key */
341 Status
= ObReferenceObjectByHandle(KeyHandle
,
347 if (!NT_SUCCESS(Status
)) return Status
;
349 if (PreviousMode
!= KernelMode
)
353 ProbeForWriteUlong(ResultLength
);
354 ProbeForWrite(KeyValueInformation
,
358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
360 Status
= _SEH2_GetExceptionCode();
364 if (!NT_SUCCESS(Status
))
366 /* Dereference and return status */
367 ObDereferenceObject(KeyObject
);
372 /* Setup the callback */
373 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
374 EnumerateValueKeyInfo
.Object
= (PVOID
)KeyObject
;
375 EnumerateValueKeyInfo
.Index
= Index
;
376 EnumerateValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
377 EnumerateValueKeyInfo
.KeyValueInformation
= KeyValueInformation
;
378 EnumerateValueKeyInfo
.Length
= Length
;
379 EnumerateValueKeyInfo
.ResultLength
= ResultLength
;
381 /* Do the callback */
382 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey
,
383 &EnumerateValueKeyInfo
);
384 if (NT_SUCCESS(Status
))
386 /* Call the internal API */
387 Status
= CmEnumerateValueKey(KeyObject
->KeyControlBlock
,
389 KeyValueInformationClass
,
394 /* Do the post callback */
395 PostOperationInfo
.Status
= Status
;
396 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey
, &PostOperationInfo
);
399 ObDereferenceObject(KeyObject
);
405 NtQueryKey(IN HANDLE KeyHandle
,
406 IN KEY_INFORMATION_CLASS KeyInformationClass
,
407 OUT PVOID KeyInformation
,
409 OUT PULONG ResultLength
)
411 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
413 PCM_KEY_BODY KeyObject
;
414 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
415 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
416 OBJECT_HANDLE_INFORMATION HandleInfo
;
418 DPRINT("NtQueryKey() KH 0x%x, KIC %d, Length %d\n",
419 KeyHandle
, KeyInformationClass
, Length
);
421 /* Reject invalid classes */
422 if ((KeyInformationClass
!= KeyBasicInformation
) &&
423 (KeyInformationClass
!= KeyNodeInformation
) &&
424 (KeyInformationClass
!= KeyFullInformation
) &&
425 (KeyInformationClass
!= KeyNameInformation
) &&
426 (KeyInformationClass
!= KeyCachedInformation
) &&
427 (KeyInformationClass
!= KeyFlagsInformation
))
430 return STATUS_INVALID_PARAMETER
;
433 /* Check if just the name is required */
434 if (KeyInformationClass
== KeyNameInformation
)
436 /* Ignore access level */
437 Status
= ObReferenceObjectByHandle(KeyHandle
,
443 if (NT_SUCCESS(Status
))
445 /* At least a single bit of access is required */
446 if (!HandleInfo
.GrantedAccess
)
449 ObDereferenceObject(KeyObject
);
450 Status
= STATUS_ACCESS_DENIED
;
456 /* Get a reference */
457 Status
= ObReferenceObjectByHandle(KeyHandle
,
465 /* Quit on failure */
466 if (!NT_SUCCESS(Status
)) return Status
;
468 if (PreviousMode
!= KernelMode
)
472 ProbeForWriteUlong(ResultLength
);
473 ProbeForWrite(KeyInformation
,
477 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
479 Status
= _SEH2_GetExceptionCode();
483 if (!NT_SUCCESS(Status
))
485 /* Dereference and return status */
486 ObDereferenceObject(KeyObject
);
491 /* Setup the callback */
492 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
493 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
494 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
495 QueryKeyInfo
.KeyInformation
= KeyInformation
;
496 QueryKeyInfo
.Length
= Length
;
497 QueryKeyInfo
.ResultLength
= ResultLength
;
499 /* Do the callback */
500 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryKey
, &QueryKeyInfo
);
501 if (NT_SUCCESS(Status
))
503 /* Call the internal API */
504 Status
= CmQueryKey(KeyObject
->KeyControlBlock
,
510 /* Do the post callback */
511 PostOperationInfo
.Status
= Status
;
512 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
515 /* Dereference and return status */
516 ObDereferenceObject(KeyObject
);
522 NtQueryValueKey(IN HANDLE KeyHandle
,
523 IN PUNICODE_STRING ValueName
,
524 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
525 OUT PVOID KeyValueInformation
,
527 OUT PULONG ResultLength
)
529 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
531 PCM_KEY_BODY KeyObject
;
532 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
533 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
534 UNICODE_STRING ValueNameCopy
= *ValueName
;
536 DPRINT("NtQueryValueKey() KH 0x%x, VN '%wZ', KVIC %d, Length %d\n",
537 KeyHandle
, ValueName
, KeyValueInformationClass
, Length
);
539 /* Verify that the handle is valid and is a registry key */
540 Status
= ObReferenceObjectByHandle(KeyHandle
,
546 if (!NT_SUCCESS(Status
)) return Status
;
548 if (PreviousMode
!= KernelMode
)
552 ProbeForWriteUlong(ResultLength
);
553 ProbeForWrite(KeyValueInformation
,
557 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
559 Status
= _SEH2_GetExceptionCode();
563 if (!NT_SUCCESS(Status
))
565 /* Dereference and return status */
566 ObDereferenceObject(KeyObject
);
571 /* Make sure the name is aligned properly */
572 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
574 /* It isn't, so we'll fail */
575 ObDereferenceObject(KeyObject
);
576 return STATUS_INVALID_PARAMETER
;
580 /* Ignore any null characters at the end */
581 while ((ValueNameCopy
.Length
) &&
582 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
585 ValueNameCopy
.Length
-= sizeof(WCHAR
);
589 /* Setup the callback */
590 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
591 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
592 QueryValueKeyInfo
.ValueName
= &ValueNameCopy
;
593 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
594 QueryValueKeyInfo
.Length
= Length
;
595 QueryValueKeyInfo
.ResultLength
= ResultLength
;
597 /* Do the callback */
598 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
599 if (NT_SUCCESS(Status
))
601 /* Call the internal API */
602 Status
= CmQueryValueKey(KeyObject
->KeyControlBlock
,
604 KeyValueInformationClass
,
609 /* Do the post callback */
610 PostOperationInfo
.Status
= Status
;
611 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
614 /* Dereference and return status */
615 ObDereferenceObject(KeyObject
);
621 NtSetValueKey(IN HANDLE KeyHandle
,
622 IN PUNICODE_STRING ValueName
,
629 PCM_KEY_BODY KeyObject
;
630 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
631 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
632 UNICODE_STRING ValueNameCopy
= *ValueName
;
634 DPRINT("NtSetValueKey() KH 0x%x, VN '%wZ', TI %x, T %d, DS %d\n",
635 KeyHandle
, ValueName
, TitleIndex
, Type
, DataSize
);
637 /* Verify that the handle is valid and is a registry key */
638 Status
= ObReferenceObjectByHandle(KeyHandle
,
644 if (!NT_SUCCESS(Status
)) return Status
;
646 /* Make sure the name is aligned, not too long, and the data under 4GB */
647 if ( (ValueNameCopy
.Length
> 32767) ||
648 ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1))) ||
649 (DataSize
> 0x80000000))
652 ObDereferenceObject(KeyObject
);
653 return STATUS_INVALID_PARAMETER
;
656 /* Ignore any null characters at the end */
657 while ((ValueNameCopy
.Length
) &&
658 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
661 ValueNameCopy
.Length
-= sizeof(WCHAR
);
664 /* Don't touch read-only keys */
665 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
668 ObDereferenceObject(KeyObject
);
669 return STATUS_ACCESS_DENIED
;
673 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
674 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
675 SetValueKeyInfo
.ValueName
= ValueName
;
676 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
677 SetValueKeyInfo
.Type
= Type
;
678 SetValueKeyInfo
.Data
= Data
;
679 SetValueKeyInfo
.DataSize
= DataSize
;
681 /* Do the callback */
682 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
683 if (NT_SUCCESS(Status
))
685 /* Call the internal API */
686 Status
= CmSetValueKey(KeyObject
->KeyControlBlock
,
693 /* Do the post-callback */
694 PostOperationInfo
.Status
= Status
;
695 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
697 /* Dereference and return status */
698 ObDereferenceObject(KeyObject
);
704 NtDeleteValueKey(IN HANDLE KeyHandle
,
705 IN PUNICODE_STRING ValueName
)
707 PCM_KEY_BODY KeyObject
;
709 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
710 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
711 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
712 UNICODE_STRING ValueNameCopy
= *ValueName
;
715 /* Verify that the handle is valid and is a registry key */
716 Status
= ObReferenceObjectByHandle(KeyHandle
,
722 if (!NT_SUCCESS(Status
)) return Status
;
724 /* Don't touch read-only keys */
725 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
728 ObDereferenceObject(KeyObject
);
729 return STATUS_ACCESS_DENIED
;
732 /* Make sure the name is aligned properly */
733 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
735 /* It isn't, so we'll fail */
736 ObDereferenceObject(KeyObject
);
737 return STATUS_INVALID_PARAMETER
;
740 /* Do the callback */
741 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
742 DeleteValueKeyInfo
.ValueName
= ValueName
;
743 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
,
744 &DeleteValueKeyInfo
);
745 if (NT_SUCCESS(Status
))
747 /* Call the internal API */
748 Status
= CmDeleteValueKey(KeyObject
->KeyControlBlock
, ValueNameCopy
);
750 /* Do the post callback */
751 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
752 PostOperationInfo
.Status
= Status
;
753 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
,
757 /* Dereference the key body */
758 ObDereferenceObject(KeyObject
);
764 NtFlushKey(IN HANDLE KeyHandle
)
767 PCM_KEY_BODY KeyObject
;
770 /* Get the key object */
771 Status
= ObReferenceObjectByHandle(KeyHandle
,
777 if (!NT_SUCCESS(Status
)) return Status
;
779 /* Lock the registry */
783 CmpAcquireKcbLockShared(KeyObject
->KeyControlBlock
);
785 /* Make sure KCB isn't deleted */
786 if (KeyObject
->KeyControlBlock
->Delete
)
789 Status
= STATUS_KEY_DELETED
;
793 /* Call the internal API */
794 Status
= CmFlushKey(KeyObject
->KeyControlBlock
, FALSE
);
797 /* Release the locks */
798 CmpReleaseKcbLock(KeyObject
->KeyControlBlock
);
801 /* Dereference the object and return status */
802 ObDereferenceObject(KeyObject
);
808 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
809 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
811 /* Call the newer API */
812 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, 0, NULL
);
817 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
818 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
821 /* Call the newer API */
822 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, Flags
, NULL
);
827 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
828 IN POBJECT_ATTRIBUTES SourceFile
,
830 IN HANDLE TrustClassKey
)
833 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
834 PCM_KEY_BODY KeyBody
= NULL
;
838 if (Flags
& ~REG_NO_LAZY_FLUSH
) return STATUS_INVALID_PARAMETER
;
840 /* Validate privilege */
841 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
844 DPRINT1("Restore Privilege missing!\n");
845 return STATUS_PRIVILEGE_NOT_HELD
;
849 KeEnterCriticalRegion();
851 /* Check if we have a trust class */
855 Status
= ObReferenceObjectByHandle(TrustClassKey
,
863 /* Call the internal API */
864 Status
= CmLoadKey(TargetKey
, SourceFile
, Flags
, KeyBody
);
866 /* Dereference the trust key, if any */
867 if (KeyBody
) ObDereferenceObject(KeyBody
);
869 /* Bring back APCs */
870 KeLeaveCriticalRegion();
878 NtNotifyChangeKey(IN HANDLE KeyHandle
,
880 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
881 IN PVOID ApcContext OPTIONAL
,
882 OUT PIO_STATUS_BLOCK IoStatusBlock
,
883 IN ULONG CompletionFilter
,
884 IN BOOLEAN WatchTree
,
887 IN BOOLEAN Asynchronous
)
889 /* Call the newer API */
890 return NtNotifyChangeMultipleKeys(KeyHandle
,
906 NtInitializeRegistry(IN USHORT Flag
)
909 NTSTATUS Status
= STATUS_SUCCESS
;
912 /* Always do this as kernel mode */
913 if (KeGetPreviousMode() == UserMode
) return ZwInitializeRegistry(Flag
);
916 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
918 /* Check if boot was accepted */
919 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
921 /* Only allow once */
922 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
923 CmBootAcceptFirstTime
= FALSE
;
925 /* Get the control set accepted */
926 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
929 /* FIXME: Save the last known good boot */
930 //Status = CmpSaveBootControlSet(Flag);
935 /* Enable lazy flush */
936 CmpHoldLazyFlush
= FALSE
;
941 /* Otherwise, invalid boot */
942 return STATUS_INVALID_PARAMETER
;
945 /* Check if this was a setup boot */
946 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
948 /* Make sure we're only called once */
949 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
952 /* Acquire registry lock */
953 //CmpLockRegistryExclusive();
955 /* Initialize the hives and lazy flusher */
956 CmpCmdInit(SetupBoot
);
958 /* FIXME: Save version data */
959 //CmpSetVersionData();
961 /* Release the registry lock */
962 //CmpUnlockRegistry();
963 return STATUS_SUCCESS
;
968 NtCompactKeys(IN ULONG Count
,
972 return STATUS_NOT_IMPLEMENTED
;
977 NtCompressKey(IN HANDLE Key
)
980 return STATUS_NOT_IMPLEMENTED
;
985 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
989 return STATUS_NOT_IMPLEMENTED
;
994 NtLockRegistryKey(IN HANDLE KeyHandle
)
997 return STATUS_NOT_IMPLEMENTED
;
1002 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
1004 IN POBJECT_ATTRIBUTES SlaveObjects
,
1006 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1007 IN PVOID ApcContext OPTIONAL
,
1008 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1009 IN ULONG CompletionFilter
,
1010 IN BOOLEAN WatchTree
,
1013 IN BOOLEAN Asynchronous
)
1016 return STATUS_NOT_IMPLEMENTED
;
1021 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1022 IN OUT PKEY_VALUE_ENTRY ValueList
,
1023 IN ULONG NumberOfValues
,
1025 IN OUT PULONG Length
,
1026 OUT PULONG ReturnLength
)
1029 return STATUS_NOT_IMPLEMENTED
;
1034 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1035 OUT PULONG HandleCount
)
1038 return STATUS_NOT_IMPLEMENTED
;
1043 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey
,
1044 IN ULONG BufferLength
,
1046 IN PULONG RequiredSize
)
1049 return STATUS_NOT_IMPLEMENTED
;
1054 NtRenameKey(IN HANDLE KeyHandle
,
1055 IN PUNICODE_STRING ReplacementName
)
1058 return STATUS_NOT_IMPLEMENTED
;
1063 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1065 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1068 return STATUS_NOT_IMPLEMENTED
;
1073 NtRestoreKey(IN HANDLE KeyHandle
,
1074 IN HANDLE FileHandle
,
1075 IN ULONG RestoreFlags
)
1078 return STATUS_NOT_IMPLEMENTED
;
1083 NtSaveKey(IN HANDLE KeyHandle
,
1084 IN HANDLE FileHandle
)
1087 return STATUS_NOT_IMPLEMENTED
;
1092 NtSaveKeyEx(IN HANDLE KeyHandle
,
1093 IN HANDLE FileHandle
,
1097 return STATUS_NOT_IMPLEMENTED
;
1102 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle
,
1103 IN HANDLE LowPrecedenceKeyHandle
,
1104 IN HANDLE FileHandle
)
1107 return STATUS_NOT_IMPLEMENTED
;
1112 NtSetInformationKey(IN HANDLE KeyHandle
,
1113 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
1114 IN PVOID KeyInformation
,
1115 IN ULONG KeyInformationLength
)
1118 return STATUS_NOT_IMPLEMENTED
;
1123 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
1125 return NtUnloadKey2(KeyObjectAttributes
, 0);
1130 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey
,
1134 NTSTATUS Status
= STATUS_SUCCESS
;
1135 OBJECT_ATTRIBUTES ObjectAttributes
;
1136 UNICODE_STRING ObjectName
;
1137 CM_PARSE_CONTEXT ParseContext
= {0};
1138 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1139 PCM_KEY_BODY KeyBody
= NULL
;
1140 ULONG ParentConv
= 0, ChildConv
= 0;
1144 /* Validate privilege */
1145 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1148 DPRINT1("Restore Privilege missing!\n");
1149 return STATUS_PRIVILEGE_NOT_HELD
;
1152 /* Check for user-mode caller */
1153 if (PreviousMode
!= KernelMode
)
1155 /* Prepare to probe parameters */
1158 /* Probe object attributes */
1159 ProbeForRead(TargetKey
,
1160 sizeof(OBJECT_ATTRIBUTES
),
1163 ObjectAttributes
= *TargetKey
;
1165 /* Probe the string */
1166 ProbeForReadUnicodeString(&TargetKey
->ObjectName
);
1168 ObjectName
= *TargetKey
->ObjectName
;
1170 ProbeForRead(ObjectName
.Buffer
,
1174 ObjectAttributes
.ObjectName
= &ObjectName
;
1176 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1178 /* Get the error code */
1179 Status
= _SEH2_GetExceptionCode();
1182 if(!NT_SUCCESS(Status
)) return Status
;
1186 /* Save the target attributes directly */
1187 ObjectAttributes
= *TargetKey
;
1190 /* Setup the parse context */
1191 ParseContext
.CreateOperation
= TRUE
;
1192 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1195 Status
= ObOpenObjectByName(&ObjectAttributes
,
1203 /* Return if failure encountered */
1204 if (!NT_SUCCESS(Status
)) return Status
;
1207 Status
= ObReferenceObjectByHandle(Handle
,
1214 /* Close the handle */
1217 /* Return if failure encountered */
1218 if (!NT_SUCCESS(Status
)) return Status
;
1220 /* Acquire the lock depending on flags */
1221 if (Flags
== REG_FORCE_UNLOAD
)
1223 /* Lock registry exclusively */
1224 CmpLockRegistryExclusive();
1231 /* Acquire the hive loading lock */
1232 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1234 /* Lock parent and child */
1235 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1236 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1238 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1240 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1242 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1245 /* Check if it's being deleted already */
1246 if (KeyBody
->KeyControlBlock
->Delete
)
1248 /* Return appropriate status */
1249 Status
= STATUS_KEY_DELETED
;
1253 /* Check if it's a readonly key */
1254 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1256 /* Return appropriate status */
1257 Status
= STATUS_ACCESS_DENIED
;
1261 /* Call the internal API */
1262 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
,
1265 /* Check if we failed, but really need to succeed */
1266 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1268 /* TODO: We should perform another attempt here */
1272 /* If CmUnloadKey failed we need to unlock registry ourselves */
1273 if (!NT_SUCCESS(Status
))
1275 if (Flags
!= REG_FORCE_UNLOAD
)
1277 /* Release the hive loading lock */
1278 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1280 /* Release two KCBs lock */
1281 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1284 /* Unlock the registry */
1285 CmpUnlockRegistry();
1289 /* Dereference the key */
1290 ObDereferenceObject(KeyBody
);
1296 return STATUS_NOT_IMPLEMENTED
;
1302 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1306 return STATUS_NOT_IMPLEMENTED
;