2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmapi.c
5 * PURPOSE: Configuration Manager - Internal Registry APIs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
10 /* INCLUDES ******************************************************************/
16 BOOLEAN CmBootAcceptFirstTime
= TRUE
;
17 BOOLEAN CmFirstTime
= TRUE
;
19 /* FUNCTIONS *****************************************************************/
23 NtCreateKey(OUT PHANDLE KeyHandle
,
24 IN ACCESS_MASK DesiredAccess
,
25 IN POBJECT_ATTRIBUTES ObjectAttributes
,
27 IN PUNICODE_STRING Class OPTIONAL
,
28 IN ULONG CreateOptions
,
29 OUT PULONG Disposition OPTIONAL
)
32 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
33 CM_PARSE_CONTEXT ParseContext
= {0};
37 DPRINT("NtCreateKey(Path: %wZ, Root %x, Access: %x, CreateOptions %x)\n",
38 ObjectAttributes
->ObjectName
, ObjectAttributes
->RootDirectory
,
39 DesiredAccess
, CreateOptions
);
41 /* Check for user-mode caller */
42 if (PreviousMode
!= KernelMode
)
44 /* Prepare to probe parameters */
47 /* Check if we have a class */
51 ParseContext
.Class
= ProbeForReadUnicodeString(Class
);
52 ProbeForRead(ParseContext
.Class
.Buffer
,
53 ParseContext
.Class
.Length
,
57 /* Probe the key handle */
58 ProbeForWriteHandle(KeyHandle
);
61 /* Probe object attributes */
62 ProbeForRead(ObjectAttributes
,
63 sizeof(OBJECT_ATTRIBUTES
),
67 ProbeForWriteUlong(Disposition
);
69 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
71 /* Return the exception code */
72 _SEH2_YIELD(return _SEH2_GetExceptionCode());
78 /* Save the class directly */
79 if (Class
) ParseContext
.Class
= *Class
;
82 /* Setup the parse context */
83 ParseContext
.CreateOperation
= TRUE
;
84 ParseContext
.CreateOptions
= CreateOptions
;
87 Status
= ObOpenObjectByName(ObjectAttributes
,
97 /* Return data to user */
98 if (NT_SUCCESS(Status
)) *KeyHandle
= Handle
;
99 if (Disposition
) *Disposition
= ParseContext
.Disposition
;
101 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
104 Status
= _SEH2_GetExceptionCode();
108 DPRINT("Returning handle %x, Status %x.\n", Handle
, Status
);
116 NtOpenKey(OUT PHANDLE KeyHandle
,
117 IN ACCESS_MASK DesiredAccess
,
118 IN POBJECT_ATTRIBUTES ObjectAttributes
)
120 CM_PARSE_CONTEXT ParseContext
= {0};
123 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
125 DPRINT("NtOpenKey(Path: %wZ, Root %x, Access: %x)\n",
126 ObjectAttributes
->ObjectName
, ObjectAttributes
->RootDirectory
, DesiredAccess
);
128 /* Check for user-mode caller */
129 if (PreviousMode
!= KernelMode
)
131 /* Prepare to probe parameters */
134 /* Probe the key handle */
135 ProbeForWriteHandle(KeyHandle
);
138 /* Probe object attributes */
139 ProbeForRead(ObjectAttributes
,
140 sizeof(OBJECT_ATTRIBUTES
),
143 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
145 /* Return the exception code */
146 _SEH2_YIELD(return _SEH2_GetExceptionCode());
151 /* Just let the object manager handle this */
152 Status
= ObOpenObjectByName(ObjectAttributes
,
160 /* Only do this if we succeeded */
161 if (NT_SUCCESS(Status
))
165 /* Return the handle to caller */
168 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
171 Status
= _SEH2_GetExceptionCode();
176 DPRINT("Returning handle %x, Status %x.\n", Handle
, Status
);
185 NtDeleteKey(IN HANDLE KeyHandle
)
187 PCM_KEY_BODY KeyObject
;
189 REG_DELETE_KEY_INFORMATION DeleteKeyInfo
;
190 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
192 DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle
);
194 /* Verify that the handle is valid and is a registry key */
195 Status
= ObReferenceObjectByHandle(KeyHandle
,
201 if (!NT_SUCCESS(Status
)) return Status
;
203 /* Setup the callback */
204 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
205 DeleteKeyInfo
.Object
= (PVOID
)KeyObject
;
206 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteKey
, &DeleteKeyInfo
);
207 if (NT_SUCCESS(Status
))
209 /* Check if we are read-only */
210 if ((KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
) ||
211 (KeyObject
->KeyControlBlock
->ParentKcb
->ExtFlags
& CM_KCB_READ_ONLY_KEY
))
214 Status
= STATUS_ACCESS_DENIED
;
218 /* Call the internal API */
219 Status
= CmDeleteKey(KeyObject
);
222 /* Do post callback */
223 PostOperationInfo
.Status
= Status
;
224 CmiCallRegisteredCallbacks(RegNtPostDeleteKey
, &PostOperationInfo
);
227 /* Dereference the object */
228 ObDereferenceObject(KeyObject
);
234 NtEnumerateKey(IN HANDLE KeyHandle
,
236 IN KEY_INFORMATION_CLASS KeyInformationClass
,
237 OUT PVOID KeyInformation
,
239 OUT PULONG ResultLength
)
241 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
243 PCM_KEY_BODY KeyObject
;
244 REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo
;
245 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
247 DPRINT("NtEnumerateKey() KH 0x%p, Index 0x%x, KIC %d, Length %lu\n",
248 KeyHandle
, Index
, KeyInformationClass
, Length
);
250 /* Reject classes we don't know about */
251 if ((KeyInformationClass
!= KeyBasicInformation
) &&
252 (KeyInformationClass
!= KeyNodeInformation
) &&
253 (KeyInformationClass
!= KeyFullInformation
))
256 return STATUS_INVALID_PARAMETER
;
259 /* Verify that the handle is valid and is a registry key */
260 Status
= ObReferenceObjectByHandle(KeyHandle
,
261 KEY_ENUMERATE_SUB_KEYS
,
266 if (!NT_SUCCESS(Status
)) return Status
;
268 if (PreviousMode
!= KernelMode
)
272 ProbeForWriteUlong(ResultLength
);
273 ProbeForWrite(KeyInformation
,
277 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
279 /* Dereference and return status */
280 ObDereferenceObject(KeyObject
);
281 _SEH2_YIELD(return _SEH2_GetExceptionCode());
286 /* Setup the callback */
287 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
288 EnumerateKeyInfo
.Object
= (PVOID
)KeyObject
;
289 EnumerateKeyInfo
.Index
= Index
;
290 EnumerateKeyInfo
.KeyInformationClass
= KeyInformationClass
;
291 EnumerateKeyInfo
.Length
= Length
;
292 EnumerateKeyInfo
.ResultLength
= ResultLength
;
294 /* Do the callback */
295 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateKey
, &EnumerateKeyInfo
);
296 if (NT_SUCCESS(Status
))
298 /* Call the internal API */
299 Status
= CmEnumerateKey(KeyObject
->KeyControlBlock
,
306 /* Do the post callback */
307 PostOperationInfo
.Status
= Status
;
308 CmiCallRegisteredCallbacks(RegNtPostEnumerateKey
, &PostOperationInfo
);
311 /* Dereference and return status */
312 ObDereferenceObject(KeyObject
);
313 DPRINT("Returning status %x.\n", Status
);
319 NtEnumerateValueKey(IN HANDLE KeyHandle
,
321 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
322 OUT PVOID KeyValueInformation
,
324 OUT PULONG ResultLength
)
326 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
328 PCM_KEY_BODY KeyObject
;
329 REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo
;
330 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
332 DPRINT("NtEnumerateValueKey() KH 0x%p, Index 0x%x, KVIC %d, Length %lu\n",
333 KeyHandle
, Index
, KeyValueInformationClass
, Length
);
335 /* Reject classes we don't know about */
336 if ((KeyValueInformationClass
!= KeyValueBasicInformation
) &&
337 (KeyValueInformationClass
!= KeyValueFullInformation
) &&
338 (KeyValueInformationClass
!= KeyValuePartialInformation
))
341 return STATUS_INVALID_PARAMETER
;
344 /* Verify that the handle is valid and is a registry key */
345 Status
= ObReferenceObjectByHandle(KeyHandle
,
351 if (!NT_SUCCESS(Status
)) return Status
;
353 if (PreviousMode
!= KernelMode
)
357 ProbeForWriteUlong(ResultLength
);
358 ProbeForWrite(KeyValueInformation
,
362 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
364 /* Dereference and return status */
365 ObDereferenceObject(KeyObject
);
366 _SEH2_YIELD(return _SEH2_GetExceptionCode());
371 /* Setup the callback */
372 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
373 EnumerateValueKeyInfo
.Object
= (PVOID
)KeyObject
;
374 EnumerateValueKeyInfo
.Index
= Index
;
375 EnumerateValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
376 EnumerateValueKeyInfo
.KeyValueInformation
= KeyValueInformation
;
377 EnumerateValueKeyInfo
.Length
= Length
;
378 EnumerateValueKeyInfo
.ResultLength
= ResultLength
;
380 /* Do the callback */
381 Status
= CmiCallRegisteredCallbacks(RegNtPreEnumerateValueKey
,
382 &EnumerateValueKeyInfo
);
383 if (NT_SUCCESS(Status
))
385 /* Call the internal API */
386 Status
= CmEnumerateValueKey(KeyObject
->KeyControlBlock
,
388 KeyValueInformationClass
,
393 /* Do the post callback */
394 PostOperationInfo
.Status
= Status
;
395 CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey
, &PostOperationInfo
);
398 ObDereferenceObject(KeyObject
);
404 NtQueryKey(IN HANDLE KeyHandle
,
405 IN KEY_INFORMATION_CLASS KeyInformationClass
,
406 OUT PVOID KeyInformation
,
408 OUT PULONG ResultLength
)
410 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
412 PCM_KEY_BODY KeyObject
;
413 REG_QUERY_KEY_INFORMATION QueryKeyInfo
;
414 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
415 OBJECT_HANDLE_INFORMATION HandleInfo
;
417 DPRINT("NtQueryKey() KH 0x%p, KIC %d, Length %lu\n",
418 KeyHandle
, KeyInformationClass
, Length
);
420 /* Reject invalid classes */
421 if ((KeyInformationClass
!= KeyBasicInformation
) &&
422 (KeyInformationClass
!= KeyNodeInformation
) &&
423 (KeyInformationClass
!= KeyFullInformation
) &&
424 (KeyInformationClass
!= KeyNameInformation
) &&
425 (KeyInformationClass
!= KeyCachedInformation
) &&
426 (KeyInformationClass
!= KeyFlagsInformation
))
429 return STATUS_INVALID_PARAMETER
;
432 /* Check if just the name is required */
433 if (KeyInformationClass
== KeyNameInformation
)
435 /* Ignore access level */
436 Status
= ObReferenceObjectByHandle(KeyHandle
,
442 if (NT_SUCCESS(Status
))
444 /* At least a single bit of access is required */
445 if (!HandleInfo
.GrantedAccess
)
448 ObDereferenceObject(KeyObject
);
449 Status
= STATUS_ACCESS_DENIED
;
455 /* Get a reference */
456 Status
= ObReferenceObjectByHandle(KeyHandle
,
464 /* Quit on failure */
465 if (!NT_SUCCESS(Status
)) return Status
;
467 if (PreviousMode
!= KernelMode
)
471 ProbeForWriteUlong(ResultLength
);
472 ProbeForWrite(KeyInformation
,
476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
478 /* Dereference and return status */
479 ObDereferenceObject(KeyObject
);
480 _SEH2_YIELD(return _SEH2_GetExceptionCode());
485 /* Setup the callback */
486 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
487 QueryKeyInfo
.Object
= (PVOID
)KeyObject
;
488 QueryKeyInfo
.KeyInformationClass
= KeyInformationClass
;
489 QueryKeyInfo
.KeyInformation
= KeyInformation
;
490 QueryKeyInfo
.Length
= Length
;
491 QueryKeyInfo
.ResultLength
= ResultLength
;
493 /* Do the callback */
494 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryKey
, &QueryKeyInfo
);
495 if (NT_SUCCESS(Status
))
497 /* Call the internal API */
498 Status
= CmQueryKey(KeyObject
->KeyControlBlock
,
504 /* Do the post callback */
505 PostOperationInfo
.Status
= Status
;
506 CmiCallRegisteredCallbacks(RegNtPostQueryKey
, &PostOperationInfo
);
509 /* Dereference and return status */
510 ObDereferenceObject(KeyObject
);
516 NtQueryValueKey(IN HANDLE KeyHandle
,
517 IN PUNICODE_STRING ValueName
,
518 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass
,
519 OUT PVOID KeyValueInformation
,
521 OUT PULONG ResultLength
)
523 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
525 PCM_KEY_BODY KeyObject
;
526 REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo
;
527 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
528 UNICODE_STRING ValueNameCopy
= *ValueName
;
530 DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n",
531 KeyHandle
, ValueName
, KeyValueInformationClass
, Length
);
533 /* Verify that the handle is valid and is a registry key */
534 Status
= ObReferenceObjectByHandle(KeyHandle
,
540 if (!NT_SUCCESS(Status
)) return Status
;
542 if (PreviousMode
!= KernelMode
)
546 ProbeForWriteUlong(ResultLength
);
547 ProbeForWrite(KeyValueInformation
,
551 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
553 /* Dereference and return status */
554 ObDereferenceObject(KeyObject
);
555 _SEH2_YIELD(return _SEH2_GetExceptionCode());
560 /* Make sure the name is aligned properly */
561 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
563 /* It isn't, so we'll fail */
564 ObDereferenceObject(KeyObject
);
565 return STATUS_INVALID_PARAMETER
;
569 /* Ignore any null characters at the end */
570 while ((ValueNameCopy
.Length
) &&
571 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
574 ValueNameCopy
.Length
-= sizeof(WCHAR
);
578 /* Setup the callback */
579 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
580 QueryValueKeyInfo
.Object
= (PVOID
)KeyObject
;
581 QueryValueKeyInfo
.ValueName
= &ValueNameCopy
;
582 QueryValueKeyInfo
.KeyValueInformationClass
= KeyValueInformationClass
;
583 QueryValueKeyInfo
.Length
= Length
;
584 QueryValueKeyInfo
.ResultLength
= ResultLength
;
586 /* Do the callback */
587 Status
= CmiCallRegisteredCallbacks(RegNtPreQueryValueKey
, &QueryValueKeyInfo
);
588 if (NT_SUCCESS(Status
))
590 /* Call the internal API */
591 Status
= CmQueryValueKey(KeyObject
->KeyControlBlock
,
593 KeyValueInformationClass
,
598 /* Do the post callback */
599 PostOperationInfo
.Status
= Status
;
600 CmiCallRegisteredCallbacks(RegNtPostQueryValueKey
, &PostOperationInfo
);
603 /* Dereference and return status */
604 ObDereferenceObject(KeyObject
);
610 NtSetValueKey(IN HANDLE KeyHandle
,
611 IN PUNICODE_STRING ValueName
,
617 NTSTATUS Status
= STATUS_SUCCESS
;
618 PCM_KEY_BODY KeyObject
= NULL
;
619 REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo
;
620 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
621 UNICODE_STRING ValueNameCopy
;
622 KPROCESSOR_MODE PreviousMode
;
626 PreviousMode
= ExGetPreviousMode();
631 /* Probe and copy the data */
632 if ((PreviousMode
!= KernelMode
) && Data
)
634 PVOID DataCopy
= ExAllocatePoolWithTag(PagedPool
, DataSize
, TAG_CM
);
636 return STATUS_NO_MEMORY
;
639 ProbeForRead(Data
, DataSize
, 1);
640 RtlCopyMemory(DataCopy
, Data
, DataSize
);
642 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
644 Status
= _SEH2_GetExceptionCode();
648 if (!NT_SUCCESS(Status
))
650 ExFreePoolWithTag(DataCopy
, TAG_CM
);
656 /* Capture the string */
657 Status
= ProbeAndCaptureUnicodeString(&ValueNameCopy
, PreviousMode
, ValueName
);
658 if (!NT_SUCCESS(Status
))
661 DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
662 KeyHandle
, &ValueNameCopy
, TitleIndex
, Type
, DataSize
);
664 /* Verify that the handle is valid and is a registry key */
665 Status
= ObReferenceObjectByHandle(KeyHandle
,
671 if (!NT_SUCCESS(Status
))
674 /* Make sure the name is aligned, not too long, and the data under 4GB */
675 if ( (ValueNameCopy
.Length
> 32767) ||
676 ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1))) ||
677 (DataSize
> 0x80000000))
680 Status
= STATUS_INVALID_PARAMETER
;
684 /* Ignore any null characters at the end */
685 while ((ValueNameCopy
.Length
) &&
686 !(ValueNameCopy
.Buffer
[ValueNameCopy
.Length
/ sizeof(WCHAR
) - 1]))
689 ValueNameCopy
.Length
-= sizeof(WCHAR
);
692 /* Don't touch read-only keys */
693 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
696 Status
= STATUS_ACCESS_DENIED
;
701 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
702 SetValueKeyInfo
.Object
= (PVOID
)KeyObject
;
703 SetValueKeyInfo
.ValueName
= &ValueNameCopy
;
704 SetValueKeyInfo
.TitleIndex
= TitleIndex
;
705 SetValueKeyInfo
.Type
= Type
;
706 SetValueKeyInfo
.Data
= Data
;
707 SetValueKeyInfo
.DataSize
= DataSize
;
709 /* Do the callback */
710 Status
= CmiCallRegisteredCallbacks(RegNtPreSetValueKey
, &SetValueKeyInfo
);
711 if (NT_SUCCESS(Status
))
713 /* Call the internal API */
714 Status
= CmSetValueKey(KeyObject
->KeyControlBlock
,
721 /* Do the post-callback */
722 PostOperationInfo
.Status
= Status
;
723 CmiCallRegisteredCallbacks(RegNtPostSetValueKey
, &PostOperationInfo
);
726 /* Dereference and return status */
728 ObDereferenceObject(KeyObject
);
729 ReleaseCapturedUnicodeString(&ValueNameCopy
, PreviousMode
);
730 if ((PreviousMode
!= KernelMode
) && Data
)
731 ExFreePoolWithTag(Data
, TAG_CM
);
737 NtDeleteValueKey(IN HANDLE KeyHandle
,
738 IN PUNICODE_STRING ValueName
)
740 PCM_KEY_BODY KeyObject
;
742 REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo
;
743 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
744 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
745 UNICODE_STRING ValueNameCopy
= *ValueName
;
748 /* Verify that the handle is valid and is a registry key */
749 Status
= ObReferenceObjectByHandle(KeyHandle
,
755 if (!NT_SUCCESS(Status
)) return Status
;
757 /* Don't touch read-only keys */
758 if (KeyObject
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
761 ObDereferenceObject(KeyObject
);
762 return STATUS_ACCESS_DENIED
;
765 /* Make sure the name is aligned properly */
766 if ((ValueNameCopy
.Length
& (sizeof(WCHAR
) - 1)))
768 /* It isn't, so we'll fail */
769 ObDereferenceObject(KeyObject
);
770 return STATUS_INVALID_PARAMETER
;
773 /* Do the callback */
774 DeleteValueKeyInfo
.Object
= (PVOID
)KeyObject
;
775 DeleteValueKeyInfo
.ValueName
= ValueName
;
776 Status
= CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey
,
777 &DeleteValueKeyInfo
);
778 if (NT_SUCCESS(Status
))
780 /* Call the internal API */
781 Status
= CmDeleteValueKey(KeyObject
->KeyControlBlock
, ValueNameCopy
);
783 /* Do the post callback */
784 PostOperationInfo
.Object
= (PVOID
)KeyObject
;
785 PostOperationInfo
.Status
= Status
;
786 CmiCallRegisteredCallbacks(RegNtPostDeleteValueKey
,
790 /* Dereference the key body */
791 ObDereferenceObject(KeyObject
);
797 NtFlushKey(IN HANDLE KeyHandle
)
800 PCM_KEY_BODY KeyObject
;
803 /* Get the key object */
804 Status
= ObReferenceObjectByHandle(KeyHandle
,
810 if (!NT_SUCCESS(Status
)) return Status
;
812 /* Lock the registry */
816 CmpAcquireKcbLockShared(KeyObject
->KeyControlBlock
);
818 /* Make sure KCB isn't deleted */
819 if (KeyObject
->KeyControlBlock
->Delete
)
822 Status
= STATUS_KEY_DELETED
;
826 /* Call the internal API */
827 Status
= CmFlushKey(KeyObject
->KeyControlBlock
, FALSE
);
830 /* Release the locks */
831 CmpReleaseKcbLock(KeyObject
->KeyControlBlock
);
834 /* Dereference the object and return status */
835 ObDereferenceObject(KeyObject
);
841 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
842 IN POBJECT_ATTRIBUTES FileObjectAttributes
)
844 /* Call the newer API */
845 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, 0, NULL
);
850 NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes
,
851 IN POBJECT_ATTRIBUTES FileObjectAttributes
,
854 /* Call the newer API */
855 return NtLoadKeyEx(KeyObjectAttributes
, FileObjectAttributes
, Flags
, NULL
);
860 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
861 IN POBJECT_ATTRIBUTES SourceFile
,
863 IN HANDLE TrustClassKey
)
866 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
867 PCM_KEY_BODY KeyBody
= NULL
;
871 if (Flags
& ~REG_NO_LAZY_FLUSH
) return STATUS_INVALID_PARAMETER
;
873 /* Validate privilege */
874 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
877 DPRINT1("Restore Privilege missing!\n");
878 return STATUS_PRIVILEGE_NOT_HELD
;
882 KeEnterCriticalRegion();
884 /* Check if we have a trust class */
888 Status
= ObReferenceObjectByHandle(TrustClassKey
,
896 /* Call the internal API */
897 Status
= CmLoadKey(TargetKey
, SourceFile
, Flags
, KeyBody
);
899 /* Dereference the trust key, if any */
900 if (KeyBody
) ObDereferenceObject(KeyBody
);
902 /* Bring back APCs */
903 KeLeaveCriticalRegion();
911 NtNotifyChangeKey(IN HANDLE KeyHandle
,
913 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
914 IN PVOID ApcContext OPTIONAL
,
915 OUT PIO_STATUS_BLOCK IoStatusBlock
,
916 IN ULONG CompletionFilter
,
917 IN BOOLEAN WatchTree
,
920 IN BOOLEAN Asynchronous
)
922 /* Call the newer API */
923 return NtNotifyChangeMultipleKeys(KeyHandle
,
939 NtInitializeRegistry(IN USHORT Flag
)
942 NTSTATUS Status
= STATUS_SUCCESS
;
945 /* Always do this as kernel mode */
946 if (KeGetPreviousMode() == UserMode
) return ZwInitializeRegistry(Flag
);
948 /* Enough of the system has booted by now */
952 if (Flag
> CM_BOOT_FLAG_MAX
) return STATUS_INVALID_PARAMETER
;
954 /* Check if boot was accepted */
955 if ((Flag
>= CM_BOOT_FLAG_ACCEPTED
) && (Flag
<= CM_BOOT_FLAG_MAX
))
957 /* Only allow once */
958 if (!CmBootAcceptFirstTime
) return STATUS_ACCESS_DENIED
;
959 CmBootAcceptFirstTime
= FALSE
;
961 /* Get the control set accepted */
962 Flag
-= CM_BOOT_FLAG_ACCEPTED
;
965 /* FIXME: Save the last known good boot */
966 //Status = CmpSaveBootControlSet(Flag);
971 /* Enable lazy flush */
972 CmpHoldLazyFlush
= FALSE
;
977 /* Otherwise, invalid boot */
978 return STATUS_INVALID_PARAMETER
;
981 /* Check if this was a setup boot */
982 SetupBoot
= (Flag
== CM_BOOT_FLAG_SETUP
? TRUE
: FALSE
);
984 /* Make sure we're only called once */
985 if (!CmFirstTime
) return STATUS_ACCESS_DENIED
;
988 /* Acquire registry lock */
989 //CmpLockRegistryExclusive();
991 /* Initialize the hives and lazy flusher */
992 CmpCmdInit(SetupBoot
);
994 /* Save version data */
997 /* Release the registry lock */
998 //CmpUnlockRegistry();
999 return STATUS_SUCCESS
;
1004 NtCompactKeys(IN ULONG Count
,
1005 IN PHANDLE KeyArray
)
1008 return STATUS_NOT_IMPLEMENTED
;
1013 NtCompressKey(IN HANDLE Key
)
1016 return STATUS_NOT_IMPLEMENTED
;
1021 NtLockProductActivationKeys(IN PULONG pPrivateVer
,
1022 IN PULONG pSafeMode
)
1025 return STATUS_NOT_IMPLEMENTED
;
1030 NtLockRegistryKey(IN HANDLE KeyHandle
)
1033 return STATUS_NOT_IMPLEMENTED
;
1038 NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle
,
1040 IN POBJECT_ATTRIBUTES SlaveObjects
,
1042 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
1043 IN PVOID ApcContext OPTIONAL
,
1044 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1045 IN ULONG CompletionFilter
,
1046 IN BOOLEAN WatchTree
,
1049 IN BOOLEAN Asynchronous
)
1052 return STATUS_NOT_IMPLEMENTED
;
1057 NtQueryMultipleValueKey(IN HANDLE KeyHandle
,
1058 IN OUT PKEY_VALUE_ENTRY ValueList
,
1059 IN ULONG NumberOfValues
,
1061 IN OUT PULONG Length
,
1062 OUT PULONG ReturnLength
)
1065 return STATUS_NOT_IMPLEMENTED
;
1070 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey
,
1071 OUT PULONG HandleCount
)
1073 KPROCESSOR_MODE PreviousMode
;
1074 PCM_KEY_BODY KeyBody
= NULL
;
1078 DPRINT("NtQueryOpenSubKeys()\n");
1082 /* Get the processor mode */
1083 PreviousMode
= KeGetPreviousMode();
1085 if (PreviousMode
!= KernelMode
)
1087 /* Prepare to probe parameters */
1090 /* Probe target key */
1091 ProbeForRead(TargetKey
,
1092 sizeof(OBJECT_ATTRIBUTES
),
1095 /* Probe handle count */
1096 ProbeForWriteUlong(HandleCount
);
1098 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1100 /* Return the exception code */
1101 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1106 /* Open a handle to the key */
1107 Status
= ObOpenObjectByName(TargetKey
,
1114 if (NT_SUCCESS(Status
))
1116 /* Reference the key object */
1117 Status
= ObReferenceObjectByHandle(KeyHandle
,
1124 /* Close the handle */
1128 /* Fail, if the key object could not be referenced */
1129 if (!NT_SUCCESS(Status
))
1132 /* Lock the registry exclusively */
1133 CmpLockRegistryExclusive();
1135 /* Fail, if we did not open a hive root key */
1136 if (KeyBody
->KeyControlBlock
->KeyCell
!=
1137 KeyBody
->KeyControlBlock
->KeyHive
->BaseBlock
->RootCell
)
1139 DPRINT("Error: Key is not a hive root key!\n");
1140 CmpUnlockRegistry();
1141 ObDereferenceObject(KeyBody
);
1142 return STATUS_INVALID_PARAMETER
;
1145 /* Call the internal API */
1146 *HandleCount
= CmCountOpenSubKeys(KeyBody
->KeyControlBlock
,
1149 /* Unlock the registry */
1150 CmpUnlockRegistry();
1152 /* Dereference the key object */
1153 ObDereferenceObject(KeyBody
);
1162 NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey
,
1163 IN ULONG BufferLength
,
1165 IN PULONG RequiredSize
)
1168 return STATUS_NOT_IMPLEMENTED
;
1173 NtRenameKey(IN HANDLE KeyHandle
,
1174 IN PUNICODE_STRING ReplacementName
)
1177 return STATUS_NOT_IMPLEMENTED
;
1182 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1184 IN POBJECT_ATTRIBUTES ReplacedObjectAttributes
)
1187 return STATUS_NOT_IMPLEMENTED
;
1192 NtRestoreKey(IN HANDLE KeyHandle
,
1193 IN HANDLE FileHandle
,
1194 IN ULONG RestoreFlags
)
1197 return STATUS_NOT_IMPLEMENTED
;
1202 NtSaveKey(IN HANDLE KeyHandle
,
1203 IN HANDLE FileHandle
)
1205 /* Call the extended API */
1206 return NtSaveKeyEx(KeyHandle
, FileHandle
, REG_STANDARD_FORMAT
);
1211 NtSaveKeyEx(IN HANDLE KeyHandle
,
1212 IN HANDLE FileHandle
,
1216 PCM_KEY_BODY KeyObject
;
1217 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1221 DPRINT("NtSaveKeyEx(0x%08X, 0x%08X, %lu)\n", KeyHandle
, FileHandle
, Flags
);
1223 /* Verify the flags */
1224 if ((Flags
!= REG_STANDARD_FORMAT
)
1225 && (Flags
!= REG_LATEST_FORMAT
)
1226 && (Flags
!= REG_NO_COMPRESSION
))
1228 /* Only one of these values can be specified */
1229 return STATUS_INVALID_PARAMETER
;
1232 /* Check for the SeBackupPrivilege */
1233 if (!SeSinglePrivilegeCheck(SeBackupPrivilege
, PreviousMode
))
1235 return STATUS_PRIVILEGE_NOT_HELD
;
1238 /* Verify that the handle is valid and is a registry key */
1239 Status
= ObReferenceObjectByHandle(KeyHandle
,
1245 if (!NT_SUCCESS(Status
)) return Status
;
1247 /* Call the internal API */
1248 Status
= CmSaveKey(KeyObject
->KeyControlBlock
, FileHandle
, Flags
);
1250 ObDereferenceObject(KeyObject
);
1256 NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle
,
1257 IN HANDLE LowPrecedenceKeyHandle
,
1258 IN HANDLE FileHandle
)
1261 return STATUS_NOT_IMPLEMENTED
;
1266 NtSetInformationKey(IN HANDLE KeyHandle
,
1267 IN KEY_SET_INFORMATION_CLASS KeyInformationClass
,
1268 IN PVOID KeyInformation
,
1269 IN ULONG KeyInformationLength
)
1272 return STATUS_NOT_IMPLEMENTED
;
1277 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes
)
1279 return NtUnloadKey2(KeyObjectAttributes
, 0);
1284 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey
,
1289 OBJECT_ATTRIBUTES ObjectAttributes
;
1290 UNICODE_STRING ObjectName
;
1291 CM_PARSE_CONTEXT ParseContext
= {0};
1292 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1293 PCM_KEY_BODY KeyBody
= NULL
;
1294 ULONG ParentConv
= 0, ChildConv
= 0;
1298 /* Validate privilege */
1299 if (!SeSinglePrivilegeCheck(SeRestorePrivilege
, PreviousMode
))
1302 DPRINT1("Restore Privilege missing!\n");
1303 return STATUS_PRIVILEGE_NOT_HELD
;
1306 /* Check for user-mode caller */
1307 if (PreviousMode
!= KernelMode
)
1309 /* Prepare to probe parameters */
1312 /* Probe object attributes */
1313 ProbeForRead(TargetKey
,
1314 sizeof(OBJECT_ATTRIBUTES
),
1317 ObjectAttributes
= *TargetKey
;
1319 /* Probe the string */
1320 ProbeForReadUnicodeString(&TargetKey
->ObjectName
);
1322 ObjectName
= *TargetKey
->ObjectName
;
1324 ProbeForRead(ObjectName
.Buffer
,
1328 ObjectAttributes
.ObjectName
= &ObjectName
;
1330 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1332 /* Return the exception code */
1333 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1339 /* Save the target attributes directly */
1340 ObjectAttributes
= *TargetKey
;
1343 /* Setup the parse context */
1344 ParseContext
.CreateOperation
= TRUE
;
1345 ParseContext
.CreateOptions
= REG_OPTION_BACKUP_RESTORE
;
1348 Status
= ObOpenObjectByName(&ObjectAttributes
,
1356 /* Return if failure encountered */
1357 if (!NT_SUCCESS(Status
)) return Status
;
1360 Status
= ObReferenceObjectByHandle(Handle
,
1367 /* Close the handle */
1370 /* Return if failure encountered */
1371 if (!NT_SUCCESS(Status
)) return Status
;
1373 /* Acquire the lock depending on flags */
1374 if (Flags
== REG_FORCE_UNLOAD
)
1376 /* Lock registry exclusively */
1377 CmpLockRegistryExclusive();
1384 /* Acquire the hive loading lock */
1385 ExAcquirePushLockExclusive(&CmpLoadHiveLock
);
1387 /* Lock parent and child */
1388 if (KeyBody
->KeyControlBlock
->ParentKcb
)
1389 ParentConv
= KeyBody
->KeyControlBlock
->ParentKcb
->ConvKey
;
1391 ParentConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1393 ChildConv
= KeyBody
->KeyControlBlock
->ConvKey
;
1395 CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv
, ParentConv
);
1398 /* Check if it's being deleted already */
1399 if (KeyBody
->KeyControlBlock
->Delete
)
1401 /* Return appropriate status */
1402 Status
= STATUS_KEY_DELETED
;
1406 /* Check if it's a readonly key */
1407 if (KeyBody
->KeyControlBlock
->ExtFlags
& CM_KCB_READ_ONLY_KEY
)
1409 /* Return appropriate status */
1410 Status
= STATUS_ACCESS_DENIED
;
1414 /* Call the internal API */
1415 Status
= CmUnloadKey(KeyBody
->KeyControlBlock
,
1418 /* Check if we failed, but really need to succeed */
1419 if ((Status
== STATUS_CANNOT_DELETE
) && (Flags
== REG_FORCE_UNLOAD
))
1421 /* TODO: We should perform another attempt here */
1425 /* If CmUnloadKey failed we need to unlock registry ourselves */
1426 if (!NT_SUCCESS(Status
))
1428 if (Flags
!= REG_FORCE_UNLOAD
)
1430 /* Release the hive loading lock */
1431 ExReleasePushLockExclusive(&CmpLoadHiveLock
);
1433 /* Release two KCBs lock */
1434 CmpReleaseTwoKcbLockByKey(ChildConv
, ParentConv
);
1437 /* Unlock the registry */
1438 CmpUnlockRegistry();
1442 /* Dereference the key */
1443 ObDereferenceObject(KeyBody
);
1449 return STATUS_NOT_IMPLEMENTED
;
1455 NtUnloadKeyEx(IN POBJECT_ATTRIBUTES TargetKey
,
1459 return STATUS_NOT_IMPLEMENTED
;