* PURPOSE: Configuration Manager - Internal Registry APIs
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Eric Kohl
+ * Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES ******************************************************************/
IN OUT PULONG ResultLength)
{
NTSTATUS Status;
- ULONG Size, SizeLeft, MinimumSize;
+ ULONG Size, SizeLeft, MinimumSize, Offset;
PKEY_INFORMATION Info = (PKEY_INFORMATION)KeyInformation;
USHORT NameLength;
+ PVOID ClassData;
/* Check if the value is compressed */
if (Node->Flags & KEY_COMP_NAME)
/* Check if the node has a class */
if (Node->ClassLength > 0)
{
- /* It does. We don't support these yet */
- ASSERTMSG("Classes not supported\n", FALSE);
+ /* Set the class offset */
+ Offset = FIELD_OFFSET(KEY_NODE_INFORMATION, Name) + NameLength;
+ Offset = ALIGN_UP_BY(Offset, sizeof(ULONG));
+ Info->KeyNodeInformation.ClassOffset = Offset;
+
+ /* Get the class data */
+ ClassData = HvGetCell(Hive, Node->Class);
+ if (ClassData == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ /* Check if we can copy anything */
+ if (Length > Offset)
+ {
+ /* Copy the class data */
+ RtlCopyMemory((PUCHAR)Info + Offset,
+ ClassData,
+ min(Node->ClassLength, Length - Offset));
+ }
+
+ /* Check if the buffer was large enough */
+ if (Length < Offset + Node->ClassLength)
+ {
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ /* Release the class cell */
+ HvReleaseCell(Hive, Node->Class);
}
else
{
/* Check if we have a class */
if (Node->ClassLength > 0)
{
- /* We do, but we currently don't support this */
- ASSERTMSG("Classes not supported\n", FALSE);
+ /* Set the class offset */
+ Offset = FIELD_OFFSET(KEY_FULL_INFORMATION, Class);
+ Info->KeyFullInformation.ClassOffset = Offset;
+
+ /* Get the class data */
+ ClassData = HvGetCell(Hive, Node->Class);
+ if (ClassData == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ /* Copy the class data */
+ NT_ASSERT(Length > Offset);
+ RtlCopyMemory(Info->KeyFullInformation.Class,
+ ClassData,
+ min(Node->ClassLength, Length - Offset));
+
+ /* Check if the buffer was large enough */
+ if (Length < Offset + Node->ClassLength)
+ {
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ /* Release the class cell */
+ HvReleaseCell(Hive, Node->Class);
}
else
{
/* We don't have a class, so set offset to -1, not 0! */
- Info->KeyNodeInformation.ClassOffset = 0xFFFFFFFF;
+ Info->KeyFullInformation.ClassOffset = 0xFFFFFFFF;
}
break;
}
/* Validate buffer length (we do not copy the name!) */
- *ResultLength = sizeof(KeyCachedInfo);
+ *ResultLength = sizeof(*KeyCachedInfo);
if (Length < *ResultLength)
{
return STATUS_BUFFER_TOO_SMALL;
return STATUS_SUCCESS;
}
+static
+NTSTATUS
+CmpQueryNameInformation(
+ _In_ PCM_KEY_CONTROL_BLOCK Kcb,
+ _Out_opt_ PKEY_NAME_INFORMATION KeyNameInfo,
+ _In_ ULONG Length,
+ _Out_ PULONG ResultLength)
+{
+ ULONG NeededLength;
+ PCM_KEY_CONTROL_BLOCK CurrentKcb;
+
+ NeededLength = 0;
+ CurrentKcb = Kcb;
+
+ /* Count the needed buffer size */
+ while (CurrentKcb)
+ {
+ if (CurrentKcb->NameBlock->Compressed)
+ NeededLength += CmpCompressedNameSize(CurrentKcb->NameBlock->Name, CurrentKcb->NameBlock->NameLength);
+ else
+ NeededLength += CurrentKcb->NameBlock->NameLength;
+
+ NeededLength += sizeof(OBJ_NAME_PATH_SEPARATOR);
+
+ CurrentKcb = CurrentKcb->ParentKcb;
+ }
+
+ _SEH2_TRY
+ {
+ *ResultLength = NeededLength + FIELD_OFFSET(KEY_NAME_INFORMATION, Name[0]);
+ if (Length < *ResultLength)
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ return _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Do the real copy */
+ KeyNameInfo->NameLength = 0;
+ CurrentKcb = Kcb;
+
+ _SEH2_TRY
+ {
+ while (CurrentKcb)
+ {
+ ULONG NameLength;
+
+ if (CurrentKcb->NameBlock->Compressed)
+ {
+ NameLength = CmpCompressedNameSize(CurrentKcb->NameBlock->Name, CurrentKcb->NameBlock->NameLength);
+ /* Copy the compressed name */
+ CmpCopyCompressedName(&KeyNameInfo->Name[(NeededLength - NameLength)/sizeof(WCHAR)],
+ NameLength,
+ CurrentKcb->NameBlock->Name,
+ CurrentKcb->NameBlock->NameLength);
+ }
+ else
+ {
+ NameLength = CurrentKcb->NameBlock->NameLength;
+ /* Otherwise, copy the raw name */
+ RtlCopyMemory(&KeyNameInfo->Name[(NeededLength - NameLength)/sizeof(WCHAR)],
+ CurrentKcb->NameBlock->Name,
+ NameLength);
+ }
+
+ NeededLength -= NameLength;
+ NeededLength -= sizeof(OBJ_NAME_PATH_SEPARATOR);
+ /* Add path separator */
+ KeyNameInfo->Name[NeededLength/sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
+ KeyNameInfo->NameLength += NameLength + sizeof(OBJ_NAME_PATH_SEPARATOR);
+
+ CurrentKcb = CurrentKcb->ParentKcb;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ return _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Make sure we copied everything */
+ ASSERT(NeededLength == 0);
+ ASSERT(KeyNameInfo->Name[0] == OBJ_NAME_PATH_SEPARATOR);
+
+ /* We're done */
+ return STATUS_SUCCESS;
+}
+
+
NTSTATUS
NTAPI
-CmQueryKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
- IN KEY_INFORMATION_CLASS KeyInformationClass,
- IN PVOID KeyInformation,
- IN ULONG Length,
- IN PULONG ResultLength)
+CmQueryKey(_In_ PCM_KEY_CONTROL_BLOCK Kcb,
+ _In_ KEY_INFORMATION_CLASS KeyInformationClass,
+ _Out_opt_ PVOID KeyInformation,
+ _In_ ULONG Length,
+ _Out_ PULONG ResultLength)
{
NTSTATUS Status;
PHHIVE Hive;
ResultLength);
break;
- /* Unsupported class for now */
case KeyNameInformation:
-
- /* Print message and fail */
- DPRINT1("Unsupported class: %d!\n", KeyInformationClass);
- Status = STATUS_NOT_IMPLEMENTED;
+ /* Call the internal API */
+ Status = CmpQueryNameInformation(Kcb,
+ KeyInformation,
+ Length,
+ ResultLength);
break;
/* Illegal classes */
if (KeyBody)
{
/* Fail */
- DPRINT1("Trusted classes not yet supported\n");
- return STATUS_NOT_IMPLEMENTED;
+ DPRINT("Trusted classes not yet supported\n");
}
/* Build a service QoS for a security context */
return SubKeys;
}
+
+HCELL_INDEX
+NTAPI
+CmpCopyCell(IN PHHIVE SourceHive,
+ IN HCELL_INDEX SourceCell,
+ IN PHHIVE DestinationHive,
+ IN HSTORAGE_TYPE StorageType)
+{
+ PCELL_DATA SourceData;
+ PCELL_DATA DestinationData = NULL;
+ HCELL_INDEX DestinationCell = HCELL_NIL;
+ LONG DataSize;
+ PAGED_CODE();
+
+ /* Get the data and the size of the source cell */
+ SourceData = HvGetCell(SourceHive, SourceCell);
+ DataSize = HvGetCellSize(SourceHive, SourceData);
+
+ /* Allocate a new cell in the destination hive */
+ DestinationCell = HvAllocateCell(DestinationHive,
+ DataSize,
+ StorageType,
+ HCELL_NIL);
+ if (DestinationCell == HCELL_NIL) goto Cleanup;
+
+ /* Get the data of the destination cell */
+ DestinationData = HvGetCell(DestinationHive, DestinationCell);
+
+ /* Copy the data from the source cell to the destination cell */
+ RtlMoveMemory(DestinationData, SourceData, DataSize);
+
+Cleanup:
+
+ /* Release the cells */
+ if (SourceData) HvReleaseCell(SourceHive, SourceCell);
+ if (DestinationData) HvReleaseCell(DestinationHive, DestinationCell);
+
+ /* Return the destination cell index */
+ return DestinationCell;
+}
+
+static
+NTSTATUS
+NTAPI
+CmpDeepCopyKeyInternal(IN PHHIVE SourceHive,
+ IN HCELL_INDEX SrcKeyCell,
+ IN PHHIVE DestinationHive,
+ IN HCELL_INDEX Parent,
+ IN HSTORAGE_TYPE StorageType,
+ OUT PHCELL_INDEX DestKeyCell OPTIONAL)
+{
+ NTSTATUS Status;
+ PCM_KEY_NODE SrcNode;
+ PCM_KEY_NODE DestNode = NULL;
+ HCELL_INDEX NewKeyCell, SubKey, NewSubKey;
+ ULONG Index, SubKeyCount;
+ PAGED_CODE();
+
+ DPRINT("CmpDeepCopyKeyInternal(0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X)\n",
+ SourceHive,
+ SrcKeyCell,
+ DestinationHive,
+ Parent,
+ StorageType,
+ DestKeyCell);
+
+ /* Get the source cell node */
+ SrcNode = HvGetCell(SourceHive, SrcKeyCell);
+
+ /* Sanity check */
+ ASSERT(SrcNode->Signature == CM_KEY_NODE_SIGNATURE);
+
+ /* Create a simple copy of the source key */
+ NewKeyCell = CmpCopyCell(SourceHive,
+ SrcKeyCell,
+ DestinationHive,
+ StorageType);
+ if (NewKeyCell == HCELL_NIL)
+ {
+ /* Not enough storage space */
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Cleanup;
+ }
+
+ /* Get the destination cell node */
+ DestNode = HvGetCell(DestinationHive, NewKeyCell);
+
+ /* Set the parent */
+ DestNode->Parent = Parent;
+
+ // TODO: These should also be copied!
+ DestNode->Security = DestNode->Class = HCELL_NIL;
+
+ /* Copy the value list */
+ Status = CmpCopyKeyValueList(SourceHive,
+ &SrcNode->ValueList,
+ DestinationHive,
+ &DestNode->ValueList,
+ StorageType);
+ if (!NT_SUCCESS(Status)) goto Cleanup;
+
+ /* Clear the invalid subkey index */
+ DestNode->SubKeyCounts[Stable] = DestNode->SubKeyCounts[Volatile] = 0;
+ DestNode->SubKeyLists[Stable] = DestNode->SubKeyLists[Volatile] = HCELL_NIL;
+
+ /* Calculate the total number of subkeys */
+ SubKeyCount = SrcNode->SubKeyCounts[Stable] + SrcNode->SubKeyCounts[Volatile];
+
+ /* Loop through all the subkeys */
+ for (Index = 0; Index < SubKeyCount; Index++)
+ {
+ /* Get the subkey */
+ SubKey = CmpFindSubKeyByNumber(SourceHive, SrcNode, Index);
+ ASSERT(SubKey != HCELL_NIL);
+
+ /* Call the function recursively for the subkey */
+ Status = CmpDeepCopyKeyInternal(SourceHive,
+ SubKey,
+ DestinationHive,
+ NewKeyCell,
+ StorageType,
+ &NewSubKey);
+ if (!NT_SUCCESS(Status)) goto Cleanup;
+
+ /* Add the copy of the subkey to the new key */
+ if (!CmpAddSubKey(DestinationHive,
+ NewKeyCell,
+ NewSubKey))
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Cleanup;
+ }
+ }
+
+ /* Set the cell index if requested and return success */
+ if (DestKeyCell) *DestKeyCell = NewKeyCell;
+ Status = STATUS_SUCCESS;
+
+Cleanup:
+
+ /* Release the cells */
+ if (SrcNode) HvReleaseCell(SourceHive, SrcKeyCell);
+ if (DestNode) HvReleaseCell(DestinationHive, NewKeyCell);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+CmpDeepCopyKey(IN PHHIVE SourceHive,
+ IN HCELL_INDEX SrcKeyCell,
+ IN PHHIVE DestinationHive,
+ IN HSTORAGE_TYPE StorageType,
+ OUT PHCELL_INDEX DestKeyCell OPTIONAL)
+{
+ /* Call the internal function */
+ return CmpDeepCopyKeyInternal(SourceHive,
+ SrcKeyCell,
+ DestinationHive,
+ HCELL_NIL,
+ StorageType,
+ DestKeyCell);
+}
+
+NTSTATUS
+NTAPI
+CmSaveKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
+ IN HANDLE FileHandle,
+ IN ULONG Flags)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PCMHIVE KeyHive = NULL;
+ PAGED_CODE();
+
+ DPRINT("CmSaveKey(0x%08X, 0x%08X, %lu)\n", Kcb, FileHandle, Flags);
+
+ /* Lock the registry and KCB */
+ CmpLockRegistry();
+ CmpAcquireKcbLockShared(Kcb);
+
+ if (Kcb->Delete)
+ {
+ /* The source key has been deleted, do nothing */
+ Status = STATUS_KEY_DELETED;
+ goto Cleanup;
+ }
+
+ if (Kcb->KeyHive == &CmiVolatileHive->Hive)
+ {
+ /* Keys that are directly in the master hive can't be saved */
+ Status = STATUS_ACCESS_DENIED;
+ goto Cleanup;
+ }
+
+ /* Create a new hive that will hold the key */
+ Status = CmpInitializeHive(&KeyHive,
+ HINIT_CREATE,
+ HIVE_VOLATILE,
+ HFILE_TYPE_PRIMARY,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0);
+ if (!NT_SUCCESS(Status)) goto Cleanup;
+
+ /* Copy the key recursively into the new hive */
+ Status = CmpDeepCopyKey(Kcb->KeyHive,
+ Kcb->KeyCell,
+ &KeyHive->Hive,
+ Stable,
+ &KeyHive->Hive.BaseBlock->RootCell);
+ if (!NT_SUCCESS(Status)) goto Cleanup;
+
+ /* Set the primary handle of the hive */
+ KeyHive->FileHandles[HFILE_TYPE_PRIMARY] = FileHandle;
+
+ /* Dump the hive into the file */
+ HvWriteHive(&KeyHive->Hive);
+
+Cleanup:
+
+ /* Free the hive */
+ if (KeyHive) CmpDestroyHive(KeyHive);
+
+ /* Release the locks */
+ CmpReleaseKcbLock(Kcb);
+ CmpUnlockRegistry();
+
+ return Status;
+}