2006-05-24 22:07:11 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Kernel
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
|
|
* FILE: ntoskrnl/ob/create.c
|
|
|
|
* PURPOSE: Manages the lifetime of an Object, including its creation,
|
|
|
|
* and deletion, as well as setting or querying any of its
|
|
|
|
* information while it is active. Since Object Types are also
|
|
|
|
* Objects, those are also managed here.
|
|
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
|
|
* Eric Kohl
|
|
|
|
* Thomas Weidenmueller (w3seek@reactos.org)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
|
|
|
#include <ntoskrnl.h>
|
|
|
|
#define NDEBUG
|
|
|
|
#include <internal/debug.h>
|
|
|
|
|
|
|
|
extern ULONG NtGlobalFlag;
|
|
|
|
|
|
|
|
POBJECT_TYPE ObTypeObjectType = NULL;
|
|
|
|
KEVENT ObpDefaultObject;
|
2006-05-29 03:32:43 +00:00
|
|
|
|
|
|
|
NPAGED_LOOKASIDE_LIST ObpNmLookasideList, ObpCiLookasideList;
|
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
WORK_QUEUE_ITEM ObpReaperWorkItem;
|
|
|
|
volatile PVOID ObpReaperList;
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
VOID
|
|
|
|
FASTCALL
|
|
|
|
ObpDeallocateObject(IN PVOID Object)
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
PVOID HeaderLocation;
|
|
|
|
POBJECT_HEADER Header;
|
|
|
|
POBJECT_TYPE ObjectType;
|
2006-05-24 22:07:11 +00:00
|
|
|
POBJECT_HEADER_HANDLE_INFO HandleInfo;
|
|
|
|
POBJECT_HEADER_NAME_INFO NameInfo;
|
|
|
|
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
|
2006-05-29 00:05:07 +00:00
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
/* Get the header and assume this is what we'll free */
|
|
|
|
Header = OBJECT_TO_OBJECT_HEADER(Object);
|
|
|
|
ObjectType = Header->Type;
|
|
|
|
HeaderLocation = Header;
|
2006-05-24 22:07:11 +00:00
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* To find the header, walk backwards from how we allocated */
|
|
|
|
if ((CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header)))
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
HeaderLocation = CreatorInfo;
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
2006-05-29 00:05:07 +00:00
|
|
|
if ((NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header)))
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
HeaderLocation = NameInfo;
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
2006-05-29 00:05:07 +00:00
|
|
|
if ((HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(Header)))
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
HeaderLocation = HandleInfo;
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Check if we have create info */
|
|
|
|
if (Header->Flags & OB_FLAG_CREATE_INFO)
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Double-check that it exists */
|
|
|
|
if (Header->ObjectCreateInfo)
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Free it */
|
2006-05-29 03:32:43 +00:00
|
|
|
ObpFreeAndReleaseCapturedAttributes(Header->ObjectCreateInfo);
|
2006-05-29 00:05:07 +00:00
|
|
|
Header->ObjectCreateInfo = NULL;
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Check if a handle database was active */
|
|
|
|
if ((HandleInfo) && (Header->Flags & OB_FLAG_SINGLE_PROCESS))
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Free it */
|
|
|
|
ExFreePool(HandleInfo->HandleCountDatabase);
|
|
|
|
HandleInfo->HandleCountDatabase = NULL;
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
2006-05-29 00:05:07 +00:00
|
|
|
|
|
|
|
/* Check if we have a name */
|
|
|
|
if ((NameInfo) && (NameInfo->Name.Buffer))
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Free it */
|
|
|
|
ExFreePool(NameInfo->Name.Buffer);
|
|
|
|
NameInfo->Name.Buffer = NULL;
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Free the object using the same allocation tag */
|
|
|
|
ExFreePoolWithTag(HeaderLocation,
|
|
|
|
ObjectType ? TAG('T', 'j', 'b', 'O') : ObjectType->Key);
|
2006-05-24 22:07:11 +00:00
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Decrease the total */
|
|
|
|
ObjectType->TotalNumberOfObjects--;
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
VOID
|
|
|
|
FASTCALL
|
|
|
|
ObpDeleteObject(IN PVOID Object)
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
POBJECT_HEADER Header;
|
|
|
|
POBJECT_TYPE ObjectType;
|
|
|
|
POBJECT_HEADER_NAME_INFO NameInfo;
|
|
|
|
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
|
|
|
|
PAGED_CODE();
|
2006-05-24 22:07:11 +00:00
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Get the header and type */
|
|
|
|
Header = OBJECT_TO_OBJECT_HEADER(Object);
|
|
|
|
ObjectType = Header->Type;
|
2006-05-24 22:07:11 +00:00
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Get creator and name information */
|
|
|
|
NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header);
|
|
|
|
CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(Header);
|
2006-05-24 22:07:11 +00:00
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Check if the object is on a type list */
|
|
|
|
if ((CreatorInfo) && !(IsListEmpty(&CreatorInfo->TypeList)))
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Remove the object from the type list */
|
|
|
|
RemoveEntryList(&CreatorInfo->TypeList);
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Check if we have a name */
|
|
|
|
if ((NameInfo) && (NameInfo->Name.Buffer))
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Free it */
|
|
|
|
ExFreePool(NameInfo->Name.Buffer);
|
|
|
|
|
|
|
|
/* Clean up the string so we don't try this again */
|
|
|
|
RtlInitUnicodeString(&NameInfo->Name, NULL);
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Check if we have a security descriptor */
|
|
|
|
if (Header->SecurityDescriptor)
|
|
|
|
{
|
|
|
|
ObjectType->TypeInfo.SecurityProcedure(Object,
|
|
|
|
DeleteSecurityDescriptor,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&Header->SecurityDescriptor,
|
|
|
|
0,
|
|
|
|
NULL);
|
|
|
|
}
|
2006-05-24 22:07:11 +00:00
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Check if we have a delete procedure */
|
|
|
|
if (ObjectType->TypeInfo.DeleteProcedure)
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Call it */
|
|
|
|
ObjectType->TypeInfo.DeleteProcedure(Object);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now de-allocate all object members */
|
|
|
|
ObpDeallocateObject(Object);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
ObpReapObject(IN PVOID Parameter)
|
|
|
|
{
|
|
|
|
POBJECT_HEADER ReapObject;
|
|
|
|
PVOID NextObject;
|
2006-05-24 22:07:11 +00:00
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Start reaping */
|
|
|
|
while((ReapObject = InterlockedExchangePointer(&ObpReaperList, NULL)))
|
|
|
|
{
|
|
|
|
/* Start deletion loop */
|
|
|
|
do
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Get the next object */
|
|
|
|
NextObject = ReapObject->NextToFree;
|
2006-05-24 22:07:11 +00:00
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Delete the object */
|
|
|
|
ObpDeleteObject(&ReapObject->Body);
|
2006-05-24 22:07:11 +00:00
|
|
|
|
2006-05-29 00:05:07 +00:00
|
|
|
/* Move to the next one */
|
|
|
|
ReapObject = NextObject;
|
|
|
|
} while(NextObject != NULL);
|
|
|
|
}
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2006-05-29 03:32:43 +00:00
|
|
|
NTAPI
|
2006-05-24 22:07:11 +00:00
|
|
|
ObpCaptureObjectName(IN OUT PUNICODE_STRING CapturedName,
|
|
|
|
IN PUNICODE_STRING ObjectName,
|
2006-05-29 03:32:43 +00:00
|
|
|
IN KPROCESSOR_MODE AccessMode,
|
|
|
|
IN BOOLEAN AllocateFromLookaside)
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2006-05-29 03:32:43 +00:00
|
|
|
ULONG StringLength, MaximumLength;
|
2006-05-24 22:07:11 +00:00
|
|
|
PWCHAR StringBuffer = NULL;
|
|
|
|
UNICODE_STRING LocalName = {}; /* <= GCC 4.0 + Optimizer */
|
2006-05-29 03:32:43 +00:00
|
|
|
PAGED_CODE();
|
|
|
|
|
2006-05-24 22:07:11 +00:00
|
|
|
/* Initialize the Input String */
|
2006-05-29 03:32:43 +00:00
|
|
|
RtlInitEmptyUnicodeString(CapturedName, NULL, 0);
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
/* Protect everything */
|
|
|
|
_SEH_TRY
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Check if we came from user mode */
|
2006-05-24 22:07:11 +00:00
|
|
|
if (AccessMode != KernelMode)
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* First Probe the String */
|
|
|
|
ProbeForReadUnicodeString(ObjectName);
|
2006-05-24 22:07:11 +00:00
|
|
|
LocalName = *ObjectName;
|
|
|
|
ProbeForRead(LocalName.Buffer,
|
|
|
|
LocalName.Length,
|
|
|
|
sizeof(WCHAR));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No probing needed */
|
|
|
|
LocalName = *ObjectName;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure there really is a string */
|
|
|
|
if ((StringLength = LocalName.Length))
|
|
|
|
{
|
|
|
|
/* Check that the size is a valid WCHAR multiple */
|
|
|
|
if ((StringLength & (sizeof(WCHAR) - 1)) ||
|
|
|
|
/* Check that the NULL-termination below will work */
|
2006-05-29 03:32:43 +00:00
|
|
|
(StringLength == (MAXUSHORT - sizeof(UNICODE_NULL) + 1)))
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
|
|
|
/* PS: Please keep the checks above expanded for clarity */
|
|
|
|
DPRINT1("Invalid String Length\n");
|
|
|
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Set the maximum length to the length plus the terminator */
|
|
|
|
MaximumLength = StringLength + sizeof(UNICODE_NULL);
|
|
|
|
|
|
|
|
/* Check if we should use the lookaside buffer */
|
|
|
|
//if (!(AllocateFromLookaside) || (MaximumLength > 248))
|
|
|
|
{
|
|
|
|
/* Nope, allocate directly from pool */
|
|
|
|
StringBuffer = ExAllocatePoolWithTag(NonPagedPool,
|
|
|
|
MaximumLength,
|
|
|
|
OB_NAME_TAG);
|
|
|
|
}
|
|
|
|
//else
|
|
|
|
{
|
|
|
|
/* Allocate from the lookaside */
|
|
|
|
// MaximumLength = 248;
|
|
|
|
// StringBuffer =
|
|
|
|
// ObpAllocateCapturedAttributes(LookasideNameBufferList);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup the string */
|
2006-05-24 22:07:11 +00:00
|
|
|
CapturedName->Length = StringLength;
|
2006-05-29 03:32:43 +00:00
|
|
|
CapturedName->MaximumLength = MaximumLength;
|
|
|
|
CapturedName->Buffer = StringBuffer;
|
|
|
|
|
|
|
|
/* Make sure we have a buffer */
|
|
|
|
if (StringBuffer)
|
|
|
|
{
|
2006-05-24 22:07:11 +00:00
|
|
|
/* Copy the string and null-terminate it */
|
|
|
|
RtlMoveMemory(StringBuffer, LocalName.Buffer, StringLength);
|
|
|
|
StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Fail */
|
|
|
|
DPRINT1("Out of Memory!\n");
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
|
|
|
|
{
|
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
if (StringBuffer) ExFreePool(StringBuffer);
|
|
|
|
}
|
|
|
|
_SEH_END;
|
2006-05-29 03:32:43 +00:00
|
|
|
|
2006-05-24 22:07:11 +00:00
|
|
|
/* Return */
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2006-05-29 03:32:43 +00:00
|
|
|
NTAPI
|
2006-05-24 22:07:11 +00:00
|
|
|
ObpCaptureObjectAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
|
|
IN KPROCESSOR_MODE AccessMode,
|
2006-05-29 03:32:43 +00:00
|
|
|
IN BOOLEAN AllocateFromLookaside,
|
2006-05-24 22:07:11 +00:00
|
|
|
IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
|
|
|
|
OUT PUNICODE_STRING ObjectName)
|
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
|
|
|
PSECURITY_QUALITY_OF_SERVICE SecurityQos;
|
|
|
|
PUNICODE_STRING LocalObjectName = NULL;
|
2006-05-29 03:32:43 +00:00
|
|
|
PAGED_CODE();
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
/* Zero out the Capture Data */
|
|
|
|
RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
|
2006-05-29 03:32:43 +00:00
|
|
|
|
2006-05-24 22:07:11 +00:00
|
|
|
/* SEH everything here for protection */
|
|
|
|
_SEH_TRY
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Check if we got attributes */
|
2006-05-24 22:07:11 +00:00
|
|
|
if (ObjectAttributes)
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Check if we're in user mode */
|
2006-05-24 22:07:11 +00:00
|
|
|
if (AccessMode != KernelMode)
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Probe the attributes */
|
2006-05-24 22:07:11 +00:00
|
|
|
ProbeForRead(ObjectAttributes,
|
|
|
|
sizeof(OBJECT_ATTRIBUTES),
|
|
|
|
sizeof(ULONG));
|
|
|
|
}
|
2006-05-29 03:32:43 +00:00
|
|
|
|
2006-05-24 22:07:11 +00:00
|
|
|
/* Validate the Size and Attributes */
|
|
|
|
if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
|
|
|
|
(ObjectAttributes->Attributes & ~OBJ_VALID_ATTRIBUTES))
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Invalid combination, fail */
|
2006-05-24 22:07:11 +00:00
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
_SEH_LEAVE;
|
|
|
|
}
|
2006-05-29 03:32:43 +00:00
|
|
|
|
2006-05-24 22:07:11 +00:00
|
|
|
/* Set some Create Info */
|
|
|
|
ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
|
|
|
|
ObjectCreateInfo->Attributes = ObjectAttributes->Attributes;
|
|
|
|
LocalObjectName = ObjectAttributes->ObjectName;
|
|
|
|
SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
|
|
|
|
SecurityQos = ObjectAttributes->SecurityQualityOfService;
|
2006-05-29 03:32:43 +00:00
|
|
|
|
|
|
|
/* Check if we have a security descriptor */
|
2006-05-24 22:07:11 +00:00
|
|
|
if (SecurityDescriptor)
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Capture it */
|
2006-05-24 22:07:11 +00:00
|
|
|
Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
|
|
|
|
AccessMode,
|
|
|
|
NonPagedPool,
|
|
|
|
TRUE,
|
2006-05-29 03:32:43 +00:00
|
|
|
&ObjectCreateInfo->
|
|
|
|
SecurityDescriptor);
|
2006-05-24 22:07:11 +00:00
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Capture failed, quit */
|
2006-05-24 22:07:11 +00:00
|
|
|
ObjectCreateInfo->SecurityDescriptor = NULL;
|
|
|
|
_SEH_LEAVE;
|
|
|
|
}
|
2006-05-29 03:32:43 +00:00
|
|
|
|
|
|
|
/* Save the probe mode and security descriptor size */
|
2006-05-24 22:07:11 +00:00
|
|
|
ObjectCreateInfo->SecurityDescriptorCharge = 2048; /* FIXME */
|
|
|
|
ObjectCreateInfo->ProbeMode = AccessMode;
|
|
|
|
}
|
2006-05-29 03:32:43 +00:00
|
|
|
|
|
|
|
/* Check if we have QoS */
|
2006-05-24 22:07:11 +00:00
|
|
|
if (SecurityQos)
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Check if we came from user mode */
|
2006-05-24 22:07:11 +00:00
|
|
|
if (AccessMode != KernelMode)
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Validate the QoS */
|
2006-05-24 22:07:11 +00:00
|
|
|
ProbeForRead(SecurityQos,
|
|
|
|
sizeof(SECURITY_QUALITY_OF_SERVICE),
|
|
|
|
sizeof(ULONG));
|
|
|
|
}
|
2006-05-29 03:32:43 +00:00
|
|
|
|
2006-05-24 22:07:11 +00:00
|
|
|
/* Save Info */
|
|
|
|
ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
|
2006-05-29 03:32:43 +00:00
|
|
|
ObjectCreateInfo->SecurityQos =
|
|
|
|
&ObjectCreateInfo->SecurityQualityOfService;
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* We don't have a name */
|
2006-05-24 22:07:11 +00:00
|
|
|
LocalObjectName = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
|
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Get the exception */
|
2006-05-24 22:07:11 +00:00
|
|
|
Status = _SEH_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH_END;
|
|
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Now check if the Object Attributes had an Object Name */
|
|
|
|
if (LocalObjectName)
|
|
|
|
{
|
|
|
|
Status = ObpCaptureObjectName(ObjectName,
|
|
|
|
LocalObjectName,
|
2006-05-29 03:32:43 +00:00
|
|
|
AccessMode,
|
|
|
|
AllocateFromLookaside);
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Clear the string */
|
2006-05-29 03:32:43 +00:00
|
|
|
RtlInitEmptyUnicodeString(ObjectName, NULL, 0);
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
/* He can't have specified a Root Directory */
|
|
|
|
if (ObjectCreateInfo->RootDirectory)
|
|
|
|
{
|
|
|
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Cleanup if we failed */
|
|
|
|
if (!NT_SUCCESS(Status)) ObpReleaseCapturedAttributes(ObjectCreateInfo);
|
|
|
|
|
|
|
|
/* Return status to caller */
|
|
|
|
return Status;
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2006-05-29 00:18:36 +00:00
|
|
|
NTAPI
|
|
|
|
ObpAllocateObject(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo,
|
|
|
|
IN PUNICODE_STRING ObjectName,
|
|
|
|
IN POBJECT_TYPE ObjectType,
|
|
|
|
IN ULONG ObjectSize,
|
|
|
|
IN KPROCESSOR_MODE PreviousMode,
|
|
|
|
IN POBJECT_HEADER *ObjectHeader)
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
|
|
|
POBJECT_HEADER Header;
|
|
|
|
BOOLEAN HasHandleInfo = FALSE;
|
|
|
|
BOOLEAN HasNameInfo = FALSE;
|
|
|
|
BOOLEAN HasCreatorInfo = FALSE;
|
|
|
|
POBJECT_HEADER_HANDLE_INFO HandleInfo;
|
|
|
|
POBJECT_HEADER_NAME_INFO NameInfo;
|
|
|
|
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
|
|
|
|
POOL_TYPE PoolType;
|
|
|
|
ULONG FinalSize = ObjectSize;
|
|
|
|
ULONG Tag;
|
2006-05-29 00:18:36 +00:00
|
|
|
PAGED_CODE();
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
/* If we don't have an Object Type yet, force NonPaged */
|
|
|
|
if (!ObjectType)
|
|
|
|
{
|
|
|
|
PoolType = NonPagedPool;
|
|
|
|
Tag = TAG('O', 'b', 'j', 'T');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PoolType = ObjectType->TypeInfo.PoolType;
|
|
|
|
Tag = ObjectType->Key;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the Object has a name */
|
|
|
|
if (ObjectName->Buffer)
|
|
|
|
{
|
|
|
|
FinalSize += sizeof(OBJECT_HEADER_NAME_INFO);
|
|
|
|
HasNameInfo = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ObjectType)
|
|
|
|
{
|
|
|
|
/* Check if the Object maintains handle counts */
|
|
|
|
if (ObjectType->TypeInfo.MaintainHandleCount)
|
|
|
|
{
|
|
|
|
FinalSize += sizeof(OBJECT_HEADER_HANDLE_INFO);
|
|
|
|
HasHandleInfo = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the Object maintains type lists */
|
|
|
|
if (ObjectType->TypeInfo.MaintainTypeList)
|
|
|
|
{
|
|
|
|
FinalSize += sizeof(OBJECT_HEADER_CREATOR_INFO);
|
|
|
|
HasCreatorInfo = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate memory for the Object and Header */
|
|
|
|
Header = ExAllocatePoolWithTag(PoolType, FinalSize, Tag);
|
2006-05-29 00:18:36 +00:00
|
|
|
if (!Header) return STATUS_INSUFFICIENT_RESOURCES;
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
/* Initialize Handle Info */
|
|
|
|
if (HasHandleInfo)
|
|
|
|
{
|
|
|
|
HandleInfo = (POBJECT_HEADER_HANDLE_INFO)Header;
|
|
|
|
HandleInfo->SingleEntry.HandleCount = 0;
|
|
|
|
Header = (POBJECT_HEADER)(HandleInfo + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the Object Name Info */
|
|
|
|
if (HasNameInfo)
|
|
|
|
{
|
|
|
|
NameInfo = (POBJECT_HEADER_NAME_INFO)Header;
|
|
|
|
NameInfo->Name = *ObjectName;
|
|
|
|
NameInfo->Directory = NULL;
|
|
|
|
Header = (POBJECT_HEADER)(NameInfo + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize Creator Info */
|
|
|
|
if (HasCreatorInfo)
|
|
|
|
{
|
|
|
|
CreatorInfo = (POBJECT_HEADER_CREATOR_INFO)Header;
|
2006-05-29 00:18:36 +00:00
|
|
|
CreatorInfo->CreatorUniqueProcess = PsGetCurrentProcess() ?
|
|
|
|
PsGetCurrentProcessId() : 0;
|
2006-05-24 22:07:11 +00:00
|
|
|
InitializeListHead(&CreatorInfo->TypeList);
|
|
|
|
Header = (POBJECT_HEADER)(CreatorInfo + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the object header */
|
|
|
|
RtlZeroMemory(Header, ObjectSize);
|
|
|
|
Header->PointerCount = 1;
|
|
|
|
Header->Type = ObjectType;
|
|
|
|
Header->Flags = OB_FLAG_CREATE_INFO;
|
2006-05-29 00:18:36 +00:00
|
|
|
Header->ObjectCreateInfo = ObjectCreateInfo;
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
/* Set the Offsets for the Info */
|
|
|
|
if (HasHandleInfo)
|
|
|
|
{
|
2006-05-29 00:18:36 +00:00
|
|
|
Header->HandleInfoOffset = HasNameInfo *
|
|
|
|
sizeof(OBJECT_HEADER_NAME_INFO) +
|
2006-05-24 22:07:11 +00:00
|
|
|
sizeof(OBJECT_HEADER_HANDLE_INFO) +
|
2006-05-29 00:18:36 +00:00
|
|
|
HasCreatorInfo *
|
|
|
|
sizeof(OBJECT_HEADER_CREATOR_INFO);
|
|
|
|
|
|
|
|
/* Set the flag so we know when freeing */
|
2006-05-24 22:07:11 +00:00
|
|
|
Header->Flags |= OB_FLAG_SINGLE_PROCESS;
|
|
|
|
}
|
|
|
|
if (HasNameInfo)
|
|
|
|
{
|
|
|
|
Header->NameInfoOffset = sizeof(OBJECT_HEADER_NAME_INFO) +
|
2006-05-29 00:18:36 +00:00
|
|
|
HasCreatorInfo *
|
|
|
|
sizeof(OBJECT_HEADER_CREATOR_INFO);
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
|
|
|
if (HasCreatorInfo) Header->Flags |= OB_FLAG_CREATOR_INFO;
|
2006-05-29 00:18:36 +00:00
|
|
|
if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_PERMANENT))
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:18:36 +00:00
|
|
|
/* Set the needed flag so we can check */
|
2006-05-24 22:07:11 +00:00
|
|
|
Header->Flags |= OB_FLAG_PERMANENT;
|
|
|
|
}
|
2006-05-29 00:18:36 +00:00
|
|
|
if ((ObjectCreateInfo) && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE))
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:18:36 +00:00
|
|
|
/* Set the needed flag so we can check */
|
2006-05-24 22:07:11 +00:00
|
|
|
Header->Flags |= OB_FLAG_EXCLUSIVE;
|
|
|
|
}
|
2006-05-29 00:18:36 +00:00
|
|
|
if (PreviousMode == KernelMode)
|
|
|
|
{
|
|
|
|
/* Set the kernel flag */
|
|
|
|
Header->Flags |= OB_FLAG_KERNEL_MODE;
|
|
|
|
}
|
2006-05-24 22:07:11 +00:00
|
|
|
|
2006-05-29 00:18:36 +00:00
|
|
|
/* Increase the number of objects of this type */
|
|
|
|
if (ObjectType) ObjectType->TotalNumberOfObjects++;
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
/* Return Header */
|
|
|
|
*ObjectHeader = Header;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
ObpCreateTypeObject(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
|
|
|
|
PUNICODE_STRING TypeName,
|
|
|
|
POBJECT_TYPE *ObjectType)
|
|
|
|
{
|
|
|
|
POBJECT_HEADER Header;
|
|
|
|
POBJECT_TYPE LocalObjectType;
|
|
|
|
ULONG HeaderSize;
|
|
|
|
NTSTATUS Status;
|
2006-05-29 00:18:36 +00:00
|
|
|
CHAR Tag[4];
|
|
|
|
OBP_LOOKUP_CONTEXT Context;
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
/* Allocate the Object */
|
|
|
|
Status = ObpAllocateObject(NULL,
|
|
|
|
TypeName,
|
|
|
|
ObTypeObjectType,
|
2006-05-25 20:14:09 +00:00
|
|
|
sizeof(OBJECT_TYPE) + sizeof(OBJECT_HEADER),
|
2006-05-29 00:18:36 +00:00
|
|
|
KernelMode,
|
2006-05-24 22:07:11 +00:00
|
|
|
(POBJECT_HEADER*)&Header);
|
2006-05-29 00:18:36 +00:00
|
|
|
if (!NT_SUCCESS(Status)) return Status;
|
2006-05-24 22:07:11 +00:00
|
|
|
LocalObjectType = (POBJECT_TYPE)&Header->Body;
|
|
|
|
|
|
|
|
/* Check if this is the first Object Type */
|
|
|
|
if (!ObTypeObjectType)
|
|
|
|
{
|
|
|
|
ObTypeObjectType = LocalObjectType;
|
|
|
|
Header->Type = ObTypeObjectType;
|
2006-05-29 00:18:36 +00:00
|
|
|
LocalObjectType->TotalNumberOfObjects = 1;
|
2006-05-24 22:07:11 +00:00
|
|
|
LocalObjectType->Key = TAG('O', 'b', 'j', 'T');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-05-29 00:18:36 +00:00
|
|
|
/* Set Tag */
|
2006-05-24 22:07:11 +00:00
|
|
|
Tag[0] = TypeName->Buffer[0];
|
|
|
|
Tag[1] = TypeName->Buffer[1];
|
|
|
|
Tag[2] = TypeName->Buffer[2];
|
|
|
|
Tag[3] = TypeName->Buffer[3];
|
|
|
|
LocalObjectType->Key = *(PULONG)Tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set it up */
|
|
|
|
LocalObjectType->TypeInfo = *ObjectTypeInitializer;
|
|
|
|
LocalObjectType->Name = *TypeName;
|
|
|
|
LocalObjectType->TypeInfo.PoolType = ObjectTypeInitializer->PoolType;
|
|
|
|
|
|
|
|
/* These two flags need to be manually set up */
|
|
|
|
Header->Flags |= OB_FLAG_KERNEL_MODE | OB_FLAG_PERMANENT;
|
|
|
|
|
|
|
|
/* Check if we have to maintain a type list */
|
|
|
|
if (NtGlobalFlag & FLG_MAINTAIN_OBJECT_TYPELIST)
|
|
|
|
{
|
|
|
|
/* Enable support */
|
|
|
|
LocalObjectType->TypeInfo.MaintainTypeList = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate how much space our header'll take up */
|
|
|
|
HeaderSize = sizeof(OBJECT_HEADER) + sizeof(OBJECT_HEADER_NAME_INFO) +
|
|
|
|
(ObjectTypeInitializer->MaintainHandleCount ?
|
|
|
|
sizeof(OBJECT_HEADER_HANDLE_INFO) : 0);
|
|
|
|
|
|
|
|
/* Update the Pool Charges */
|
|
|
|
if (ObjectTypeInitializer->PoolType == NonPagedPool)
|
|
|
|
{
|
|
|
|
LocalObjectType->TypeInfo.DefaultNonPagedPoolCharge += HeaderSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LocalObjectType->TypeInfo.DefaultPagedPoolCharge += HeaderSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All objects types need a security procedure */
|
|
|
|
if (!ObjectTypeInitializer->SecurityProcedure)
|
|
|
|
{
|
|
|
|
LocalObjectType->TypeInfo.SecurityProcedure = SeDefaultObjectMethod;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Select the Wait Object */
|
|
|
|
if (LocalObjectType->TypeInfo.UseDefaultObject)
|
|
|
|
{
|
|
|
|
/* Add the SYNCHRONIZE access mask since it's waitable */
|
|
|
|
LocalObjectType->TypeInfo.ValidAccessMask |= SYNCHRONIZE;
|
|
|
|
|
|
|
|
/* Use the "Default Object", a simple event */
|
|
|
|
LocalObjectType->DefaultObject = &ObpDefaultObject;
|
|
|
|
}
|
|
|
|
/* Special system objects get an optimized hack so they can be waited on */
|
|
|
|
else if (TypeName->Length == 8 && !wcscmp(TypeName->Buffer, L"File"))
|
|
|
|
{
|
|
|
|
LocalObjectType->DefaultObject = (PVOID)FIELD_OFFSET(FILE_OBJECT, Event);
|
|
|
|
}
|
|
|
|
/* FIXME: When LPC stops sucking, add a hack for Waitable Ports */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No default Object */
|
|
|
|
LocalObjectType->DefaultObject = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize Object Type components */
|
|
|
|
ExInitializeResourceLite(&LocalObjectType->Mutex);
|
|
|
|
InitializeListHead(&LocalObjectType->TypeList);
|
|
|
|
|
|
|
|
/* Insert it into the Object Directory */
|
|
|
|
if (ObpTypeDirectoryObject)
|
|
|
|
{
|
|
|
|
Context.Directory = ObpTypeDirectoryObject;
|
|
|
|
Context.DirectoryLocked = TRUE;
|
|
|
|
ObpLookupEntryDirectory(ObpTypeDirectoryObject,
|
|
|
|
TypeName,
|
|
|
|
OBJ_CASE_INSENSITIVE,
|
|
|
|
FALSE,
|
|
|
|
&Context);
|
|
|
|
ObpInsertEntryDirectory(ObpTypeDirectoryObject, &Context, Header);
|
|
|
|
ObReferenceObject(ObpTypeDirectoryObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
*ObjectType = LocalObjectType;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
ObCreateObject(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL,
|
|
|
|
IN POBJECT_TYPE Type,
|
|
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
|
|
|
|
IN KPROCESSOR_MODE AccessMode,
|
|
|
|
IN OUT PVOID ParseContext OPTIONAL,
|
|
|
|
IN ULONG ObjectSize,
|
|
|
|
IN ULONG PagedPoolCharge OPTIONAL,
|
|
|
|
IN ULONG NonPagedPoolCharge OPTIONAL,
|
|
|
|
OUT PVOID *Object)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
POBJECT_CREATE_INFORMATION ObjectCreateInfo;
|
|
|
|
UNICODE_STRING ObjectName;
|
|
|
|
POBJECT_HEADER Header;
|
|
|
|
DPRINT("ObCreateObject(Type %p ObjectAttributes %p, Object %p)\n",
|
|
|
|
Type, ObjectAttributes, Object);
|
2006-05-25 20:14:09 +00:00
|
|
|
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Allocate a capture buffer */
|
|
|
|
ObjectCreateInfo = ObpAllocateCapturedAttributes(LookasideCreateInfoList);
|
2006-05-29 00:18:36 +00:00
|
|
|
if (!ObjectCreateInfo) return STATUS_INSUFFICIENT_RESOURCES;
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
/* Capture all the info */
|
|
|
|
Status = ObpCaptureObjectAttributes(ObjectAttributes,
|
|
|
|
ObjectAttributesAccessMode,
|
2006-05-29 03:32:43 +00:00
|
|
|
FALSE,
|
2006-05-24 22:07:11 +00:00
|
|
|
ObjectCreateInfo,
|
|
|
|
&ObjectName);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
2006-05-29 00:18:36 +00:00
|
|
|
/* Validate attributes */
|
|
|
|
if (Type->TypeInfo.InvalidAttributes &
|
|
|
|
ObjectCreateInfo->Attributes)
|
2006-05-24 22:07:11 +00:00
|
|
|
{
|
2006-05-29 00:18:36 +00:00
|
|
|
/* Fail */
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Save the pool charges */
|
|
|
|
ObjectCreateInfo->PagedPoolCharge = PagedPoolCharge;
|
|
|
|
ObjectCreateInfo->NonPagedPoolCharge = NonPagedPoolCharge;
|
|
|
|
|
|
|
|
/* Allocate the Object */
|
|
|
|
Status = ObpAllocateObject(ObjectCreateInfo,
|
|
|
|
&ObjectName,
|
|
|
|
Type,
|
|
|
|
ObjectSize + sizeof(OBJECT_HEADER),
|
|
|
|
AccessMode,
|
|
|
|
&Header);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Return the Object */
|
|
|
|
*Object = &Header->Body;
|
2006-05-29 03:32:43 +00:00
|
|
|
|
|
|
|
/* Check if this is a permanent object */
|
|
|
|
if (Header->Flags & OB_FLAG_PERMANENT)
|
|
|
|
{
|
|
|
|
/* Do the privilege check */
|
|
|
|
if (!SeSinglePrivilegeCheck(SeCreatePermanentPrivilege,
|
|
|
|
ObjectAttributesAccessMode))
|
2006-05-29 00:18:36 +00:00
|
|
|
{
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Fail */
|
|
|
|
ObpDeallocateObject(*Object);
|
|
|
|
Status = STATUS_PRIVILEGE_NOT_HELD;
|
2006-05-29 00:18:36 +00:00
|
|
|
}
|
2006-05-29 03:32:43 +00:00
|
|
|
}
|
2006-05-29 00:18:36 +00:00
|
|
|
|
2006-05-29 03:32:43 +00:00
|
|
|
/* Return status */
|
2006-05-29 00:18:36 +00:00
|
|
|
return Status;
|
|
|
|
}
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
2006-05-25 20:14:09 +00:00
|
|
|
|
2006-05-24 22:07:11 +00:00
|
|
|
/* Release the Capture Info, we don't need it */
|
|
|
|
ObpReleaseCapturedAttributes(ObjectCreateInfo);
|
2006-05-29 03:32:43 +00:00
|
|
|
if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName);
|
2006-05-24 22:07:11 +00:00
|
|
|
}
|
2006-05-25 20:14:09 +00:00
|
|
|
|
2006-05-24 22:07:11 +00:00
|
|
|
/* We failed, so release the Buffer */
|
2006-05-29 03:32:43 +00:00
|
|
|
ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
|
2006-05-24 22:07:11 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
* @name NtQueryObject
|
|
|
|
* @implemented NT4
|
|
|
|
*
|
|
|
|
* The NtQueryObject routine <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param ObjectHandle
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param ObjectInformationClass
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param ObjectInformation
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param Length
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param ResultLength
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @return STATUS_SUCCESS or appropriate error value.
|
|
|
|
*
|
|
|
|
* @remarks None.
|
|
|
|
*
|
|
|
|
*--*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtQueryObject(IN HANDLE ObjectHandle,
|
|
|
|
IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
|
|
|
OUT PVOID ObjectInformation,
|
|
|
|
IN ULONG Length,
|
|
|
|
OUT PULONG ResultLength OPTIONAL)
|
|
|
|
{
|
|
|
|
OBJECT_HANDLE_INFORMATION HandleInfo;
|
|
|
|
POBJECT_HEADER ObjectHeader;
|
|
|
|
ULONG InfoLength;
|
|
|
|
PVOID Object;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
Status = ObReferenceObjectByHandle(ObjectHandle,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
KeGetPreviousMode(),
|
|
|
|
&Object,
|
|
|
|
&HandleInfo);
|
|
|
|
if (!NT_SUCCESS (Status)) return Status;
|
|
|
|
|
2006-05-25 20:14:09 +00:00
|
|
|
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
|
2006-05-24 22:07:11 +00:00
|
|
|
|
|
|
|
switch (ObjectInformationClass)
|
|
|
|
{
|
|
|
|
case ObjectBasicInformation:
|
|
|
|
InfoLength = sizeof(OBJECT_BASIC_INFORMATION);
|
|
|
|
if (Length != sizeof(OBJECT_BASIC_INFORMATION))
|
|
|
|
{
|
|
|
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
POBJECT_BASIC_INFORMATION BasicInfo;
|
|
|
|
|
|
|
|
BasicInfo = (POBJECT_BASIC_INFORMATION)ObjectInformation;
|
|
|
|
BasicInfo->Attributes = HandleInfo.HandleAttributes;
|
|
|
|
BasicInfo->GrantedAccess = HandleInfo.GrantedAccess;
|
|
|
|
BasicInfo->HandleCount = ObjectHeader->HandleCount;
|
|
|
|
BasicInfo->PointerCount = ObjectHeader->PointerCount;
|
|
|
|
BasicInfo->PagedPoolUsage = 0; /* FIXME*/
|
|
|
|
BasicInfo->NonPagedPoolUsage = 0; /* FIXME*/
|
|
|
|
BasicInfo->NameInformationLength = 0; /* FIXME*/
|
|
|
|
BasicInfo->TypeInformationLength = 0; /* FIXME*/
|
|
|
|
BasicInfo->SecurityDescriptorLength = 0; /* FIXME*/
|
|
|
|
if (ObjectHeader->Type == ObSymbolicLinkType)
|
|
|
|
{
|
|
|
|
BasicInfo->CreateTime.QuadPart =
|
|
|
|
((POBJECT_SYMBOLIC_LINK)Object)->CreationTime.QuadPart;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BasicInfo->CreateTime.QuadPart = (ULONGLONG)0;
|
|
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ObjectNameInformation:
|
|
|
|
Status = ObQueryNameString(Object,
|
|
|
|
(POBJECT_NAME_INFORMATION)ObjectInformation,
|
|
|
|
Length,
|
|
|
|
&InfoLength);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ObjectTypeInformation:
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ObjectAllTypesInformation:
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ObjectHandleInformation:
|
|
|
|
InfoLength = sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION);
|
|
|
|
if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
|
|
|
|
{
|
|
|
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Status = ObpQueryHandleAttributes(
|
|
|
|
ObjectHandle,
|
|
|
|
(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)ObjectInformation);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Status = STATUS_INVALID_INFO_CLASS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ObDereferenceObject (Object);
|
|
|
|
|
|
|
|
if (ResultLength != NULL) *ResultLength = InfoLength;
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
* @name NtSetInformationObject
|
|
|
|
* @implemented NT4
|
|
|
|
*
|
|
|
|
* The NtSetInformationObject routine <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param ObjectHandle
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param ObjectInformationClass
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param ObjectInformation
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @param Length
|
|
|
|
* <FILLMEIN>
|
|
|
|
*
|
|
|
|
* @return STATUS_SUCCESS or appropriate error value.
|
|
|
|
*
|
|
|
|
* @remarks None.
|
|
|
|
*
|
|
|
|
*--*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
NtSetInformationObject(IN HANDLE ObjectHandle,
|
|
|
|
IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
|
|
|
IN PVOID ObjectInformation,
|
|
|
|
IN ULONG Length)
|
|
|
|
{
|
|
|
|
PVOID Object;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
if (ObjectInformationClass != ObjectHandleInformation)
|
|
|
|
return STATUS_INVALID_INFO_CLASS;
|
|
|
|
|
|
|
|
if (Length != sizeof (OBJECT_HANDLE_ATTRIBUTE_INFORMATION))
|
|
|
|
return STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
|
|
|
|
Status = ObReferenceObjectByHandle(ObjectHandle,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
KeGetPreviousMode(),
|
|
|
|
&Object,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS (Status)) return Status;
|
|
|
|
|
|
|
|
Status = ObpSetHandleAttributes(ObjectHandle,
|
|
|
|
(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)
|
|
|
|
ObjectInformation);
|
|
|
|
|
|
|
|
ObDereferenceObject (Object);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
/* EOF */
|