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 /* Check for user-mode caller */
43 if (PreviousMode
!= KernelMode
)
45 /* Prepare to probe parameters */
48 /* Check if we have a class */
52 ParseContext
.Class
= ProbeForReadUnicodeString(Class
);
53 ProbeForRead(ParseContext
.Class
.Buffer
,
54 ParseContext
.Class
.Length
,
58 /* Probe the key handle */
59 ProbeForWriteHandle(KeyHandle
);
62 /* Probe object attributes */
63 ProbeForRead(ObjectAttributes
,
64 sizeof(OBJECT_ATTRIBUTES
),
68 ProbeForWriteUlong(Disposition
);
70 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
72 /* Return the exception code */
73 _SEH2_YIELD(return _SEH2_GetExceptionCode());
79 /* Save the class directly */
80 if (Class
) ParseContext
.Class
= *Class
;
83 /* Setup the parse context */
84 ParseContext
.CreateOperation
= TRUE
;
85 ParseContext
.CreateOptions
= CreateOptions
;
88 Status
= ObOpenObjectByName(ObjectAttributes
,
98 /* Return data to user */
99 if (NT_SUCCESS(Status
)) *KeyHandle
= Handle
;
100 if (Disposition
) *Disposition
= ParseContext
.Disposition
;
102 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
105 Status
= _SEH2_GetExceptionCode();
109 DPRINT("Returning handle %x, Status %x.\n", Handle
, Status
);
117 NtOpenKey(OUT PHANDLE KeyHandle
,
118 IN ACCESS_MASK DesiredAccess
,
119 IN POBJECT_ATTRIBUTES ObjectAttributes
)
121 CM_PARSE_CONTEXT ParseContext
= {0};
124 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
126 DPRINT("NtOpenKey(Path: %wZ, Root %x, Access: %x)\n",
127 ObjectAttributes
->ObjectName
, ObjectAttributes
->RootDirectory
, DesiredAccess
);
129 /* Check for user-mode caller */
130 if (PreviousMode
!= KernelMode
)
132 /* Prepare to probe parameters */
135 /* Probe the key handle */
136 ProbeForWriteHandle(KeyHandle
);
139 /* Probe object attributes */
140 ProbeForRead(ObjectAttributes
,
141 sizeof(OBJECT_ATTRIBUTES
),
144 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
146 /* Return the exception code */
147 _SEH2_YIELD(return _SEH2_GetExceptionCode());
152 /* Just let the object manager handle this */
153 Status
= ObOpenObjectByName(ObjectAttributes
,
161 /* Only do this if we succeeded */
162 if (NT_SUCCESS(Status
))
166 /* Return the handle to caller */
169 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
172 Status
= _SEH2_GetExceptionCode();
177 DPRINT("Returning handle %x, Status %x.\n", Handle
, Status
);
186 NtDeleteKey(IN HANDLE KeyHandle
)
188 PCM_KEY_BODY KeyObject
;
190 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
191 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
193 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle
);
195 /* Verify that the handle is valid and is a registry key */
196 Status
= ObReferenceObjectByHandle(KeyHandle
,
202 if (!NT_SUCCESS(Status
)) return Status
;
204 /* Setup the callback */
205 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
206 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
207 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteKey
, &DeleteKeyInfo
);
208 if (NT_SUCCESS(Status
))
210 /* Check if we are read-only */
211 if ((KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
) ||
212 (KeyObject
->KeyControlBlock
->ParentKcb
->ExtFlags
& CM_KCB_READ_ONLY_KEY
))
215 Status
= STATUS_ACCESS_DENIED
;
219 /* Call the internal API */
220 Status
= CmDeleteKey(KeyObject
);
223 /* Do post callback */
224 PostOperationInfo
.Status
= Status
;
225 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
228 /* Dereference the object */
229 ObDereferenceObject(KeyObject
);
235 NtEnumerateKey(IN HANDLE KeyHandle
,
237 IN KEY_INFORMATION_CLASS KeyInformationClass
,
238 OUT PVOID KeyInformation
,
240 OUT PULONG ResultLength
)
242 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
244 PCM_KEY_BODY KeyObject
;
245 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
246 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
248 DPRINT("NtEnumerateKey() KH 0x%p, Index 0x%x, KIC %d, Length %lu\n",
249 KeyHandle
, Index
, KeyInformationClass
, Length
);
251 /* Reject classes we don't know about */
252 if ((KeyInformationClass
!= KeyBasicInformation
) &&
253 (KeyInformationClass
!= KeyNodeInformation
) &&
254 (KeyInformationClass
!= KeyFullInformation
))
257 return STATUS_INVALID_PARAMETER
;
260 /* Verify that the handle is valid and is a registry key */
261 Status
= ObReferenceObjectByHandle(KeyHandle
,
262 KEY_ENUMERATE_SUB_KEYS
,
267 if (!NT_SUCCESS(Status
)) return Status
;
269 if (PreviousMode
!= KernelMode
)
273 ProbeForWriteUlong(ResultLength
);
274 ProbeForWrite(KeyInformation
,
278 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
280 /* Dereference and return status */
281 ObDereferenceObject(KeyObject
);
282 _SEH2_YIELD(return _SEH2_GetExceptionCode());
287 /* Setup the callback */
288 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
289 EnumerateKeyInfo
.Object
= (PVOID
)KeyObject
;
290 EnumerateKeyInfo
.Index
= Index
;
291 EnumerateKeyInfo
.KeyInformationClass
= KeyInformationClass
;
292 EnumerateKeyInfo
.Length
= Length
;
293 EnumerateKeyInfo
.ResultLength
= ResultLength
;
295 /* Do the callback */
296 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateKey
, &EnumerateKeyInfo
);
297 if (NT_SUCCESS(Status
))
299 /* Call the internal API */
300 Status
= CmEnumerateKey(KeyObject
->KeyControlBlock
,
307 /* Do the post callback */
308 PostOperationInfo
.Status
= Status
;
309 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
312 /* Dereference and return status */
313 ObDereferenceObject(KeyObject
);
314 DPRINT("Returning status %x.\n", Status
);
320 NtEnumerateValueKey(IN HANDLE KeyHandle
,
322 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
323 OUT PVOID KeyValueInformation
,
325 OUT PULONG ResultLength
)
327 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
329 PCM_KEY_BODY KeyObject
;
330 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo
;
331 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
333 DPRINT("NtEnumerateValueKey() KH 0x%p, Index 0x%x, KVIC %d, Length %lu\n",
334 KeyHandle
, Index
, KeyValueInformationClass
, Length
);
336 /* Reject classes we don't know about */
337 if ((KeyValueInformationClass
!= KeyValueBasicInformation
) &&
338 (KeyValueInformationClass
!= KeyValueFullInformation
) &&
339 (KeyValueInformationClass
!= KeyValuePartialInformation
))
342 return STATUS_INVALID_PARAMETER
;
345 /* Verify that the handle is valid and is a registry key */
346 Status
= ObReferenceObjectByHandle(KeyHandle
,
352 if (!NT_SUCCESS(Status
)) return Status
;
354 if (PreviousMode
!= KernelMode
)
358 ProbeForWriteUlong(ResultLength
);
359 ProbeForWrite(KeyValueInformation
,
363 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
365 /* Dereference and return status */
366 ObDereferenceObject(KeyObject
);
367 _SEH2_YIELD(return _SEH2_GetExceptionCode());
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%p, KIC %d, Length %lu\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 /* Dereference and return status */
480 ObDereferenceObject(KeyObject
);
481 _SEH2_YIELD(return _SEH2_GetExceptionCode());
486 /* Setup the callback */
487 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
488 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
489 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
490 QueryKeyInfo
.KeyInformation
= KeyInformation
;
491 QueryKeyInfo
.Length
= Length
;
492 QueryKeyInfo
.ResultLength
= ResultLength
;
494 /* Do the callback */
495 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryKey
, &QueryKeyInfo
);
496 if (NT_SUCCESS(Status
))
498 /* Call the internal API */
499 Status
= CmQueryKey(KeyObject
->KeyControlBlock
,
505 /* Do the post callback */
506 PostOperationInfo
.Status
= Status
;
507 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
510 /* Dereference and return status */
511 ObDereferenceObject(KeyObject
);
517 NtQueryValueKey(IN HANDLE KeyHandle
,
518 IN PUNICODE_STRING ValueName
,
519 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
520 OUT PVOID KeyValueInformation
,
522 OUT PULONG ResultLength
)
524 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
526 PCM_KEY_BODY KeyObject
;
527 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
528 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
529 UNICODE_STRING ValueNameCopy
= *ValueName
;
531 DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n",
532 KeyHandle
, ValueName
, KeyValueInformationClass
, Length
);
534 /* Verify that the handle is valid and is a registry key */
535 Status
= ObReferenceObjectByHandle(KeyHandle
,
541 if (!NT_SUCCESS(Status
)) return Status
;
543 if (PreviousMode
!= KernelMode
)
547 ProbeForWriteUlong(ResultLength
);
548 ProbeForWrite(KeyValueInformation
,
552 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
554 /* Dereference and return status */
555 ObDereferenceObject(KeyObject
);
556 _SEH2_YIELD(return _SEH2_GetExceptionCode());
561 /* Make sure the name is aligned properly */
562 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
564 /* It isn't, so we'll fail */
565 ObDereferenceObject(KeyObject
);
566 return STATUS_INVALID_PARAMETER
;
570 /* Ignore any null characters at the end */
571 while ((ValueNameCopy
.Length
) &&
572 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
575 ValueNameCopy
.Length
-= sizeof(WCHAR
);
579 /* Setup the callback */
580 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
581 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
582 QueryValueKeyInfo
.ValueName
= &ValueNameCopy
;
583 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
584 QueryValueKeyInfo
.Length
= Length
;
585 QueryValueKeyInfo
.ResultLength
= ResultLength
;
587 /* Do the callback */
588 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
589 if (NT_SUCCESS(Status
))
591 /* Call the internal API */
592 Status
= CmQueryValueKey(KeyObject
->KeyControlBlock
,
594 KeyValueInformationClass
,
599 /* Do the post callback */
600 PostOperationInfo
.Status
= Status
;
601 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
604 /* Dereference and return status */
605 ObDereferenceObject(KeyObject
);
611 NtSetValueKey(IN HANDLE KeyHandle
,
612 IN PUNICODE_STRING ValueName
,
618 NTSTATUS Status
= STATUS_SUCCESS
;
619 PCM_KEY_BODY KeyObject
= NULL
;
620 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
621 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
622 UNICODE_STRING ValueNameCopy
;
623 KPROCESSOR_MODE PreviousMode
;
627 PreviousMode
= ExGetPreviousMode();
632 /* Probe and copy the data */
633 if ((PreviousMode
!= KernelMode
) && Data
)
635 PVOID DataCopy
= ExAllocatePoolWithTag(PagedPool
, DataSize
, TAG_CM
);
637 return STATUS_NO_MEMORY
;
640 ProbeForRead(Data
, DataSize
, 1);
641 RtlCopyMemory(DataCopy
, Data
, DataSize
);
643 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
645 Status
= _SEH2_GetExceptionCode();
649 if (!NT_SUCCESS(Status
))
651 ExFreePoolWithTag(DataCopy
, TAG_CM
);
657 /* Capture the string */
658 Status
= ProbeAndCaptureUnicodeString(&ValueNameCopy
, PreviousMode
, ValueName
);
659 if (!NT_SUCCESS(Status
))
662 DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
663 KeyHandle
, &ValueNameCopy
, TitleIndex
, Type
, DataSize
);
665 /* Verify that the handle is valid and is a registry key */
666 Status
= ObReferenceObjectByHandle(KeyHandle
,
672 if (!NT_SUCCESS(Status
))
675 /* Make sure the name is aligned, not too long, and the data under 4GB */
676 if ( (ValueNameCopy
.Length
> 32767) ||
677 ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1))) ||
678 (DataSize
> 0x80000000))
681 Status
= STATUS_INVALID_PARAMETER
;
685 /* Ignore any null characters at the end */
686 while ((ValueNameCopy
.Length
) &&
687 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
690 ValueNameCopy
.Length
-= sizeof(WCHAR
);
693 /* Don't touch read-only keys */
694 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
697 Status
= STATUS_ACCESS_DENIED
;
702 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
703 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
704 SetValueKeyInfo
.ValueName
= &ValueNameCopy
;
705 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
706 SetValueKeyInfo
.Type
= Type
;
707 SetValueKeyInfo
.Data
= Data
;
708 SetValueKeyInfo
.DataSize
= DataSize
;
710 /* Do the callback */
711 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
712 if (NT_SUCCESS(Status
))
714 /* Call the internal API */
715 Status
= CmSetValueKey(KeyObject
->KeyControlBlock
,
722 /* Do the post-callback */
723 PostOperationInfo
.Status
= Status
;
724 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
727 /* Dereference and return status */
729 ObDereferenceObject(KeyObject
);
730 ReleaseCapturedUnicodeString(&ValueNameCopy
, PreviousMode
);
731 if ((PreviousMode
!= KernelMode
) && Data
)
732 ExFreePoolWithTag(Data
, TAG_CM
);
738 NtDeleteValueKey(IN HANDLE KeyHandle
,
739 IN PUNICODE_STRING ValueName
)
741 PCM_KEY_BODY KeyObject
;
743 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
744 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
745 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
746 UNICODE_STRING ValueNameCopy
= *ValueName
;
749 /* Verify that the handle is valid and is a registry key */
750 Status
= ObReferenceObjectByHandle(KeyHandle
,
756 if (!NT_SUCCESS(Status
)) return Status
;
758 /* Don't touch read-only keys */
759 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
762 ObDereferenceObject(KeyObject
);
763 return STATUS_ACCESS_DENIED
;
766 /* Make sure the name is aligned properly */
767 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
769 /* It isn't, so we'll fail */
770 ObDereferenceObject(KeyObject
);
771 return STATUS_INVALID_PARAMETER
;
774 /* Do the callback */
775 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
776 DeleteValueKeyInfo
.ValueName
= ValueName
;
777 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
,
778 &DeleteValueKeyInfo
);
779 if (NT_SUCCESS(Status
))
781 /* Call the internal API */
782 Status
= CmDeleteValueKey(KeyObject
->KeyControlBlock
, ValueNameCopy
);
784 /* Do the post callback */
785 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
786 PostOperationInfo
.Status
= Status
;
787 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
,
791 /* Dereference the key body */
792 ObDereferenceObject(KeyObject
);
798 NtFlushKey(IN HANDLE KeyHandle
)
801 PCM_KEY_BODY KeyObject
;
804 /* Get the key object */
805 Status
= ObReferenceObjectByHandle(KeyHandle
,
811 if (!NT_SUCCESS(Status
)) return Status
;
813 /* Lock the registry */
817 CmpAcquireKcbLockShared(KeyObject
->KeyControlBlock
);
819 /* Make sure KCB isn't deleted */
820 if (KeyObject
->KeyControlBlock
->Delete
)
823 Status
= STATUS_KEY_DELETED
;
827 /* Call the internal API */
828 Status
= CmFlushKey(KeyObject
->KeyControlBlock
, FALSE
);
831 /* Release the locks */
832 CmpReleaseKcbLock(KeyObject
->KeyControlBlock
);
835 /* Dereference the object and return status */
836 ObDereferenceObject(KeyObject
);
842 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
843 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
845 /* Call the newer API */
846 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, 0, NULL
);
851 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
852 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
855 /* Call the newer API */
856 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, Flags
, NULL
);
861 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
862 IN POBJECT_ATTRIBUTES SourceFile
,
864 IN HANDLE TrustClassKey
)
867 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
868 PCM_KEY_BODY KeyBody
= NULL
;
872 if (Flags
& ~REG_NO_LAZY_FLUSH
) return STATUS_INVALID_PARAMETER
;
874 /* Validate privilege */
875 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
878 DPRINT1("Restore Privilege missing!\n");
879 return STATUS_PRIVILEGE_NOT_HELD
;
883 KeEnterCriticalRegion();
885 /* Check if we have a trust class */
889 Status
= ObReferenceObjectByHandle(TrustClassKey
,
897 /* Call the internal API */
898 Status
= CmLoadKey(TargetKey
, SourceFile
, Flags
, KeyBody
);
900 /* Dereference the trust key, if any */
901 if (KeyBody
) ObDereferenceObject(KeyBody
);
903 /* Bring back APCs */
904 KeLeaveCriticalRegion();
912 NtNotifyChangeKey(IN HANDLE KeyHandle
,
914 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
915 IN PVOID ApcContext OPTIONAL
,
916 OUT PIO_STATUS_BLOCK IoStatusBlock
,
917 IN ULONG CompletionFilter
,
918 IN BOOLEAN WatchTree
,
921 IN BOOLEAN Asynchronous
)
923 /* Call the newer API */
924 return NtNotifyChangeMultipleKeys(KeyHandle
,
940 NtInitializeRegistry(IN USHORT Flag
)
943 NTSTATUS Status
= STATUS_SUCCESS
;
946 /* Always do this as kernel mode */
947 if (KeGetPreviousMode() == UserMode
) return ZwInitializeRegistry(Flag
);
949 /* Enough of the system has booted by now */
953 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
955 /* Check if boot was accepted */
956 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
958 /* Only allow once */
959 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
960 CmBootAcceptFirstTime
= FALSE
;
962 /* Get the control set accepted */
963 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
966 /* FIXME: Save the last known good boot */
967 //Status = CmpSaveBootControlSet(Flag);
972 /* Enable lazy flush */
973 CmpHoldLazyFlush
= FALSE
;
978 /* Otherwise, invalid boot */
979 return STATUS_INVALID_PARAMETER
;
982 /* Check if this was a setup boot */
983 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
985 /* Make sure we're only called once */
986 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
989 /* Acquire registry lock */
990 //CmpLockRegistryExclusive();
992 /* Initialize the hives and lazy flusher */
993 CmpCmdInit(SetupBoot
);
995 /* Save version data */
998 /* Release the registry lock */
999 //CmpUnlockRegistry();
1000 return STATUS_SUCCESS
;
1005 NtCompactKeys(IN ULONG Count
,
1006 IN PHANDLE KeyArray
)
1009 return STATUS_NOT_IMPLEMENTED
;
1014 NtCompressKey(IN HANDLE Key
)
1017 return STATUS_NOT_IMPLEMENTED
;
1020 // FIXME: different for different windows versions!
1021 #define PRODUCT_ACTIVATION_VERSION 7749
1025 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
1026 IN PULONG pSafeMode
)
1028 KPROCESSOR_MODE PreviousMode
;
1030 PreviousMode
= ExGetPreviousMode();
1033 /* Check if the caller asked for the version */
1034 if (pPrivateVer
!= NULL
)
1036 /* For user mode, probe it */
1037 if (PreviousMode
!= KernelMode
)
1039 ProbeForRead(pPrivateVer
, sizeof(ULONG
), sizeof(ULONG
));
1042 /* Return the expected version */
1043 *pPrivateVer
= PRODUCT_ACTIVATION_VERSION
;
1046 /* Check if the caller asked for safe mode mode state */
1047 if (pSafeMode
!= NULL
)
1049 /* For user mode, probe it */
1050 if (PreviousMode
!= KernelMode
)
1052 ProbeForRead(pSafeMode
, sizeof(ULONG
), sizeof(ULONG
));
1055 /* Return the safe boot mode state */
1056 *pSafeMode
= InitSafeBootMode
;
1059 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1061 return _SEH2_GetExceptionCode();
1065 return STATUS_SUCCESS
;
1070 NtLockRegistryKey(IN HANDLE KeyHandle
)
1073 return STATUS_NOT_IMPLEMENTED
;
1078 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
1080 IN POBJECT_ATTRIBUTES SlaveObjects
,
1082 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1083 IN PVOID ApcContext OPTIONAL
,
1084 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1085 IN ULONG CompletionFilter
,
1086 IN BOOLEAN WatchTree
,
1089 IN BOOLEAN Asynchronous
)
1092 return STATUS_NOT_IMPLEMENTED
;
1097 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1098 IN OUT PKEY_VALUE_ENTRY ValueList
,
1099 IN ULONG NumberOfValues
,
1101 IN OUT PULONG Length
,
1102 OUT PULONG ReturnLength
)
1105 return STATUS_NOT_IMPLEMENTED
;
1110 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1111 OUT PULONG HandleCount
)
1113 KPROCESSOR_MODE PreviousMode
;
1114 PCM_KEY_BODY KeyBody
= NULL
;
1118 DPRINT("NtQueryOpenSubKeys()\n");
1122 /* Get the processor mode */
1123 PreviousMode
= KeGetPreviousMode();
1125 if (PreviousMode
!= KernelMode
)
1127 /* Prepare to probe parameters */
1130 /* Probe target key */
1131 ProbeForRead(TargetKey
,
1132 sizeof(OBJECT_ATTRIBUTES
),
1135 /* Probe handle count */
1136 ProbeForWriteUlong(HandleCount
);
1138 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1140 /* Return the exception code */
1141 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1146 /* Open a handle to the key */
1147 Status
= ObOpenObjectByName(TargetKey
,
1154 if (NT_SUCCESS(Status
))
1156 /* Reference the key object */
1157 Status
= ObReferenceObjectByHandle(KeyHandle
,
1164 /* Close the handle */
1168 /* Fail, if the key object could not be referenced */
1169 if (!NT_SUCCESS(Status
))
1172 /* Lock the registry exclusively */
1173 CmpLockRegistryExclusive();
1175 /* Fail, if we did not open a hive root key */
1176 if (KeyBody
->KeyControlBlock
->KeyCell
!=
1177 KeyBody
->KeyControlBlock
->KeyHive
->BaseBlock
->RootCell
)
1179 DPRINT("Error: Key is not a hive root key!\n");
1180 CmpUnlockRegistry();
1181 ObDereferenceObject(KeyBody
);
1182 return STATUS_INVALID_PARAMETER
;
1185 /* Call the internal API */
1186 *HandleCount
= CmCountOpenSubKeys(KeyBody
->KeyControlBlock
,
1189 /* Unlock the registry */
1190 CmpUnlockRegistry();
1192 /* Dereference the key object */
1193 ObDereferenceObject(KeyBody
);
1202 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey
,
1203 IN ULONG BufferLength
,
1205 IN PULONG RequiredSize
)
1208 return STATUS_NOT_IMPLEMENTED
;
1213 NtRenameKey(IN HANDLE KeyHandle
,
1214 IN PUNICODE_STRING ReplacementName
)
1217 return STATUS_NOT_IMPLEMENTED
;
1222 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1224 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1227 return STATUS_NOT_IMPLEMENTED
;
1232 NtRestoreKey(IN HANDLE KeyHandle
,
1233 IN HANDLE FileHandle
,
1234 IN ULONG RestoreFlags
)
1237 return STATUS_NOT_IMPLEMENTED
;
1242 NtSaveKey(IN HANDLE KeyHandle
,
1243 IN HANDLE FileHandle
)
1245 /* Call the extended API */
1246 return NtSaveKeyEx(KeyHandle
, FileHandle
, REG_STANDARD_FORMAT
);
1251 NtSaveKeyEx(IN HANDLE KeyHandle
,
1252 IN HANDLE FileHandle
,
1256 PCM_KEY_BODY KeyObject
;
1257 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1261 DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle
, FileHandle
, Flags
);
1263 /* Verify the flags */
1264 if ((Flags
!= REG_STANDARD_FORMAT
)
1265 && (Flags
!= REG_LATEST_FORMAT
)
1266 && (Flags
!= REG_NO_COMPRESSION
))
1268 /* Only one of these values can be specified */
1269 return STATUS_INVALID_PARAMETER
;
1272 /* Check for the SeBackupPrivilege */
1273 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1275 return STATUS_PRIVILEGE_NOT_HELD
;
1278 /* Verify that the handle is valid and is a registry key */
1279 Status
= ObReferenceObjectByHandle(KeyHandle
,
1285 if (!NT_SUCCESS(Status
)) return Status
;
1287 /* Call the internal API */
1288 Status
= CmSaveKey(KeyObject
->KeyControlBlock
, FileHandle
, Flags
);
1290 ObDereferenceObject(KeyObject
);
1296 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle
,
1297 IN HANDLE LowPrecedenceKeyHandle
,
1298 IN HANDLE FileHandle
)
1300 KPROCESSOR_MODE PreviousMode
;
1301 PCM_KEY_BODY HighPrecedenceKeyObject
= NULL
;
1302 PCM_KEY_BODY LowPrecedenceKeyObject
= NULL
;
1307 DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n",
1308 HighPrecedenceKeyHandle
, LowPrecedenceKeyHandle
, FileHandle
);
1310 PreviousMode
= ExGetPreviousMode();
1312 /* Check for the SeBackupPrivilege */
1313 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1315 return STATUS_PRIVILEGE_NOT_HELD
;
1318 /* Verify that the handles are valid and are registry keys */
1319 Status
= ObReferenceObjectByHandle(HighPrecedenceKeyHandle
,
1323 (PVOID
*)&HighPrecedenceKeyObject
,
1325 if (!NT_SUCCESS(Status
))
1328 Status
= ObReferenceObjectByHandle(LowPrecedenceKeyHandle
,
1332 (PVOID
*)&LowPrecedenceKeyObject
,
1334 if (!NT_SUCCESS(Status
))
1337 /* Call the internal API */
1338 Status
= CmSaveMergedKeys(HighPrecedenceKeyObject
->KeyControlBlock
,
1339 LowPrecedenceKeyObject
->KeyControlBlock
,
1343 if (LowPrecedenceKeyObject
)
1344 ObDereferenceObject(LowPrecedenceKeyObject
);
1346 if (HighPrecedenceKeyObject
)
1347 ObDereferenceObject(HighPrecedenceKeyObject
);
1354 NtSetInformationKey(IN HANDLE KeyHandle
,
1355 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
1356 IN PVOID KeyInformation
,
1357 IN ULONG KeyInformationLength
)
1360 return STATUS_NOT_IMPLEMENTED
;
1365 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
1367 return NtUnloadKey2(KeyObjectAttributes
, 0);
1372 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey
,
1376 OBJECT_ATTRIBUTES ObjectAttributes
;
1377 UNICODE_STRING ObjectName
;
1378 CM_PARSE_CONTEXT ParseContext
= {0};
1379 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1380 PCM_KEY_BODY KeyBody
= NULL
;
1381 ULONG ParentConv
= 0, ChildConv
= 0;
1386 /* Validate privilege */
1387 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1390 DPRINT1("Restore Privilege missing!\n");
1391 return STATUS_PRIVILEGE_NOT_HELD
;
1394 /* Check for user-mode caller */
1395 if (PreviousMode
!= KernelMode
)
1397 /* Prepare to probe parameters */
1400 /* Probe object attributes */
1401 ProbeForRead(TargetKey
,
1402 sizeof(OBJECT_ATTRIBUTES
),
1405 ObjectAttributes
= *TargetKey
;
1407 /* Probe the string */
1408 ProbeForReadUnicodeString(&TargetKey
->ObjectName
);
1410 ObjectName
= *TargetKey
->ObjectName
;
1412 ProbeForRead(ObjectName
.Buffer
,
1416 ObjectAttributes
.ObjectName
= &ObjectName
;
1418 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1420 /* Return the exception code */
1421 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1427 /* Save the target attributes directly */
1428 ObjectAttributes
= *TargetKey
;
1431 /* Setup the parse context */
1432 ParseContext
.CreateOperation
= TRUE
;
1433 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1436 Status
= ObOpenObjectByName(&ObjectAttributes
,
1444 /* Return if failure encountered */
1445 if (!NT_SUCCESS(Status
)) return Status
;
1448 Status
= ObReferenceObjectByHandle(Handle
,
1455 /* Close the handle */
1458 /* Return if failure encountered */
1459 if (!NT_SUCCESS(Status
)) return Status
;
1461 /* Acquire the lock depending on flags */
1462 if (Flags
== REG_FORCE_UNLOAD
)
1464 /* Lock registry exclusively */
1465 CmpLockRegistryExclusive();
1472 /* Acquire the hive loading lock */
1473 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1475 /* Lock parent and child */
1476 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1477 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1479 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1481 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1483 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1486 /* Check if it's being deleted already */
1487 if (KeyBody
->KeyControlBlock
->Delete
)
1489 /* Return appropriate status */
1490 Status
= STATUS_KEY_DELETED
;
1494 /* Check if it's a readonly key */
1495 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1497 /* Return appropriate status */
1498 Status
= STATUS_ACCESS_DENIED
;
1502 /* Call the internal API */
1503 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
,
1506 /* Check if we failed, but really need to succeed */
1507 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1509 /* TODO: We should perform another attempt here */
1513 /* If CmUnloadKey failed we need to unlock registry ourselves */
1514 if (!NT_SUCCESS(Status
))
1516 if (Flags
!= REG_FORCE_UNLOAD
)
1518 /* Release two KCBs lock */
1519 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1521 /* Release the hive loading lock */
1522 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1525 /* Unlock the registry */
1526 CmpUnlockRegistry();
1530 /* Dereference the key */
1531 ObDereferenceObject(KeyBody
);
1539 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1543 return STATUS_NOT_IMPLEMENTED
;