windows-nt/Source/XPSP1/NT/ds/security/base/lsa/server/lht.cxx

835 lines
19 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1997.
//
// File: lht.cxx
//
// Contents: Context handle management for servers
//
// Classes:
//
// Functions:
//
// History: 1-31-97 RichardW Created
//
//----------------------------------------------------------------------------
#include <lsapch.hxx>
#include "sht.hxx"
#include "lht.hxx"
//
// Due to the high number of connections for servers, the client context list
// for a particular session could grow into the thousands. At that stage, a
// linear list that is searched to validate a handle is prohibitively expensive.
//
// Thus, the faster, if more expensive to set up and add handle package
//
HP_INITIALIZE_FN LhtInitialize ;
HP_CREATE_FN LhtCreate ;
HP_DELETE_FN LhtDelete ;
HP_ADD_HANDLE_FN LhtAddHandle ;
HP_DELETE_HANDLE_FN LhtDeleteHandle ;
HP_VALIDATE_HANDLE_FN LhtValidateHandle ;
HP_REF_HANDLE_FN LhtRefHandle ;
HP_DEREF_HANDLE_KEY_FN LhtDerefHandleKey ;
HP_GET_HANDLE_CONTEXT_FN LhtGetHandleContext ;
HP_RELEASE_CONTEXT_FN LhtReleaseContext ;
HANDLE_PACKAGE LargeHandlePackage = {
sizeof( LARGE_HANDLE_TABLE ),
LhtInitialize,
LhtCreate,
LhtDelete,
LhtAddHandle,
LhtDeleteHandle,
LhtValidateHandle,
LhtRefHandle,
LhtDerefHandleKey,
LhtGetHandleContext,
LhtReleaseContext
};
ULONG LhtFastMem ;
ULONG LhtShiftValues[] = { 4, 12, 16, 20 };
#define IndexFromHandle( Level, Handle ) \
( ( ((PSecHandle) Handle)->dwUpper >> LhtShiftValues[ Level ] ) & HANDLE_TABLE_MASK )
#define LhtLockTable( t ) \
if ( (((PLARGE_HANDLE_TABLE) t)->Flags & LHT_NO_SERIALIZE ) == 0 ) \
{ \
RtlEnterCriticalSection( &((PLARGE_HANDLE_TABLE)t)->Lock ); \
}
#define LhtUnlockTable( t ) \
if ( (((PLARGE_HANDLE_TABLE) t)->Flags & LHT_NO_SERIALIZE ) == 0 ) \
{ \
RtlLeaveCriticalSection( &((PLARGE_HANDLE_TABLE)t)->Lock ); \
}
#define LHT_ACTION_ADDREF 0
#define LHT_ACTION_DELREF 1
#define LHT_ACTION_FORCEDEL 2
#define LHT_ACTION_VALIDATE 3
#define LHT_ACTION_ADDHANDLE 4
#define LHT_ACTION_DELHANDLE 5
#define LHT_ACTION_MASK 0x0000FFFF
#define LHT_ACTION_LOCKED 0x00010000
#define LHTP_DEREF_NOT_DEL 0x10000000
#define LHTP_HANDLE_CHECKED 0x20000000
//+---------------------------------------------------------------------------
//
// Function: LhtInitialize
//
// Synopsis: Initializes the LHT handle package
//
// Arguments: (none)
//
// History: 2-03-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
LhtInitialize(
VOID
)
{
return TRUE ;
}
//+---------------------------------------------------------------------------
//
// Function: LhtCreate
//
// Synopsis: Creates a large handle table. The table is referenced through
// the returned pointer
//
// Arguments: [Flags] -- Flags as defined by handle.hxx
//
// History: 2-03-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PVOID
LhtCreate(
IN ULONG Flags,
IN PVOID HandleTable,
IN PHP_ENUM_CALLBACK_FN Callback
)
{
PLARGE_HANDLE_TABLE Table ;
ULONG i;
if ( HandleTable )
{
Table = (PLARGE_HANDLE_TABLE) HandleTable ;
}
else
{
Table = (PLARGE_HANDLE_TABLE) LsapAllocatePrivateHeap( sizeof( LARGE_HANDLE_TABLE ) );
}
if ( Table )
{
Table->Tag = LHT_TAG ;
Table->Flags = 0 ;
Table->Flags = (Flags & HANDLE_PACKAGE_GENERAL_FLAGS);
if ( Flags & HANDLE_PACKAGE_CALLBACK_ON_DELETE )
{
Table->DeleteCallback = Callback ;
}
else
{
Table->DeleteCallback = NULL ;
}
if ( HandleTable )
{
Table->Flags |= LHT_NO_FREE ;
}
Table->Depth = 0 ;
if ( ( Flags & LHT_NO_SERIALIZE ) == 0 )
{
NTSTATUS Status = RtlInitializeCriticalSection( &Table->Lock );
if (!NT_SUCCESS(Status))
{
if ( !HandleTable )
{
LsapFreePrivateHeap( Table );
}
Table = NULL ;
}
}
}
if ( Table )
{
for ( i = 0 ; i < HANDLE_TABLE_SIZE ; i++ )
{
SmallHandlePackage.Create( Flags | HANDLE_PACKAGE_NO_SERIALIZE,
& Table->Lists[i],
Callback );
}
}
return Table ;
}
//+---------------------------------------------------------------------------
//
// Function: LhtpDeleteTable
//
// Synopsis: Delete table worker function
//
// Arguments: [Table] --
// [Callback] --
//
// History: 4-15-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID
LhtpDeleteTable(
PLARGE_HANDLE_TABLE Table,
PHP_ENUM_CALLBACK_FN Callback
)
{
ULONG Index ;
PSEC_HANDLE_ENTRY Entry ;
PLIST_ENTRY Scan ;
LhtLockTable( Table );
for ( Index = 0 ; Index < HANDLE_TABLE_SIZE ; Index++ )
{
if ( Table->Lists[Index].Flags & LHT_SUB_TABLE )
{
LhtpDeleteTable( (PLARGE_HANDLE_TABLE) Table->Lists[Index].List.Flink,
Callback );
}
else
{
SmallHandlePackage.Delete( &Table->Lists[ Index ], Callback );
}
}
LhtUnlockTable( Table );
if ( (Table->Flags & LHT_NO_SERIALIZE) == 0 )
{
RtlDeleteCriticalSection( &Table->Lock );
}
if ( ( Table->Flags & LHT_NO_FREE ) == 0 )
{
LsapFreePrivateHeap( Table );
}
}
//+---------------------------------------------------------------------------
//
// Function: LhtDelete
//
// Synopsis: Delete a table
//
// Arguments: [HandleTable] --
// [Callback] --
//
// History: 4-15-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
LhtDelete(
PVOID HandleTable,
PHP_ENUM_CALLBACK_FN Callback
)
{
PLARGE_HANDLE_TABLE Table ;
Table = (PLARGE_HANDLE_TABLE) HandleTable ;
LhtLockTable( Table );
Table->Flags |= LHT_DELETE_PENDING ;
LhtpDeleteTable( Table, Callback );
return TRUE ;
}
//+---------------------------------------------------------------------------
//
// Function: LhtpFindHandle
//
// Synopsis: Worker function that grovels a handle table
//
// Arguments: [HandleTable] -- Table to scan
// [Handle] -- handle to search for
// [Action] -- action to take on the handle record
//
// History: 2-03-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PSEC_HANDLE_ENTRY
LhtpFindHandle(
PVOID HandleTable,
PSecHandle Handle,
ULONG Action,
PBOOL Removed,
PVOID * FinalTable OPTIONAL
)
{
PLARGE_HANDLE_TABLE Table ;
PSEC_HANDLE_ENTRY Entry ;
PLIST_ENTRY Scan ;
ULONG Index ;
BOOL Locked ;
Table = (PLARGE_HANDLE_TABLE) HandleTable ;
LhtLockTable( Table );
Entry = NULL ;
while ( TRUE )
{
Index = (ULONG) IndexFromHandle( Table->Depth, Handle );
if ( Table->Lists[ Index ].Flags & LHT_SUB_TABLE )
{
Table = (PLARGE_HANDLE_TABLE) Table->Lists[ Index ].List.Flink ;
continue;
}
Entry = ShtpFindHandle( &Table->Lists[ Index ], Handle, Action, Removed );
if ( FinalTable )
{
*FinalTable = &Table->Lists[ Index ] ;
}
break;
}
Table = (PLARGE_HANDLE_TABLE) HandleTable ;
LhtUnlockTable( Table );
return Entry ;
}
//+---------------------------------------------------------------------------
//
// Function: LhtpConvertSmallToLarge
//
// Synopsis: Worker to convert small tables to large
//
// Arguments: [Small] --
// [Large] --
//
// History: 7-08-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
LhtpConvertSmallToLarge(
PSMALL_HANDLE_TABLE Small,
PLARGE_HANDLE_TABLE Large
)
{
ULONG NewIndex ;
PSEC_HANDLE_ENTRY Entry ;
while ( Entry = ShtpPopHandle( Small ) )
{
NewIndex = (ULONG) IndexFromHandle( Large->Depth, &(Entry->Handle) );
ShtpInsertHandle( &Large->Lists[ NewIndex ], Entry );
}
return TRUE ;
}
//+---------------------------------------------------------------------------
//
// Function: LhtpExpandTable
//
// Synopsis: Expands the given index into its own table
//
// Effects: New table associated with given index
//
// Arguments: [Table] -- Source table
// [Index] -- Source index
//
// Requires: Table must be write-locked
//
// History: 1-31-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
LhtpExpandTable(
PLARGE_HANDLE_TABLE Table,
ULONG Index
)
{
PLARGE_HANDLE_TABLE NewTable ;
PLIST_ENTRY List;
ULONG NewFlags ;
NewFlags = HANDLE_PACKAGE_NO_SERIALIZE ;
if ( Table->DeleteCallback )
{
NewFlags |= HANDLE_PACKAGE_CALLBACK_ON_DELETE ;
}
NewTable = (PLARGE_HANDLE_TABLE) LhtCreate( NewFlags |
LHT_CHILD,
NULL,
Table->DeleteCallback );
if ( !NewTable )
{
return FALSE ;
}
NewTable->Depth = Table->Depth + 1 ;
NewTable->Parent = Table ;
NewTable->IndexOfParent = Index ;
LhtpConvertSmallToLarge( &Table->Lists[ Index ], NewTable );
Table->Lists[ Index ].List.Flink = (PLIST_ENTRY) NewTable ;
Table->Lists[ Index ].Flags = LHT_SUB_TABLE ;
return TRUE ;
}
//+---------------------------------------------------------------------------
//
// Function: LhtConvertSmallToLarge
//
// Synopsis: Converts a small handle table to a large one
//
// Arguments: [Small] --
//
// History: 7-08-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PVOID
LhtConvertSmallToLarge(
PVOID Small
)
{
PLARGE_HANDLE_TABLE Large ;
PSMALL_HANDLE_TABLE SmallTable = (PSMALL_HANDLE_TABLE) Small ;
PULONG Tag ;
Tag = (PULONG) Small ;
if ( *Tag == LHT_TAG )
{
return Small ;
}
if ( *Tag != SHT_TAG )
{
return NULL ;
}
Large = (PLARGE_HANDLE_TABLE) LhtCreate( (SmallTable->DeleteCallback ?
HANDLE_PACKAGE_CALLBACK_ON_DELETE : 0),
NULL,
SmallTable->DeleteCallback );
if ( Large )
{
LhtpConvertSmallToLarge( SmallTable, Large );
ShtDelete( Small, NULL );
return Large ;
}
return NULL ;
}
//+---------------------------------------------------------------------------
//
// Function: LhtAddHandle
//
// Synopsis: Add a handle to a handle table
//
// Arguments: [HandleTable] -- Table to add the handle to
// [Handle] -- Handle to add
//
// History: 2-03-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
LhtAddHandle(
PVOID HandleTable,
PSecHandle Handle,
PVOID Context,
ULONG Flags
)
{
PSEC_HANDLE_ENTRY Entry ;
PLARGE_HANDLE_TABLE Table ;
ULONG Index ;
Table = (PLARGE_HANDLE_TABLE) HandleTable ;
LhtLockTable( Table );
Entry = LhtpFindHandle( HandleTable,
Handle,
LHT_ACTION_ADDHANDLE,
NULL,
NULL );
if ( Entry )
{
LhtUnlockTable( Table );
return TRUE ;
}
//
// No entry, need to insert one.
//
while ( TRUE )
{
Index = (ULONG) IndexFromHandle( Table->Depth, Handle );
if ( Table->Lists[ Index ].Flags & LHT_SUB_TABLE )
{
Table = (PLARGE_HANDLE_TABLE) Table->Lists[ Index ].List.Flink ;
continue;
}
if(SmallHandlePackage.AddHandle( &Table->Lists[ Index ], Handle, Context, Flags ))
{
if ( Table->Lists[ Index ].Count > HANDLE_SPLIT_THRESHOLD )
{
LhtpExpandTable( Table, Index );
}
break;
}
LhtUnlockTable( (PLARGE_HANDLE_TABLE)HandleTable );
return FALSE;
}
Table = (PLARGE_HANDLE_TABLE) HandleTable ;
Table->Count++;
LhtUnlockTable( Table );
return TRUE ;
}
//+---------------------------------------------------------------------------
//
// Function: LhtDeleteHandle
//
// Synopsis: Delete a handle from the table
//
// Arguments: [HandleTable] -- Table
// [Handle] -- Handle to delete
// [Force] -- Force delete, even if handle is not ref'd to zero
//
// History: 2-03-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
LhtDeleteHandle(
PVOID HandleTable,
PSecHandle Handle,
ULONG Options
)
{
PSEC_HANDLE_ENTRY Entry ;
PLARGE_HANDLE_TABLE Table ;
BOOL Removed;
ULONG Action ;
if ( Options & DELHANDLE_FORCE )
{
Action = LHT_ACTION_FORCEDEL ;
}
else if ( Options & LHTP_DEREF_NOT_DEL )
{
Action = LHT_ACTION_DELREF | LHTP_HANDLE_CHECKED ;
}
else
{
Action = LHT_ACTION_DELHANDLE ;
}
Entry = LhtpFindHandle( HandleTable,
Handle,
Action,
&Removed,
NULL );
if ( Entry )
{
if ( Removed )
{
Table = (PLARGE_HANDLE_TABLE) HandleTable ;
LhtLockTable( Table );
Table->Count--;
LhtUnlockTable( Table );
if ( (Table->DeleteCallback) &&
((Options & DELHANDLE_NO_CALLBACK) == 0 ) &&
((Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK ) == 0 ) )
{
Table->DeleteCallback(
&Entry->Handle,
Entry->Context,
Entry->HandleIssuedCount // Entry->RefCount
);
}
if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 )
{
LsapFreePrivateHeap( Entry );
}
}
return TRUE ;
}
return FALSE ;
}
//+---------------------------------------------------------------------------
//
// Function: LhtValidateHandle
//
// Synopsis: Validate that a handle is within the table
//
// Arguments: [HandleTable] --
// [Handle] --
//
// History: 2-03-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
LhtValidateHandle(
PVOID HandleTable,
PSecHandle Handle,
BOOL Deref
)
{
PSEC_HANDLE_ENTRY Entry ;
PLARGE_HANDLE_TABLE Table ;
BOOL Removed ;
Entry = LhtpFindHandle(
HandleTable,
Handle,
(Deref ? LHT_ACTION_DELHANDLE : LHT_ACTION_VALIDATE),
&Removed,
NULL );
if ( Entry )
{
if ( Removed )
{
Table = (PLARGE_HANDLE_TABLE) HandleTable ;
LhtLockTable( Table );
Table->Count--;
LhtUnlockTable( Table );
if ( ( Table->DeleteCallback ) &&
( ( Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK) == 0 ) )
{
Table->DeleteCallback(
&Entry->Handle,
Entry->Context,
Entry->HandleIssuedCount // Entry->RefCount
);
}
if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 )
{
LsapFreePrivateHeap( Entry );
}
}
return TRUE ;
}
else
{
return FALSE ;
}
}
PVOID
LhtRefHandle(
PVOID HandleTable,
PSecHandle Handle
)
{
PSEC_HANDLE_ENTRY Entry ;
Entry = LhtpFindHandle(
HandleTable,
Handle,
LHT_ACTION_ADDREF,
NULL,
NULL );
return Entry ;
}
VOID
LhtDerefHandleKey(
PVOID HandleTable,
PVOID HandleKey
)
{
PSEC_HANDLE_ENTRY Entry = (PSEC_HANDLE_ENTRY) HandleKey ;
LhtDeleteHandle( HandleTable, &Entry->Handle, LHTP_DEREF_NOT_DEL );
}
PVOID
LhtGetHandleContext(
PVOID HandleTable,
PSecHandle Handle
)
{
PSEC_HANDLE_ENTRY Entry ;
Entry = LhtpFindHandle(
HandleTable,
Handle,
LHT_ACTION_ADDREF,
NULL,
NULL );
if ( Entry )
{
return Entry->Context ;
}
else
{
return NULL ;
}
}
BOOL
LhtReleaseContext(
PVOID HandleTable,
PSecHandle Handle
)
{
PSEC_HANDLE_ENTRY Entry ;
PLARGE_HANDLE_TABLE Table ;
BOOL Removed;
Entry = LhtpFindHandle( HandleTable,
Handle,
LHT_ACTION_DELREF,
&Removed,
NULL );
if ( Entry )
{
if ( Removed )
{
Table = (PLARGE_HANDLE_TABLE) HandleTable ;
LhtLockTable( Table );
Table->Count--;
LhtUnlockTable( Table );
if ( ( Table->DeleteCallback ) &&
( ( Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK ) == 0 ) )
{
Table->DeleteCallback( &Entry->Handle, Entry->Context, Entry->RefCount );
}
if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 )
{
LsapFreePrivateHeap( Entry );
}
}
return TRUE ;
}
return FALSE ;
}