reactos/ntoskrnl/wmi/guidobj.c
Thomas Faber 5e891f727f
[NTOS:WMI] WMIP_GUID_OBJECT must start with an event object, as it is waitable.
The initializer for WmipGuidObjectType does not set UseDefaultObject,
and it's possible for user mode to obtain a handle to a GUID object
with SYNCHRONIZE access. Therefore that handle can be passed to
NtWaitForSingleObject, which means it must start with a DISPATCHER_HEADER.
2020-02-15 20:43:26 +01:00

302 lines
8.8 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/wmi/guidobj.c
* PURPOSE: I/O Windows Management Instrumentation (WMI) Support
* PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#include <wmistr.h>
#include "wmip.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ******************************************************************/
POBJECT_TYPE WmipGuidObjectType;
GENERIC_MAPPING WmipGenericMapping =
{
WMIGUID_QUERY,
WMIGUID_SET,
WMIGUID_EXECUTE,
WMIGUID_ALL_ACCESS
};
/* FUNCTIONS *****************************************************************/
NTSTATUS
NTAPI
WmipSecurityMethod(
_In_ PVOID Object,
_In_ SECURITY_OPERATION_CODE OperationType,
_In_ PSECURITY_INFORMATION SecurityInformation,
_In_ PSECURITY_DESCRIPTOR SecurityDescriptor,
_Inout_ PULONG CapturedLength,
_Inout_ PSECURITY_DESCRIPTOR *ObjectSecurityDescriptor,
_In_ POOL_TYPE PoolType,
_In_ PGENERIC_MAPPING GenericMapping)
{
PAGED_CODE();
ASSERT((PoolType == PagedPool) || (PoolType == NonPagedPool));
ASSERT((OperationType == QuerySecurityDescriptor) ||
(OperationType == SetSecurityDescriptor) ||
(OperationType == AssignSecurityDescriptor) ||
(OperationType == DeleteSecurityDescriptor));
if (OperationType == QuerySecurityDescriptor)
{
return ObQuerySecurityDescriptorInfo(Object,
SecurityInformation,
SecurityDescriptor,
CapturedLength,
ObjectSecurityDescriptor);
}
else if (OperationType == SetSecurityDescriptor)
{
return ObSetSecurityDescriptorInfo(Object,
SecurityInformation,
SecurityDescriptor,
ObjectSecurityDescriptor,
PoolType,
GenericMapping);
}
else if (OperationType == AssignSecurityDescriptor)
{
ObAssignObjectSecurityDescriptor(Object, SecurityDescriptor, PoolType);
return STATUS_SUCCESS;
}
else if (OperationType == DeleteSecurityDescriptor)
{
return ObDeassignSecurity(ObjectSecurityDescriptor);
}
ASSERT(FALSE);
return STATUS_INVALID_PARAMETER;
}
VOID
NTAPI
WmipDeleteMethod(
_In_ PVOID Object)
{
PWMIP_GUID_OBJECT GuidObject = Object;
/* Check if the object is attached to an IRP */
if (GuidObject->Irp != NULL)
{
/* This is not supported yet */
ASSERT(FALSE);
}
}
VOID
NTAPI
WmipCloseMethod(
_In_opt_ PEPROCESS Process,
_In_ PVOID Object,
_In_ ACCESS_MASK GrantedAccess,
_In_ ULONG ProcessHandleCount,
_In_ ULONG SystemHandleCount)
{
/* For now nothing */
}
NTSTATUS
NTAPI
WmipInitializeGuidObjectType(
VOID)
{
static UNICODE_STRING GuidObjectName = RTL_CONSTANT_STRING(L"WmiGuid");
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
NTSTATUS Status;
/* Setup the object type initializer */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
ObjectTypeInitializer.GenericMapping = WmipGenericMapping;
ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.MaintainHandleCount = FALSE;
ObjectTypeInitializer.ValidAccessMask = STANDARD_RIGHTS_ALL | 0xFFF;
ObjectTypeInitializer.SecurityRequired = TRUE;
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(WMIP_GUID_OBJECT);
ObjectTypeInitializer.SecurityProcedure = WmipSecurityMethod;
ObjectTypeInitializer.DeleteProcedure = WmipDeleteMethod;
ObjectTypeInitializer.CloseProcedure = WmipCloseMethod;
/* Create the object type */
Status = ObCreateObjectType(&GuidObjectName,
&ObjectTypeInitializer,
0,
&WmipGuidObjectType);
if (!NT_SUCCESS(Status))
{
DPRINT1("ObCreateObjectType failed: 0x%lx\n", Status);
}
return Status;
}
static
NTSTATUS
WmipGUIDFromString(
_In_ PUNICODE_STRING GuidString,
_Out_ PGUID Guid)
{
WCHAR Buffer[GUID_STRING_LENGTH + 2];
UNICODE_STRING String;
/* Validate string length */
if (GuidString->Length != GUID_STRING_LENGTH * sizeof(WCHAR))
{
return STATUS_INVALID_PARAMETER;
}
/* Copy the string and wrap it in {} */
RtlCopyMemory(&Buffer[1], GuidString->Buffer, GuidString->Length);
Buffer[0] = L'{';
Buffer[GUID_STRING_LENGTH + 1] = L'}';
String.Buffer = Buffer;
String.Length = String.MaximumLength = sizeof(Buffer);
return RtlGUIDFromString(&String, Guid);
}
static
NTSTATUS
WmipCreateGuidObject(
_In_ const GUID *Guid,
_Out_ PWMIP_GUID_OBJECT *OutGuidObject)
{
OBJECT_ATTRIBUTES ObjectAttributes;
PWMIP_GUID_OBJECT GuidObject;
NTSTATUS Status;
/* Initialize object attributes for an unnamed object */
InitializeObjectAttributes(&ObjectAttributes,
NULL,
0,
NULL,
NULL); // FIXME: security descriptor!
/* Create the GUID object */
Status = ObCreateObject(KernelMode,
WmipGuidObjectType,
&ObjectAttributes,
KernelMode,
NULL,
sizeof(WMIP_GUID_OBJECT),
0,
0,
(PVOID*)&GuidObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("WMI: failed to create GUID object: 0x%lx\n", Status);
return Status;
}
RtlZeroMemory(GuidObject, sizeof(*GuidObject));
KeInitializeEvent(&GuidObject->Event, NotificationEvent, FALSE);
GuidObject->Guid = *Guid;
*OutGuidObject = GuidObject;
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
WmipOpenGuidObject(
_In_ LPCGUID Guid,
_In_ ACCESS_MASK DesiredAccess,
_In_ KPROCESSOR_MODE AccessMode,
_Out_ PHANDLE OutGuidObjectHandle,
_Outptr_ PVOID *OutGuidObject)
{
PWMIP_GUID_OBJECT GuidObject;
ULONG HandleAttributes;
NTSTATUS Status;
/* Create the GUID object */
Status = WmipCreateGuidObject(Guid, &GuidObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create GUID object: 0x%lx\n", Status);
*OutGuidObject = NULL;
return Status;
}
/* Set handle attributes */
HandleAttributes = (AccessMode == KernelMode) ? OBJ_KERNEL_HANDLE : 0;
/* Get a handle for the object */
Status = ObOpenObjectByPointer(GuidObject,
HandleAttributes,
0,
DesiredAccess,
WmipGuidObjectType,
AccessMode,
OutGuidObjectHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("ObOpenObjectByPointer failed: 0x%lx\n", Status);
ObDereferenceObject(GuidObject);
GuidObject = NULL;
}
*OutGuidObject = GuidObject;
return Status;
}
NTSTATUS
NTAPI
WmipOpenGuidObjectByName(
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ ACCESS_MASK DesiredAccess,
_In_ KPROCESSOR_MODE AccessMode,
_Out_ PHANDLE OutGuidObjectHandle,
_Outptr_ PVOID *OutGuidObject)
{
static UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\WmiGuid\\");
UNICODE_STRING GuidString;
NTSTATUS Status;
GUID Guid;
PAGED_CODE();
/* Check if we have the expected prefix */
if (!RtlPrefixUnicodeString(&Prefix, ObjectAttributes->ObjectName, FALSE))
{
DPRINT1("WMI: Invalid prefix for guid object '%wZ'\n",
ObjectAttributes->ObjectName);
return STATUS_INVALID_PARAMETER;
}
/* Extract the GUID string */
GuidString = *ObjectAttributes->ObjectName;
GuidString.Buffer += Prefix.Length / sizeof(WCHAR);
GuidString.Length -= Prefix.Length;
/* Convert the string into a GUID structure */
Status = WmipGUIDFromString(&GuidString, &Guid);
if (!NT_SUCCESS(Status))
{
DPRINT1("WMI: Invalid uuid format for guid '%wZ'\n", &GuidString);
return Status;
}
return WmipOpenGuidObject(&Guid,
DesiredAccess,
AccessMode,
OutGuidObjectHandle,
OutGuidObject);
}