windows-nt/Source/XPSP1/NT/termsrv/drivers/termdd/khandle.c
2020-09-26 16:20:57 +08:00

558 lines
12 KiB
C

/*************************************************************************
*
* khandle.c
*
* Manage kernel mode handles for transport drivers.
*
* Copyright 1998, Microsoft.
*
*************************************************************************/
/*
* Includes
*/
#include <precomp.h>
#pragma hdrstop
ULONG gHandleTableSize;
#ifdef TERMDD_NO_USE_TABLE_PACKAGE
typedef struct _TDHANDLE_ENTRY {
LIST_ENTRY Link;
PVOID Context;
ULONG ContextSize;
} TDHANDLE_ENTRY, *PTDHANDLE_ENTRY;
/*
* Global Data
*/
LIST_ENTRY IcaTdHandleList;
/*
* These set of routines allows TD's to create a handle that will survive
* across them being unloaded and re-loaded. This allows a handle to be
* passed back to ICASRV in a secure manner.
*
* NOTE: We do not deal with ICASRV leaking these handles. It never exits.
* If it does, we will need to have ICADD return a real NT handle, or
* destroy all handles for a TD when it unloads.
*/
/*****************************************************************************
*
* IcaCreateHandle
*
* Create a handle entry for the context and length.
*
* ENTRY:
* Param1 (input/output)
* Comments
*
* EXIT:
* STATUS_SUCCESS - no error
*
****************************************************************************/
NTSTATUS
IcaCreateHandle(
PVOID Context,
ULONG ContextSize,
PVOID *ppHandle
)
{
KIRQL OldIrql;
PTDHANDLE_ENTRY p;
p = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(TDHANDLE_ENTRY) );
if( p == NULL ) {
return( STATUS_NO_MEMORY );
}
RtlZeroMemory( p, sizeof(TDHANDLE_ENTRY) );
p->Context = Context;
p->ContextSize = ContextSize;
*ppHandle = (PVOID)p;
IcaAcquireSpinLock( &IcaSpinLock, &OldIrql );
InsertHeadList( &IcaTdHandleList, &p->Link );
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
InterlockedIncrement(&gHandleTableSize);
return( STATUS_SUCCESS );
}
/*****************************************************************************
*
* IcaReturnHandle
*
* Return the context and length for the handle.
*
* ENTRY:
* Param1 (input/output)
* Comments
*
* EXIT:
* STATUS_SUCCESS - no error
*
****************************************************************************/
NTSTATUS
IcaReturnHandle(
PVOID Handle,
PVOID *ppContext,
PULONG pContextSize
)
{
KIRQL OldIrql;
PLIST_ENTRY pEntry;
PTDHANDLE_ENTRY p;
IcaAcquireSpinLock( &IcaSpinLock, &OldIrql );
pEntry = IcaTdHandleList.Flink;
while( pEntry != &IcaTdHandleList ) {
p = CONTAINING_RECORD( pEntry, TDHANDLE_ENTRY, Link );
if( (PVOID)p == Handle ) {
*ppContext = p->Context;
*pContextSize = p->ContextSize;
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
return( STATUS_SUCCESS );
}
pEntry = pEntry->Flink;
}
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
return( STATUS_INVALID_HANDLE );
}
/*****************************************************************************
*
* IcaCloseHandle
*
* Return the context and length for the handle. Delete the
* handle entry.
*
* ENTRY:
* Param1 (input/output)
* Comments
*
* EXIT:
* STATUS_SUCCESS - no error
*
****************************************************************************/
NTSTATUS
IcaCloseHandle(
PVOID Handle,
PVOID *ppContext,
PULONG pContextSize
)
{
KIRQL OldIrql;
PLIST_ENTRY pEntry;
PTDHANDLE_ENTRY p;
IcaAcquireSpinLock( &IcaSpinLock, &OldIrql );
pEntry = IcaTdHandleList.Flink;
while( pEntry != &IcaTdHandleList ) {
p = CONTAINING_RECORD( pEntry, TDHANDLE_ENTRY, Link );
if( (PVOID)p == Handle ) {
RemoveEntryList( &p->Link );
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
InterlockedDecrement(&gHandleTableSize);
*ppContext = p->Context;
*pContextSize = p->ContextSize;
ICA_FREE_POOL( p );
return( STATUS_SUCCESS );
}
pEntry = pEntry->Flink;
}
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
return( STATUS_INVALID_HANDLE );
}
/*****************************************************************************
*
* IcaInitializeHandleTable
*
* Initializes handle table at driver load.
*
* ENTRY:
* None
* Comments
*
* EXIT:
* None
*
****************************************************************************/
void
IcaInitializeHandleTable(
void
)
{
InitializeListHead( &IcaTdHandleList );
}
/*****************************************************************************
*
* IcaCleanupHandleTable
*
* Cleans up handle table at driver unload.
*
* ENTRY:
* None
* Comments
*
* EXIT:
* None
*
****************************************************************************/
void
IcaCleanupHandleTable(
void
)
{
KIRQL OldIrql;
PLIST_ENTRY pEntry;
PTDHANDLE_ENTRY p;
KdPrint(("TermDD: IcaCleanupHandleTable table size is %d\n",gHandleTableSize));
for (pEntry = IcaTdHandleList.Flink; pEntry != &IcaTdHandleList; pEntry = IcaTdHandleList.Flink) {
p = CONTAINING_RECORD( pEntry, TDHANDLE_ENTRY, Link );
RemoveEntryList(&p->Links);
ICA_FREE_POOL( p->Context );
ICA_FREE_POOL( p );
}
}
#else
typedef struct _TDHANDLE_ENTRY {
PVOID Context;
ULONG ContextSize;
} TDHANDLE_ENTRY, *PTDHANDLE_ENTRY;
RTL_GENERIC_TABLE IcaHandleReferenceTable;
RTL_GENERIC_COMPARE_RESULTS
NTAPI
IcaCompareHandleTableEntry (
IN struct _RTL_GENERIC_TABLE *Table,
IN PVOID FirstInstance,
IN PVOID SecondInstance
);
PVOID
IcaAllocateHandleTableEntry (
IN struct _RTL_GENERIC_TABLE *Table,
IN CLONG ByteSize
);
VOID
IcaFreeHandleTableEntry (
IN struct _RTL_GENERIC_TABLE *Table,
IN PVOID Buffer
);
/*****************************************************************************
*
* IcaInitializeHandleTable
*
* Initializes handle table at driver load.
*
* ENTRY:
* None
* Comments
*
* EXIT:
* None
*
****************************************************************************/
void
IcaInitializeHandleTable(
void
)
{
RtlInitializeGenericTable( &IcaHandleReferenceTable,
IcaCompareHandleTableEntry,
IcaAllocateHandleTableEntry,
IcaFreeHandleTableEntry,
NULL);
}
/*****************************************************************************
*
* IcaCleanupHandleTable
*
* Cleanup handle table at driver unload.
*
* ENTRY:
* None
* Comments
*
* EXIT:
* None
*
****************************************************************************/
void
IcaCleanupHandleTable(
void
)
{
KIRQL OldIrql;
PLIST_ENTRY pEntry;
PTDHANDLE_ENTRY p;
PVOID pContext;
TDHANDLE_ENTRY key;
KdPrint(("TermDD: IcaCleanupHandleTable table size is %d\n",gHandleTableSize));
while (p = RtlEnumerateGenericTable(&IcaHandleReferenceTable,TRUE)) {
key.Context = p->Context;
RtlDeleteElementGenericTable(&IcaHandleReferenceTable, &key);
ICA_FREE_POOL(key.Context);
}
}
/*****************************************************************************
*
* IcaCreateHandle
*
* Create a handle entry for the context and length.
*
* ENTRY:
* Param1 (input/output)
* Comments
*
* EXIT:
* STATUS_SUCCESS - no error
*
****************************************************************************/
NTSTATUS
IcaCreateHandle(
PVOID Context,
ULONG ContextSize,
PVOID *ppHandle
)
{
KIRQL OldIrql;
TDHANDLE_ENTRY key;
BOOLEAN bNewElement;
key.Context = Context;
key.ContextSize = ContextSize;
IcaAcquireSpinLock( &IcaSpinLock, &OldIrql );
if (!RtlInsertElementGenericTable(&IcaHandleReferenceTable,(PVOID) &key, sizeof(TDHANDLE_ENTRY), &bNewElement )) {
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
return STATUS_NO_MEMORY;
}
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
ASSERT(bNewElement);
if (!bNewElement) {
return STATUS_INVALID_PARAMETER;
}
InterlockedIncrement(&gHandleTableSize);
*ppHandle = Context;
return( STATUS_SUCCESS );
}
/*****************************************************************************
*
* IcaReturnHandle
*
* Return the context and length for the handle.
*
* ENTRY:
* Param1 (input/output)
* Comments
*
* EXIT:
* STATUS_SUCCESS - no error
*
****************************************************************************/
NTSTATUS
IcaReturnHandle(
PVOID Handle,
PVOID *ppContext,
PULONG pContextSize
)
{
KIRQL OldIrql;
PTDHANDLE_ENTRY p;
TDHANDLE_ENTRY key;
key.Context = Handle;
IcaAcquireSpinLock( &IcaSpinLock, &OldIrql );
p = RtlLookupElementGenericTable(&IcaHandleReferenceTable, &key);
if (p != NULL) {
*ppContext = p->Context;
*pContextSize = p->ContextSize;
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
return STATUS_SUCCESS;
} else {
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
return STATUS_INVALID_HANDLE;
}
}
/*****************************************************************************
*
* IcaCloseHandle
*
* Return the context and length for the handle. Delete the
* handle entry.
*
* ENTRY:
* Param1 (input/output)
* Comments
*
* EXIT:
* STATUS_SUCCESS - no error
*
****************************************************************************/
NTSTATUS
IcaCloseHandle(
PVOID Handle,
PVOID *ppContext,
PULONG pContextSize
)
{
KIRQL OldIrql;
PTDHANDLE_ENTRY p;
TDHANDLE_ENTRY key;
key.Context = Handle;
IcaAcquireSpinLock( &IcaSpinLock, &OldIrql );
p = RtlLookupElementGenericTable(&IcaHandleReferenceTable, &key);
if (p != NULL) {
*ppContext = p->Context;
*pContextSize = p->ContextSize;
RtlDeleteElementGenericTable(&IcaHandleReferenceTable, &key);
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
InterlockedDecrement(&gHandleTableSize);
return STATUS_SUCCESS;
} else {
IcaReleaseSpinLock( &IcaSpinLock, OldIrql );
return STATUS_INVALID_HANDLE;
}
}
/*****************************************************************************
*
* IcaCompareHandleTableEntry
*
* Generic table support.Compare two handles table entry instances
*
*
****************************************************************************/
RTL_GENERIC_COMPARE_RESULTS
NTAPI
IcaCompareHandleTableEntry (
IN struct _RTL_GENERIC_TABLE *Table,
IN PVOID FirstInstance,
IN PVOID SecondInstance
)
{
ULONG_PTR FirstHandle = (ULONG_PTR)((PTDHANDLE_ENTRY)FirstInstance)->Context;
ULONG_PTR SecondHandle = (ULONG_PTR)((PTDHANDLE_ENTRY)SecondInstance)->Context;
if (FirstHandle < SecondHandle ) {
return GenericLessThan;
}
if (FirstHandle > SecondHandle ) {
return GenericGreaterThan;
}
return GenericEqual;
}
/*****************************************************************************
*
* IcaAllocateHandleTableEntry
*
* Generic table support. Allocates a new table entry
*
*
****************************************************************************/
PVOID
IcaAllocateHandleTableEntry (
IN struct _RTL_GENERIC_TABLE *Table,
IN CLONG ByteSize
)
{
return ICA_ALLOCATE_POOL( NonPagedPool, ByteSize );
}
/*****************************************************************************
*
* IcaFreeHandleTableEntry
*
* Generic table support. frees a new table entry
*
*
****************************************************************************/
VOID
IcaFreeHandleTableEntry (
IN struct _RTL_GENERIC_TABLE *Table,
IN PVOID Buffer
)
{
ICA_FREE_POOL(Buffer);
}
#endif