2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/ntapi.c
5 * PURPOSE: Configuration Manager - Internal Registry APIs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
10 /* INCLUDES ******************************************************************/
16 BOOLEAN CmBootAcceptFirstTime
= TRUE
;
17 BOOLEAN CmFirstTime
= TRUE
;
18 extern ULONG InitSafeBootMode
;
20 /* FUNCTIONS *****************************************************************/
24 NtCreateKey(OUT PHANDLE KeyHandle
,
25 IN ACCESS_MASK DesiredAccess
,
26 IN POBJECT_ATTRIBUTES ObjectAttributes
,
28 IN PUNICODE_STRING Class OPTIONAL
,
29 IN ULONG CreateOptions
,
30 OUT PULONG Disposition OPTIONAL
)
33 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
34 CM_PARSE_CONTEXT ParseContext
= {0};
38 DPRINT("NtCreateKey(Path: %wZ, Root %x, Access: %x, CreateOptions %x)\n",
39 ObjectAttributes
->ObjectName
, ObjectAttributes
->RootDirectory
,
40 DesiredAccess
, CreateOptions
);
42 /* Ignore the WOW64 flag, it's not valid in the kernel */
43 DesiredAccess
&= ~KEY_WOW64_RES
;
45 /* Check for user-mode caller */
46 if (PreviousMode
!= KernelMode
)
48 /* Prepare to probe parameters */
51 /* Check if we have a class */
55 ParseContext
.Class
= ProbeForReadUnicodeString(Class
);
56 ProbeForRead(ParseContext
.Class
.Buffer
,
57 ParseContext
.Class
.Length
,
61 /* Probe the key handle */
62 ProbeForWriteHandle(KeyHandle
);
65 /* Probe object attributes */
66 ProbeForRead(ObjectAttributes
,
67 sizeof(OBJECT_ATTRIBUTES
),
71 ProbeForWriteUlong(Disposition
);
73 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
75 /* Return the exception code */
76 _SEH2_YIELD(return _SEH2_GetExceptionCode());
82 /* Save the class directly */
83 if (Class
) ParseContext
.Class
= *Class
;
86 /* Setup the parse context */
87 ParseContext
.CreateOperation
= TRUE
;
88 ParseContext
.CreateOptions
= CreateOptions
;
91 Status
= ObOpenObjectByName(ObjectAttributes
,
101 /* Return data to user */
102 if (NT_SUCCESS(Status
)) *KeyHandle
= Handle
;
103 if (Disposition
) *Disposition
= ParseContext
.Disposition
;
105 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
108 Status
= _SEH2_GetExceptionCode();
112 DPRINT("Returning handle %x, Status %x.\n", Handle
, Status
);
120 NtOpenKey(OUT PHANDLE KeyHandle
,
121 IN ACCESS_MASK DesiredAccess
,
122 IN POBJECT_ATTRIBUTES ObjectAttributes
)
124 CM_PARSE_CONTEXT ParseContext
= {0};
127 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
129 DPRINT("NtOpenKey(Path: %wZ, Root %x, Access: %x)\n",
130 ObjectAttributes
->ObjectName
, ObjectAttributes
->RootDirectory
, DesiredAccess
);
132 /* Ignore the WOW64 flag, it's not valid in the kernel */
133 DesiredAccess
&= ~KEY_WOW64_RES
;
135 /* Check for user-mode caller */
136 if (PreviousMode
!= KernelMode
)
138 /* Prepare to probe parameters */
141 /* Probe the key handle */
142 ProbeForWriteHandle(KeyHandle
);
145 /* Probe object attributes */
146 ProbeForRead(ObjectAttributes
,
147 sizeof(OBJECT_ATTRIBUTES
),
150 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
152 /* Return the exception code */
153 _SEH2_YIELD(return _SEH2_GetExceptionCode());
158 /* Just let the object manager handle this */
159 Status
= ObOpenObjectByName(ObjectAttributes
,
167 /* Only do this if we succeeded */
168 if (NT_SUCCESS(Status
))
172 /* Return the handle to caller */
175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
178 Status
= _SEH2_GetExceptionCode();
183 DPRINT("Returning handle %x, Status %x.\n", Handle
, Status
);
192 NtDeleteKey(IN HANDLE KeyHandle
)
194 PCM_KEY_BODY KeyObject
;
196 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
197 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
199 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle
);
201 /* Verify that the handle is valid and is a registry key */
202 Status
= ObReferenceObjectByHandle(KeyHandle
,
208 if (!NT_SUCCESS(Status
)) return Status
;
210 /* Setup the callback */
211 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
212 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
213 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteKey
, &DeleteKeyInfo
);
214 if (NT_SUCCESS(Status
))
216 /* Check if we are read-only */
217 if ((KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
) ||
218 (KeyObject
->KeyControlBlock
->ParentKcb
->ExtFlags
& CM_KCB_READ_ONLY_KEY
))
221 Status
= STATUS_ACCESS_DENIED
;
225 /* Call the internal API */
226 Status
= CmDeleteKey(KeyObject
);
229 /* Do post callback */
230 PostOperationInfo
.Status
= Status
;
231 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
234 /* Dereference the object */
235 ObDereferenceObject(KeyObject
);
241 NtEnumerateKey(IN HANDLE KeyHandle
,
243 IN KEY_INFORMATION_CLASS KeyInformationClass
,
244 OUT PVOID KeyInformation
,
246 OUT PULONG ResultLength
)
248 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
250 PCM_KEY_BODY KeyObject
;
251 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
252 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
254 DPRINT("NtEnumerateKey() KH 0x%p, Index 0x%x, KIC %d, Length %lu\n",
255 KeyHandle
, Index
, KeyInformationClass
, Length
);
257 /* Reject classes we don't know about */
258 if ((KeyInformationClass
!= KeyBasicInformation
) &&
259 (KeyInformationClass
!= KeyNodeInformation
) &&
260 (KeyInformationClass
!= KeyFullInformation
))
263 return STATUS_INVALID_PARAMETER
;
266 /* Verify that the handle is valid and is a registry key */
267 Status
= ObReferenceObjectByHandle(KeyHandle
,
268 KEY_ENUMERATE_SUB_KEYS
,
273 if (!NT_SUCCESS(Status
)) return Status
;
275 if (PreviousMode
!= KernelMode
)
279 ProbeForWriteUlong(ResultLength
);
280 ProbeForWrite(KeyInformation
,
284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
286 /* Dereference and return status */
287 ObDereferenceObject(KeyObject
);
288 _SEH2_YIELD(return _SEH2_GetExceptionCode());
293 /* Setup the callback */
294 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
295 EnumerateKeyInfo
.Object
= (PVOID
)KeyObject
;
296 EnumerateKeyInfo
.Index
= Index
;
297 EnumerateKeyInfo
.KeyInformationClass
= KeyInformationClass
;
298 EnumerateKeyInfo
.Length
= Length
;
299 EnumerateKeyInfo
.ResultLength
= ResultLength
;
301 /* Do the callback */
302 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateKey
, &EnumerateKeyInfo
);
303 if (NT_SUCCESS(Status
))
305 /* Call the internal API */
306 Status
= CmEnumerateKey(KeyObject
->KeyControlBlock
,
313 /* Do the post callback */
314 PostOperationInfo
.Status
= Status
;
315 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
318 /* Dereference and return status */
319 ObDereferenceObject(KeyObject
);
320 DPRINT("Returning status %x.\n", Status
);
326 NtEnumerateValueKey(IN HANDLE KeyHandle
,
328 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
329 OUT PVOID KeyValueInformation
,
331 OUT PULONG ResultLength
)
333 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
335 PCM_KEY_BODY KeyObject
;
336 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo
;
337 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
339 DPRINT("NtEnumerateValueKey() KH 0x%p, Index 0x%x, KVIC %d, Length %lu\n",
340 KeyHandle
, Index
, KeyValueInformationClass
, Length
);
342 /* Reject classes we don't know about */
343 if ((KeyValueInformationClass
!= KeyValueBasicInformation
) &&
344 (KeyValueInformationClass
!= KeyValueFullInformation
) &&
345 (KeyValueInformationClass
!= KeyValuePartialInformation
))
348 return STATUS_INVALID_PARAMETER
;
351 /* Verify that the handle is valid and is a registry key */
352 Status
= ObReferenceObjectByHandle(KeyHandle
,
358 if (!NT_SUCCESS(Status
)) return Status
;
360 if (PreviousMode
!= KernelMode
)
364 ProbeForWriteUlong(ResultLength
);
365 ProbeForWrite(KeyValueInformation
,
369 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
371 /* Dereference and return status */
372 ObDereferenceObject(KeyObject
);
373 _SEH2_YIELD(return _SEH2_GetExceptionCode());
378 /* Setup the callback */
379 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
380 EnumerateValueKeyInfo
.Object
= (PVOID
)KeyObject
;
381 EnumerateValueKeyInfo
.Index
= Index
;
382 EnumerateValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
383 EnumerateValueKeyInfo
.KeyValueInformation
= KeyValueInformation
;
384 EnumerateValueKeyInfo
.Length
= Length
;
385 EnumerateValueKeyInfo
.ResultLength
= ResultLength
;
387 /* Do the callback */
388 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey
,
389 &EnumerateValueKeyInfo
);
390 if (NT_SUCCESS(Status
))
392 /* Call the internal API */
393 Status
= CmEnumerateValueKey(KeyObject
->KeyControlBlock
,
395 KeyValueInformationClass
,
400 /* Do the post callback */
401 PostOperationInfo
.Status
= Status
;
402 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey
, &PostOperationInfo
);
405 ObDereferenceObject(KeyObject
);
411 NtQueryKey(IN HANDLE KeyHandle
,
412 IN KEY_INFORMATION_CLASS KeyInformationClass
,
413 OUT PVOID KeyInformation
,
415 OUT PULONG ResultLength
)
417 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
419 PCM_KEY_BODY KeyObject
;
420 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
421 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
422 OBJECT_HANDLE_INFORMATION HandleInfo
;
424 DPRINT("NtQueryKey() KH 0x%p, KIC %d, Length %lu\n",
425 KeyHandle
, KeyInformationClass
, Length
);
427 /* Reject invalid classes */
428 if ((KeyInformationClass
!= KeyBasicInformation
) &&
429 (KeyInformationClass
!= KeyNodeInformation
) &&
430 (KeyInformationClass
!= KeyFullInformation
) &&
431 (KeyInformationClass
!= KeyNameInformation
) &&
432 (KeyInformationClass
!= KeyCachedInformation
) &&
433 (KeyInformationClass
!= KeyFlagsInformation
))
436 return STATUS_INVALID_PARAMETER
;
439 /* Check if just the name is required */
440 if (KeyInformationClass
== KeyNameInformation
)
442 /* Ignore access level */
443 Status
= ObReferenceObjectByHandle(KeyHandle
,
449 if (NT_SUCCESS(Status
))
451 /* At least a single bit of access is required */
452 if (!HandleInfo
.GrantedAccess
)
455 ObDereferenceObject(KeyObject
);
456 Status
= STATUS_ACCESS_DENIED
;
462 /* Get a reference */
463 Status
= ObReferenceObjectByHandle(KeyHandle
,
471 /* Quit on failure */
472 if (!NT_SUCCESS(Status
)) return Status
;
474 if (PreviousMode
!= KernelMode
)
478 ProbeForWriteUlong(ResultLength
);
479 ProbeForWrite(KeyInformation
,
483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
485 /* Dereference and return status */
486 ObDereferenceObject(KeyObject
);
487 _SEH2_YIELD(return _SEH2_GetExceptionCode());
492 /* Setup the callback */
493 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
494 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
495 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
496 QueryKeyInfo
.KeyInformation
= KeyInformation
;
497 QueryKeyInfo
.Length
= Length
;
498 QueryKeyInfo
.ResultLength
= ResultLength
;
500 /* Do the callback */
501 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryKey
, &QueryKeyInfo
);
502 if (NT_SUCCESS(Status
))
504 /* Call the internal API */
505 Status
= CmQueryKey(KeyObject
->KeyControlBlock
,
511 /* Do the post callback */
512 PostOperationInfo
.Status
= Status
;
513 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
516 /* Dereference and return status */
517 ObDereferenceObject(KeyObject
);
523 NtQueryValueKey(IN HANDLE KeyHandle
,
524 IN PUNICODE_STRING ValueName
,
525 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
526 OUT PVOID KeyValueInformation
,
528 OUT PULONG ResultLength
)
530 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
532 PCM_KEY_BODY KeyObject
;
533 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
534 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
535 UNICODE_STRING ValueNameCopy
= *ValueName
;
539 DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n",
540 KeyHandle
, ValueName
, KeyValueInformationClass
, Length
);
542 /* Reject classes we don't know about */
543 if ((KeyValueInformationClass
!= KeyValueBasicInformation
) &&
544 (KeyValueInformationClass
!= KeyValueFullInformation
) &&
545 (KeyValueInformationClass
!= KeyValuePartialInformation
) &&
546 (KeyValueInformationClass
!= KeyValueFullInformationAlign64
) &&
547 (KeyValueInformationClass
!= KeyValuePartialInformationAlign64
))
550 return STATUS_INVALID_PARAMETER
;
553 /* Verify that the handle is valid and is a registry key */
554 Status
= ObReferenceObjectByHandle(KeyHandle
,
560 if (!NT_SUCCESS(Status
)) return Status
;
562 if (PreviousMode
!= KernelMode
)
566 ProbeForWriteUlong(ResultLength
);
567 ProbeForWrite(KeyValueInformation
,
571 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
573 /* Dereference and return status */
574 ObDereferenceObject(KeyObject
);
575 _SEH2_YIELD(return _SEH2_GetExceptionCode());
580 /* Make sure the name is aligned properly */
581 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
583 /* It isn't, so we'll fail */
584 ObDereferenceObject(KeyObject
);
585 return STATUS_INVALID_PARAMETER
;
589 /* Ignore any null characters at the end */
590 while ((ValueNameCopy
.Length
) &&
591 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
594 ValueNameCopy
.Length
-= sizeof(WCHAR
);
598 /* Setup the callback */
599 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
600 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
601 QueryValueKeyInfo
.ValueName
= &ValueNameCopy
;
602 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
603 QueryValueKeyInfo
.Length
= Length
;
604 QueryValueKeyInfo
.ResultLength
= ResultLength
;
606 /* Do the callback */
607 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
608 if (NT_SUCCESS(Status
))
610 /* Call the internal API */
611 Status
= CmQueryValueKey(KeyObject
->KeyControlBlock
,
613 KeyValueInformationClass
,
618 /* Do the post callback */
619 PostOperationInfo
.Status
= Status
;
620 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
623 /* Dereference and return status */
624 ObDereferenceObject(KeyObject
);
630 NtSetValueKey(IN HANDLE KeyHandle
,
631 IN PUNICODE_STRING ValueName
,
637 NTSTATUS Status
= STATUS_SUCCESS
;
638 PCM_KEY_BODY KeyObject
= NULL
;
639 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
640 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
641 UNICODE_STRING ValueNameCopy
;
642 KPROCESSOR_MODE PreviousMode
;
646 PreviousMode
= ExGetPreviousMode();
651 /* Probe and copy the data */
652 if ((PreviousMode
!= KernelMode
) && (DataSize
!= 0))
654 PVOID DataCopy
= ExAllocatePoolWithTag(PagedPool
, DataSize
, TAG_CM
);
656 return STATUS_INSUFFICIENT_RESOURCES
;
659 ProbeForRead(Data
, DataSize
, 1);
660 RtlCopyMemory(DataCopy
, Data
, DataSize
);
662 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
664 Status
= _SEH2_GetExceptionCode();
668 if (!NT_SUCCESS(Status
))
670 ExFreePoolWithTag(DataCopy
, TAG_CM
);
676 /* Capture the string */
677 Status
= ProbeAndCaptureUnicodeString(&ValueNameCopy
, PreviousMode
, ValueName
);
678 if (!NT_SUCCESS(Status
))
681 DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
682 KeyHandle
, &ValueNameCopy
, TitleIndex
, Type
, DataSize
);
684 /* Verify that the handle is valid and is a registry key */
685 Status
= ObReferenceObjectByHandle(KeyHandle
,
691 if (!NT_SUCCESS(Status
))
694 /* Make sure the name is aligned, not too long, and the data under 4GB */
695 if ( (ValueNameCopy
.Length
> 32767) ||
696 ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1))) ||
697 (DataSize
> 0x80000000))
700 Status
= STATUS_INVALID_PARAMETER
;
704 /* Ignore any null characters at the end */
705 while ((ValueNameCopy
.Length
) &&
706 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
709 ValueNameCopy
.Length
-= sizeof(WCHAR
);
712 /* Don't touch read-only keys */
713 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
716 Status
= STATUS_ACCESS_DENIED
;
721 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
722 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
723 SetValueKeyInfo
.ValueName
= &ValueNameCopy
;
724 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
725 SetValueKeyInfo
.Type
= Type
;
726 SetValueKeyInfo
.Data
= Data
;
727 SetValueKeyInfo
.DataSize
= DataSize
;
729 /* Do the callback */
730 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
731 if (NT_SUCCESS(Status
))
733 /* Call the internal API */
734 Status
= CmSetValueKey(KeyObject
->KeyControlBlock
,
740 /* Do the post-callback */
741 PostOperationInfo
.Status
= Status
;
742 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
746 /* Dereference and return status */
748 ObDereferenceObject(KeyObject
);
749 ReleaseCapturedUnicodeString(&ValueNameCopy
, PreviousMode
);
750 if ((PreviousMode
!= KernelMode
) && Data
)
751 ExFreePoolWithTag(Data
, TAG_CM
);
757 NtDeleteValueKey(IN HANDLE KeyHandle
,
758 IN PUNICODE_STRING ValueName
)
760 PCM_KEY_BODY KeyObject
;
762 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
763 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
764 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
765 UNICODE_STRING ValueNameCopy
= *ValueName
;
768 /* Verify that the handle is valid and is a registry key */
769 Status
= ObReferenceObjectByHandle(KeyHandle
,
775 if (!NT_SUCCESS(Status
)) return Status
;
777 /* Don't touch read-only keys */
778 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
781 ObDereferenceObject(KeyObject
);
782 return STATUS_ACCESS_DENIED
;
785 /* Make sure the name is aligned properly */
786 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
788 /* It isn't, so we'll fail */
789 ObDereferenceObject(KeyObject
);
790 return STATUS_INVALID_PARAMETER
;
793 /* Do the callback */
794 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
795 DeleteValueKeyInfo
.ValueName
= ValueName
;
796 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
,
797 &DeleteValueKeyInfo
);
798 if (NT_SUCCESS(Status
))
800 /* Call the internal API */
801 Status
= CmDeleteValueKey(KeyObject
->KeyControlBlock
, ValueNameCopy
);
803 /* Do the post callback */
804 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
805 PostOperationInfo
.Status
= Status
;
806 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
,
810 /* Dereference the key body */
811 ObDereferenceObject(KeyObject
);
817 NtFlushKey(IN HANDLE KeyHandle
)
820 PCM_KEY_BODY KeyObject
;
823 /* Get the key object */
824 Status
= ObReferenceObjectByHandle(KeyHandle
,
830 if (!NT_SUCCESS(Status
)) return Status
;
832 /* Lock the registry */
836 CmpAcquireKcbLockShared(KeyObject
->KeyControlBlock
);
838 /* Make sure KCB isn't deleted */
839 if (KeyObject
->KeyControlBlock
->Delete
)
842 Status
= STATUS_KEY_DELETED
;
846 /* Call the internal API */
847 Status
= CmFlushKey(KeyObject
->KeyControlBlock
, FALSE
);
850 /* Release the locks */
851 CmpReleaseKcbLock(KeyObject
->KeyControlBlock
);
854 /* Dereference the object and return status */
855 ObDereferenceObject(KeyObject
);
861 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
862 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
864 /* Call the newer API */
865 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, 0, NULL
);
870 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
871 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
874 /* Call the newer API */
875 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, Flags
, NULL
);
880 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
881 IN POBJECT_ATTRIBUTES SourceFile
,
883 IN HANDLE TrustClassKey
)
886 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
887 PCM_KEY_BODY KeyBody
= NULL
;
891 if (Flags
& ~REG_NO_LAZY_FLUSH
) return STATUS_INVALID_PARAMETER
;
893 /* Validate privilege */
894 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
896 DPRINT1("Restore Privilege missing!\n");
897 return STATUS_PRIVILEGE_NOT_HELD
;
901 KeEnterCriticalRegion();
903 /* Check if we have a trust class */
907 Status
= ObReferenceObjectByHandle(TrustClassKey
,
915 /* Call the internal API */
916 Status
= CmLoadKey(TargetKey
, SourceFile
, Flags
, KeyBody
);
918 /* Dereference the trust key, if any */
919 if (KeyBody
) ObDereferenceObject(KeyBody
);
921 /* Bring back APCs */
922 KeLeaveCriticalRegion();
930 NtNotifyChangeKey(IN HANDLE KeyHandle
,
932 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
933 IN PVOID ApcContext OPTIONAL
,
934 OUT PIO_STATUS_BLOCK IoStatusBlock
,
935 IN ULONG CompletionFilter
,
936 IN BOOLEAN WatchTree
,
939 IN BOOLEAN Asynchronous
)
941 /* Call the newer API */
942 return NtNotifyChangeMultipleKeys(KeyHandle
,
958 NtInitializeRegistry(IN USHORT Flag
)
961 NTSTATUS Status
= STATUS_SUCCESS
;
964 /* Always do this as kernel mode */
965 if (KeGetPreviousMode() == UserMode
) return ZwInitializeRegistry(Flag
);
967 /* Enough of the system has booted by now */
971 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
973 /* Check if boot was accepted */
974 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
976 /* Only allow once */
977 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
978 CmBootAcceptFirstTime
= FALSE
;
980 /* Get the control set accepted */
981 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
984 /* FIXME: Save the last known good boot */
985 //Status = CmpSaveBootControlSet(Flag);
990 /* Enable lazy flush */
991 CmpHoldLazyFlush
= FALSE
;
996 /* Otherwise, invalid boot */
997 return STATUS_INVALID_PARAMETER
;
1000 /* Check if this was a setup boot */
1001 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
1003 /* Make sure we're only called once */
1004 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
1005 CmFirstTime
= FALSE
;
1007 /* Acquire registry lock */
1008 //CmpLockRegistryExclusive();
1010 /* Initialize the hives and lazy flusher */
1011 CmpCmdInit(SetupBoot
);
1013 /* Save version data */
1014 CmpSetVersionData();
1016 /* Release the registry lock */
1017 //CmpUnlockRegistry();
1018 return STATUS_SUCCESS
;
1023 NtCompactKeys(IN ULONG Count
,
1024 IN PHANDLE KeyArray
)
1027 return STATUS_NOT_IMPLEMENTED
;
1032 NtCompressKey(IN HANDLE Key
)
1035 return STATUS_NOT_IMPLEMENTED
;
1038 // FIXME: different for different windows versions!
1039 #define PRODUCT_ACTIVATION_VERSION 7749
1043 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
1044 IN PULONG pSafeMode
)
1046 KPROCESSOR_MODE PreviousMode
;
1048 PreviousMode
= ExGetPreviousMode();
1051 /* Check if the caller asked for the version */
1052 if (pPrivateVer
!= NULL
)
1054 /* For user mode, probe it */
1055 if (PreviousMode
!= KernelMode
)
1057 ProbeForRead(pPrivateVer
, sizeof(ULONG
), sizeof(ULONG
));
1060 /* Return the expected version */
1061 *pPrivateVer
= PRODUCT_ACTIVATION_VERSION
;
1064 /* Check if the caller asked for safe mode mode state */
1065 if (pSafeMode
!= NULL
)
1067 /* For user mode, probe it */
1068 if (PreviousMode
!= KernelMode
)
1070 ProbeForRead(pSafeMode
, sizeof(ULONG
), sizeof(ULONG
));
1073 /* Return the safe boot mode state */
1074 *pSafeMode
= InitSafeBootMode
;
1077 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1079 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1083 return STATUS_SUCCESS
;
1088 NtLockRegistryKey(IN HANDLE KeyHandle
)
1091 return STATUS_NOT_IMPLEMENTED
;
1096 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
1098 IN POBJECT_ATTRIBUTES SlaveObjects
,
1100 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1101 IN PVOID ApcContext OPTIONAL
,
1102 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1103 IN ULONG CompletionFilter
,
1104 IN BOOLEAN WatchTree
,
1107 IN BOOLEAN Asynchronous
)
1110 return STATUS_NOT_IMPLEMENTED
;
1115 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1116 IN OUT PKEY_VALUE_ENTRY ValueList
,
1117 IN ULONG NumberOfValues
,
1119 IN OUT PULONG Length
,
1120 OUT PULONG ReturnLength
)
1123 return STATUS_NOT_IMPLEMENTED
;
1128 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1129 OUT PULONG HandleCount
)
1131 KPROCESSOR_MODE PreviousMode
;
1132 PCM_KEY_BODY KeyBody
= NULL
;
1136 DPRINT("NtQueryOpenSubKeys()\n");
1140 /* Get the processor mode */
1141 PreviousMode
= KeGetPreviousMode();
1143 /* Check for user-mode caller */
1144 if (PreviousMode
!= KernelMode
)
1146 /* Prepare to probe parameters */
1149 /* Probe target key */
1150 ProbeForRead(TargetKey
,
1151 sizeof(OBJECT_ATTRIBUTES
),
1154 /* Probe handle count */
1155 ProbeForWriteUlong(HandleCount
);
1157 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1159 /* Return the exception code */
1160 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1165 /* Open a handle to the key */
1166 Status
= ObOpenObjectByName(TargetKey
,
1173 if (NT_SUCCESS(Status
))
1175 /* Reference the key object */
1176 Status
= ObReferenceObjectByHandle(KeyHandle
,
1183 /* Close the handle */
1187 /* Fail, if the key object could not be referenced */
1188 if (!NT_SUCCESS(Status
))
1191 /* Lock the registry exclusively */
1192 CmpLockRegistryExclusive();
1194 /* Fail, if we did not open a hive root key */
1195 if (KeyBody
->KeyControlBlock
->KeyCell
!=
1196 KeyBody
->KeyControlBlock
->KeyHive
->BaseBlock
->RootCell
)
1198 DPRINT("Error: Key is not a hive root key!\n");
1199 CmpUnlockRegistry();
1200 ObDereferenceObject(KeyBody
);
1201 return STATUS_INVALID_PARAMETER
;
1204 /* Call the internal API */
1205 *HandleCount
= CmCountOpenSubKeys(KeyBody
->KeyControlBlock
,
1208 /* Unlock the registry */
1209 CmpUnlockRegistry();
1211 /* Dereference the key object */
1212 ObDereferenceObject(KeyBody
);
1221 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey
,
1222 IN ULONG BufferLength
,
1224 IN PULONG RequiredSize
)
1227 return STATUS_NOT_IMPLEMENTED
;
1232 NtRenameKey(IN HANDLE KeyHandle
,
1233 IN PUNICODE_STRING ReplacementName
)
1236 return STATUS_NOT_IMPLEMENTED
;
1241 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1243 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1246 return STATUS_NOT_IMPLEMENTED
;
1251 NtRestoreKey(IN HANDLE KeyHandle
,
1252 IN HANDLE FileHandle
,
1253 IN ULONG RestoreFlags
)
1256 return STATUS_NOT_IMPLEMENTED
;
1261 NtSaveKey(IN HANDLE KeyHandle
,
1262 IN HANDLE FileHandle
)
1264 /* Call the extended API */
1265 return NtSaveKeyEx(KeyHandle
, FileHandle
, REG_STANDARD_FORMAT
);
1270 NtSaveKeyEx(IN HANDLE KeyHandle
,
1271 IN HANDLE FileHandle
,
1275 PCM_KEY_BODY KeyObject
;
1276 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1280 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle
, FileHandle
, Flags
);
1282 /* Verify the flags */
1283 if ((Flags
!= REG_STANDARD_FORMAT
)
1284 && (Flags
!= REG_LATEST_FORMAT
)
1285 && (Flags
!= REG_NO_COMPRESSION
))
1287 /* Only one of these values can be specified */
1288 return STATUS_INVALID_PARAMETER
;
1291 /* Validate privilege */
1292 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1294 return STATUS_PRIVILEGE_NOT_HELD
;
1297 /* Verify that the handle is valid and is a registry key */
1298 Status
= ObReferenceObjectByHandle(KeyHandle
,
1304 if (!NT_SUCCESS(Status
)) return Status
;
1306 /* Call the internal API */
1307 Status
= CmSaveKey(KeyObject
->KeyControlBlock
, FileHandle
, Flags
);
1309 ObDereferenceObject(KeyObject
);
1315 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle
,
1316 IN HANDLE LowPrecedenceKeyHandle
,
1317 IN HANDLE FileHandle
)
1319 KPROCESSOR_MODE PreviousMode
;
1320 PCM_KEY_BODY HighPrecedenceKeyObject
= NULL
;
1321 PCM_KEY_BODY LowPrecedenceKeyObject
= NULL
;
1326 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n",
1327 HighPrecedenceKeyHandle
, LowPrecedenceKeyHandle
, FileHandle
);
1329 PreviousMode
= ExGetPreviousMode();
1331 /* Validate privilege */
1332 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1334 return STATUS_PRIVILEGE_NOT_HELD
;
1337 /* Verify that the handles are valid and are registry keys */
1338 Status
= ObReferenceObjectByHandle(HighPrecedenceKeyHandle
,
1342 (PVOID
*)&HighPrecedenceKeyObject
,
1344 if (!NT_SUCCESS(Status
))
1347 Status
= ObReferenceObjectByHandle(LowPrecedenceKeyHandle
,
1351 (PVOID
*)&LowPrecedenceKeyObject
,
1353 if (!NT_SUCCESS(Status
))
1356 /* Call the internal API */
1357 Status
= CmSaveMergedKeys(HighPrecedenceKeyObject
->KeyControlBlock
,
1358 LowPrecedenceKeyObject
->KeyControlBlock
,
1362 if (LowPrecedenceKeyObject
)
1363 ObDereferenceObject(LowPrecedenceKeyObject
);
1365 if (HighPrecedenceKeyObject
)
1366 ObDereferenceObject(HighPrecedenceKeyObject
);
1373 NtSetInformationKey(IN HANDLE KeyHandle
,
1374 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
1375 IN PVOID KeyInformation
,
1376 IN ULONG KeyInformationLength
)
1379 return STATUS_NOT_IMPLEMENTED
;
1384 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
1386 return NtUnloadKey2(KeyObjectAttributes
, 0);
1391 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey
,
1395 OBJECT_ATTRIBUTES ObjectAttributes
;
1396 UNICODE_STRING ObjectName
;
1397 CM_PARSE_CONTEXT ParseContext
= {0};
1398 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1399 PCM_KEY_BODY KeyBody
= NULL
;
1400 ULONG ParentConv
= 0, ChildConv
= 0;
1405 /* Validate privilege */
1406 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1408 DPRINT1("Restore Privilege missing!\n");
1409 return STATUS_PRIVILEGE_NOT_HELD
;
1412 /* Check for user-mode caller */
1413 if (PreviousMode
!= KernelMode
)
1415 /* Prepare to probe parameters */
1418 /* Probe object attributes */
1419 ProbeForRead(TargetKey
,
1420 sizeof(OBJECT_ATTRIBUTES
),
1423 ObjectAttributes
= *TargetKey
;
1425 /* Probe the string */
1426 ProbeForReadUnicodeString(&TargetKey
->ObjectName
);
1428 ObjectName
= *TargetKey
->ObjectName
;
1430 ProbeForRead(ObjectName
.Buffer
,
1434 ObjectAttributes
.ObjectName
= &ObjectName
;
1436 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1438 /* Return the exception code */
1439 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1445 /* Save the target attributes directly */
1446 ObjectAttributes
= *TargetKey
;
1449 /* Setup the parse context */
1450 ParseContext
.CreateOperation
= TRUE
;
1451 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1454 Status
= ObOpenObjectByName(&ObjectAttributes
,
1462 /* Return if failure encountered */
1463 if (!NT_SUCCESS(Status
)) return Status
;
1466 Status
= ObReferenceObjectByHandle(Handle
,
1473 /* Close the handle */
1476 /* Return if failure encountered */
1477 if (!NT_SUCCESS(Status
)) return Status
;
1479 /* Acquire the lock depending on flags */
1480 if (Flags
== REG_FORCE_UNLOAD
)
1482 /* Lock registry exclusively */
1483 CmpLockRegistryExclusive();
1490 /* Acquire the hive loading lock */
1491 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1493 /* Lock parent and child */
1494 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1495 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1497 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1499 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1501 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1504 /* Check if it's being deleted already */
1505 if (KeyBody
->KeyControlBlock
->Delete
)
1507 /* Return appropriate status */
1508 Status
= STATUS_KEY_DELETED
;
1512 /* Check if it's a read-only key */
1513 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1515 /* Return appropriate status */
1516 Status
= STATUS_ACCESS_DENIED
;
1520 /* Call the internal API */
1521 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
,
1524 /* Check if we failed, but really need to succeed */
1525 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1527 /* TODO: We should perform another attempt here */
1531 /* If CmUnloadKey failed we need to unlock registry ourselves */
1532 if (!NT_SUCCESS(Status
))
1534 if (Flags
!= REG_FORCE_UNLOAD
)
1536 /* Release the KCB locks */
1537 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1539 /* Release the hive loading lock */
1540 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1543 /* Unlock the registry */
1544 CmpUnlockRegistry();
1548 /* Dereference the key */
1549 ObDereferenceObject(KeyBody
);
1557 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1561 return STATUS_NOT_IMPLEMENTED
;