/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/config/cmapi.c
+ * FILE: ntoskrnl/config/ntapi.c
* PURPOSE: Configuration Manager - Internal Registry APIs
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Eric Kohl
BOOLEAN CmBootAcceptFirstTime = TRUE;
BOOLEAN CmFirstTime = TRUE;
+extern ULONG InitSafeBootMode;
+
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+/*
+ * Adapted from ntoskrnl/include/internal/ob_x.h:ObpReleaseObjectCreateInformation()
+ */
+VOID
+ReleaseCapturedObjectAttributes(
+ _In_ POBJECT_ATTRIBUTES CapturedObjectAttributes,
+ _In_ KPROCESSOR_MODE AccessMode)
+{
+ /* Check if we have a security descriptor */
+ if (CapturedObjectAttributes->SecurityDescriptor)
+ {
+ /* Release it */
+ SeReleaseSecurityDescriptor(CapturedObjectAttributes->SecurityDescriptor,
+ AccessMode,
+ TRUE);
+ CapturedObjectAttributes->SecurityDescriptor = NULL;
+ }
+
+ /* Check if we have an object name */
+ if (CapturedObjectAttributes->ObjectName)
+ {
+ /* Release it */
+ ReleaseCapturedUnicodeString(CapturedObjectAttributes->ObjectName, AccessMode);
+ }
+}
+
+/*
+ * Adapted from ntoskrnl/ob/oblife.c:ObpCaptureObjectCreateInformation()
+ */
+NTSTATUS
+ProbeAndCaptureObjectAttributes(
+ _Out_ POBJECT_ATTRIBUTES CapturedObjectAttributes,
+ _Out_ PUNICODE_STRING ObjectName,
+ _In_ KPROCESSOR_MODE AccessMode,
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ BOOLEAN CaptureSecurity)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ // PSECURITY_QUALITY_OF_SERVICE SecurityQos;
+ PUNICODE_STRING LocalObjectName = NULL;
+
+ /* Zero out the Capture Data */
+ RtlZeroMemory(CapturedObjectAttributes, sizeof(*CapturedObjectAttributes));
+
+ /* SEH everything here for protection */
+ _SEH2_TRY
+ {
+ /* Check if we got attributes */
+ if (ObjectAttributes)
+ {
+ /* Check if we're in user mode */
+ if (AccessMode != KernelMode)
+ {
+ /* Probe the attributes */
+ ProbeForRead(ObjectAttributes,
+ sizeof(OBJECT_ATTRIBUTES),
+ sizeof(ULONG));
+ }
+
+ /* Validate the Size and Attributes */
+ if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
+ (ObjectAttributes->Attributes & ~OBJ_VALID_KERNEL_ATTRIBUTES)) // Understood as all the possible valid attributes
+ {
+ /* Invalid combination, fail */
+ _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
+ }
+
+ /* Set some Create Info and do not allow user-mode kernel handles */
+ CapturedObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES);
+ CapturedObjectAttributes->RootDirectory = ObjectAttributes->RootDirectory;
+ CapturedObjectAttributes->Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, AccessMode);
+ LocalObjectName = ObjectAttributes->ObjectName;
+ SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
+ // SecurityQos = ObjectAttributes->SecurityQualityOfService;
+
+ /* Check if we have a security descriptor */
+ if (CaptureSecurity && SecurityDescriptor)
+ {
+ /*
+ * Capture it.
+ * Note: This has an implicit memory barrier due
+ * to the function call, so cleanup is safe here.
+ */
+ Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
+ AccessMode,
+ NonPagedPool,
+ TRUE,
+ &CapturedObjectAttributes->
+ SecurityDescriptor);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Capture failed, quit */
+ CapturedObjectAttributes->SecurityDescriptor = NULL;
+ _SEH2_YIELD(return Status);
+ }
+ }
+ else
+ {
+ CapturedObjectAttributes->SecurityDescriptor = NULL;
+ }
+
+#if 0
+// We don't use the QoS!
+
+ /* Check if we have QoS */
+ if (SecurityQos)
+ {
+ /* Check if we came from user mode */
+ if (AccessMode != KernelMode)
+ {
+ /* Validate the QoS */
+ ProbeForRead(SecurityQos,
+ sizeof(SECURITY_QUALITY_OF_SERVICE),
+ sizeof(ULONG));
+ }
+
+ /* Save Info */
+ CapturedObjectAttributes->SecurityQualityOfService = *SecurityQos;
+ CapturedObjectAttributes->SecurityQos =
+ &CapturedObjectAttributes->SecurityQualityOfService;
+ }
+#else
+ CapturedObjectAttributes->SecurityQualityOfService = NULL;
+#endif
+ }
+ else
+ {
+ /* We don't have a name */
+ LocalObjectName = NULL;
+ }
+ }
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
+ {
+ /* Cleanup and return the exception code */
+ ReleaseCapturedObjectAttributes(CapturedObjectAttributes, AccessMode);
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ /* Now check if the Object Attributes had an Object Name */
+ if (LocalObjectName)
+ {
+ Status = ProbeAndCaptureUnicodeString(ObjectName, AccessMode, LocalObjectName);
+ }
+ else
+ {
+ /* Clear the string */
+ RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
+
+ /* It cannot have specified a Root Directory */
+ if (CapturedObjectAttributes->RootDirectory)
+ {
+ Status = STATUS_OBJECT_NAME_INVALID;
+ }
+ }
+
+ /* Set the caputured object attributes name pointer to the one the user gave to us */
+ CapturedObjectAttributes->ObjectName = ObjectName;
+
+ /* Cleanup if we failed */
+ if (!NT_SUCCESS(Status))
+ {
+ ReleaseCapturedObjectAttributes(CapturedObjectAttributes, AccessMode);
+ }
+
+ /* Return status to caller */
+ return Status;
+}
+
+static
+NTSTATUS
+CmpConvertHandleToKernelHandle(
+ _In_ HANDLE SourceHandle,
+ _In_opt_ POBJECT_TYPE ObjectType,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ KPROCESSOR_MODE AccessMode,
+ _Out_ PHANDLE KernelHandle)
+{
+ NTSTATUS Status;
+ PVOID Object;
+
+ *KernelHandle = NULL;
+
+ /* NULL handle is valid */
+ if (SourceHandle == NULL)
+ return STATUS_SUCCESS;
+
+ /* Get the object pointer */
+ Status = ObReferenceObjectByHandle(SourceHandle,
+ DesiredAccess,
+ ObjectType,
+ AccessMode,
+ &Object,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ /* Create a kernel handle from the pointer */
+ Status = ObOpenObjectByPointer(Object,
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ DesiredAccess,
+ ObjectType,
+ KernelMode,
+ KernelHandle);
+
+ /* Dereference the object */
+ ObDereferenceObject(Object);
+ return Status;
+}
+
/* FUNCTIONS *****************************************************************/
ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory,
DesiredAccess, CreateOptions);
+ /* Ignore the WOW64 flag, it's not valid in the kernel */
+ DesiredAccess &= ~KEY_WOW64_RES;
+
/* Check for user-mode caller */
if (PreviousMode != KernelMode)
{
DPRINT("NtOpenKey(Path: %wZ, Root %x, Access: %x)\n",
ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory, DesiredAccess);
+ /* Ignore the WOW64 flag, it's not valid in the kernel */
+ DesiredAccess &= ~KEY_WOW64_RES;
+
/* Check for user-mode caller */
if (PreviousMode != KernelMode)
{
/* Just let the object manager handle this */
Status = ObOpenObjectByName(ObjectAttributes,
CmpKeyObjectType,
- ExGetPreviousMode(),
+ PreviousMode,
NULL,
DesiredAccess,
&ParseContext,
CmiCallRegisteredCallbacks(RegNtPostDeleteKey, &PostOperationInfo);
}
- /* Dereference the object */
+ /* Dereference and return status */
ObDereferenceObject(KeyObject);
return Status;
}
Status = ObReferenceObjectByHandle(KeyHandle,
KEY_ENUMERATE_SUB_KEYS,
CmpKeyObjectType,
- ExGetPreviousMode(),
+ PreviousMode,
(PVOID*)&KeyObject,
NULL);
if (!NT_SUCCESS(Status)) return Status;
PCM_KEY_BODY KeyObject;
REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo;
REG_POST_OPERATION_INFORMATION PostOperationInfo;
+
PAGED_CODE();
+
DPRINT("NtEnumerateValueKey() KH 0x%p, Index 0x%x, KVIC %d, Length %lu\n",
KeyHandle, Index, KeyValueInformationClass, Length);
/* Reject classes we don't know about */
- if ((KeyValueInformationClass != KeyValueBasicInformation) &&
- (KeyValueInformationClass != KeyValueFullInformation) &&
- (KeyValueInformationClass != KeyValuePartialInformation))
+ if ((KeyValueInformationClass != KeyValueBasicInformation) &&
+ (KeyValueInformationClass != KeyValueFullInformation) &&
+ (KeyValueInformationClass != KeyValuePartialInformation) &&
+ (KeyValueInformationClass != KeyValueFullInformationAlign64) &&
+ (KeyValueInformationClass != KeyValuePartialInformationAlign64))
{
/* Fail */
return STATUS_INVALID_PARAMETER;
Status = ObReferenceObjectByHandle(KeyHandle,
KEY_QUERY_VALUE,
CmpKeyObjectType,
- ExGetPreviousMode(),
+ PreviousMode,
(PVOID*)&KeyObject,
NULL);
if (!NT_SUCCESS(Status)) return Status;
CmiCallRegisteredCallbacks(RegNtPostEnumerateValueKey, &PostOperationInfo);
}
+ /* Dereference and return status */
ObDereferenceObject(KeyObject);
return Status;
}
Status = ObReferenceObjectByHandle(KeyHandle,
0,
CmpKeyObjectType,
- ExGetPreviousMode(),
+ PreviousMode,
(PVOID*)&KeyObject,
&HandleInfo);
if (NT_SUCCESS(Status))
Status = ObReferenceObjectByHandle(KeyHandle,
KEY_QUERY_VALUE,
CmpKeyObjectType,
- ExGetPreviousMode(),
+ PreviousMode,
(PVOID*)&KeyObject,
NULL);
}
IN ULONG Length,
OUT PULONG ResultLength)
{
- KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PCM_KEY_BODY KeyObject;
REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
REG_POST_OPERATION_INFORMATION PostOperationInfo;
- UNICODE_STRING ValueNameCopy = *ValueName;
+ UNICODE_STRING ValueNameCopy;
+
PAGED_CODE();
+
DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n",
KeyHandle, ValueName, KeyValueInformationClass, Length);
+ /* Reject classes we don't know about */
+ if ((KeyValueInformationClass != KeyValueBasicInformation) &&
+ (KeyValueInformationClass != KeyValueFullInformation) &&
+ (KeyValueInformationClass != KeyValuePartialInformation) &&
+ (KeyValueInformationClass != KeyValueFullInformationAlign64) &&
+ (KeyValueInformationClass != KeyValuePartialInformationAlign64))
+ {
+ /* Fail */
+ return STATUS_INVALID_PARAMETER;
+ }
+
/* Verify that the handle is valid and is a registry key */
Status = ObReferenceObjectByHandle(KeyHandle,
KEY_QUERY_VALUE,
CmpKeyObjectType,
- ExGetPreviousMode(),
+ PreviousMode,
(PVOID*)&KeyObject,
NULL);
- if (!NT_SUCCESS(Status)) return Status;
+ if (!NT_SUCCESS(Status))
+ return Status;
if (PreviousMode != KernelMode)
{
_SEH2_END;
}
+ /* Capture the string */
+ Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
+ if (!NT_SUCCESS(Status))
+ goto Quit;
+
/* Make sure the name is aligned properly */
if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
{
/* It isn't, so we'll fail */
- ObDereferenceObject(KeyObject);
- return STATUS_INVALID_PARAMETER;
+ Status = STATUS_INVALID_PARAMETER;
+ goto Quit;
}
- else
+
+ /* Ignore any null characters at the end */
+ while ((ValueNameCopy.Length) &&
+ !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
{
- /* Ignore any null characters at the end */
- while ((ValueNameCopy.Length) &&
- !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
- {
- /* Skip it */
- ValueNameCopy.Length -= sizeof(WCHAR);
- }
+ /* Skip it */
+ ValueNameCopy.Length -= sizeof(WCHAR);
}
/* Setup the callback */
CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
}
+Quit:
+ if (ValueNameCopy.Buffer)
+ ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
+
/* Dereference and return status */
ObDereferenceObject(KeyObject);
return Status;
IN ULONG DataSize)
{
NTSTATUS Status = STATUS_SUCCESS;
- PCM_KEY_BODY KeyObject = NULL;
+ KPROCESSOR_MODE PreviousMode;
+ PCM_KEY_BODY KeyObject;
REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
REG_POST_OPERATION_INFORMATION PostOperationInfo;
UNICODE_STRING ValueNameCopy;
- KPROCESSOR_MODE PreviousMode;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
+ /* Verify that the handle is valid and is a registry key */
+ Status = ObReferenceObjectByHandle(KeyHandle,
+ KEY_SET_VALUE,
+ CmpKeyObjectType,
+ PreviousMode,
+ (PVOID*)&KeyObject,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
if (!DataSize)
Data = NULL;
/* Probe and copy the data */
- if ((PreviousMode != KernelMode) && Data)
+ if ((PreviousMode != KernelMode) && (DataSize != 0))
{
PVOID DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM);
if (!DataCopy)
- return STATUS_NO_MEMORY;
+ {
+ /* Dereference and return status */
+ ObDereferenceObject(KeyObject);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
_SEH2_TRY
{
ProbeForRead(Data, DataSize, 1);
if (!NT_SUCCESS(Status))
{
+ /* Dereference and return status */
ExFreePoolWithTag(DataCopy, TAG_CM);
+ ObDereferenceObject(KeyObject);
return Status;
}
Data = DataCopy;
/* Capture the string */
Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
if (!NT_SUCCESS(Status))
- goto end;
+ goto Quit;
DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
KeyHandle, &ValueNameCopy, TitleIndex, Type, DataSize);
- /* Verify that the handle is valid and is a registry key */
- Status = ObReferenceObjectByHandle(KeyHandle,
- KEY_SET_VALUE,
- CmpKeyObjectType,
- ExGetPreviousMode(),
- (PVOID*)&KeyObject,
- NULL);
- if (!NT_SUCCESS(Status))
- goto end;
-
/* Make sure the name is aligned, not too long, and the data under 4GB */
if ( (ValueNameCopy.Length > 32767) ||
((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) ||
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
- goto end;
+ goto Quit;
}
/* Ignore any null characters at the end */
{
/* Fail */
Status = STATUS_ACCESS_DENIED;
- goto end;
+ goto Quit;
}
/* Setup callback */
Type,
Data,
DataSize);
+
+ /* Do the post-callback */
+ PostOperationInfo.Status = Status;
+ CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
}
- /* Do the post-callback */
- PostOperationInfo.Status = Status;
- CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
+Quit:
+ if (ValueNameCopy.Buffer)
+ ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
-end:
- /* Dereference and return status */
- if (KeyObject)
- ObDereferenceObject(KeyObject);
- ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
if ((PreviousMode != KernelMode) && Data)
ExFreePoolWithTag(Data, TAG_CM);
+
+ /* Dereference and return status */
+ ObDereferenceObject(KeyObject);
return Status;
}
NtDeleteValueKey(IN HANDLE KeyHandle,
IN PUNICODE_STRING ValueName)
{
- PCM_KEY_BODY KeyObject;
NTSTATUS Status;
+ PCM_KEY_BODY KeyObject;
REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
REG_POST_OPERATION_INFORMATION PostOperationInfo;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
- UNICODE_STRING ValueNameCopy = *ValueName;
+ UNICODE_STRING ValueNameCopy;
+
PAGED_CODE();
/* Verify that the handle is valid and is a registry key */
KEY_SET_VALUE,
CmpKeyObjectType,
PreviousMode,
- (PVOID *)&KeyObject,
+ (PVOID*)&KeyObject,
NULL);
- if (!NT_SUCCESS(Status)) return Status;
+ if (!NT_SUCCESS(Status))
+ return Status;
- /* Don't touch read-only keys */
- if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
- {
- /* Fail */
- ObDereferenceObject(KeyObject);
- return STATUS_ACCESS_DENIED;
- }
+ /* Capture the string */
+ Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
+ if (!NT_SUCCESS(Status))
+ goto Quit;
/* Make sure the name is aligned properly */
if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
{
/* It isn't, so we'll fail */
- ObDereferenceObject(KeyObject);
- return STATUS_INVALID_PARAMETER;
+ Status = STATUS_INVALID_PARAMETER;
+ goto Quit;
+ }
+
+ /* Don't touch read-only keys */
+ if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
+ {
+ /* Fail */
+ Status = STATUS_ACCESS_DENIED;
+ goto Quit;
}
/* Do the callback */
&PostOperationInfo);
}
- /* Dereference the key body */
+Quit:
+ if (ValueNameCopy.Buffer)
+ ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
+
+ /* Dereference and return status */
ObDereferenceObject(KeyObject);
return Status;
}
{
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ OBJECT_ATTRIBUTES CapturedTargetKey;
+ OBJECT_ATTRIBUTES CapturedSourceFile;
+ UNICODE_STRING TargetKeyName, SourceFileName;
+ HANDLE KmTargetKeyRootDir = NULL, KmSourceFileRootDir = NULL;
PCM_KEY_BODY KeyBody = NULL;
+
PAGED_CODE();
/* Validate flags */
- if (Flags & ~REG_NO_LAZY_FLUSH) return STATUS_INVALID_PARAMETER;
+ if (Flags & ~REG_NO_LAZY_FLUSH)
+ return STATUS_INVALID_PARAMETER;
/* Validate privilege */
if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
{
- /* Fail */
DPRINT1("Restore Privilege missing!\n");
return STATUS_PRIVILEGE_NOT_HELD;
}
/* Block APCs */
KeEnterCriticalRegion();
+ /* Check for user-mode caller */
+ if (PreviousMode != KernelMode)
+ {
+ /* Prepare to probe parameters */
+ _SEH2_TRY
+ {
+ /* Probe target key */
+ ProbeForRead(TargetKey,
+ sizeof(OBJECT_ATTRIBUTES),
+ sizeof(ULONG));
+
+ /* Probe source file */
+ ProbeForRead(SourceFile,
+ sizeof(OBJECT_ATTRIBUTES),
+ sizeof(ULONG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return the exception code */
+ Status = _SEH2_GetExceptionCode();
+ _SEH2_YIELD(goto Quit);
+ }
+ _SEH2_END;
+ }
+
+ /* Probe and capture the target key attributes, including the security */
+ Status = ProbeAndCaptureObjectAttributes(&CapturedTargetKey,
+ &TargetKeyName,
+ PreviousMode,
+ TargetKey,
+ TRUE);
+ if (!NT_SUCCESS(Status))
+ goto Quit;
+
+ /*
+ * Probe and capture the source file attributes, but not the security.
+ * A proper security context is built by CmLoadKey().
+ */
+ Status = ProbeAndCaptureObjectAttributes(&CapturedSourceFile,
+ &SourceFileName,
+ PreviousMode,
+ SourceFile,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode);
+ goto Quit;
+ }
+
+ /* Make sure the target key root directory handle is a kernel handle */
+ Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory,
+ CmpKeyObjectType,
+ KEY_READ,
+ PreviousMode,
+ &KmTargetKeyRootDir);
+ if (!NT_SUCCESS(Status))
+ goto Cleanup;
+ CapturedTargetKey.RootDirectory = KmTargetKeyRootDir;
+ CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
+
+ /* Make sure the source file root directory handle is a kernel handle */
+ Status = CmpConvertHandleToKernelHandle(CapturedSourceFile.RootDirectory,
+ IoFileObjectType,
+ FILE_TRAVERSE,
+ PreviousMode,
+ &KmSourceFileRootDir);
+ if (!NT_SUCCESS(Status))
+ goto Cleanup;
+ CapturedSourceFile.RootDirectory = KmSourceFileRootDir;
+ CapturedSourceFile.Attributes |= OBJ_KERNEL_HANDLE;
+
/* Check if we have a trust class */
if (TrustClassKey)
{
0,
CmpKeyObjectType,
PreviousMode,
- (PVOID *)&KeyBody,
+ (PVOID*)&KeyBody,
NULL);
}
/* Call the internal API */
- Status = CmLoadKey(TargetKey, SourceFile, Flags, KeyBody);
+ Status = CmLoadKey(&CapturedTargetKey,
+ &CapturedSourceFile,
+ Flags,
+ KeyBody);
/* Dereference the trust key, if any */
if (KeyBody) ObDereferenceObject(KeyBody);
+Cleanup:
+ /* Close the local kernel handles */
+ if (KmSourceFileRootDir)
+ ObCloseHandle(KmSourceFileRootDir, KernelMode);
+ if (KmTargetKeyRootDir)
+ ObCloseHandle(KmTargetKeyRootDir, KernelMode);
+
+ /* Release the captured object attributes */
+ ReleaseCapturedObjectAttributes(&CapturedSourceFile, PreviousMode);
+ ReleaseCapturedObjectAttributes(&CapturedTargetKey, PreviousMode);
+
+Quit:
/* Bring back APCs */
KeLeaveCriticalRegion();
PAGED_CODE();
/* Always do this as kernel mode */
- if (KeGetPreviousMode() == UserMode) return ZwInitializeRegistry(Flag);
+ if (KeGetPreviousMode() == UserMode)
+ return ZwInitializeRegistry(Flag);
/* Enough of the system has booted by now */
Ki386PerfEnd();
-
+
/* Validate flag */
if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
Flag -= CM_BOOT_FLAG_ACCEPTED;
if (Flag)
{
- /* FIXME: Save the last known good boot */
- //Status = CmpSaveBootControlSet(Flag);
+ /* Save the last known good boot */
+ Status = CmpSaveBootControlSet(Flag);
/* Notify HAL */
HalEndOfBoot();
if (!CmFirstTime) return STATUS_ACCESS_DENIED;
CmFirstTime = FALSE;
- /* Acquire registry lock */
- //CmpLockRegistryExclusive();
+ /* Lock the registry exclusively */
+ CmpLockRegistryExclusive();
/* Initialize the hives and lazy flusher */
CmpCmdInit(SetupBoot);
CmpSetVersionData();
/* Release the registry lock */
- //CmpUnlockRegistry();
+ CmpUnlockRegistry();
return STATUS_SUCCESS;
}
return STATUS_NOT_IMPLEMENTED;
}
+// FIXME: different for different windows versions!
+#define PRODUCT_ACTIVATION_VERSION 7749
+
NTSTATUS
NTAPI
NtLockProductActivationKeys(IN PULONG pPrivateVer,
IN PULONG pSafeMode)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ KPROCESSOR_MODE PreviousMode;
+
+ PreviousMode = ExGetPreviousMode();
+ _SEH2_TRY
+ {
+ /* Check if the caller asked for the version */
+ if (pPrivateVer != NULL)
+ {
+ /* For user mode, probe it */
+ if (PreviousMode != KernelMode)
+ {
+ ProbeForRead(pPrivateVer, sizeof(ULONG), sizeof(ULONG));
+ }
+
+ /* Return the expected version */
+ *pPrivateVer = PRODUCT_ACTIVATION_VERSION;
+ }
+
+ /* Check if the caller asked for safe mode mode state */
+ if (pSafeMode != NULL)
+ {
+ /* For user mode, probe it */
+ if (PreviousMode != KernelMode)
+ {
+ ProbeForRead(pSafeMode, sizeof(ULONG), sizeof(ULONG));
+ }
+
+ /* Return the safe boot mode state */
+ *pSafeMode = InitSafeBootMode;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ return STATUS_SUCCESS;
}
NTSTATUS
IN ULONG Length,
IN BOOLEAN Asynchronous)
{
- UNIMPLEMENTED;
+ UNIMPLEMENTED_ONCE;
return STATUS_NOT_IMPLEMENTED;
}
/* Get the processor mode */
PreviousMode = KeGetPreviousMode();
+ /* Check for user-mode caller */
if (PreviousMode != KernelMode)
{
/* Prepare to probe parameters */
KEY_READ,
CmpKeyObjectType,
PreviousMode,
- (PVOID *)&KeyBody,
+ (PVOID*)&KeyBody,
NULL);
/* Close the handle */
}
/* Call the internal API */
- *HandleCount = CmCountOpenSubKeys(KeyBody->KeyControlBlock,
- FALSE);
+ *HandleCount = CmpEnumerateOpenSubKeys(KeyBody->KeyControlBlock,
+ FALSE, FALSE);
/* Unlock the registry */
CmpUnlockRegistry();
IN ULONG Flags)
{
NTSTATUS Status;
+ HANDLE KmFileHandle = NULL;
PCM_KEY_BODY KeyObject;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PAGED_CODE();
- DPRINT("NtSaveKeyEx(0x%08X, 0x%08X, %lu)\n", KeyHandle, FileHandle, Flags);
+ DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle, FileHandle, Flags);
/* Verify the flags */
if ((Flags != REG_STANDARD_FORMAT)
return STATUS_INVALID_PARAMETER;
}
- /* Check for the SeBackupPrivilege */
+ /* Validate privilege */
if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
{
return STATUS_PRIVILEGE_NOT_HELD;
}
+ /* Make sure the target file handle is a kernel handle */
+ Status = CmpConvertHandleToKernelHandle(FileHandle,
+ IoFileObjectType,
+ FILE_WRITE_DATA,
+ PreviousMode,
+ &KmFileHandle);
+ if (!NT_SUCCESS(Status))
+ goto Quit;
+
/* Verify that the handle is valid and is a registry key */
Status = ObReferenceObjectByHandle(KeyHandle,
KEY_READ,
PreviousMode,
(PVOID*)&KeyObject,
NULL);
- if (!NT_SUCCESS(Status)) return Status;
+ if (!NT_SUCCESS(Status))
+ goto Quit;
/* Call the internal API */
- Status = CmSaveKey(KeyObject->KeyControlBlock, FileHandle, Flags);
+ Status = CmSaveKey(KeyObject->KeyControlBlock, KmFileHandle, Flags);
+ /* Dereference the registry key */
ObDereferenceObject(KeyObject);
+
+Quit:
+ /* Close the local kernel handle */
+ if (KmFileHandle)
+ ObCloseHandle(KmFileHandle, KernelMode);
+
return Status;
}
IN HANDLE LowPrecedenceKeyHandle,
IN HANDLE FileHandle)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ NTSTATUS Status;
+ KPROCESSOR_MODE PreviousMode;
+ HANDLE KmFileHandle = NULL;
+ PCM_KEY_BODY HighPrecedenceKeyObject = NULL;
+ PCM_KEY_BODY LowPrecedenceKeyObject = NULL;
+
+ PAGED_CODE();
+
+ DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n",
+ HighPrecedenceKeyHandle, LowPrecedenceKeyHandle, FileHandle);
+
+ PreviousMode = ExGetPreviousMode();
+
+ /* Validate privilege */
+ if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
+ {
+ return STATUS_PRIVILEGE_NOT_HELD;
+ }
+
+ /* Make sure the target file handle is a kernel handle */
+ Status = CmpConvertHandleToKernelHandle(FileHandle,
+ IoFileObjectType,
+ FILE_WRITE_DATA,
+ PreviousMode,
+ &KmFileHandle);
+ if (!NT_SUCCESS(Status))
+ goto Quit;
+
+ /* Verify that the handles are valid and are registry keys */
+ Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle,
+ KEY_READ,
+ CmpKeyObjectType,
+ PreviousMode,
+ (PVOID*)&HighPrecedenceKeyObject,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ goto Quit;
+
+ Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle,
+ KEY_READ,
+ CmpKeyObjectType,
+ PreviousMode,
+ (PVOID*)&LowPrecedenceKeyObject,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ goto Quit;
+
+ /* Call the internal API */
+ Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock,
+ LowPrecedenceKeyObject->KeyControlBlock,
+ KmFileHandle);
+
+Quit:
+ /* Dereference the opened key objects */
+ if (LowPrecedenceKeyObject)
+ ObDereferenceObject(LowPrecedenceKeyObject);
+ if (HighPrecedenceKeyObject)
+ ObDereferenceObject(HighPrecedenceKeyObject);
+
+ /* Close the local kernel handle */
+ if (KmFileHandle)
+ ObCloseHandle(KmFileHandle, KernelMode);
+
+ return Status;
}
NTSTATUS
NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
IN ULONG Flags)
{
-#if 0
NTSTATUS Status;
- OBJECT_ATTRIBUTES ObjectAttributes;
+ OBJECT_ATTRIBUTES CapturedTargetKey;
UNICODE_STRING ObjectName;
+ HANDLE KmTargetKeyRootDir = NULL;
CM_PARSE_CONTEXT ParseContext = {0};
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PCM_KEY_BODY KeyBody = NULL;
ULONG ParentConv = 0, ChildConv = 0;
HANDLE Handle;
+
PAGED_CODE();
/* Validate privilege */
if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
{
- /* Fail */
DPRINT1("Restore Privilege missing!\n");
return STATUS_PRIVILEGE_NOT_HELD;
}
sizeof(OBJECT_ATTRIBUTES),
sizeof(ULONG));
- ObjectAttributes = *TargetKey;
+ CapturedTargetKey = *TargetKey;
/* Probe the string */
- ProbeForReadUnicodeString(&TargetKey->ObjectName);
-
- ObjectName = *TargetKey->ObjectName;
-
+ ObjectName = ProbeForReadUnicodeString(CapturedTargetKey.ObjectName);
ProbeForRead(ObjectName.Buffer,
ObjectName.Length,
sizeof(WCHAR));
- ObjectAttributes.ObjectName = &ObjectName;
+ CapturedTargetKey.ObjectName = &ObjectName;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
else
{
/* Save the target attributes directly */
- ObjectAttributes = *TargetKey;
+ CapturedTargetKey = *TargetKey;
}
+ /* Make sure the target key root directory handle is a kernel handle */
+ Status = CmpConvertHandleToKernelHandle(CapturedTargetKey.RootDirectory,
+ CmpKeyObjectType,
+ KEY_WRITE,
+ PreviousMode,
+ &KmTargetKeyRootDir);
+ if (!NT_SUCCESS(Status))
+ return Status;
+ CapturedTargetKey.RootDirectory = KmTargetKeyRootDir;
+ CapturedTargetKey.Attributes |= OBJ_KERNEL_HANDLE;
+
/* Setup the parse context */
ParseContext.CreateOperation = TRUE;
ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
/* Do the create */
- Status = ObOpenObjectByName(&ObjectAttributes,
+ /* Open a local handle to the key */
+ Status = ObOpenObjectByName(&CapturedTargetKey,
CmpKeyObjectType,
KernelMode,
NULL,
KEY_WRITE,
&ParseContext,
&Handle);
+ if (NT_SUCCESS(Status))
+ {
+ /* Reference the key object */
+ Status = ObReferenceObjectByHandle(Handle,
+ KEY_WRITE,
+ CmpKeyObjectType,
+ KernelMode,
+ (PVOID*)&KeyBody,
+ NULL);
- /* Return if failure encountered */
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Reference it */
- Status = ObReferenceObjectByHandle(Handle,
- KEY_WRITE,
- CmpKeyObjectType,
- KernelMode,
- (PVOID *)&KeyBody,
- NULL);
+ /* Close the handle */
+ ObCloseHandle(Handle, KernelMode);
+ }
- /* Close the handle */
- ZwClose(Handle);
+ /* Close the local kernel handle */
+ if (KmTargetKeyRootDir)
+ ObCloseHandle(KmTargetKeyRootDir, KernelMode);
- /* Return if failure encountered */
- if (!NT_SUCCESS(Status)) return Status;
+ /* Return if a failure was encountered */
+ if (!NT_SUCCESS(Status))
+ return Status;
/* Acquire the lock depending on flags */
if (Flags == REG_FORCE_UNLOAD)
{
/* Return appropriate status */
Status = STATUS_KEY_DELETED;
- goto Quickie;
+ goto Quit;
}
- /* Check if it's a readonly key */
+ /* Check if it's a read-only key */
if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
{
/* Return appropriate status */
Status = STATUS_ACCESS_DENIED;
- goto Quickie;
+ goto Quit;
}
- /* Call the internal API */
- Status = CmUnloadKey(KeyBody->KeyControlBlock,
- Flags);
+ /* Call the internal API. Note that CmUnloadKey() unlocks the registry only on success. */
+ Status = CmUnloadKey(KeyBody->KeyControlBlock, Flags);
/* Check if we failed, but really need to succeed */
if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD))
{
/* TODO: We should perform another attempt here */
- ASSERT(FALSE);
+ _SEH2_TRY
+ {
+ DPRINT1("NtUnloadKey2(%wZ): We want to force-unload the hive but couldn't unload it: Retrying is UNIMPLEMENTED!\n", TargetKey->ObjectName);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ _SEH2_END;
}
- /* If CmUnloadKey failed we need to unlock registry ourselves */
+ /* If CmUnloadKey() failed we need to unlock registry ourselves */
if (!NT_SUCCESS(Status))
{
if (Flags != REG_FORCE_UNLOAD)
{
+ /* Release the KCB locks */
+ CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv);
+
/* Release the hive loading lock */
ExReleasePushLockExclusive(&CmpLoadHiveLock);
-
- /* Release two KCBs lock */
- CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv);
}
/* Unlock the registry */
CmpUnlockRegistry();
}
-Quickie:
+Quit:
/* Dereference the key */
ObDereferenceObject(KeyBody);
/* Return status */
return Status;
-#else
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-#endif
}
NTSTATUS