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
))
883 DPRINT1("Restore Privilege missing!\n");
884 return STATUS_PRIVILEGE_NOT_HELD
;
888 KeEnterCriticalRegion();
890 /* Check if we have a trust class */
894 Status
= ObReferenceObjectByHandle(TrustClassKey
,
902 /* Call the internal API */
903 Status
= CmLoadKey(TargetKey
, SourceFile
, Flags
, KeyBody
);
905 /* Dereference the trust key, if any */
906 if (KeyBody
) ObDereferenceObject(KeyBody
);
908 /* Bring back APCs */
909 KeLeaveCriticalRegion();
917 NtNotifyChangeKey(IN HANDLE KeyHandle
,
919 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
920 IN PVOID ApcContext OPTIONAL
,
921 OUT PIO_STATUS_BLOCK IoStatusBlock
,
922 IN ULONG CompletionFilter
,
923 IN BOOLEAN WatchTree
,
926 IN BOOLEAN Asynchronous
)
928 /* Call the newer API */
929 return NtNotifyChangeMultipleKeys(KeyHandle
,
945 NtInitializeRegistry(IN USHORT Flag
)
948 NTSTATUS Status
= STATUS_SUCCESS
;
951 /* Always do this as kernel mode */
952 if (KeGetPreviousMode() == UserMode
) return ZwInitializeRegistry(Flag
);
954 /* Enough of the system has booted by now */
958 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
960 /* Check if boot was accepted */
961 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
963 /* Only allow once */
964 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
965 CmBootAcceptFirstTime
= FALSE
;
967 /* Get the control set accepted */
968 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
971 /* FIXME: Save the last known good boot */
972 //Status = CmpSaveBootControlSet(Flag);
977 /* Enable lazy flush */
978 CmpHoldLazyFlush
= FALSE
;
983 /* Otherwise, invalid boot */
984 return STATUS_INVALID_PARAMETER
;
987 /* Check if this was a setup boot */
988 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
990 /* Make sure we're only called once */
991 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
994 /* Acquire registry lock */
995 //CmpLockRegistryExclusive();
997 /* Initialize the hives and lazy flusher */
998 CmpCmdInit(SetupBoot
);
1000 /* Save version data */
1001 CmpSetVersionData();
1003 /* Release the registry lock */
1004 //CmpUnlockRegistry();
1005 return STATUS_SUCCESS
;
1010 NtCompactKeys(IN ULONG Count
,
1011 IN PHANDLE KeyArray
)
1014 return STATUS_NOT_IMPLEMENTED
;
1019 NtCompressKey(IN HANDLE Key
)
1022 return STATUS_NOT_IMPLEMENTED
;
1025 // FIXME: different for different windows versions!
1026 #define PRODUCT_ACTIVATION_VERSION 7749
1030 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
1031 IN PULONG pSafeMode
)
1033 KPROCESSOR_MODE PreviousMode
;
1035 PreviousMode
= ExGetPreviousMode();
1038 /* Check if the caller asked for the version */
1039 if (pPrivateVer
!= NULL
)
1041 /* For user mode, probe it */
1042 if (PreviousMode
!= KernelMode
)
1044 ProbeForRead(pPrivateVer
, sizeof(ULONG
), sizeof(ULONG
));
1047 /* Return the expected version */
1048 *pPrivateVer
= PRODUCT_ACTIVATION_VERSION
;
1051 /* Check if the caller asked for safe mode mode state */
1052 if (pSafeMode
!= NULL
)
1054 /* For user mode, probe it */
1055 if (PreviousMode
!= KernelMode
)
1057 ProbeForRead(pSafeMode
, sizeof(ULONG
), sizeof(ULONG
));
1060 /* Return the safe boot mode state */
1061 *pSafeMode
= InitSafeBootMode
;
1064 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1066 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1070 return STATUS_SUCCESS
;
1075 NtLockRegistryKey(IN HANDLE KeyHandle
)
1078 return STATUS_NOT_IMPLEMENTED
;
1083 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
1085 IN POBJECT_ATTRIBUTES SlaveObjects
,
1087 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1088 IN PVOID ApcContext OPTIONAL
,
1089 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1090 IN ULONG CompletionFilter
,
1091 IN BOOLEAN WatchTree
,
1094 IN BOOLEAN Asynchronous
)
1097 return STATUS_NOT_IMPLEMENTED
;
1102 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1103 IN OUT PKEY_VALUE_ENTRY ValueList
,
1104 IN ULONG NumberOfValues
,
1106 IN OUT PULONG Length
,
1107 OUT PULONG ReturnLength
)
1110 return STATUS_NOT_IMPLEMENTED
;
1115 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1116 OUT PULONG HandleCount
)
1118 KPROCESSOR_MODE PreviousMode
;
1119 PCM_KEY_BODY KeyBody
= NULL
;
1123 DPRINT("NtQueryOpenSubKeys()\n");
1127 /* Get the processor mode */
1128 PreviousMode
= KeGetPreviousMode();
1130 /* Check for user-mode caller */
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 /* Validate privilege */
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 /* Validate privilege */
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
))
1395 DPRINT1("Restore Privilege missing!\n");
1396 return STATUS_PRIVILEGE_NOT_HELD
;
1399 /* Check for user-mode caller */
1400 if (PreviousMode
!= KernelMode
)
1402 /* Prepare to probe parameters */
1405 /* Probe object attributes */
1406 ProbeForRead(TargetKey
,
1407 sizeof(OBJECT_ATTRIBUTES
),
1410 ObjectAttributes
= *TargetKey
;
1412 /* Probe the string */
1413 ProbeForReadUnicodeString(&TargetKey
->ObjectName
);
1415 ObjectName
= *TargetKey
->ObjectName
;
1417 ProbeForRead(ObjectName
.Buffer
,
1421 ObjectAttributes
.ObjectName
= &ObjectName
;
1423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1425 /* Return the exception code */
1426 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1432 /* Save the target attributes directly */
1433 ObjectAttributes
= *TargetKey
;
1436 /* Setup the parse context */
1437 ParseContext
.CreateOperation
= TRUE
;
1438 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1441 Status
= ObOpenObjectByName(&ObjectAttributes
,
1449 /* Return if failure encountered */
1450 if (!NT_SUCCESS(Status
)) return Status
;
1453 Status
= ObReferenceObjectByHandle(Handle
,
1460 /* Close the handle */
1463 /* Return if failure encountered */
1464 if (!NT_SUCCESS(Status
)) return Status
;
1466 /* Acquire the lock depending on flags */
1467 if (Flags
== REG_FORCE_UNLOAD
)
1469 /* Lock registry exclusively */
1470 CmpLockRegistryExclusive();
1477 /* Acquire the hive loading lock */
1478 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1480 /* Lock parent and child */
1481 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1482 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1484 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1486 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1488 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1491 /* Check if it's being deleted already */
1492 if (KeyBody
->KeyControlBlock
->Delete
)
1494 /* Return appropriate status */
1495 Status
= STATUS_KEY_DELETED
;
1499 /* Check if it's a read-only key */
1500 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1502 /* Return appropriate status */
1503 Status
= STATUS_ACCESS_DENIED
;
1507 /* Call the internal API */
1508 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
,
1511 /* Check if we failed, but really need to succeed */
1512 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1514 /* TODO: We should perform another attempt here */
1518 /* If CmUnloadKey failed we need to unlock registry ourselves */
1519 if (!NT_SUCCESS(Status
))
1521 if (Flags
!= REG_FORCE_UNLOAD
)
1523 /* Release the KCB locks */
1524 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1526 /* Release the hive loading lock */
1527 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1530 /* Unlock the registry */
1531 CmpUnlockRegistry();
1535 /* Dereference the key */
1536 ObDereferenceObject(KeyBody
);
1544 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1548 return STATUS_NOT_IMPLEMENTED
;