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
;
537 DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n",
538 KeyHandle
, ValueName
, KeyValueInformationClass
, Length
);
540 /* Verify that the handle is valid and is a registry key */
541 Status
= ObReferenceObjectByHandle(KeyHandle
,
547 if (!NT_SUCCESS(Status
)) return Status
;
549 if (PreviousMode
!= KernelMode
)
553 ProbeForWriteUlong(ResultLength
);
554 ProbeForWrite(KeyValueInformation
,
558 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
560 /* Dereference and return status */
561 ObDereferenceObject(KeyObject
);
562 _SEH2_YIELD(return _SEH2_GetExceptionCode());
567 /* Make sure the name is aligned properly */
568 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
570 /* It isn't, so we'll fail */
571 ObDereferenceObject(KeyObject
);
572 return STATUS_INVALID_PARAMETER
;
576 /* Ignore any null characters at the end */
577 while ((ValueNameCopy
.Length
) &&
578 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
581 ValueNameCopy
.Length
-= sizeof(WCHAR
);
585 /* Setup the callback */
586 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
587 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
588 QueryValueKeyInfo
.ValueName
= &ValueNameCopy
;
589 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
590 QueryValueKeyInfo
.Length
= Length
;
591 QueryValueKeyInfo
.ResultLength
= ResultLength
;
593 /* Do the callback */
594 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
595 if (NT_SUCCESS(Status
))
597 /* Call the internal API */
598 Status
= CmQueryValueKey(KeyObject
->KeyControlBlock
,
600 KeyValueInformationClass
,
605 /* Do the post callback */
606 PostOperationInfo
.Status
= Status
;
607 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
610 /* Dereference and return status */
611 ObDereferenceObject(KeyObject
);
617 NtSetValueKey(IN HANDLE KeyHandle
,
618 IN PUNICODE_STRING ValueName
,
624 NTSTATUS Status
= STATUS_SUCCESS
;
625 PCM_KEY_BODY KeyObject
= NULL
;
626 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
627 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
628 UNICODE_STRING ValueNameCopy
;
629 KPROCESSOR_MODE PreviousMode
;
633 PreviousMode
= ExGetPreviousMode();
638 /* Probe and copy the data */
639 if ((PreviousMode
!= KernelMode
) && (DataSize
!= 0))
641 PVOID DataCopy
= ExAllocatePoolWithTag(PagedPool
, DataSize
, TAG_CM
);
643 return STATUS_INSUFFICIENT_RESOURCES
;
646 ProbeForRead(Data
, DataSize
, 1);
647 RtlCopyMemory(DataCopy
, Data
, DataSize
);
649 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
651 Status
= _SEH2_GetExceptionCode();
655 if (!NT_SUCCESS(Status
))
657 ExFreePoolWithTag(DataCopy
, TAG_CM
);
663 /* Capture the string */
664 Status
= ProbeAndCaptureUnicodeString(&ValueNameCopy
, PreviousMode
, ValueName
);
665 if (!NT_SUCCESS(Status
))
668 DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
669 KeyHandle
, &ValueNameCopy
, TitleIndex
, Type
, DataSize
);
671 /* Verify that the handle is valid and is a registry key */
672 Status
= ObReferenceObjectByHandle(KeyHandle
,
678 if (!NT_SUCCESS(Status
))
681 /* Make sure the name is aligned, not too long, and the data under 4GB */
682 if ( (ValueNameCopy
.Length
> 32767) ||
683 ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1))) ||
684 (DataSize
> 0x80000000))
687 Status
= STATUS_INVALID_PARAMETER
;
691 /* Ignore any null characters at the end */
692 while ((ValueNameCopy
.Length
) &&
693 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
696 ValueNameCopy
.Length
-= sizeof(WCHAR
);
699 /* Don't touch read-only keys */
700 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
703 Status
= STATUS_ACCESS_DENIED
;
708 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
709 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
710 SetValueKeyInfo
.ValueName
= &ValueNameCopy
;
711 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
712 SetValueKeyInfo
.Type
= Type
;
713 SetValueKeyInfo
.Data
= Data
;
714 SetValueKeyInfo
.DataSize
= DataSize
;
716 /* Do the callback */
717 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
718 if (NT_SUCCESS(Status
))
720 /* Call the internal API */
721 Status
= CmSetValueKey(KeyObject
->KeyControlBlock
,
728 /* Do the post-callback */
729 PostOperationInfo
.Status
= Status
;
730 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
733 /* Dereference and return status */
735 ObDereferenceObject(KeyObject
);
736 ReleaseCapturedUnicodeString(&ValueNameCopy
, PreviousMode
);
737 if ((PreviousMode
!= KernelMode
) && Data
)
738 ExFreePoolWithTag(Data
, TAG_CM
);
744 NtDeleteValueKey(IN HANDLE KeyHandle
,
745 IN PUNICODE_STRING ValueName
)
747 PCM_KEY_BODY KeyObject
;
749 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
750 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
751 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
752 UNICODE_STRING ValueNameCopy
= *ValueName
;
755 /* Verify that the handle is valid and is a registry key */
756 Status
= ObReferenceObjectByHandle(KeyHandle
,
762 if (!NT_SUCCESS(Status
)) return Status
;
764 /* Don't touch read-only keys */
765 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
768 ObDereferenceObject(KeyObject
);
769 return STATUS_ACCESS_DENIED
;
772 /* Make sure the name is aligned properly */
773 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
775 /* It isn't, so we'll fail */
776 ObDereferenceObject(KeyObject
);
777 return STATUS_INVALID_PARAMETER
;
780 /* Do the callback */
781 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
782 DeleteValueKeyInfo
.ValueName
= ValueName
;
783 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
,
784 &DeleteValueKeyInfo
);
785 if (NT_SUCCESS(Status
))
787 /* Call the internal API */
788 Status
= CmDeleteValueKey(KeyObject
->KeyControlBlock
, ValueNameCopy
);
790 /* Do the post callback */
791 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
792 PostOperationInfo
.Status
= Status
;
793 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
,
797 /* Dereference the key body */
798 ObDereferenceObject(KeyObject
);
804 NtFlushKey(IN HANDLE KeyHandle
)
807 PCM_KEY_BODY KeyObject
;
810 /* Get the key object */
811 Status
= ObReferenceObjectByHandle(KeyHandle
,
817 if (!NT_SUCCESS(Status
)) return Status
;
819 /* Lock the registry */
823 CmpAcquireKcbLockShared(KeyObject
->KeyControlBlock
);
825 /* Make sure KCB isn't deleted */
826 if (KeyObject
->KeyControlBlock
->Delete
)
829 Status
= STATUS_KEY_DELETED
;
833 /* Call the internal API */
834 Status
= CmFlushKey(KeyObject
->KeyControlBlock
, FALSE
);
837 /* Release the locks */
838 CmpReleaseKcbLock(KeyObject
->KeyControlBlock
);
841 /* Dereference the object and return status */
842 ObDereferenceObject(KeyObject
);
848 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
849 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
851 /* Call the newer API */
852 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, 0, NULL
);
857 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
858 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
861 /* Call the newer API */
862 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, Flags
, NULL
);
867 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
868 IN POBJECT_ATTRIBUTES SourceFile
,
870 IN HANDLE TrustClassKey
)
873 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
874 PCM_KEY_BODY KeyBody
= NULL
;
878 if (Flags
& ~REG_NO_LAZY_FLUSH
) return STATUS_INVALID_PARAMETER
;
880 /* Validate privilege */
881 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
884 DPRINT1("Restore Privilege missing!\n");
885 return STATUS_PRIVILEGE_NOT_HELD
;
889 KeEnterCriticalRegion();
891 /* Check if we have a trust class */
895 Status
= ObReferenceObjectByHandle(TrustClassKey
,
903 /* Call the internal API */
904 Status
= CmLoadKey(TargetKey
, SourceFile
, Flags
, KeyBody
);
906 /* Dereference the trust key, if any */
907 if (KeyBody
) ObDereferenceObject(KeyBody
);
909 /* Bring back APCs */
910 KeLeaveCriticalRegion();
918 NtNotifyChangeKey(IN HANDLE KeyHandle
,
920 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
921 IN PVOID ApcContext OPTIONAL
,
922 OUT PIO_STATUS_BLOCK IoStatusBlock
,
923 IN ULONG CompletionFilter
,
924 IN BOOLEAN WatchTree
,
927 IN BOOLEAN Asynchronous
)
929 /* Call the newer API */
930 return NtNotifyChangeMultipleKeys(KeyHandle
,
946 NtInitializeRegistry(IN USHORT Flag
)
949 NTSTATUS Status
= STATUS_SUCCESS
;
952 /* Always do this as kernel mode */
953 if (KeGetPreviousMode() == UserMode
) return ZwInitializeRegistry(Flag
);
955 /* Enough of the system has booted by now */
959 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
961 /* Check if boot was accepted */
962 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
964 /* Only allow once */
965 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
966 CmBootAcceptFirstTime
= FALSE
;
968 /* Get the control set accepted */
969 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
972 /* FIXME: Save the last known good boot */
973 //Status = CmpSaveBootControlSet(Flag);
978 /* Enable lazy flush */
979 CmpHoldLazyFlush
= FALSE
;
984 /* Otherwise, invalid boot */
985 return STATUS_INVALID_PARAMETER
;
988 /* Check if this was a setup boot */
989 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
991 /* Make sure we're only called once */
992 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
995 /* Acquire registry lock */
996 //CmpLockRegistryExclusive();
998 /* Initialize the hives and lazy flusher */
999 CmpCmdInit(SetupBoot
);
1001 /* Save version data */
1002 CmpSetVersionData();
1004 /* Release the registry lock */
1005 //CmpUnlockRegistry();
1006 return STATUS_SUCCESS
;
1011 NtCompactKeys(IN ULONG Count
,
1012 IN PHANDLE KeyArray
)
1015 return STATUS_NOT_IMPLEMENTED
;
1020 NtCompressKey(IN HANDLE Key
)
1023 return STATUS_NOT_IMPLEMENTED
;
1026 // FIXME: different for different windows versions!
1027 #define PRODUCT_ACTIVATION_VERSION 7749
1031 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
1032 IN PULONG pSafeMode
)
1034 KPROCESSOR_MODE PreviousMode
;
1036 PreviousMode
= ExGetPreviousMode();
1039 /* Check if the caller asked for the version */
1040 if (pPrivateVer
!= NULL
)
1042 /* For user mode, probe it */
1043 if (PreviousMode
!= KernelMode
)
1045 ProbeForRead(pPrivateVer
, sizeof(ULONG
), sizeof(ULONG
));
1048 /* Return the expected version */
1049 *pPrivateVer
= PRODUCT_ACTIVATION_VERSION
;
1052 /* Check if the caller asked for safe mode mode state */
1053 if (pSafeMode
!= NULL
)
1055 /* For user mode, probe it */
1056 if (PreviousMode
!= KernelMode
)
1058 ProbeForRead(pSafeMode
, sizeof(ULONG
), sizeof(ULONG
));
1061 /* Return the safe boot mode state */
1062 *pSafeMode
= InitSafeBootMode
;
1065 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1067 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1071 return STATUS_SUCCESS
;
1076 NtLockRegistryKey(IN HANDLE KeyHandle
)
1079 return STATUS_NOT_IMPLEMENTED
;
1084 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
1086 IN POBJECT_ATTRIBUTES SlaveObjects
,
1088 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1089 IN PVOID ApcContext OPTIONAL
,
1090 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1091 IN ULONG CompletionFilter
,
1092 IN BOOLEAN WatchTree
,
1095 IN BOOLEAN Asynchronous
)
1098 return STATUS_NOT_IMPLEMENTED
;
1103 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1104 IN OUT PKEY_VALUE_ENTRY ValueList
,
1105 IN ULONG NumberOfValues
,
1107 IN OUT PULONG Length
,
1108 OUT PULONG ReturnLength
)
1111 return STATUS_NOT_IMPLEMENTED
;
1116 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1117 OUT PULONG HandleCount
)
1119 KPROCESSOR_MODE PreviousMode
;
1120 PCM_KEY_BODY KeyBody
= NULL
;
1124 DPRINT("NtQueryOpenSubKeys()\n");
1128 /* Get the processor mode */
1129 PreviousMode
= KeGetPreviousMode();
1131 if (PreviousMode
!= KernelMode
)
1133 /* Prepare to probe parameters */
1136 /* Probe target key */
1137 ProbeForRead(TargetKey
,
1138 sizeof(OBJECT_ATTRIBUTES
),
1141 /* Probe handle count */
1142 ProbeForWriteUlong(HandleCount
);
1144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1146 /* Return the exception code */
1147 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1152 /* Open a handle to the key */
1153 Status
= ObOpenObjectByName(TargetKey
,
1160 if (NT_SUCCESS(Status
))
1162 /* Reference the key object */
1163 Status
= ObReferenceObjectByHandle(KeyHandle
,
1170 /* Close the handle */
1174 /* Fail, if the key object could not be referenced */
1175 if (!NT_SUCCESS(Status
))
1178 /* Lock the registry exclusively */
1179 CmpLockRegistryExclusive();
1181 /* Fail, if we did not open a hive root key */
1182 if (KeyBody
->KeyControlBlock
->KeyCell
!=
1183 KeyBody
->KeyControlBlock
->KeyHive
->BaseBlock
->RootCell
)
1185 DPRINT("Error: Key is not a hive root key!\n");
1186 CmpUnlockRegistry();
1187 ObDereferenceObject(KeyBody
);
1188 return STATUS_INVALID_PARAMETER
;
1191 /* Call the internal API */
1192 *HandleCount
= CmCountOpenSubKeys(KeyBody
->KeyControlBlock
,
1195 /* Unlock the registry */
1196 CmpUnlockRegistry();
1198 /* Dereference the key object */
1199 ObDereferenceObject(KeyBody
);
1208 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey
,
1209 IN ULONG BufferLength
,
1211 IN PULONG RequiredSize
)
1214 return STATUS_NOT_IMPLEMENTED
;
1219 NtRenameKey(IN HANDLE KeyHandle
,
1220 IN PUNICODE_STRING ReplacementName
)
1223 return STATUS_NOT_IMPLEMENTED
;
1228 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1230 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1233 return STATUS_NOT_IMPLEMENTED
;
1238 NtRestoreKey(IN HANDLE KeyHandle
,
1239 IN HANDLE FileHandle
,
1240 IN ULONG RestoreFlags
)
1243 return STATUS_NOT_IMPLEMENTED
;
1248 NtSaveKey(IN HANDLE KeyHandle
,
1249 IN HANDLE FileHandle
)
1251 /* Call the extended API */
1252 return NtSaveKeyEx(KeyHandle
, FileHandle
, REG_STANDARD_FORMAT
);
1257 NtSaveKeyEx(IN HANDLE KeyHandle
,
1258 IN HANDLE FileHandle
,
1262 PCM_KEY_BODY KeyObject
;
1263 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1267 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle
, FileHandle
, Flags
);
1269 /* Verify the flags */
1270 if ((Flags
!= REG_STANDARD_FORMAT
)
1271 && (Flags
!= REG_LATEST_FORMAT
)
1272 && (Flags
!= REG_NO_COMPRESSION
))
1274 /* Only one of these values can be specified */
1275 return STATUS_INVALID_PARAMETER
;
1278 /* Check for the SeBackupPrivilege */
1279 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1281 return STATUS_PRIVILEGE_NOT_HELD
;
1284 /* Verify that the handle is valid and is a registry key */
1285 Status
= ObReferenceObjectByHandle(KeyHandle
,
1291 if (!NT_SUCCESS(Status
)) return Status
;
1293 /* Call the internal API */
1294 Status
= CmSaveKey(KeyObject
->KeyControlBlock
, FileHandle
, Flags
);
1296 ObDereferenceObject(KeyObject
);
1302 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle
,
1303 IN HANDLE LowPrecedenceKeyHandle
,
1304 IN HANDLE FileHandle
)
1306 KPROCESSOR_MODE PreviousMode
;
1307 PCM_KEY_BODY HighPrecedenceKeyObject
= NULL
;
1308 PCM_KEY_BODY LowPrecedenceKeyObject
= NULL
;
1313 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n",
1314 HighPrecedenceKeyHandle
, LowPrecedenceKeyHandle
, FileHandle
);
1316 PreviousMode
= ExGetPreviousMode();
1318 /* Check for the SeBackupPrivilege */
1319 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1321 return STATUS_PRIVILEGE_NOT_HELD
;
1324 /* Verify that the handles are valid and are registry keys */
1325 Status
= ObReferenceObjectByHandle(HighPrecedenceKeyHandle
,
1329 (PVOID
*)&HighPrecedenceKeyObject
,
1331 if (!NT_SUCCESS(Status
))
1334 Status
= ObReferenceObjectByHandle(LowPrecedenceKeyHandle
,
1338 (PVOID
*)&LowPrecedenceKeyObject
,
1340 if (!NT_SUCCESS(Status
))
1343 /* Call the internal API */
1344 Status
= CmSaveMergedKeys(HighPrecedenceKeyObject
->KeyControlBlock
,
1345 LowPrecedenceKeyObject
->KeyControlBlock
,
1349 if (LowPrecedenceKeyObject
)
1350 ObDereferenceObject(LowPrecedenceKeyObject
);
1352 if (HighPrecedenceKeyObject
)
1353 ObDereferenceObject(HighPrecedenceKeyObject
);
1360 NtSetInformationKey(IN HANDLE KeyHandle
,
1361 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
1362 IN PVOID KeyInformation
,
1363 IN ULONG KeyInformationLength
)
1366 return STATUS_NOT_IMPLEMENTED
;
1371 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
1373 return NtUnloadKey2(KeyObjectAttributes
, 0);
1378 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey
,
1382 OBJECT_ATTRIBUTES ObjectAttributes
;
1383 UNICODE_STRING ObjectName
;
1384 CM_PARSE_CONTEXT ParseContext
= {0};
1385 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1386 PCM_KEY_BODY KeyBody
= NULL
;
1387 ULONG ParentConv
= 0, ChildConv
= 0;
1392 /* Validate privilege */
1393 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1396 DPRINT1("Restore Privilege missing!\n");
1397 return STATUS_PRIVILEGE_NOT_HELD
;
1400 /* Check for user-mode caller */
1401 if (PreviousMode
!= KernelMode
)
1403 /* Prepare to probe parameters */
1406 /* Probe object attributes */
1407 ProbeForRead(TargetKey
,
1408 sizeof(OBJECT_ATTRIBUTES
),
1411 ObjectAttributes
= *TargetKey
;
1413 /* Probe the string */
1414 ProbeForReadUnicodeString(&TargetKey
->ObjectName
);
1416 ObjectName
= *TargetKey
->ObjectName
;
1418 ProbeForRead(ObjectName
.Buffer
,
1422 ObjectAttributes
.ObjectName
= &ObjectName
;
1424 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1426 /* Return the exception code */
1427 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1433 /* Save the target attributes directly */
1434 ObjectAttributes
= *TargetKey
;
1437 /* Setup the parse context */
1438 ParseContext
.CreateOperation
= TRUE
;
1439 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1442 Status
= ObOpenObjectByName(&ObjectAttributes
,
1450 /* Return if failure encountered */
1451 if (!NT_SUCCESS(Status
)) return Status
;
1454 Status
= ObReferenceObjectByHandle(Handle
,
1461 /* Close the handle */
1464 /* Return if failure encountered */
1465 if (!NT_SUCCESS(Status
)) return Status
;
1467 /* Acquire the lock depending on flags */
1468 if (Flags
== REG_FORCE_UNLOAD
)
1470 /* Lock registry exclusively */
1471 CmpLockRegistryExclusive();
1478 /* Acquire the hive loading lock */
1479 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1481 /* Lock parent and child */
1482 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1483 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1485 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1487 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1489 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1492 /* Check if it's being deleted already */
1493 if (KeyBody
->KeyControlBlock
->Delete
)
1495 /* Return appropriate status */
1496 Status
= STATUS_KEY_DELETED
;
1500 /* Check if it's a readonly key */
1501 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1503 /* Return appropriate status */
1504 Status
= STATUS_ACCESS_DENIED
;
1508 /* Call the internal API */
1509 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
,
1512 /* Check if we failed, but really need to succeed */
1513 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1515 /* TODO: We should perform another attempt here */
1519 /* If CmUnloadKey failed we need to unlock registry ourselves */
1520 if (!NT_SUCCESS(Status
))
1522 if (Flags
!= REG_FORCE_UNLOAD
)
1524 /* Release the KCB locks */
1525 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1527 /* Release the hive loading lock */
1528 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1531 /* Unlock the registry */
1532 CmpUnlockRegistry();
1536 /* Dereference the key */
1537 ObDereferenceObject(KeyBody
);
1545 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1549 return STATUS_NOT_IMPLEMENTED
;