reactos/ntoskrnl/ob/obhandle.c
Art Yerkes c501d8112c Create a branch for network fixes.
svn path=/branches/aicom-network-fixes/; revision=34994
2008-08-01 11:32:26 +00:00

3299 lines
96 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ob/obhandle.c
* PURPOSE: Manages all functions related to the Object Manager handle
* implementation, including creating and destroying handles
* and/or handle tables, duplicating objects, and setting the
* permanent or temporary flags.
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Eric Kohl
* Thomas Weidenmueller (w3seek@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
PHANDLE_TABLE ObpKernelHandleTable = NULL;
ULONG ObpAccessProtectCloseBit = MAXIMUM_ALLOWED;
#define TAG_OB_HANDLE TAG('O', 'b', 'H', 'd')
/* PRIVATE FUNCTIONS *********************************************************/
PHANDLE_TABLE
NTAPI
ObReferenceProcessHandleTable(IN PEPROCESS Process)
{
PHANDLE_TABLE HandleTable = NULL;
/* Lock the process */
if (ExAcquireRundownProtection(&Process->RundownProtect))
{
/* Get the handle table */
HandleTable = Process->ObjectTable;
if (!HandleTable)
{
/* No table, release the lock */
ExReleaseRundownProtection(&Process->RundownProtect);
}
}
/* Return the handle table */
return HandleTable;
}
VOID
NTAPI
ObDereferenceProcessHandleTable(IN PEPROCESS Process)
{
/* Release the process lock */
ExReleaseRundownProtection(&Process->RundownProtect);
}
NTSTATUS
NTAPI
ObpReferenceProcessObjectByHandle(IN HANDLE Handle,
IN PEPROCESS Process,
IN PHANDLE_TABLE HandleTable,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation,
OUT PACCESS_MASK AuditMask)
{
PHANDLE_TABLE_ENTRY HandleEntry;
POBJECT_HEADER ObjectHeader;
ACCESS_MASK GrantedAccess;
ULONG Attributes;
PETHREAD Thread = PsGetCurrentThread();
NTSTATUS Status;
/* Assume failure */
*Object = NULL;
/* Check if this is a special handle */
if (HandleToLong(Handle) < 0)
{
/* Check if the caller wants the current process */
if (Handle == NtCurrentProcess())
{
/* Return handle info */
HandleInformation->HandleAttributes = 0;
HandleInformation->GrantedAccess = Process->GrantedAccess;
/* No audit mask */
*AuditMask = 0;
/* Reference ourselves */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Process);
InterlockedIncrement(&ObjectHeader->PointerCount);
/* Return the pointer */
*Object = Process;
ASSERT(*Object != NULL);
return STATUS_SUCCESS;
}
/* Check if the caller wants the current thread */
if (Handle == NtCurrentThread())
{
/* Return handle information */
HandleInformation->HandleAttributes = 0;
HandleInformation->GrantedAccess = Thread->GrantedAccess;
/* Reference ourselves */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Thread);
InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
/* No audit mask */
*AuditMask = 0;
/* Return the pointer */
*Object = Thread;
ASSERT(*Object != NULL);
return STATUS_SUCCESS;
}
/* This is a kernel handle... do we have access? */
if (AccessMode == KernelMode)
{
/* Use the kernel handle table and get the actual handle value */
Handle = ObKernelHandleToHandle(Handle);
HandleTable = ObpKernelHandleTable;
}
else
{
/* This is an illegal attempt to access a kernel handle */
return STATUS_INVALID_HANDLE;
}
}
/* Enter a critical region while we touch the handle table */
ASSERT(HandleTable != NULL);
KeEnterCriticalRegion();
/* Get the handle entry */
HandleEntry = ExMapHandleToPointer(HandleTable, Handle);
if (HandleEntry)
{
/* Get the object header and validate the type*/
ObjectHeader = ObpGetHandleObject(HandleEntry);
/* Get the granted access and validate it */
GrantedAccess = HandleEntry->GrantedAccess;
/* Mask out the internal attributes */
Attributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
/* Fill out the information */
HandleInformation->HandleAttributes = Attributes;
HandleInformation->GrantedAccess = GrantedAccess;
/* No audit mask (FIXME!) */
*AuditMask = 0;
/* Return the pointer */
*Object = &ObjectHeader->Body;
/* Add a reference */
InterlockedExchangeAdd(&ObjectHeader->PointerCount, 1);
/* Unlock the handle */
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
KeLeaveCriticalRegion();
/* Return success */
ASSERT(*Object != NULL);
return STATUS_SUCCESS;
}
else
{
/* Invalid handle */
Status = STATUS_INVALID_HANDLE;
}
/* Return failure status */
KeLeaveCriticalRegion();
return Status;
}
BOOLEAN
NTAPI
ObpEnumFindHandleProcedure(IN PHANDLE_TABLE_ENTRY HandleEntry,
IN HANDLE Handle,
IN PVOID Context)
{
POBJECT_HEADER ObjectHeader;
ACCESS_MASK GrantedAccess;
ULONG HandleAttributes;
POBP_FIND_HANDLE_DATA FindData = Context;
/* Get the object header */
ObjectHeader = ObpGetHandleObject(HandleEntry);
/* Make sure it's valid and matching */
if ((FindData->ObjectHeader) && (FindData->ObjectHeader != ObjectHeader))
{
/* No match, fail */
return FALSE;
}
/* Now attempt to match the object type */
if ((FindData->ObjectType) && (FindData->ObjectType != ObjectHeader->Type))
{
/* No match, fail */
return FALSE;
}
/* Check if we have extra information */
if (FindData->HandleInformation)
{
/* Get the granted access and attributes */
GrantedAccess = HandleEntry->GrantedAccess;
HandleAttributes = HandleEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES;
/* Attempt to match them */
if ((FindData->HandleInformation->HandleAttributes != HandleAttributes) ||
(FindData->HandleInformation->GrantedAccess != GrantedAccess))
{
/* No match, fail */
return FALSE;
}
}
/* We have a match */
return TRUE;
}
POBJECT_HANDLE_COUNT_ENTRY
NTAPI
ObpInsertHandleCount(IN POBJECT_HEADER ObjectHeader)
{
POBJECT_HEADER_HANDLE_INFO HandleInfo;
POBJECT_HANDLE_COUNT_ENTRY FreeEntry;
POBJECT_HANDLE_COUNT_DATABASE HandleDatabase, OldHandleDatabase;
ULONG i;
ULONG Size, OldSize;
OBJECT_HANDLE_COUNT_DATABASE SingleDatabase;
PAGED_CODE();
/* Get the handle info */
HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
if (!HandleInfo) return NULL;
/* Check if we only have one entry */
if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
{
/* Fill out the single entry */
SingleDatabase.CountEntries = 1;
SingleDatabase.HandleCountEntries[0] = HandleInfo->SingleEntry;
/* Use this as the old size */
OldHandleDatabase = &SingleDatabase;
OldSize = sizeof(SingleDatabase);
/* Now we'll have two entries, and an entire DB */
i = 2;
Size = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
((i - 1) * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
}
else
{
/* We already have a DB, get the information from it */
OldHandleDatabase = HandleInfo->HandleCountDatabase;
i = OldHandleDatabase->CountEntries;
OldSize = sizeof(OBJECT_HANDLE_COUNT_DATABASE) +
((i - 1) * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
/* Add 4 more entries */
i += 4;
Size = OldSize + (4 * sizeof(OBJECT_HANDLE_COUNT_ENTRY));
}
/* Allocate the DB */
HandleDatabase = ExAllocatePoolWithTag(PagedPool, Size, TAG_OB_HANDLE);
if (!HandleDatabase) return NULL;
/* Copy the old database */
RtlCopyMemory(HandleDatabase, OldHandleDatabase, OldSize);
/* Check if we he had a single entry before */
if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
{
/* Now we have more */
ObjectHeader->Flags &= ~OB_FLAG_SINGLE_PROCESS;
}
else
{
/* Otherwise we had a DB, free it */
ExFreePool(OldHandleDatabase);
}
/* Find the end of the copy and zero out the new data */
FreeEntry = (PVOID)((ULONG_PTR)HandleDatabase + OldSize);
RtlZeroMemory(FreeEntry, Size - OldSize);
/* Set the new information and return the free entry */
HandleDatabase->CountEntries = i;
HandleInfo->HandleCountDatabase = HandleDatabase;
return FreeEntry;
}
NTSTATUS
NTAPI
ObpIncrementHandleDataBase(IN POBJECT_HEADER ObjectHeader,
IN PEPROCESS Process,
IN OUT PULONG NewProcessHandleCount)
{
POBJECT_HEADER_HANDLE_INFO HandleInfo;
POBJECT_HANDLE_COUNT_ENTRY HandleEntry, FreeEntry = NULL;
POBJECT_HANDLE_COUNT_DATABASE HandleDatabase;
ULONG i;
PAGED_CODE();
/* Get the handle info and check if we only have one entry */
HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
{
/* Check if the entry is free */
if (!HandleInfo->SingleEntry.HandleCount)
{
/* Add ours */
HandleInfo->SingleEntry.HandleCount = 1;
HandleInfo->SingleEntry.Process = Process;
/* Return success and 1 handle */
*NewProcessHandleCount = 1;
return STATUS_SUCCESS;
}
else if (HandleInfo->SingleEntry.Process == Process)
{
/* Busy entry, but same process */
*NewProcessHandleCount = ++HandleInfo->SingleEntry.HandleCount;
return STATUS_SUCCESS;
}
else
{
/* Insert a new entry */
FreeEntry = ObpInsertHandleCount(ObjectHeader);
if (!FreeEntry) return STATUS_INSUFFICIENT_RESOURCES;
ASSERT(!FreeEntry->Process);
ASSERT(!FreeEntry->HandleCount);
/* Fill it out */
FreeEntry->Process = Process;
FreeEntry->HandleCount = 1;
/* Return success and 1 handle */
*NewProcessHandleCount = 1;
return STATUS_SUCCESS;
}
}
/* We have a database instead */
HandleDatabase = HandleInfo->HandleCountDatabase;
if (HandleDatabase)
{
/* Get the entries and loop them */
i = HandleDatabase->CountEntries;
HandleEntry = &HandleDatabase->HandleCountEntries[0];
while (i)
{
/* Check if this is a match */
if (HandleEntry->Process == Process)
{
/* Found it, get the process handle count */
*NewProcessHandleCount = ++HandleEntry->HandleCount;
return STATUS_SUCCESS;
}
else if (!HandleEntry->HandleCount)
{
/* Found a free entry */
FreeEntry = HandleEntry;
}
/* Keep looping */
HandleEntry++;
i--;
}
/* Check if we couldn't find a free entry */
if (!FreeEntry)
{
/* Allocate one */
FreeEntry = ObpInsertHandleCount(ObjectHeader);
if (!FreeEntry) return STATUS_INSUFFICIENT_RESOURCES;
ASSERT(!FreeEntry->Process);
ASSERT(!FreeEntry->HandleCount);
}
/* Fill out the entry */
FreeEntry->Process = Process;
FreeEntry->HandleCount = 1;
*NewProcessHandleCount = 1;
}
/* Return success if we got here */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
ObpChargeQuotaForObject(IN POBJECT_HEADER ObjectHeader,
IN POBJECT_TYPE ObjectType,
OUT PBOOLEAN NewObject)
{
POBJECT_HEADER_QUOTA_INFO ObjectQuota;
ULONG PagedPoolCharge, NonPagedPoolCharge;
/* Get quota information */
ObjectQuota = OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader);
*NewObject = FALSE;
/* Check if this is a new object */
if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
{
/* Remove the flag */
ObjectHeader->Flags &= ~ OB_FLAG_CREATE_INFO;
if (ObjectQuota)
{
/* We have a quota, get the charges */
PagedPoolCharge = ObjectQuota->PagedPoolCharge;
NonPagedPoolCharge = ObjectQuota->NonPagedPoolCharge;
}
else
{
/* Get it from the object type */
PagedPoolCharge = ObjectType->TypeInfo.DefaultPagedPoolCharge;
NonPagedPoolCharge = ObjectType->TypeInfo.DefaultNonPagedPoolCharge;
}
/* Charge the quota */
ObjectHeader->QuotaBlockCharged = (PVOID)1;
#if 0
PsChargeSharedPoolQuota(PsGetCurrentProcess(),
PagedPoolCharge,
NonPagedPoolCharge);
#endif
/* Check if we don't have a quota block */
if (!ObjectHeader->QuotaBlockCharged) return STATUS_QUOTA_EXCEEDED;
/* Now set the flag */
*NewObject = TRUE;
}
/* Return success */
return STATUS_SUCCESS;
}
/*++
* @name ObpDecrementHandleCount
*
* The ObpDecrementHandleCount routine <FILLMEIN>
*
* @param ObjectBody
* <FILLMEIN>.
*
* @param Process
* <FILLMEIN>.
*
* @param GrantedAccess
* <FILLMEIN>.
*
* @return None.
*
* @remarks None.
*
*--*/
VOID
NTAPI
ObpDecrementHandleCount(IN PVOID ObjectBody,
IN PEPROCESS Process,
IN ACCESS_MASK GrantedAccess,
IN POBJECT_TYPE ObjectType)
{
POBJECT_HEADER ObjectHeader;
LONG SystemHandleCount, ProcessHandleCount;
LONG NewCount;
KIRQL CalloutIrql;
POBJECT_HEADER_HANDLE_INFO HandleInfo;
POBJECT_HANDLE_COUNT_ENTRY HandleEntry;
POBJECT_HANDLE_COUNT_DATABASE HandleDatabase;
ULONG i;
PAGED_CODE();
/* Get the object type and header */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(ObjectBody);
OBTRACE(OB_HANDLE_DEBUG,
"%s - Decrementing count for: %p. HC LC %lx %lx\n",
__FUNCTION__,
ObjectBody,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
/* Lock the object */
ObpAcquireObjectLock(ObjectHeader);
/* Set default counts */
SystemHandleCount = ObjectHeader->HandleCount;
ProcessHandleCount = 0;
/* Decrement the handle count */
NewCount = InterlockedDecrement(&ObjectHeader->HandleCount);
/* Check if we're out of handles and this was an exclusive object */
if (!(NewCount) && (ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
{
/* Clear the exclusive flag */
OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = NULL;
}
/* Is the object type keeping track of handles? */
if (ObjectType->TypeInfo.MaintainHandleCount)
{
/* Get handle information */
HandleInfo = OBJECT_HEADER_TO_HANDLE_INFO(ObjectHeader);
/* Check if there's only a single entry */
if (ObjectHeader->Flags & OB_FLAG_SINGLE_PROCESS)
{
/* It should be us */
ASSERT(HandleInfo->SingleEntry.Process == Process);
ASSERT(HandleInfo->SingleEntry.HandleCount > 0);
/* Get the handle counts */
ProcessHandleCount = HandleInfo->SingleEntry.HandleCount--;
HandleEntry = &HandleInfo->SingleEntry;
}
else
{
/* Otherwise, get the database */
HandleDatabase = HandleInfo->HandleCountDatabase;
if (HandleDatabase)
{
/* Get the entries and loop them */
i = HandleDatabase->CountEntries;
HandleEntry = &HandleDatabase->HandleCountEntries[0];
while (i)
{
/* Check if this is a match */
if ((HandleEntry->HandleCount) &&
(HandleEntry->Process == Process))
{
/* Found it, get the process handle count */
ProcessHandleCount = HandleEntry->HandleCount--;
break;
}
/* Keep looping */
HandleEntry++;
i--;
}
}
else
{
/* No database, so no entry */
HandleEntry = NULL;
}
}
/* Check if this is the last handle */
if (ProcessHandleCount == 1)
{
/* Then clear the entry */
HandleEntry->Process = NULL;
HandleEntry->HandleCount = 0;
}
}
/* Release the lock */
ObpReleaseObjectLock(ObjectHeader);
/* Check if we have a close procedure */
if (ObjectType->TypeInfo.CloseProcedure)
{
/* Call it */
ObpCalloutStart(&CalloutIrql);
ObjectType->TypeInfo.CloseProcedure(Process,
ObjectBody,
GrantedAccess,
ProcessHandleCount,
SystemHandleCount);
ObpCalloutEnd(CalloutIrql, "Close", ObjectType, ObjectBody);
}
/* Check if we should delete the object */
ObpDeleteNameCheck(ObjectBody);
/* Decrease the total number of handles for this type */
InterlockedDecrement((PLONG)&ObjectType->TotalNumberOfHandles);
OBTRACE(OB_HANDLE_DEBUG,
"%s - Decremented count for: %p. HC LC %lx %lx\n",
__FUNCTION__,
ObjectBody,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
}
/*++
* @name ObpCloseHandleTableEntry
*
* The ObpCloseHandleTableEntry routine <FILLMEIN>
*
* @param HandleTable
* <FILLMEIN>.
*
* @param HandleEntry
* <FILLMEIN>.
*
* @param Handle
* <FILLMEIN>.
*
* @param AccessMode
* <FILLMEIN>.
*
* @param IgnoreHandleProtection
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObpCloseHandleTableEntry(IN PHANDLE_TABLE HandleTable,
IN PHANDLE_TABLE_ENTRY HandleEntry,
IN HANDLE Handle,
IN KPROCESSOR_MODE AccessMode,
IN BOOLEAN IgnoreHandleProtection)
{
PVOID Body;
POBJECT_TYPE ObjectType;
POBJECT_HEADER ObjectHeader;
ACCESS_MASK GrantedAccess;
KIRQL CalloutIrql;
PAGED_CODE();
/* Get the object data */
ObjectHeader = ObpGetHandleObject(HandleEntry);
ObjectType = ObjectHeader->Type;
Body = &ObjectHeader->Body;
GrantedAccess = HandleEntry->GrantedAccess;
OBTRACE(OB_HANDLE_DEBUG,
"%s - Closing handle: %lx for %p. HC LC %lx %lx\n",
__FUNCTION__,
Handle,
Body,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
/* Check if the object has an Okay To Close procedure */
if (ObjectType->TypeInfo.OkayToCloseProcedure)
{
/* Call it and check if it's not letting us close it */
ObpCalloutStart(&CalloutIrql);
if (!ObjectType->TypeInfo.OkayToCloseProcedure(PsGetCurrentProcess(),
Body,
Handle,
AccessMode))
{
/* Fail */
ObpCalloutEnd(CalloutIrql, "NtClose", ObjectType, Body);
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
return STATUS_HANDLE_NOT_CLOSABLE;
}
/* Success, validate callout retrn */
ObpCalloutEnd(CalloutIrql, "NtClose", ObjectType, Body);
}
/* The callback allowed us to close it, but does the handle itself? */
if ((HandleEntry->ObAttributes & OBJ_PROTECT_CLOSE) &&
!(IgnoreHandleProtection))
{
/* It doesn't, are we from user mode? */
if (AccessMode != KernelMode)
{
/* We are! Unlock the entry */
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
/* Make sure we have a debug port */
if (PsGetCurrentProcess()->DebugPort)
{
/* Raise an exception */
return KeRaiseUserException(STATUS_HANDLE_NOT_CLOSABLE);
}
else
{
/* Return the error instead */
return STATUS_HANDLE_NOT_CLOSABLE;
}
}
else
{
/* Otherwise, bugcheck the OS */
KeBugCheckEx(0x8B, (ULONG_PTR)Handle, 0, 0, 0);
}
}
/* Destroy and unlock the handle entry */
ExDestroyHandle(HandleTable, Handle, HandleEntry);
/* Now decrement the handle count */
ObpDecrementHandleCount(Body,
PsGetCurrentProcess(),
GrantedAccess,
ObjectType);
/* Dereference the object as well */
ObDereferenceObject(Body);
/* Return to caller */
OBTRACE(OB_HANDLE_DEBUG,
"%s - Closed handle: %lx for %p. HC LC %lx %lx\n",
__FUNCTION__,
Handle,
Body,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
return STATUS_SUCCESS;
}
/*++
* @name ObpIncrementHandleCount
*
* The ObpIncrementHandleCount routine <FILLMEIN>
*
* @param Object
* <FILLMEIN>.
*
* @param AccessState
* <FILLMEIN>.
*
* @param AccessMode
* <FILLMEIN>.
*
* @param HandleAttributes
* <FILLMEIN>.
*
* @param Process
* <FILLMEIN>.
*
* @param OpenReason
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObpIncrementHandleCount(IN PVOID Object,
IN PACCESS_STATE AccessState,
IN KPROCESSOR_MODE AccessMode,
IN ULONG HandleAttributes,
IN PEPROCESS Process,
IN OB_OPEN_REASON OpenReason)
{
POBJECT_HEADER ObjectHeader;
POBJECT_TYPE ObjectType;
ULONG ProcessHandleCount;
NTSTATUS Status;
PEPROCESS ExclusiveProcess;
BOOLEAN Exclusive = FALSE, NewObject;
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
KIRQL CalloutIrql;
KPROCESSOR_MODE ProbeMode;
ULONG Total;
PAGED_CODE();
/* Get the object header and type */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
ObjectType = ObjectHeader->Type;
OBTRACE(OB_HANDLE_DEBUG,
"%s - Incrementing count for: %p. Reason: %lx. HC LC %lx %lx\n",
__FUNCTION__,
Object,
OpenReason,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
/* Check if caller is forcing user mode */
if (HandleAttributes & OBJ_FORCE_ACCESS_CHECK)
{
/* Force it */
ProbeMode = UserMode;
}
else
{
/* Keep original setting */
ProbeMode = AccessMode;
}
/* Lock the object */
ObpAcquireObjectLock(ObjectHeader);
/* Charge quota and remove the creator info flag */
Status = ObpChargeQuotaForObject(ObjectHeader, ObjectType, &NewObject);
if (!NT_SUCCESS(Status)) return Status;
/* Check if the open is exclusive */
if (HandleAttributes & OBJ_EXCLUSIVE)
{
/* Check if the object allows this, or if the inherit flag was given */
if ((HandleAttributes & OBJ_INHERIT) ||
!(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
{
/* Incorrect attempt */
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Check if we have access to it */
ExclusiveProcess = OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader);
if ((!(ExclusiveProcess) && (ObjectHeader->HandleCount)) ||
((ExclusiveProcess) && (ExclusiveProcess != PsGetCurrentProcess())))
{
/* This isn't the right process */
Status = STATUS_ACCESS_DENIED;
goto Quickie;
}
/* Now you got exclusive access */
Exclusive = TRUE;
}
else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) &&
(OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader)))
{
/* Caller didn't want exclusive access, but the object is exclusive */
Status = STATUS_ACCESS_DENIED;
goto Quickie;
}
/*
* Check if this is an object that went from 0 handles back to existence,
* but doesn't have an open procedure, only a close procedure. This means
* that it will never realize that the object is back alive, so we must
* fail the request.
*/
if (!(ObjectHeader->HandleCount) &&
!(NewObject) &&
(ObjectType->TypeInfo.MaintainHandleCount) &&
!(ObjectType->TypeInfo.OpenProcedure) &&
(ObjectType->TypeInfo.CloseProcedure))
{
/* Fail */
Status = STATUS_UNSUCCESSFUL;
goto Quickie;
}
/* Check if we're opening an existing handle */
if ((OpenReason == ObOpenHandle) ||
((OpenReason == ObDuplicateHandle) && (AccessState)))
{
/* Validate the caller's access to this object */
if (!ObCheckObjectAccess(Object,
AccessState,
TRUE,
AccessMode,
&Status))
{
/* Access was denied, so fail */
goto Quickie;
}
}
else if (OpenReason == ObCreateHandle)
{
/* Convert MAXIMUM_ALLOWED to GENERIC_ALL */
if (AccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED)
{
/* Mask out MAXIMUM_ALLOWED and stick GENERIC_ALL instead */
AccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED;
AccessState->RemainingDesiredAccess |= GENERIC_ALL;
}
/* Check if we have to map the GENERIC mask */
if (AccessState->RemainingDesiredAccess & GENERIC_ACCESS)
{
/* Map it to the correct access masks */
RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
&ObjectType->TypeInfo.GenericMapping);
}
/* Check if the caller is trying to access system security */
if (AccessState->RemainingDesiredAccess & ACCESS_SYSTEM_SECURITY)
{
/* FIXME: TODO */
DPRINT1("ACCESS_SYSTEM_SECURITY not validated!\n");
}
}
/* Check if this is an exclusive handle */
if (Exclusive)
{
/* Save the owner process */
OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
}
/* Increase the handle count */
InterlockedIncrement(&ObjectHeader->HandleCount);
ProcessHandleCount = 0;
/* Check if we have a handle database */
if (ObjectType->TypeInfo.MaintainHandleCount)
{
/* Increment the handle database */
Status = ObpIncrementHandleDataBase(ObjectHeader,
Process,
&ProcessHandleCount);
if (!NT_SUCCESS(Status))
{
/* FIXME: This should never happen for now */
DPRINT1("Unhandled case\n");
KEBUGCHECK(0);
goto Quickie;
}
}
/* Release the lock */
ObpReleaseObjectLock(ObjectHeader);
/* Check if we have an open procedure */
Status = STATUS_SUCCESS;
if (ObjectType->TypeInfo.OpenProcedure)
{
/* Call it */
ObpCalloutStart(&CalloutIrql);
Status = ObjectType->TypeInfo.OpenProcedure(OpenReason,
Process,
Object,
AccessState ?
AccessState->
PreviouslyGrantedAccess :
0,
ProcessHandleCount);
ObpCalloutEnd(CalloutIrql, "Open", ObjectType, Object);
/* Check if the open procedure failed */
if (!NT_SUCCESS(Status))
{
/* FIXME: This should never happen for now */
DPRINT1("Unhandled case\n");
KEBUGCHECK(0);
return Status;
}
}
/* Check if this is a create operation */
if (OpenReason == ObCreateHandle)
{
/* Check if we have creator info */
CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(ObjectHeader);
if (CreatorInfo)
{
/* We do, acquire the lock */
ObpEnterObjectTypeMutex(ObjectType);
/* Insert us on the list */
InsertTailList(&ObjectType->TypeList, &CreatorInfo->TypeList);
/* Release the lock */
ObpLeaveObjectTypeMutex(ObjectType);
}
}
/* Increase total number of handles */
Total = InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
if (Total > ObjectType->HighWaterNumberOfHandles)
{
/* Fixup count */
ObjectType->HighWaterNumberOfHandles = Total;
}
/* Trace call and return */
OBTRACE(OB_HANDLE_DEBUG,
"%s - Incremented count for: %p. Reason: %lx HC LC %lx %lx\n",
__FUNCTION__,
Object,
OpenReason,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
return Status;
Quickie:
/* Release lock and return */
ObpReleaseObjectLock(ObjectHeader);
return Status;
}
/*++
* @name ObpIncrementUnnamedHandleCount
*
* The ObpIncrementUnnamedHandleCount routine <FILLMEIN>
*
* @param Object
* <FILLMEIN>.
*
* @param AccessState
* <FILLMEIN>.
*
* @param AccessMode
* <FILLMEIN>.
*
* @param HandleAttributes
* <FILLMEIN>.
*
* @param Process
* <FILLMEIN>.
*
* @param OpenReason
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObpIncrementUnnamedHandleCount(IN PVOID Object,
IN PACCESS_MASK DesiredAccess,
IN KPROCESSOR_MODE AccessMode,
IN ULONG HandleAttributes,
IN PEPROCESS Process)
{
POBJECT_HEADER ObjectHeader;
POBJECT_TYPE ObjectType;
ULONG ProcessHandleCount;
NTSTATUS Status;
PEPROCESS ExclusiveProcess;
BOOLEAN Exclusive = FALSE, NewObject;
POBJECT_HEADER_CREATOR_INFO CreatorInfo;
KIRQL CalloutIrql;
ULONG Total;
/* Get the object header and type */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
ObjectType = ObjectHeader->Type;
OBTRACE(OB_HANDLE_DEBUG,
"%s - Incrementing count for: %p. UNNAMED. HC LC %lx %lx\n",
__FUNCTION__,
Object,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
/* Lock the object */
ObpAcquireObjectLock(ObjectHeader);
/* Charge quota and remove the creator info flag */
Status = ObpChargeQuotaForObject(ObjectHeader, ObjectType, &NewObject);
if (!NT_SUCCESS(Status)) return Status;
/* Check if the open is exclusive */
if (HandleAttributes & OBJ_EXCLUSIVE)
{
/* Check if the object allows this, or if the inherit flag was given */
if ((HandleAttributes & OBJ_INHERIT) ||
!(ObjectHeader->Flags & OB_FLAG_EXCLUSIVE))
{
/* Incorrect attempt */
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Check if we have access to it */
ExclusiveProcess = OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader);
if ((!(ExclusiveProcess) && (ObjectHeader->HandleCount)) ||
((ExclusiveProcess) && (ExclusiveProcess != PsGetCurrentProcess())))
{
/* This isn't the right process */
Status = STATUS_ACCESS_DENIED;
goto Quickie;
}
/* Now you got exclusive access */
Exclusive = TRUE;
}
else if ((ObjectHeader->Flags & OB_FLAG_EXCLUSIVE) &&
(OBJECT_HEADER_TO_EXCLUSIVE_PROCESS(ObjectHeader)))
{
/* Caller didn't want exclusive access, but the object is exclusive */
Status = STATUS_ACCESS_DENIED;
goto Quickie;
}
/*
* Check if this is an object that went from 0 handles back to existence,
* but doesn't have an open procedure, only a close procedure. This means
* that it will never realize that the object is back alive, so we must
* fail the request.
*/
if (!(ObjectHeader->HandleCount) &&
!(NewObject) &&
(ObjectType->TypeInfo.MaintainHandleCount) &&
!(ObjectType->TypeInfo.OpenProcedure) &&
(ObjectType->TypeInfo.CloseProcedure))
{
/* Fail */
Status = STATUS_UNSUCCESSFUL;
goto Quickie;
}
/* Convert MAXIMUM_ALLOWED to GENERIC_ALL */
if (*DesiredAccess & MAXIMUM_ALLOWED)
{
/* Mask out MAXIMUM_ALLOWED and stick GENERIC_ALL instead */
*DesiredAccess &= ~MAXIMUM_ALLOWED;
*DesiredAccess |= GENERIC_ALL;
}
/* Check if we have to map the GENERIC mask */
if (*DesiredAccess & GENERIC_ACCESS)
{
/* Map it to the correct access masks */
RtlMapGenericMask(DesiredAccess,
&ObjectType->TypeInfo.GenericMapping);
}
/* Check if this is an exclusive handle */
if (Exclusive)
{
/* Save the owner process */
OBJECT_HEADER_TO_QUOTA_INFO(ObjectHeader)->ExclusiveProcess = Process;
}
/* Increase the handle count */
InterlockedIncrement(&ObjectHeader->HandleCount);
ProcessHandleCount = 0;
/* Check if we have a handle database */
if (ObjectType->TypeInfo.MaintainHandleCount)
{
/* Increment the handle database */
Status = ObpIncrementHandleDataBase(ObjectHeader,
Process,
&ProcessHandleCount);
if (!NT_SUCCESS(Status))
{
/* FIXME: This should never happen for now */
DPRINT1("Unhandled case\n");
KEBUGCHECK(0);
goto Quickie;
}
}
/* Release the lock */
ObpReleaseObjectLock(ObjectHeader);
/* Check if we have an open procedure */
Status = STATUS_SUCCESS;
if (ObjectType->TypeInfo.OpenProcedure)
{
/* Call it */
ObpCalloutStart(&CalloutIrql);
Status = ObjectType->TypeInfo.OpenProcedure(ObCreateHandle,
Process,
Object,
*DesiredAccess,
ProcessHandleCount);
ObpCalloutEnd(CalloutIrql, "Open", ObjectType, Object);
/* Check if the open procedure failed */
if (!NT_SUCCESS(Status))
{
/* FIXME: This should never happen for now */
DPRINT1("Unhandled case\n");
KEBUGCHECK(0);
return Status;
}
}
/* Check if we have creator info */
CreatorInfo = OBJECT_HEADER_TO_CREATOR_INFO(ObjectHeader);
if (CreatorInfo)
{
/* We do, acquire the lock */
ObpEnterObjectTypeMutex(ObjectType);
/* Insert us on the list */
InsertTailList(&ObjectType->TypeList, &CreatorInfo->TypeList);
/* Release the lock */
ObpLeaveObjectTypeMutex(ObjectType);
}
/* Increase total number of handles */
Total = InterlockedIncrement((PLONG)&ObjectType->TotalNumberOfHandles);
if (Total > ObjectType->HighWaterNumberOfHandles)
{
/* Fixup count */
ObjectType->HighWaterNumberOfHandles = Total;
}
/* Trace call and return */
OBTRACE(OB_HANDLE_DEBUG,
"%s - Incremented count for: %p. UNNAMED HC LC %lx %lx\n",
__FUNCTION__,
Object,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
return Status;
Quickie:
/* Release lock and return */
ObpReleaseObjectLock(ObjectHeader);
return Status;
}
/*++
* @name ObpCreateUnnamedHandle
*
* The ObpCreateUnnamedHandle routine <FILLMEIN>
*
* @param Object
* <FILLMEIN>.
*
* @param DesiredAccess
* <FILLMEIN>.
*
* @param AdditionalReferences
* <FILLMEIN>.
*
* @param HandleAttributes
* <FILLMEIN>.
*
* @param AccessMode
* <FILLMEIN>.
*
* @param ReturnedObject
* <FILLMEIN>.
*
* @param ReturnedHandle
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObpCreateUnnamedHandle(IN PVOID Object,
IN ACCESS_MASK DesiredAccess,
IN ULONG AdditionalReferences,
IN ULONG HandleAttributes,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *ReturnedObject,
OUT PHANDLE ReturnedHandle)
{
HANDLE_TABLE_ENTRY NewEntry;
POBJECT_HEADER ObjectHeader;
HANDLE Handle;
KAPC_STATE ApcState;
BOOLEAN AttachedToProcess = FALSE, KernelHandle = FALSE;
PVOID HandleTable;
NTSTATUS Status;
ACCESS_MASK GrantedAccess;
POBJECT_TYPE ObjectType;
PAGED_CODE();
/* Get the object header and type */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
ObjectType = ObjectHeader->Type;
OBTRACE(OB_HANDLE_DEBUG,
"%s - Creating handle for: %p. UNNAMED. HC LC %lx %lx\n",
__FUNCTION__,
Object,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
/* Save the object header */
NewEntry.Object = ObjectHeader;
/* Mask out the internal attributes */
NewEntry.ObAttributes |= HandleAttributes & OBJ_HANDLE_ATTRIBUTES;
/* Check if this is a kernel handle */
if (HandleAttributes & OBJ_KERNEL_HANDLE)
{
/* Set the handle table */
HandleTable = ObpKernelHandleTable;
KernelHandle = TRUE;
/* Check if we're not in the system process */
if (PsGetCurrentProcess() != PsInitialSystemProcess)
{
/* Attach to the system process */
KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
AttachedToProcess = TRUE;
}
}
else
{
/* Get the current handle table */
HandleTable = PsGetCurrentProcess()->ObjectTable;
}
/* Increment the handle count */
Status = ObpIncrementUnnamedHandleCount(Object,
&DesiredAccess,
AccessMode,
HandleAttributes,
PsGetCurrentProcess());
if (!NT_SUCCESS(Status))
{
/*
* We failed (meaning security failure, according to NT Internals)
* detach and return
*/
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
return Status;
}
/* Remove what's not in the valid access mask */
GrantedAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
ACCESS_SYSTEM_SECURITY);
/* Handle extra references */
if (AdditionalReferences)
{
/* Add them to the header */
InterlockedExchangeAdd(&ObjectHeader->PointerCount,
AdditionalReferences);
}
/* Save the access mask */
NewEntry.GrantedAccess = GrantedAccess;
/*
* Create the actual handle. We'll need to do this *after* calling
* ObpIncrementHandleCount to make sure that Object Security is valid
* (specified in Gl00my documentation on Ob)
*/
OBTRACE(OB_HANDLE_DEBUG,
"%s - Handle Properties: [%p-%lx-%lx]\n",
__FUNCTION__,
NewEntry.Object, NewEntry.ObAttributes & 3, NewEntry.GrantedAccess);
Handle = ExCreateHandle(HandleTable, &NewEntry);
/* Make sure we got a handle */
if (Handle)
{
/* Check if this was a kernel handle */
if (KernelHandle) Handle = ObMarkHandleAsKernelHandle(Handle);
/* Return handle and object */
*ReturnedHandle = Handle;
/* Return the new object only if caller wanted it biased */
if ((AdditionalReferences) && (ReturnedObject))
{
/* Return it */
*ReturnedObject = Object;
}
/* Detach if needed */
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
/* Trace and return */
OBTRACE(OB_HANDLE_DEBUG,
"%s - Returning Handle: %lx HC LC %lx %lx\n",
__FUNCTION__,
Handle,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
return STATUS_SUCCESS;
}
/* Handle extra references */
if (AdditionalReferences)
{
/* Dereference it as many times as required */
InterlockedExchangeAdd(&ObjectHeader->PointerCount,
-(LONG)AdditionalReferences);
}
/* Decrement the handle count and detach */
ObpDecrementHandleCount(&ObjectHeader->Body,
PsGetCurrentProcess(),
GrantedAccess,
ObjectType);
/* Detach and fail */
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
return STATUS_INSUFFICIENT_RESOURCES;
}
/*++
* @name ObpCreateHandle
*
* The ObpCreateHandle routine <FILLMEIN>
*
* @param OpenReason
* <FILLMEIN>.
*
* @param Object
* <FILLMEIN>.
*
* @param Type
* <FILLMEIN>.
*
* @param AccessState
* <FILLMEIN>.
*
* @param AdditionalReferences
* <FILLMEIN>.
*
* @param HandleAttributes
* <FILLMEIN>.
*
* @param AccessMode
* <FILLMEIN>.
*
* @param ReturnedObject
* <FILLMEIN>.
*
* @param ReturnedHandle
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks Cleans up the Lookup Context on return.
*
*--*/
NTSTATUS
NTAPI
ObpCreateHandle(IN OB_OPEN_REASON OpenReason,
IN PVOID Object,
IN POBJECT_TYPE Type OPTIONAL,
IN PACCESS_STATE AccessState,
IN ULONG AdditionalReferences,
IN ULONG HandleAttributes,
IN POBP_LOOKUP_CONTEXT Context,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *ReturnedObject,
OUT PHANDLE ReturnedHandle)
{
HANDLE_TABLE_ENTRY NewEntry;
POBJECT_HEADER ObjectHeader;
HANDLE Handle;
KAPC_STATE ApcState;
BOOLEAN AttachedToProcess = FALSE, KernelHandle = FALSE;
POBJECT_TYPE ObjectType;
PVOID HandleTable;
NTSTATUS Status;
ACCESS_MASK DesiredAccess, GrantedAccess;
PAUX_ACCESS_DATA AuxData;
PAGED_CODE();
/* Get the object header and type */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
ObjectType = ObjectHeader->Type;
OBTRACE(OB_HANDLE_DEBUG,
"%s - Creating handle for: %p. Reason: %lx. HC LC %lx %lx\n",
__FUNCTION__,
Object,
OpenReason,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
/* Check if the types match */
if ((Type) && (ObjectType != Type))
{
/* They don't, cleanup */
if (Context) ObpReleaseLookupContext(Context);
return STATUS_OBJECT_TYPE_MISMATCH;
}
/* Save the object header */
NewEntry.Object = ObjectHeader;
/* Check if this is a kernel handle */
if (HandleAttributes & OBJ_KERNEL_HANDLE)
{
/* Set the handle table */
HandleTable = ObpKernelHandleTable;
KernelHandle = TRUE;
/* Check if we're not in the system process */
if (PsGetCurrentProcess() != PsInitialSystemProcess)
{
/* Attach to the system process */
KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
AttachedToProcess = TRUE;
}
}
else
{
/* Get the current handle table */
HandleTable = PsGetCurrentProcess()->ObjectTable;
}
/* Increment the handle count */
Status = ObpIncrementHandleCount(Object,
AccessState,
AccessMode,
HandleAttributes,
PsGetCurrentProcess(),
OpenReason);
if (!NT_SUCCESS(Status))
{
/*
* We failed (meaning security failure, according to NT Internals)
* detach and return
*/
if (Context) ObpReleaseLookupContext(Context);
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
return Status;
}
/* Check if we are doing audits on close */
if (AccessState->GenerateOnClose)
{
/* Force the attribute on */
HandleAttributes |= OBJ_AUDIT_OBJECT_CLOSE;
}
/* Mask out the internal attributes */
NewEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
/* Get the original desired access */
DesiredAccess = AccessState->RemainingDesiredAccess |
AccessState->PreviouslyGrantedAccess;
/* Remove what's not in the valid access mask */
GrantedAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
ACCESS_SYSTEM_SECURITY);
/* Update the value in the access state */
AccessState->PreviouslyGrantedAccess = GrantedAccess;
/* Get the auxiliary data */
AuxData = AccessState->AuxData;
/* Handle extra references */
if (AdditionalReferences)
{
/* Add them to the header */
InterlockedExchangeAdd(&ObjectHeader->PointerCount, AdditionalReferences);
}
/* Now we can release the object */
if (Context) ObpReleaseLookupContext(Context);
/* Save the access mask */
NewEntry.GrantedAccess = GrantedAccess;
/*
* Create the actual handle. We'll need to do this *after* calling
* ObpIncrementHandleCount to make sure that Object Security is valid
* (specified in Gl00my documentation on Ob)
*/
OBTRACE(OB_HANDLE_DEBUG,
"%s - Handle Properties: [%p-%lx-%lx]\n",
__FUNCTION__,
NewEntry.Object, NewEntry.ObAttributes & 3, NewEntry.GrantedAccess);
Handle = ExCreateHandle(HandleTable, &NewEntry);
/* Make sure we got a handle */
if (Handle)
{
/* Check if this was a kernel handle */
if (KernelHandle) Handle = ObMarkHandleAsKernelHandle(Handle);
/* Return it */
*ReturnedHandle = Handle;
/* Check if we need to generate on audit */
if (AccessState->GenerateAudit)
{
/* Audit the handle creation */
//SeAuditHandleCreation(AccessState, Handle);
}
/* Check if this was a create */
if (OpenReason == ObCreateHandle)
{
/* Check if we need to audit the privileges */
if ((AuxData->PrivilegeSet) &&
(AuxData->PrivilegeSet->PrivilegeCount))
{
/* Do the audit */
#if 0
SePrivilegeObjectAuditAlarm(Handle,
&AccessState->
SubjectSecurityContext,
GrantedAccess,
AuxData->PrivilegeSet,
TRUE,
ExGetPreviousMode());
#endif
}
}
/* Return the new object only if caller wanted it biased */
if ((AdditionalReferences) && (ReturnedObject))
{
/* Return it */
*ReturnedObject = Object;
}
/* Detach if needed */
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
/* Trace and return */
OBTRACE(OB_HANDLE_DEBUG,
"%s - Returning Handle: %lx HC LC %lx %lx\n",
__FUNCTION__,
Handle,
ObjectHeader->HandleCount,
ObjectHeader->PointerCount);
return STATUS_SUCCESS;
}
/* Decrement the handle count and detach */
ObpDecrementHandleCount(&ObjectHeader->Body,
PsGetCurrentProcess(),
GrantedAccess,
ObjectType);
/* Handle extra references */
if (AdditionalReferences)
{
/* Check how many extra references were added */
if (AdditionalReferences > 1)
{
/* Dereference it many times */
InterlockedExchangeAdd(&ObjectHeader->PointerCount,
-(LONG)(AdditionalReferences - 1));
}
/* Dereference the object one last time */
ObDereferenceObject(Object);
}
/* Detach if necessary and fail */
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
return STATUS_INSUFFICIENT_RESOURCES;
}
/*++
* @name ObpCloseHandle
*
* The ObpCloseHandle routine <FILLMEIN>
*
* @param Handle
* <FILLMEIN>.
*
* @param AccessMode
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObpCloseHandle(IN HANDLE Handle,
IN KPROCESSOR_MODE AccessMode)
{
PVOID HandleTable;
BOOLEAN AttachedToProcess = FALSE;
KAPC_STATE ApcState;
PHANDLE_TABLE_ENTRY HandleTableEntry;
NTSTATUS Status;
PEPROCESS Process = PsGetCurrentProcess();
PAGED_CODE();
OBTRACE(OB_HANDLE_DEBUG,
"%s - Closing handle: %lx\n", __FUNCTION__, Handle);
/* Check if we're dealing with a kernel handle */
if (ObIsKernelHandle(Handle, AccessMode))
{
/* Use the kernel table and convert the handle */
HandleTable = ObpKernelHandleTable;
Handle = ObKernelHandleToHandle(Handle);
/* Check if we're not in the system process */
if (Process != PsInitialSystemProcess)
{
/* Attach to the system process */
KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);
AttachedToProcess = TRUE;
}
}
else
{
/* Use the process's handle table */
HandleTable = Process->ObjectTable;
}
/* Enter a critical region to protect handle access */
KeEnterCriticalRegion();
/* Get the handle entry */
HandleTableEntry = ExMapHandleToPointer(HandleTable, Handle);
if (HandleTableEntry)
{
/* Now close the entry */
Status = ObpCloseHandleTableEntry(HandleTable,
HandleTableEntry,
Handle,
AccessMode,
FALSE);
/* We can quit the critical region now */
KeLeaveCriticalRegion();
/* Detach and return success */
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
Status = STATUS_SUCCESS;
}
else
{
/* We failed, quit the critical region */
KeLeaveCriticalRegion();
/* Detach */
if (AttachedToProcess) KeUnstackDetachProcess(&ApcState);
/* Check if we have a valid handle that's not the process or thread */
if ((Handle) &&
(Handle != NtCurrentProcess()) &&
(Handle != NtCurrentThread()))
{
/* Check if we came from user mode */
if (AccessMode != KernelMode)
{
/* Check if we have no debug port */
if (Process->DebugPort)
{
/* Make sure we're not attached */
if (!KeIsAttachedProcess())
{
/* Raise an exception */
return KeRaiseUserException(STATUS_INVALID_HANDLE);
}
}
}
else
{
/* This is kernel mode. Check if we're exiting */
if (!(PsIsThreadTerminating(PsGetCurrentThread())) &&
(Process->Peb))
{
/* Check if the debugger is enabled */
if (KdDebuggerEnabled)
{
/* Bugcheck */
KeBugCheckEx(0, (ULONG_PTR)Handle, 1, 0, 0);
}
}
}
}
/* Set invalid status */
Status = STATUS_INVALID_HANDLE;
}
/* Return status */
OBTRACE(OB_HANDLE_DEBUG,
"%s - Closed handle: %lx S: %lx\n",
__FUNCTION__, Handle, Status);
return Status;
}
/*++
* @name ObpSetHandleAttributes
*
* The ObpSetHandleAttributes routine <FILLMEIN>
*
* @param HandleTableEntry
* <FILLMEIN>.
*
* @param Context
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
BOOLEAN
NTAPI
ObpSetHandleAttributes(IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
IN ULONG_PTR Context)
{
POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo = (PVOID)Context;
POBJECT_HEADER ObjectHeader = ObpGetHandleObject(HandleTableEntry);
/* Check if making the handle inheritable */
if (SetHandleInfo->Information.Inherit)
{
/* Check if inheriting is not supported for this object */
if (ObjectHeader->Type->TypeInfo.InvalidAttributes & OBJ_INHERIT)
{
/* Fail without changing anything */
return FALSE;
}
/* Set the flag */
HandleTableEntry->ObAttributes |= OBJ_INHERIT;
}
else
{
/* Otherwise this implies we're removing the flag */
HandleTableEntry->ObAttributes &= ~OBJ_INHERIT;
}
/* Check if making the handle protected */
if (SetHandleInfo->Information.ProtectFromClose)
{
/* Set the flag */
HandleTableEntry->GrantedAccess |= ObpAccessProtectCloseBit;
}
else
{
/* Otherwise, remove it */
HandleTableEntry->GrantedAccess &= ~ObpAccessProtectCloseBit;
}
/* Return success */
return TRUE;
}
/*++
* @name ObpCloseHandleCallback
*
* The ObpCloseHandleCallback routine <FILLMEIN>
*
* @param HandleTable
* <FILLMEIN>.
*
* @param Object
* <FILLMEIN>.
*
* @param GrantedAccess
* <FILLMEIN>.
*
* @param Context
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
BOOLEAN
NTAPI
ObpCloseHandleCallback(IN PHANDLE_TABLE_ENTRY HandleTableEntry,
IN HANDLE Handle,
IN PVOID Context)
{
POBP_CLOSE_HANDLE_CONTEXT CloseContext = (POBP_CLOSE_HANDLE_CONTEXT)Context;
/* Simply decrement the handle count */
ObpCloseHandleTableEntry(CloseContext->HandleTable,
HandleTableEntry,
Handle,
CloseContext->AccessMode,
TRUE);
return TRUE;
}
/*++
* @name ObpDuplicateHandleCallback
*
* The ObpDuplicateHandleCallback routine <FILLMEIN>
*
* @param HandleTable
* <FILLMEIN>.
*
* @param HandleTableEntry
* <FILLMEIN>.
*
* @param Context
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
BOOLEAN
NTAPI
ObpDuplicateHandleCallback(IN PEPROCESS Process,
IN PHANDLE_TABLE HandleTable,
IN PHANDLE_TABLE_ENTRY OldEntry,
IN PHANDLE_TABLE_ENTRY HandleTableEntry)
{
POBJECT_HEADER ObjectHeader;
BOOLEAN Ret = FALSE;
ACCESS_STATE AccessState;
NTSTATUS Status;
PAGED_CODE();
/* Make sure that the handle is inheritable */
Ret = (HandleTableEntry->ObAttributes & OBJ_INHERIT) != 0;
if (Ret)
{
/* Get the object header */
ObjectHeader = ObpGetHandleObject(HandleTableEntry);
/* Increment the pointer count */
InterlockedIncrement(&ObjectHeader->PointerCount);
/* Release the handle lock */
ExUnlockHandleTableEntry(HandleTable, OldEntry);
/* Setup the access state */
AccessState.PreviouslyGrantedAccess = HandleTableEntry->GrantedAccess;
/* Call the shared routine for incrementing handles */
Status = ObpIncrementHandleCount(&ObjectHeader->Body,
&AccessState,
KernelMode,
HandleTableEntry->ObAttributes & OBJ_HANDLE_ATTRIBUTES,
Process,
ObInheritHandle);
if (!NT_SUCCESS(Status))
{
/* Return failure */
ObDereferenceObject(&ObjectHeader->Body);
Ret = FALSE;
}
}
else
{
/* Release the handle lock */
ExUnlockHandleTableEntry(HandleTable, OldEntry);
}
/* Return duplication result */
return Ret;
}
VOID
NTAPI
ObClearProcessHandleTable(IN PEPROCESS Process)
{
/* FIXME */
}
/*++
* @name ObpCreateHandleTable
*
* The ObpCreateHandleTable routine <FILLMEIN>
*
* @param Parent
* <FILLMEIN>.
*
* @param Process
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObInitProcess(IN PEPROCESS Parent OPTIONAL,
IN PEPROCESS Process)
{
PHANDLE_TABLE ParentTable, ObjectTable;
/* Check for a parent */
if (Parent)
{
/* Reference the parent's table */
ParentTable = ObReferenceProcessHandleTable(Parent);
if (!ParentTable) return STATUS_PROCESS_IS_TERMINATING;
/* Duplicate it */
ObjectTable = ExDupHandleTable(Process,
ParentTable,
ObpDuplicateHandleCallback,
OBJ_INHERIT);
}
else
{
/* Otherwise just create a new table */
ParentTable = NULL;
ObjectTable = ExCreateHandleTable(Process);
}
/* Make sure we have a table */
if (ObjectTable)
{
/* Associate it */
Process->ObjectTable = ObjectTable;
/* Check for auditing */
if (SeDetailedAuditingWithToken(NULL))
{
/* FIXME: TODO */
DPRINT1("Need auditing!\n");
}
/* Get rid of the old table now */
if (ParentTable) ObDereferenceProcessHandleTable(Parent);
/* We are done */
return STATUS_SUCCESS;
}
else
{
/* Fail */
Process->ObjectTable = NULL;
if (ParentTable) ObDereferenceProcessHandleTable(Parent);
return STATUS_INSUFFICIENT_RESOURCES;
}
}
/*++
* @name ObKillProcess
*
* The ObKillProcess routine <FILLMEIN>
*
* @param Process
* <FILLMEIN>.
*
* @return None.
*
* @remarks None.
*
*--*/
VOID
NTAPI
ObKillProcess(IN PEPROCESS Process)
{
PHANDLE_TABLE HandleTable;
OBP_CLOSE_HANDLE_CONTEXT Context;
BOOLEAN HardErrors;
PAGED_CODE();
/* Wait for process rundown and then complete it */
ExWaitForRundownProtectionRelease(&Process->RundownProtect);
ExRundownCompleted(&Process->RundownProtect);
/* Get the object table */
HandleTable = Process->ObjectTable;
if (!HandleTable) return;
/* Disable hard errors while we close handles */
HardErrors = IoSetThreadHardErrorMode(FALSE);
/* Enter a critical region */
KeEnterCriticalRegion();
/* Fill out the context */
Context.AccessMode = KernelMode;
Context.HandleTable = HandleTable;
/* Sweep the handle table to close all handles */
ExSweepHandleTable(HandleTable,
ObpCloseHandleCallback,
&Context);
ASSERT(HandleTable->HandleCount == 0);
/* Leave the critical region */
KeLeaveCriticalRegion();
/* Re-enable hard errors */
IoSetThreadHardErrorMode(HardErrors);
/* Destroy the object table */
Process->ObjectTable = NULL;
ExDestroyHandleTable(HandleTable, NULL);
}
NTSTATUS
NTAPI
ObDuplicateObject(IN PEPROCESS SourceProcess,
IN HANDLE SourceHandle,
IN PEPROCESS TargetProcess OPTIONAL,
IN PHANDLE TargetHandle OPTIONAL,
IN ACCESS_MASK DesiredAccess,
IN ULONG HandleAttributes,
IN ULONG Options,
IN KPROCESSOR_MODE PreviousMode)
{
HANDLE_TABLE_ENTRY NewHandleEntry;
BOOLEAN AttachedToProcess = FALSE;
PVOID SourceObject;
POBJECT_HEADER ObjectHeader;
POBJECT_TYPE ObjectType;
HANDLE NewHandle;
KAPC_STATE ApcState;
NTSTATUS Status;
ACCESS_MASK TargetAccess, SourceAccess;
ACCESS_STATE AccessState;
PACCESS_STATE PassedAccessState = NULL;
AUX_ACCESS_DATA AuxData;
PHANDLE_TABLE HandleTable;
OBJECT_HANDLE_INFORMATION HandleInformation;
ULONG AuditMask;
PAGED_CODE();
OBTRACE(OB_HANDLE_DEBUG,
"%s - Duplicating handle: %lx for %p into %p\n",
__FUNCTION__,
SourceHandle,
SourceProcess,
TargetProcess);
/* Assume failure */
if (TargetHandle) *TargetHandle = NULL;
/* Check if we're not duplicating the same access */
if (!(Options & DUPLICATE_SAME_ACCESS))
{
/* Validate the desired access */
Status = STATUS_SUCCESS; //ObpValidateDesiredAccess(DesiredAccess);
if (!NT_SUCCESS(Status)) return Status;
}
/* Reference the object table */
HandleTable = ObReferenceProcessHandleTable(SourceProcess);
if (!HandleTable) return STATUS_PROCESS_IS_TERMINATING;
/* Reference the process object */
Status = ObpReferenceProcessObjectByHandle(SourceHandle,
SourceProcess,
HandleTable,
PreviousMode,
&SourceObject,
&HandleInformation,
&AuditMask);
if (!NT_SUCCESS(Status))
{
/* Fail */
ObDereferenceProcessHandleTable(SourceProcess);
return Status;
}
else
{
/* Check if we have to don't have to audit object close */
if (!(HandleInformation.HandleAttributes & OBJ_AUDIT_OBJECT_CLOSE))
{
/* Then there is no audit mask */
AuditMask = 0;
}
}
/* Check if there's no target process */
if (!TargetProcess)
{
/* Check if the caller wanted actual duplication */
if (!(Options & DUPLICATE_CLOSE_SOURCE))
{
/* Invalid request */
Status = STATUS_INVALID_PARAMETER;
}
else
{
/* Otherwise, do the attach */
KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
/* Close the handle and detach */
NtClose(SourceHandle);
KeUnstackDetachProcess(&ApcState);
}
/* Return */
ObDereferenceProcessHandleTable(SourceProcess);
ObDereferenceObject(SourceObject);
return Status;
}
/* Get the target handle table */
HandleTable = ObReferenceProcessHandleTable(TargetProcess);
if (!HandleTable)
{
/* Check if the caller wanted us to close the handle */
if (Options & DUPLICATE_CLOSE_SOURCE)
{
/* Do the attach */
KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
/* Close the handle and detach */
NtClose(SourceHandle);
KeUnstackDetachProcess(&ApcState);
}
/* Return */
ObDereferenceProcessHandleTable(SourceProcess);
ObDereferenceObject(SourceObject);
return STATUS_PROCESS_IS_TERMINATING;
}
/* Get the source access */
SourceAccess = HandleInformation.GrantedAccess;
/* Check if we're not in the target process */
if (TargetProcess != PsGetCurrentProcess())
{
/* Attach to it */
KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
AttachedToProcess = TRUE;
}
/* Check if we're duplicating the attributes */
if (Options & DUPLICATE_SAME_ATTRIBUTES)
{
/* Duplicate them */
HandleAttributes = HandleInformation.HandleAttributes;
}
else
{
/* Don't allow caller to bypass auditing */
HandleAttributes |= HandleInformation.HandleAttributes &
OBJ_AUDIT_OBJECT_CLOSE;
}
/* Check if we're duplicating the access */
if (Options & DUPLICATE_SAME_ACCESS) DesiredAccess = SourceAccess;
/* Get object data */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(SourceObject);
ObjectType = ObjectHeader->Type;
/* Fill out the entry */
RtlZeroMemory(&NewHandleEntry, sizeof(HANDLE_TABLE_ENTRY));
NewHandleEntry.Object = ObjectHeader;
NewHandleEntry.ObAttributes |= (HandleAttributes & OBJ_HANDLE_ATTRIBUTES);
/* Check if we're using a generic mask */
if (DesiredAccess & GENERIC_ACCESS)
{
/* Map it */
RtlMapGenericMask(&DesiredAccess,
&ObjectType->TypeInfo.GenericMapping);
}
/* Set the target access, always propagate ACCESS_SYSTEM_SECURITY */
TargetAccess = DesiredAccess & (ObjectType->TypeInfo.ValidAccessMask |
ACCESS_SYSTEM_SECURITY);
NewHandleEntry.GrantedAccess = TargetAccess;
/* Check if we're asking for new access */
if (TargetAccess & ~SourceAccess)
{
/* We are. We need the security procedure to validate this */
if (ObjectType->TypeInfo.SecurityProcedure == SeDefaultObjectMethod)
{
/* Use our built-in access state */
PassedAccessState = &AccessState;
Status = SeCreateAccessState(&AccessState,
&AuxData,
TargetAccess,
&ObjectType->TypeInfo.GenericMapping);
}
else
{
/* Otherwise we can't allow this privilege elevation */
Status = STATUS_ACCESS_DENIED;
}
}
else
{
/* We don't need an access state */
Status = STATUS_SUCCESS;
}
/* Make sure the access state was created OK */
if (NT_SUCCESS(Status))
{
/* Add a new handle */
Status = ObpIncrementHandleCount(SourceObject,
PassedAccessState,
PreviousMode,
HandleAttributes,
PsGetCurrentProcess(),
ObDuplicateHandle);
}
/* Check if we were attached */
if (AttachedToProcess)
{
/* We can safely detach now */
KeUnstackDetachProcess(&ApcState);
AttachedToProcess = FALSE;
}
/* Check if we have to close the source handle */
if (Options & DUPLICATE_CLOSE_SOURCE)
{
/* Attach and close */
KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
NtClose(SourceHandle);
KeUnstackDetachProcess(&ApcState);
}
/* Check if we had an access state */
if (PassedAccessState) SeDeleteAccessState(PassedAccessState);
/* Now check if incrementing actually failed */
if (!NT_SUCCESS(Status))
{
/* Dereference handle tables */
ObDereferenceProcessHandleTable(SourceProcess);
ObDereferenceProcessHandleTable(TargetProcess);
/* Dereference the source object */
ObDereferenceObject(SourceObject);
return Status;
}
/* Now create the handle */
NewHandle = ExCreateHandle(HandleTable, &NewHandleEntry);
if (!NewHandle)
{
/* Undo the increment */
ObpDecrementHandleCount(SourceObject,
TargetProcess,
TargetAccess,
ObjectType);
/* Deference the object and set failure status */
ObDereferenceObject(SourceObject);
Status = STATUS_INSUFFICIENT_RESOURCES;
}
/* Return the handle */
if (TargetHandle) *TargetHandle = NewHandle;
/* Dereference handle tables */
ObDereferenceProcessHandleTable(SourceProcess);
ObDereferenceProcessHandleTable(TargetProcess);
/* Return status */
OBTRACE(OB_HANDLE_DEBUG,
"%s - Duplicated handle: %lx for %p into %p. Source: %p HC PC %lx %lx\n",
__FUNCTION__,
NewHandle,
SourceProcess,
TargetProcess,
SourceObject,
ObjectHeader->PointerCount,
ObjectHeader->HandleCount);
return Status;
}
/* PUBLIC FUNCTIONS *********************************************************/
/*++
* @name ObOpenObjectByName
* @implemented NT4
*
* The ObOpenObjectByName routine <FILLMEIN>
*
* @param ObjectAttributes
* <FILLMEIN>.
*
* @param ObjectType
* <FILLMEIN>.
*
* @param AccessMode
* <FILLMEIN>.
*
* @param PassedAccessState
* <FILLMEIN>.
*
* @param DesiredAccess
* <FILLMEIN>.
*
* @param ParseContext
* <FILLMEIN>.
*
* @param Handle
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
IN PACCESS_STATE PassedAccessState,
IN ACCESS_MASK DesiredAccess,
IN OUT PVOID ParseContext,
OUT PHANDLE Handle)
{
PVOID Object = NULL;
UNICODE_STRING ObjectName;
NTSTATUS Status;
POBJECT_HEADER ObjectHeader;
PGENERIC_MAPPING GenericMapping = NULL;
OB_OPEN_REASON OpenReason;
POB_TEMP_BUFFER TempBuffer;
PAGED_CODE();
/* Assume failure */
*Handle = NULL;
/* Check if we didn't get any Object Attributes */
if (!ObjectAttributes)
{
/* Fail with special status code */
return STATUS_INVALID_PARAMETER;
}
/* Allocate the temporary buffer */
TempBuffer = ExAllocatePoolWithTag(NonPagedPool,
sizeof(OB_TEMP_BUFFER),
TAG_OB_TEMP_STORAGE);
if (!TempBuffer) return STATUS_INSUFFICIENT_RESOURCES;
/* Capture all the info */
Status = ObpCaptureObjectCreateInformation(ObjectAttributes,
AccessMode,
TRUE,
&TempBuffer->ObjectCreateInfo,
&ObjectName);
if (!NT_SUCCESS(Status))
{
/* Fail */
ExFreePool(TempBuffer);
return Status;
}
/* Check if we didn't get an access state */
if (!PassedAccessState)
{
/* Try to get the generic mapping if we can */
if (ObjectType) GenericMapping = &ObjectType->TypeInfo.GenericMapping;
/* Use our built-in access state */
PassedAccessState = &TempBuffer->LocalAccessState;
Status = SeCreateAccessState(&TempBuffer->LocalAccessState,
&TempBuffer->AuxData,
DesiredAccess,
GenericMapping);
if (!NT_SUCCESS(Status)) goto Quickie;
}
/* Get the security descriptor */
if (TempBuffer->ObjectCreateInfo.SecurityDescriptor)
{
/* Save it in the access state */
PassedAccessState->SecurityDescriptor =
TempBuffer->ObjectCreateInfo.SecurityDescriptor;
}
/* Now do the lookup */
Status = ObpLookupObjectName(TempBuffer->ObjectCreateInfo.RootDirectory,
&ObjectName,
TempBuffer->ObjectCreateInfo.Attributes,
ObjectType,
AccessMode,
ParseContext,
TempBuffer->ObjectCreateInfo.SecurityQos,
NULL,
PassedAccessState,
&TempBuffer->LookupContext,
&Object);
if (!NT_SUCCESS(Status))
{
/* Cleanup after lookup */
ObpReleaseLookupContext(&TempBuffer->LookupContext);
goto Cleanup;
}
/* Check if this object has create information */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
if (ObjectHeader->Flags & OB_FLAG_CREATE_INFO)
{
/* Then we are creating a new handle */
OpenReason = ObCreateHandle;
/* Check if we still have create info */
if (ObjectHeader->ObjectCreateInfo)
{
/* Free it */
ObpFreeObjectCreateInformation(ObjectHeader->
ObjectCreateInfo);
ObjectHeader->ObjectCreateInfo = NULL;
}
}
else
{
/* Otherwise, we are merely opening it */
OpenReason = ObOpenHandle;
}
/* Check if we have invalid object attributes */
if (ObjectHeader->Type->TypeInfo.InvalidAttributes &
TempBuffer->ObjectCreateInfo.Attributes)
{
/* Set failure code */
Status = STATUS_INVALID_PARAMETER;
/* Cleanup after lookup */
ObpReleaseLookupContext(&TempBuffer->LookupContext);
/* Dereference the object */
ObDereferenceObject(Object);
}
else
{
/* Create the actual handle now */
Status = ObpCreateHandle(OpenReason,
Object,
ObjectType,
PassedAccessState,
0,
TempBuffer->ObjectCreateInfo.Attributes,
&TempBuffer->LookupContext,
AccessMode,
NULL,
Handle);
if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
}
Cleanup:
/* Delete the access state */
if (PassedAccessState == &TempBuffer->LocalAccessState)
{
SeDeleteAccessState(PassedAccessState);
}
Quickie:
/* Release the object attributes and temporary buffer */
ObpReleaseObjectCreateInformation(&TempBuffer->ObjectCreateInfo);
if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
ExFreePool(TempBuffer);
/* Return status */
OBTRACE(OB_HANDLE_DEBUG,
"%s - returning Object %p with PC S: %lx %lx\n",
__FUNCTION__,
Object,
Object ? OBJECT_TO_OBJECT_HEADER(Object)->PointerCount : -1,
Status);
return Status;
}
/*++
* @name ObOpenObjectByPointer
* @implemented NT4
*
* The ObOpenObjectByPointer routine <FILLMEIN>
*
* @param Object
* <FILLMEIN>.
*
* @param HandleAttributes
* <FILLMEIN>.
*
* @param PassedAccessState
* <FILLMEIN>.
*
* @param DesiredAccess
* <FILLMEIN>.
*
* @param ObjectType
* <FILLMEIN>.
*
* @param AccessMode
* <FILLMEIN>.
*
* @param Handle
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObOpenObjectByPointer(IN PVOID Object,
IN ULONG HandleAttributes,
IN PACCESS_STATE PassedAccessState,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
OUT PHANDLE Handle)
{
POBJECT_HEADER Header;
NTSTATUS Status;
ACCESS_STATE AccessState;
AUX_ACCESS_DATA AuxData;
PAGED_CODE();
/* Assume failure */
*Handle = NULL;
/* Reference the object */
Status = ObReferenceObjectByPointer(Object,
0,
ObjectType,
AccessMode);
if (!NT_SUCCESS(Status)) return Status;
/* Get the Header Info */
Header = OBJECT_TO_OBJECT_HEADER(Object);
/* Check if we didn't get an access state */
if (!PassedAccessState)
{
/* Use our built-in access state */
PassedAccessState = &AccessState;
Status = SeCreateAccessState(&AccessState,
&AuxData,
DesiredAccess,
&Header->Type->TypeInfo.GenericMapping);
if (!NT_SUCCESS(Status))
{
/* Fail */
ObDereferenceObject(Object);
return Status;
}
}
/* Check if we have invalid object attributes */
if (Header->Type->TypeInfo.InvalidAttributes & HandleAttributes)
{
/* Delete the access state */
if (PassedAccessState == &AccessState)
{
SeDeleteAccessState(PassedAccessState);
}
/* Dereference the object */
ObDereferenceObject(Object);
return STATUS_INVALID_PARAMETER;
}
/* Create the handle */
Status = ObpCreateHandle(ObOpenHandle,
Object,
ObjectType,
PassedAccessState,
0,
HandleAttributes,
NULL,
AccessMode,
NULL,
Handle);
if (!NT_SUCCESS(Status)) ObDereferenceObject(Object);
/* Delete the access state */
if (PassedAccessState == &AccessState)
{
SeDeleteAccessState(PassedAccessState);
}
/* Return */
OBTRACE(OB_HANDLE_DEBUG,
"%s - returning Object with PC S: %lx %lx\n",
__FUNCTION__,
OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
Status);
return Status;
}
/*++
* @name ObFindHandleForObject
* @implemented NT4
*
* The ObFindHandleForObject routine <FILLMEIN>
*
* @param Process
* <FILLMEIN>.
*
* @param Object
* <FILLMEIN>.
*
* @param ObjectType
* <FILLMEIN>.
*
* @param HandleInformation
* <FILLMEIN>.
*
* @param HandleReturn
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
BOOLEAN
NTAPI
ObFindHandleForObject(IN PEPROCESS Process,
IN PVOID Object,
IN POBJECT_TYPE ObjectType,
IN POBJECT_HANDLE_INFORMATION HandleInformation,
OUT PHANDLE Handle)
{
OBP_FIND_HANDLE_DATA FindData;
BOOLEAN Result = FALSE;
PVOID ObjectTable;
/* Make sure we have an object table */
ObjectTable = ObReferenceProcessHandleTable(Process);
if (ObjectTable)
{
/* Check if we have an object */
if (Object)
{
/* Set its header */
FindData.ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
}
else
{
/* Otherwise, no object to match*/
FindData.ObjectHeader = NULL;
}
/* Set other information */
FindData.ObjectType = ObjectType;
FindData.HandleInformation = HandleInformation;
/* Enumerate the handle table */
if (ExEnumHandleTable(Process->ObjectTable,
ObpEnumFindHandleProcedure,
&FindData,
Handle))
{
/* Set success */
Result = TRUE;
}
/* Let go of the table */
ObDereferenceProcessHandleTable(Process);
}
/* Return the result */
return Result;
}
/*++
* @name ObInsertObject
* @implemented NT4
*
* The ObInsertObject routine <FILLMEIN>
*
* @param Object
* <FILLMEIN>.
*
* @param PassedAccessState
* <FILLMEIN>.
*
* @param DesiredAccess
* <FILLMEIN>.
*
* @param AdditionalReferences
* <FILLMEIN>.
*
* @param ReferencedObject
* <FILLMEIN>.
*
* @param Handle
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObInsertObject(IN PVOID Object,
IN PACCESS_STATE AccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess,
IN ULONG ObjectPointerBias,
OUT PVOID *NewObject OPTIONAL,
OUT PHANDLE Handle)
{
POBJECT_CREATE_INFORMATION ObjectCreateInfo;
POBJECT_HEADER ObjectHeader;
POBJECT_TYPE ObjectType;
PUNICODE_STRING ObjectName;
PVOID InsertObject;
PSECURITY_DESCRIPTOR ParentDescriptor = NULL;
BOOLEAN SdAllocated = FALSE;
POBJECT_HEADER_NAME_INFO ObjectNameInfo;
OBP_LOOKUP_CONTEXT Context;
ACCESS_STATE LocalAccessState;
AUX_ACCESS_DATA AuxData;
OB_OPEN_REASON OpenReason;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status = STATUS_SUCCESS, RealStatus;
BOOLEAN IsNewObject;
PAGED_CODE();
/* Get the Header */
ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);
/* Detect invalid insert */
if (!(ObjectHeader->Flags & OB_FLAG_CREATE_INFO))
{
/* Display warning and break into debugger */
DPRINT1("OB: Attempting to insert existing object %08x\n", Object);
DbgBreakPoint();
/* Allow debugger to continue */
ObDereferenceObject(Object);
return STATUS_INVALID_PARAMETER;
}
/* Get the create and name info, as well as the object type */
ObjectCreateInfo = ObjectHeader->ObjectCreateInfo;
ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader);
ObjectType = ObjectHeader->Type;
ObjectName = NULL;
/* Check if this is an named object */
if ((ObjectNameInfo) && (ObjectNameInfo->Name.Buffer))
{
/* Get the object name */
ObjectName = &ObjectNameInfo->Name;
}
/* Sanity check */
ASSERT((Handle) ||
((ObjectPointerBias == 0) &&
(ObjectName == NULL) &&
(ObjectType->TypeInfo.SecurityRequired) &&
(NewObject == NULL)));
/* Check if the object is unnamed and also doesn't have security */
PreviousMode = KeGetPreviousMode();
if (!(ObjectType->TypeInfo.SecurityRequired) && !(ObjectName))
{
/* Assume failure */
*Handle = NULL;
ObjectHeader->ObjectCreateInfo = NULL;
/* Create the handle */
Status = ObpCreateUnnamedHandle(Object,
DesiredAccess,
ObjectPointerBias + 1,
ObjectCreateInfo->Attributes,
PreviousMode,
NewObject,
Handle);
/* Free the create information */
ObpFreeObjectCreateInformation(ObjectCreateInfo);
/* Release the object name information */
ObpDereferenceNameInfo(ObjectNameInfo);
/* Remove the extra keep-alive reference */
ObDereferenceObject(Object);
/* Return */
OBTRACE(OB_HANDLE_DEBUG,
"%s - returning Object with PC S: %lx %lx\n",
__FUNCTION__,
ObjectHeader->PointerCount,
Status);
return Status;
}
/* Check if we didn't get an access state */
if (!AccessState)
{
/* Use our built-in access state */
AccessState = &LocalAccessState;
Status = SeCreateAccessState(&LocalAccessState,
&AuxData,
DesiredAccess,
&ObjectType->TypeInfo.GenericMapping);
if (!NT_SUCCESS(Status))
{
/* Fail */
ObpDereferenceNameInfo(ObjectNameInfo);
ObDereferenceObject(Object);
return Status;
}
}
/* Save the security descriptor */
AccessState->SecurityDescriptor = ObjectCreateInfo->SecurityDescriptor;
/* Validate the access mask */
Status = STATUS_SUCCESS;//ObpValidateAccessMask(AccessState);
if (!NT_SUCCESS(Status))
{
/* Fail */
ObpDereferenceNameInfo(ObjectNameInfo);
ObDereferenceObject(Object);
return Status;
}
/* Setup a lookup context */
ObpInitializeLookupContext(&Context);
InsertObject = Object;
OpenReason = ObCreateHandle;
/* Check if the object is named */
if (ObjectName)
{
/* Look it up */
Status = ObpLookupObjectName(ObjectCreateInfo->RootDirectory,
ObjectName,
ObjectCreateInfo->Attributes,
ObjectType,
(ObjectHeader->Flags & OB_FLAG_KERNEL_MODE) ?
KernelMode : UserMode,
ObjectCreateInfo->ParseContext,
ObjectCreateInfo->SecurityQos,
Object,
AccessState,
&Context,
&InsertObject);
/* Check if we found an object that doesn't match the one requested */
if ((NT_SUCCESS(Status)) && (InsertObject) && (Object != InsertObject))
{
/* This means we're opening an object, not creating a new one */
OpenReason = ObOpenHandle;
/* Make sure the caller said it's OK to do this */
if (ObjectCreateInfo->Attributes & OBJ_OPENIF)
{
/* He did, but did he want this type? */
if (ObjectType != OBJECT_TO_OBJECT_HEADER(InsertObject)->Type)
{
/* Wrong type, so fail */
Status = STATUS_OBJECT_TYPE_MISMATCH;
}
else
{
/* Right type, so warn */
Status = STATUS_OBJECT_NAME_EXISTS;
}
}
else
{
/* Check if this was a symbolic link */
if (OBJECT_TO_OBJECT_HEADER(InsertObject)->Type ==
ObSymbolicLinkType)
{
/* Dereference it */
ObDereferenceObject(InsertObject);
}
/* Caller wanted to create a new object, fail */
Status = STATUS_OBJECT_NAME_COLLISION;
}
}
/* Check if anything until now failed */
if (!NT_SUCCESS(Status))
{
/* Cleanup after lookup */
ObpReleaseLookupContext(&Context);
/* Remove query reference that we added */
ObpDereferenceNameInfo(ObjectNameInfo);
/* Dereference the object and delete the access state */
ObDereferenceObject(Object);
if (AccessState == &LocalAccessState)
{
/* We used a local one; delete it */
SeDeleteAccessState(AccessState);
}
/* Return failure code */
return Status;
}
else
{
/* Check if this is a symbolic link */
if (ObjectType == ObSymbolicLinkType)
{
/* Create the internal name */
ObpCreateSymbolicLinkName(Object);
}
}
}
/* Now check if this object is being created */
if (InsertObject == Object)
{
/* Check if it's named or forces security */
if ((ObjectName) || (ObjectType->TypeInfo.SecurityRequired))
{
/* Make sure it's inserted into an object directory */
if ((ObjectNameInfo) && (ObjectNameInfo->Directory))
{
/* Get the current descriptor */
ObGetObjectSecurity(ObjectNameInfo->Directory,
&ParentDescriptor,
&SdAllocated);
}
/* Now assign it */
Status = ObAssignSecurity(AccessState,
ParentDescriptor,
Object,
ObjectType);
/* Check if we captured one */
if (ParentDescriptor)
{
/* We did, release it */
ObReleaseObjectSecurity(ParentDescriptor, SdAllocated);
}
else if (NT_SUCCESS(Status))
{
/* Other we didn't, but we were able to use the current SD */
SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
ObjectCreateInfo->ProbeMode,
TRUE);
/* Clear the current one */
AccessState->SecurityDescriptor =
ObjectCreateInfo->SecurityDescriptor = NULL;
}
}
/* Check if anything until now failed */
if (!NT_SUCCESS(Status))
{
/* Check if the directory was added */
if (Context.DirectoryLocked)
{
/* Weird case where we need to do a manual delete */
DPRINT1("Unhandled path\n");
KEBUGCHECK(0);
}
/* Cleanup the lookup */
ObpReleaseLookupContext(&Context);
/* Remove query reference that we added */
ObpDereferenceNameInfo(ObjectNameInfo);
/* Dereference the object and delete the access state */
ObDereferenceObject(Object);
if (AccessState == &LocalAccessState)
{
/* We used a local one; delete it */
SeDeleteAccessState(AccessState);
}
/* Return failure code */
KEBUGCHECK(0);
return Status;
}
}
/* Save the actual status until here */
RealStatus = Status;
/* Check if caller wants us to create a handle */
ObjectHeader->ObjectCreateInfo = NULL;
if (Handle)
{
/* Create the handle */
Status = ObpCreateHandle(OpenReason,
InsertObject,
NULL,
AccessState,
ObjectPointerBias + 1,
ObjectCreateInfo->Attributes,
&Context,
PreviousMode,
NewObject,
Handle);
if (!NT_SUCCESS(Status))
{
/* If the object had a name, backout everything */
if (ObjectName) ObpDeleteNameCheck(Object);
/* Return the status of the failure */
*Handle = NULL;
RealStatus = Status;
}
/* Remove a query reference */
ObpDereferenceNameInfo(ObjectNameInfo);
/* Remove the extra keep-alive reference */
ObDereferenceObject(Object);
}
else
{
/* Otherwise, lock the object */
ObpAcquireObjectLock(ObjectHeader);
/* And charge quota for the process to make it appear as used */
RealStatus = ObpChargeQuotaForObject(ObjectHeader,
ObjectType,
&IsNewObject);
/* Release the lock */
ObpReleaseObjectLock(ObjectHeader);
/* Check if we failed and dereference the object if so */
if (!NT_SUCCESS(RealStatus)) ObDereferenceObject(Object);
}
/* We can delete the Create Info now */
ObpFreeObjectCreateInformation(ObjectCreateInfo);
/* Check if we created our own access state and delete it if so */
if (AccessState == &LocalAccessState) SeDeleteAccessState(AccessState);
/* Return status code */
OBTRACE(OB_HANDLE_DEBUG,
"%s - returning Object with PC S/RS: %lx %lx %lx\n",
__FUNCTION__,
OBJECT_TO_OBJECT_HEADER(Object)->PointerCount,
RealStatus, Status);
return RealStatus;
}
/*++
* @name ObCloseHandle
* @implemented NT5.1
*
* The ObCloseHandle routine <FILLMEIN>
*
* @param Handle
* <FILLMEIN>.
*
* @param AccessMode
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
ObCloseHandle(IN HANDLE Handle,
IN KPROCESSOR_MODE AccessMode)
{
/* Call the internal API */
return ObpCloseHandle(Handle, AccessMode);
}
/*++
* @name NtClose
* @implemented NT4
*
* The NtClose routine <FILLMEIN>
*
* @param Handle
* <FILLMEIN>.
*
* @return <FILLMEIN>.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
NtClose(IN HANDLE Handle)
{
/* Call the internal API */
return ObpCloseHandle(Handle, ExGetPreviousMode());
}
NTSTATUS
NTAPI
NtDuplicateObject(IN HANDLE SourceProcessHandle,
IN HANDLE SourceHandle,
IN HANDLE TargetProcessHandle OPTIONAL,
OUT PHANDLE TargetHandle OPTIONAL,
IN ACCESS_MASK DesiredAccess,
IN ULONG HandleAttributes,
IN ULONG Options)
{
PEPROCESS SourceProcess, TargetProcess, Target;
HANDLE hTarget;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_SUCCESS;
OBTRACE(OB_HANDLE_DEBUG,
"%s - Duplicating handle: %lx for %lx into %lx.\n",
__FUNCTION__,
SourceHandle,
SourceProcessHandle,
TargetProcessHandle);
/* Check if we have a target handle */
if ((TargetHandle) && (PreviousMode != KernelMode))
{
/* Enter SEH */
_SEH_TRY
{
/* Probe the handle and assume failure */
ProbeForWriteHandle(TargetHandle);
*TargetHandle = NULL;
}
_SEH_HANDLE
{
/* Get the exception status */
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status)) return Status;
}
/* Now reference the input handle */
Status = ObReferenceObjectByHandle(SourceProcessHandle,
PROCESS_DUP_HANDLE,
PsProcessType,
PreviousMode,
(PVOID*)&SourceProcess,
NULL);
if (!NT_SUCCESS(Status)) return(Status);
/* Check if got a target handle */
if (TargetProcessHandle)
{
/* Now reference the output handle */
Status = ObReferenceObjectByHandle(TargetProcessHandle,
PROCESS_DUP_HANDLE,
PsProcessType,
PreviousMode,
(PVOID*)&TargetProcess,
NULL);
if (NT_SUCCESS(Status))
{
/* Use this target process */
Target = TargetProcess;
}
else
{
/* No target process */
Target = NULL;
}
}
else
{
/* No target process */
Status = STATUS_SUCCESS;
Target = NULL;
}
/* Call the internal routine */
Status = ObDuplicateObject(SourceProcess,
SourceHandle,
Target,
&hTarget,
DesiredAccess,
HandleAttributes,
Options,
PreviousMode);
/* Check if the caller wanted the return handle */
if (TargetHandle)
{
/* Protect the write to user mode */
_SEH_TRY
{
/* Write the new handle */
*TargetHandle = hTarget;
}
_SEH_HANDLE
{
/* Otherwise, get the exception code */
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
/* Dereference the processes */
OBTRACE(OB_HANDLE_DEBUG,
"%s - Duplicated handle: %lx into %lx S %lx\n",
__FUNCTION__,
hTarget,
TargetProcessHandle,
Status);
if (Target) ObDereferenceObject(Target);
ObDereferenceObject(SourceProcess);
return Status;
}
#undef ObIsKernelHandle
BOOLEAN
NTAPI
ObIsKernelHandle(IN HANDLE Handle)
{
/* We know we're kernel mode, so just check for the kernel handle flag */
return (BOOLEAN)((ULONG_PTR)Handle & KERNEL_HANDLE_FLAG);
}
/* EOF */