mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2035 lines
46 KiB
2035 lines
46 KiB
//+-----------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1991 - 1992
|
|
//
|
|
// File: SesMgr.c
|
|
//
|
|
// Contents: "Session" manager implementation
|
|
//
|
|
// Functions: InitSessionManager -- Sets up the session manager
|
|
// CreateSession -- Create a session
|
|
// DeleteSession -- Delete a session
|
|
// LocateSession -- Locates a session based on CallerContext
|
|
// GetAndSetSession -- Sticks session in TLS
|
|
// FreeSession -- Frees a session from a thread
|
|
// AddCredHandle -- Adds a cred handle to session
|
|
// DelCredHandle -- Deletes a cred handle from a session
|
|
//
|
|
// History:
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
#include <lsapch.hxx>
|
|
extern "C"
|
|
{
|
|
#include <adtp.h>
|
|
}
|
|
|
|
NTSTATUS
|
|
LsapCleanUpHandles(
|
|
PSession pSession,
|
|
PVOID Ignored
|
|
);
|
|
|
|
NTSTATUS
|
|
I_DeleteSession(PSession pSession);
|
|
|
|
RTL_CRITICAL_SECTION csSessionMgr;
|
|
|
|
#if DBG
|
|
|
|
ULONG SessionLock;
|
|
|
|
#define LockSessions(x) RtlEnterCriticalSection(&csSessionMgr); SessionLock = x
|
|
#define UnlockSessions() SessionLock = 0; RtlLeaveCriticalSection(&csSessionMgr)
|
|
|
|
#else
|
|
|
|
#define LockSessions(x) RtlEnterCriticalSection(&csSessionMgr)
|
|
#define UnlockSessions() RtlLeaveCriticalSection(&csSessionMgr)
|
|
|
|
#endif
|
|
|
|
#define SM_ICREATE 1
|
|
#define SM_DELETE 2
|
|
#define SM_ADDRUNDOWN 3
|
|
#define SM_DELRUNDOWN 4
|
|
#define SM_ADDHANDLE 5
|
|
#define SM_DELHANDLE 6
|
|
#define SM_VALIDHANDLE 7
|
|
#define SM_CLONE 9
|
|
#define SM_CLEANUP 10
|
|
#define SM_FINDEFS 11
|
|
#define SM_UPDATEEFS 12
|
|
#define SM_ADDCONNECT 13
|
|
|
|
|
|
PSession pDefaultSession;
|
|
PSession pEfsSession ;
|
|
|
|
LIST_ENTRY SessionList ;
|
|
LIST_ENTRY SessionConnectList ;
|
|
|
|
|
|
VOID
|
|
LsapContextRundown(
|
|
PSecHandle phContext,
|
|
PVOID Context,
|
|
ULONG RefCount
|
|
);
|
|
|
|
VOID
|
|
LsapCredentialRundown(
|
|
PSecHandle phCreds,
|
|
PVOID Context,
|
|
ULONG RefCount
|
|
);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: InitSessionManager()
|
|
//
|
|
// Synopsis: Initializes whatever is needed to track sessions
|
|
//
|
|
// Effects: csSessionMgr, psSessionList;
|
|
//
|
|
// Arguments: void
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: TRUE if success, FALSE otherwise.
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
InitSessionManager(void)
|
|
{
|
|
NTSTATUS scRet = STATUS_SUCCESS;
|
|
PSession pSession;
|
|
Session sSess;
|
|
|
|
//
|
|
// Fake a session during init:
|
|
//
|
|
|
|
|
|
SetCurrentPackageId( SPMGR_ID );
|
|
|
|
SetCurrentSession( &sSess );
|
|
|
|
scRet = RtlInitializeCriticalSection(&csSessionMgr);
|
|
|
|
if (FAILED(scRet))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
SmallHandlePackage.Initialize();
|
|
LargeHandlePackage.Initialize();
|
|
|
|
InitializeListHead( &SessionList );
|
|
|
|
InitializeListHead( &SessionConnectList );
|
|
|
|
scRet = CreateSession(
|
|
&NtCurrentTeb()->ClientId,
|
|
FALSE,
|
|
LSA_PROCESS_NAME,
|
|
0, // no flags
|
|
&pSession
|
|
);
|
|
|
|
if (FAILED(scRet))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
pSession->fSession |= SESFLAG_DEFAULT | SESFLAG_TCB_PRIV ;
|
|
|
|
pDefaultSession = pSession;
|
|
|
|
SetCurrentSession( pSession );
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
VOID
|
|
LsapFindEfsSession(
|
|
VOID
|
|
)
|
|
{
|
|
PLIST_ENTRY Scan ;
|
|
PSession pSession ;
|
|
|
|
LockSessions( SM_FINDEFS );
|
|
|
|
Scan = SessionList.Flink ;
|
|
|
|
while ( Scan != &SessionList )
|
|
{
|
|
pSession = CONTAINING_RECORD( Scan, Session, List );
|
|
|
|
if ( (pSession->dwProcessID == pDefaultSession->dwProcessID) &&
|
|
((pSession->fSession & SESFLAG_KERNEL) != 0 ) )
|
|
{
|
|
pEfsSession = pSession ;
|
|
break;
|
|
}
|
|
|
|
Scan = Scan->Flink ;
|
|
}
|
|
|
|
UnlockSessions();
|
|
|
|
if ( !pEfsSession )
|
|
{
|
|
DebugLog(( DEB_ERROR, "EFS Session not found\n" ));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
LsapUpdateEfsSession(
|
|
PSession pSession
|
|
)
|
|
{
|
|
if ( !pEfsSession )
|
|
{
|
|
return ;
|
|
}
|
|
|
|
LockSessions( SM_UPDATEEFS );
|
|
LockSession( pSession );
|
|
LockSession( pEfsSession );
|
|
|
|
pEfsSession->SharedData = pSession->SharedData ;
|
|
pSession->SharedData->cRefs++ ;
|
|
pEfsSession->fSession |= SESFLAG_EFS ;
|
|
|
|
UnlockSession( pEfsSession );
|
|
UnlockSession( pSession );
|
|
UnlockSessions();
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CreateSession()
|
|
//
|
|
// Synopsis: Creates a new session.
|
|
//
|
|
// Effects: Session list.
|
|
//
|
|
// Arguments: fOpenImmediate - TRUE indicates the process should be opened
|
|
//
|
|
// ppSession - receives a pointer to the session.
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
CreateSession( CLIENT_ID * pClientId,
|
|
BOOL fOpenImmediate,
|
|
PWCHAR ClientProcessName,
|
|
ULONG Flags,
|
|
PSession * ppSession)
|
|
{
|
|
NTSTATUS scRet = STATUS_SUCCESS;
|
|
PSession pSession;
|
|
LPWSTR ClientName;
|
|
PLIST_ENTRY Scan ;
|
|
PLSAP_SESSION_CONNECT Connect ;
|
|
ULONG ConnectType = 0 ;
|
|
|
|
DebugLog(( DEB_TRACE, "Creating session for [%x.%x]\n",
|
|
pClientId->UniqueProcess, pClientId->UniqueThread ));
|
|
|
|
*ppSession = NULL;
|
|
|
|
if ( *ClientProcessName )
|
|
{
|
|
ConnectType |= SESSION_CONNECT_TRUSTED ;
|
|
|
|
ClientName = (LPWSTR) LsapAllocatePrivateHeap(
|
|
(wcslen(ClientProcessName)+1) * sizeof(WCHAR));
|
|
|
|
if (ClientName == NULL)
|
|
{
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
wcscpy(ClientName,ClientProcessName);
|
|
}
|
|
else
|
|
{
|
|
ConnectType |= SESSION_CONNECT_UNTRUSTED ;
|
|
|
|
ClientName = NULL;
|
|
}
|
|
|
|
|
|
pSession = (PSession) LsapAllocatePrivateHeap( sizeof( Session ) );
|
|
if (!pSession)
|
|
{
|
|
*ppSession = NULL;
|
|
if( ClientName != NULL )
|
|
{
|
|
LsapFreePrivateHeap( ClientName );
|
|
}
|
|
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
RtlZeroMemory(pSession, sizeof(Session));
|
|
|
|
//
|
|
// Initialize stuff:
|
|
//
|
|
|
|
pSession->fSession = Flags;
|
|
|
|
//
|
|
// we check for this much later, after some same initializing
|
|
// steps, so we can use the common cleanup
|
|
//
|
|
|
|
scRet = RtlInitializeCriticalSection( &pSession->SessionLock );
|
|
|
|
InitializeListHead( &pSession->SectionList );
|
|
InitializeListHead( &pSession->RundownList );
|
|
|
|
pSession->ClientProcessName = ClientName;
|
|
pSession->dwProcessID = HandleToUlong(pClientId->UniqueProcess);
|
|
|
|
//
|
|
// Store the handle cleanup as a rundown function
|
|
//
|
|
|
|
if ( NT_SUCCESS( scRet ) )
|
|
{
|
|
if ( !AddRundown( pSession,
|
|
LsapCleanUpHandles,
|
|
NULL ) )
|
|
{
|
|
scRet = STATUS_NO_MEMORY ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Lock the sessions now so we know that no new kernel sessions
|
|
// will be created
|
|
//
|
|
|
|
LockSessions(SM_ICREATE);
|
|
|
|
//
|
|
// Add the session to the list
|
|
//
|
|
|
|
InsertTailList( &SessionList, &pSession->List );
|
|
|
|
//
|
|
// *Now* check if we're doing ok:
|
|
//
|
|
|
|
if ( !NT_SUCCESS( scRet ))
|
|
{
|
|
UnlockSessions();
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If the caller is from kernel mode, look for an existing kernel
|
|
// session to use the handle list from.
|
|
//
|
|
|
|
if ((Flags & SESFLAG_MAYBEKERNEL) != 0)
|
|
{
|
|
PSession pTrace = NULL;
|
|
|
|
//
|
|
// Find a kernel-mode session and use its handle list. Make sure
|
|
// it's not the default LSA session, although it is ok to use the
|
|
// session tagged as the EFS one. This will keep the EFS session
|
|
// and the (primary) rdr session in sync.
|
|
//
|
|
|
|
Scan = SessionList.Flink ;
|
|
|
|
while ( Scan != &SessionList )
|
|
{
|
|
pTrace = CONTAINING_RECORD( Scan, Session, List );
|
|
|
|
if ( pTrace != pSession )
|
|
{
|
|
if ( ( (pTrace->fSession & SESFLAG_KERNEL) != 0 ) &&
|
|
( ( (pTrace->fSession & SESFLAG_EFS) != 0 ) ||
|
|
( pTrace->dwProcessID != pDefaultSession->dwProcessID ) ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
pTrace = NULL ;
|
|
|
|
Scan = Scan->Flink ;
|
|
|
|
}
|
|
|
|
//
|
|
// If we found a session, use its handle list and queue
|
|
//
|
|
|
|
if (pTrace != NULL)
|
|
{
|
|
pTrace->SharedData->cRefs++;
|
|
pSession->SharedData = pTrace->SharedData;
|
|
DebugLog(( DEB_TRACE, "Linking session %p to %p\n",
|
|
pSession, pTrace ));
|
|
}
|
|
|
|
//
|
|
// ConnectType is not definite, it is a hint to others
|
|
// watching for new sessions
|
|
//
|
|
|
|
ConnectType |= SESSION_CONNECT_KERNEL ;
|
|
}
|
|
|
|
//
|
|
// If we don't have a handle list yet, create one and set it to NULL
|
|
//
|
|
|
|
if (pSession->SharedData == NULL)
|
|
{
|
|
if ( pSession->fSession & SESFLAG_MAYBEKERNEL )
|
|
{
|
|
pSession->SharedData = (PLSAP_SHARED_SESSION_DATA) LsapAllocatePrivateHeap(
|
|
sizeof( LSAP_SHARED_SESSION_DATA ) );
|
|
}
|
|
else
|
|
{
|
|
pSession->SharedData = &pSession->DefaultData ;
|
|
}
|
|
|
|
if ( pSession->SharedData )
|
|
{
|
|
|
|
RtlZeroMemory(
|
|
pSession->SharedData,
|
|
sizeof( LSAP_SHARED_SESSION_DATA ) );
|
|
|
|
//
|
|
// Create Handle Tables:
|
|
//
|
|
|
|
pSession->SharedData->CredHandlePackage = &SmallHandlePackage ;
|
|
pSession->SharedData->ContextHandlePackage = &LargeHandlePackage ;
|
|
|
|
pSession->SharedData->CredTable = pSession->SharedData->CredHandlePackage->Create(
|
|
HANDLE_PACKAGE_CALLBACK_ON_DELETE,
|
|
NULL,
|
|
LsapCredentialRundown );
|
|
|
|
pSession->SharedData->ContextTable = pSession->SharedData->ContextHandlePackage->Create(
|
|
HANDLE_PACKAGE_CALLBACK_ON_DELETE,
|
|
NULL,
|
|
LsapContextRundown );
|
|
|
|
if ((pSession->SharedData->CredTable == NULL) || (pSession->SharedData->ContextTable == NULL))
|
|
{
|
|
scRet = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
pSession->SharedData->cRefs = 1;
|
|
}
|
|
else
|
|
{
|
|
scRet = STATUS_INSUFFICIENT_RESOURCES ;
|
|
}
|
|
|
|
}
|
|
|
|
UnlockSessions();
|
|
|
|
//
|
|
// Check for callbacks when a client connects. Note, this does
|
|
// not need to be under the session list lock, because it is
|
|
// sufficient that no client is using the session until the
|
|
// callbacks are complete. Since the connection attempt is
|
|
// stalled until this returns, that requirement is met.
|
|
//
|
|
|
|
Scan = SessionConnectList.Flink ;
|
|
while ( Scan != &SessionConnectList )
|
|
{
|
|
Connect = CONTAINING_RECORD( Scan, LSAP_SESSION_CONNECT, List );
|
|
|
|
if ( Connect->ConnectFilter & ConnectType )
|
|
{
|
|
Connect->Callback( pSession, Connect->Parameter );
|
|
}
|
|
|
|
Scan = Scan->Flink ;
|
|
}
|
|
|
|
|
|
*ppSession = pSession ;
|
|
|
|
if (fOpenImmediate & (NT_SUCCESS(scRet)))
|
|
{
|
|
scRet = LsapOpenCaller(pSession);
|
|
}
|
|
|
|
//
|
|
// If we failed somewhere, cleanup now.
|
|
//
|
|
|
|
Cleanup:
|
|
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
I_DeleteSession(pSession);
|
|
*ppSession = NULL;
|
|
}
|
|
return(scRet);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CloneSession
|
|
//
|
|
// Synopsis: Temporary copy of a session for scavenger threads
|
|
//
|
|
// Arguments: [pOriginalSession] --
|
|
// [ppSession] --
|
|
//
|
|
// History: 5-18-95 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
CloneSession(
|
|
PSession pOriginalSession,
|
|
PSession * ppSession,
|
|
ULONG Flags )
|
|
{
|
|
PSession pSession;
|
|
NTSTATUS Status ;
|
|
BOOL LockInitialized = FALSE ;
|
|
|
|
pSession = (PSession) LsapAllocatePrivateHeap( sizeof( Session ) );
|
|
|
|
if ( !pSession )
|
|
{
|
|
*ppSession = NULL ;
|
|
|
|
return STATUS_NO_MEMORY ;
|
|
}
|
|
|
|
//
|
|
// Make sure there is no one else mucking with general session stuff
|
|
//
|
|
|
|
LockSessions(SM_CLONE);
|
|
|
|
Status = STATUS_SUCCESS ;
|
|
|
|
//
|
|
// Copy all the interesting bits
|
|
//
|
|
|
|
CopyMemory(pSession, pOriginalSession, sizeof(Session));
|
|
|
|
//
|
|
// Make sure it has its own critical section
|
|
//
|
|
|
|
Status = RtlInitializeCriticalSection( &pSession->SessionLock );
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
LockInitialized = TRUE ;
|
|
}
|
|
|
|
//
|
|
// note that it is a clone
|
|
//
|
|
|
|
pSession->fSession |= ( SESFLAG_CLONE | Flags );
|
|
|
|
//
|
|
// Initialize our own rundown list.
|
|
//
|
|
|
|
InitializeListHead( &pSession->RundownList );
|
|
|
|
//
|
|
// Use our own rundown
|
|
//
|
|
|
|
if ( AddRundown( pSession, LsapCleanUpHandles, NULL ) )
|
|
{
|
|
pOriginalSession->SharedData->cRefs++;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NO_MEMORY ;
|
|
}
|
|
|
|
UnlockSessions();
|
|
|
|
if ( !NT_SUCCESS( Status ) )
|
|
{
|
|
|
|
if ( LockInitialized )
|
|
{
|
|
RtlDeleteCriticalSection( &pSession->SessionLock );
|
|
}
|
|
LsapFreePrivateHeap( pSession );
|
|
|
|
*ppSession = NULL ;
|
|
|
|
return Status ;
|
|
}
|
|
|
|
//
|
|
// Set the reference count of the clone to -1, so that the a single
|
|
// ref/deref will kill it.
|
|
//
|
|
|
|
pSession->RefCount = -1;
|
|
|
|
//
|
|
// Clones do *NOT* get added to the session list.
|
|
//
|
|
|
|
*ppSession = pSession;
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
CreateShadowSession(
|
|
DWORD ProcessId,
|
|
PSession * NewSession
|
|
)
|
|
{
|
|
NTSTATUS Status ;
|
|
CLIENT_ID ClientId;
|
|
PSession Session ;
|
|
|
|
|
|
ClientId.UniqueProcess = (HANDLE) LongToHandle(ProcessId) ;
|
|
ClientId.UniqueThread = NULL ;
|
|
|
|
Status = CreateSession(
|
|
&ClientId,
|
|
FALSE,
|
|
L"",
|
|
SESFLAG_SHADOW,
|
|
&Session );
|
|
|
|
*NewSession = Session ;
|
|
|
|
return Status ;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
LsapDeleteContextWrap(
|
|
PSecHandle Handle,
|
|
PVOID Context,
|
|
ULONG RefCount
|
|
)
|
|
{
|
|
PLSA_CALL_INFO CallInfo ;
|
|
|
|
CallInfo = LsapGetCurrentCall();
|
|
|
|
CallInfo->CallInfo.CallCount = RefCount ;
|
|
|
|
WLsaDeleteContext( Handle );
|
|
|
|
CallInfo->CallInfo.CallCount = 0 ;
|
|
}
|
|
|
|
VOID
|
|
WINAPI
|
|
LsapFreeCredWrap(
|
|
PSecHandle Handle,
|
|
PVOID Context,
|
|
ULONG RefCount
|
|
)
|
|
{
|
|
PLSA_CALL_INFO CallInfo ;
|
|
|
|
CallInfo = LsapGetCurrentCall();
|
|
|
|
CallInfo->CallInfo.CallCount = RefCount ;
|
|
|
|
WLsaFreeCredHandle( Handle );
|
|
|
|
CallInfo->CallInfo.CallCount = 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapCleanUpHandles
|
|
//
|
|
// Synopsis: Closes all context and credential handles for a session
|
|
//
|
|
// Arguments: [pSession] --
|
|
// [Ignored] --
|
|
//
|
|
// History: 5-15-97 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
LsapCleanUpHandles(
|
|
PSession pSession,
|
|
PVOID Ignored
|
|
)
|
|
{
|
|
NTSTATUS scRet = STATUS_SUCCESS;
|
|
PSession pSave;
|
|
ULONG HandleRefs;
|
|
PLIST_ENTRY ListEntry;
|
|
LSA_CALL_INFO CallInfo ;
|
|
HANDLE hImp ;
|
|
|
|
|
|
//
|
|
// If this is the last user of the handle lists, cleanup
|
|
//
|
|
|
|
if ( pSession->SharedData == NULL )
|
|
{
|
|
return STATUS_SUCCESS ;
|
|
}
|
|
|
|
LockSessions(SM_CLEANUP);
|
|
|
|
pSession->SharedData->cRefs--;
|
|
HandleRefs = pSession->SharedData->cRefs;
|
|
|
|
UnlockSessions();
|
|
|
|
if (HandleRefs == 0)
|
|
{
|
|
|
|
LsapInitializeCallInfo( &CallInfo,
|
|
FALSE );
|
|
|
|
CallInfo.CallInfo.Attributes |= SECPKG_CALL_CLEANUP ;
|
|
|
|
LsapSetCurrentCall( &CallInfo );
|
|
|
|
pSave = GetCurrentSession();
|
|
|
|
SetCurrentSession( pSession );
|
|
|
|
|
|
if (pSession->SharedData->ContextTable != NULL)
|
|
{
|
|
pSession->SharedData->ContextHandlePackage->Delete( pSession->SharedData->ContextTable,
|
|
LsapDeleteContextWrap );
|
|
}
|
|
|
|
if (pSession->SharedData->CredTable != NULL)
|
|
{
|
|
pSession->SharedData->CredHandlePackage->Delete( pSession->SharedData->CredTable,
|
|
LsapFreeCredWrap );
|
|
}
|
|
|
|
if ( pSession->fSession & SESFLAG_KERNEL )
|
|
{
|
|
LsapFreePrivateHeap( pSession->SharedData );
|
|
}
|
|
|
|
SetCurrentSession( pSave );
|
|
|
|
LsapSetCurrentCall( NULL );
|
|
}
|
|
|
|
pSession->SharedData = NULL;
|
|
|
|
return(scRet);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: I_DeleteSession()
|
|
//
|
|
// Synopsis: Deletes the session indicated
|
|
//
|
|
// Effects: Frees memory
|
|
//
|
|
// Arguments: pSession Session to delete
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
NTSTATUS
|
|
I_DeleteSession(PSession pSession)
|
|
{
|
|
PSession pTrace;
|
|
PLIST_ENTRY List ;
|
|
PLSAP_SESSION_RUNDOWN Rundown ;
|
|
int i;
|
|
|
|
DebugLog(( DEB_TRACE, "DeleteSession( %x )\n", pSession ));
|
|
|
|
DsysAssertMsg(pSession, "DeleteSession passed null pointer");
|
|
|
|
pSession->fSession |= SESFLAG_CLEANUP;
|
|
|
|
|
|
//
|
|
// Clones aren't in the list, so don't try to unlink it
|
|
//
|
|
|
|
if ( ( pSession->fSession & SESFLAG_CLONE ) == 0 )
|
|
{
|
|
LockSessions(SM_DELETE);
|
|
|
|
RemoveEntryList( &pSession->List );
|
|
|
|
UnlockSessions();
|
|
}
|
|
|
|
//
|
|
// Execute the rundown functions
|
|
//
|
|
|
|
LockSession( pSession );
|
|
|
|
while ( !IsListEmpty( &pSession->RundownList ) )
|
|
{
|
|
List = RemoveHeadList( &pSession->RundownList );
|
|
|
|
Rundown = CONTAINING_RECORD( List, LSAP_SESSION_RUNDOWN, List );
|
|
|
|
Rundown->Rundown( pSession, Rundown->Parameter );
|
|
|
|
LsapFreePrivateHeap( Rundown );
|
|
}
|
|
|
|
UnlockSession( pSession );
|
|
|
|
RtlDeleteCriticalSection( &pSession->SessionLock );
|
|
|
|
if (pSession->fSession & SESFLAG_CLONE)
|
|
{
|
|
//
|
|
// Clones are not part of the global list, and are
|
|
// around just for bookkeepping for scavenger threads
|
|
//
|
|
|
|
pSession->dwProcessID = 0xFFFFFFFF;
|
|
|
|
LsapFreePrivateHeap( pSession );
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Close our handles
|
|
//
|
|
|
|
if (pSession->hProcess)
|
|
NtClose(pSession->hProcess);
|
|
|
|
if (pSession->hPort)
|
|
{
|
|
NtClose(pSession->hPort);
|
|
}
|
|
|
|
pSession->dwProcessID = 0xFFFFFFFF;
|
|
|
|
|
|
if( pSession->ClientProcessName )
|
|
{
|
|
LsapFreePrivateHeap( pSession->ClientProcessName );
|
|
}
|
|
|
|
LsapFreePrivateHeap( pSession );
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
HRESULT
|
|
LsapDeleteWorkQueue(
|
|
PSession pSession,
|
|
PVOID Parameter
|
|
)
|
|
{
|
|
if ( pSession->SharedData->pQueue )
|
|
{
|
|
DeleteSubordinateQueue( pSession->SharedData->pQueue, 0 );
|
|
|
|
pSession->SharedData->pQueue = NULL ;
|
|
}
|
|
|
|
return STATUS_SUCCESS ;
|
|
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SpmpReferenceSession
|
|
//
|
|
// Synopsis: Ups the ref count on a session
|
|
//
|
|
// Arguments: [pSession] --
|
|
//
|
|
// History: 5-18-95 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
SpmpReferenceSession(
|
|
PSession pSession)
|
|
{
|
|
InterlockedIncrement(&pSession->RefCount);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SpmpDereferenceSession
|
|
//
|
|
// Synopsis: Derefs a session. If the session goes negative, it gets
|
|
// deleted.
|
|
//
|
|
// Arguments: [pSession] --
|
|
//
|
|
// History: 5-18-95 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
SpmpDereferenceSession(
|
|
PSession pSession)
|
|
{
|
|
LONG RefCount = InterlockedDecrement(&pSession->RefCount);
|
|
|
|
if( RefCount < 0 )
|
|
{
|
|
if ( pSession == pDefaultSession )
|
|
{
|
|
pSession->RefCount = 1 ;
|
|
}
|
|
else
|
|
{
|
|
DsysAssert( (pSession->RefCount == -1) && (RefCount == -1) );
|
|
I_DeleteSession(pSession);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
LsapSessionDisconnect(
|
|
PSession pSession
|
|
)
|
|
{
|
|
if ( pSession->SharedData->cRefs == 1 )
|
|
{
|
|
LsapDeleteWorkQueue( pSession, NULL );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: FreeSession
|
|
//
|
|
// Synopsis: Frees a session
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void
|
|
FreeSession(PSession pSession)
|
|
{
|
|
if (pSession == NULL)
|
|
{
|
|
pSession = GetCurrentSession();
|
|
}
|
|
|
|
if (!pSession)
|
|
{
|
|
DebugLog((DEB_ERROR, "FreeSession: No Session?\n"));
|
|
return;
|
|
}
|
|
|
|
TlsSetValue(dwSession, pDefaultSession);
|
|
}
|
|
|
|
|
|
//
|
|
// Rundown Semantics:
|
|
//
|
|
// Rundowns allow other functions to be called when a session is closed. This
|
|
// is useful if you need to keep something around as long as a client is
|
|
// connected, but need to clean up afterwards.
|
|
//
|
|
// Rules: You cannot call back into or reference the client process. This is
|
|
// because the process has already terminated.
|
|
//
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AddRundown
|
|
//
|
|
// Synopsis: Adds a function to be called when the session is terminated
|
|
//
|
|
// Arguments: [pSession] --
|
|
// [RundownFn] --
|
|
// [pvParameter] --
|
|
//
|
|
// History: 5-18-95 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
AddRundown(
|
|
PSession pSession,
|
|
PLSAP_SESSION_RUNDOWN_FN RundownFn,
|
|
PVOID pvParameter)
|
|
{
|
|
PLSAP_SESSION_RUNDOWN Rundown ;
|
|
|
|
Rundown = (PLSAP_SESSION_RUNDOWN) LsapAllocatePrivateHeap(
|
|
sizeof( LSAP_SESSION_RUNDOWN ) );
|
|
|
|
if ( Rundown )
|
|
{
|
|
Rundown->Rundown = RundownFn ;
|
|
Rundown->Parameter = pvParameter ;
|
|
|
|
LockSession( pSession );
|
|
|
|
InsertTailList( &pSession->RundownList, &Rundown->List );
|
|
|
|
UnlockSession( pSession );
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
return FALSE ;
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: DelRundown
|
|
//
|
|
// Synopsis: Removes a rundown function from a session
|
|
//
|
|
// Arguments: [pSession] --
|
|
// [RundownFn] --
|
|
//
|
|
// History: 5-18-95 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
DelRundown(
|
|
PSession pSession,
|
|
PLSAP_SESSION_RUNDOWN_FN RundownFn
|
|
)
|
|
{
|
|
PLIST_ENTRY Scan;
|
|
PLSAP_SESSION_RUNDOWN Rundown ;
|
|
|
|
LockSession( pSession );
|
|
|
|
Scan = pSession->RundownList.Flink ;
|
|
|
|
Rundown = NULL ;
|
|
|
|
while ( Scan != &pSession->RundownList )
|
|
{
|
|
Rundown = (PLSAP_SESSION_RUNDOWN) Scan ;
|
|
|
|
if ( Rundown->Rundown == RundownFn )
|
|
{
|
|
RemoveEntryList( &Rundown->List );
|
|
|
|
break;
|
|
}
|
|
|
|
Rundown = NULL ;
|
|
|
|
Scan = Scan->Flink ;
|
|
}
|
|
|
|
UnlockSession( pSession );
|
|
|
|
if ( Rundown )
|
|
{
|
|
LsapFreePrivateHeap( Rundown );
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
return FALSE ;
|
|
|
|
}
|
|
|
|
BOOL
|
|
AddConnectionHook(
|
|
PLSAP_SESSION_CONNECT_FN ConnectFn,
|
|
PVOID Parameter,
|
|
ULONG Filter
|
|
)
|
|
{
|
|
PLSAP_SESSION_CONNECT Connect ;
|
|
|
|
Connect = (PLSAP_SESSION_CONNECT) LsapAllocatePrivateHeap( sizeof( LSAP_SESSION_CONNECT ) );
|
|
|
|
if ( Connect )
|
|
{
|
|
Connect->Callback = ConnectFn ;
|
|
Connect->ConnectFilter = Filter ;
|
|
Connect->Parameter = Parameter ;
|
|
|
|
LockSessions( SM_ADDCONNECT );
|
|
|
|
InsertTailList( &SessionConnectList, &Connect->List );
|
|
|
|
UnlockSessions();
|
|
}
|
|
|
|
return (Connect != NULL) ;
|
|
}
|
|
|
|
|
|
VOID
|
|
LsapCredentialRundown(
|
|
PSecHandle phCreds,
|
|
PVOID Context,
|
|
ULONG RefCount
|
|
)
|
|
{
|
|
PSession pSession = (PSession) Context ;
|
|
NTSTATUS scRet;
|
|
PLSAP_SECURITY_PACKAGE pPackage;
|
|
PSession Previous ;
|
|
|
|
|
|
Previous = GetCurrentSession();
|
|
|
|
if ( ( ( pSession->fSession & SESFLAG_KERNEL ) != 0 ) &&
|
|
( ( Previous->fSession & SESFLAG_KERNEL ) != 0 ) )
|
|
{
|
|
NOTHING ;
|
|
}
|
|
else
|
|
{
|
|
SetCurrentSession( pSession );
|
|
|
|
}
|
|
|
|
DebugLog((DEB_TRACE, "[%x] CredentialRundown (%p:%p) RefCount=%lu\n",
|
|
pSession->dwProcessID, phCreds->dwUpper, phCreds->dwLower, RefCount));
|
|
|
|
pPackage = SpmpValidRequest(phCreds->dwLower,
|
|
SP_ORDINAL_FREECREDHANDLE );
|
|
|
|
if (pPackage)
|
|
{
|
|
PLSA_CALL_INFO CallInfo;
|
|
ULONG OldRefCount;
|
|
|
|
SetCurrentPackageId(phCreds->dwLower);
|
|
|
|
StartCallToPackage( pPackage );
|
|
|
|
ASSERT( RefCount );
|
|
|
|
CallInfo = LsapGetCurrentCall();
|
|
OldRefCount = CallInfo->CallInfo.CallCount;
|
|
CallInfo->CallInfo.CallCount = RefCount;
|
|
|
|
__try
|
|
{
|
|
scRet = pPackage->FunctionTable.FreeCredentialsHandle(
|
|
phCreds->dwUpper);
|
|
}
|
|
__except (SP_EXCEPTION)
|
|
{
|
|
scRet = GetExceptionCode();
|
|
scRet = SPException(scRet, phCreds->dwLower);
|
|
}
|
|
|
|
CallInfo->CallInfo.CallCount = OldRefCount;
|
|
|
|
EndCallToPackage( pPackage );
|
|
|
|
LsapDelPackageHandle( pPackage, FALSE );
|
|
}
|
|
|
|
SetCurrentSession( Previous );
|
|
}
|
|
|
|
|
|
VOID
|
|
LsapContextRundown(
|
|
PSecHandle phContext,
|
|
PVOID Context,
|
|
ULONG RefCount
|
|
)
|
|
{
|
|
PSession Session = (PSession) Context;
|
|
PSession Previous ;
|
|
PLSAP_SECURITY_PACKAGE pspPackage;
|
|
PLSA_CALL_INFO CallInfo;
|
|
ULONG OldRefCount;
|
|
|
|
NTSTATUS scRet ;
|
|
|
|
|
|
Previous = GetCurrentSession();
|
|
|
|
if ( ( ( Session->fSession & SESFLAG_KERNEL ) != 0 ) &&
|
|
( ( Previous->fSession & SESFLAG_KERNEL ) != 0 ) )
|
|
{
|
|
NOTHING ;
|
|
}
|
|
else
|
|
{
|
|
SetCurrentSession( Session );
|
|
|
|
}
|
|
|
|
|
|
pspPackage = SpmpValidRequest( phContext->dwLower,
|
|
SP_ORDINAL_DELETECTXT);
|
|
|
|
if (! pspPackage )
|
|
{
|
|
DebugLog((DEB_ERROR,"[%x] Invalid request for DeleteContext, package: %d\n",
|
|
Session->dwProcessID, phContext->dwLower));
|
|
return ;
|
|
}
|
|
|
|
DebugLog(( DEB_TRACE, "[%x] ContextRundown(%p:%p)\n",
|
|
Session->dwProcessID, phContext->dwUpper,
|
|
phContext->dwLower ));
|
|
|
|
SetCurrentPackageId(phContext->dwLower);
|
|
|
|
StartCallToPackage( pspPackage );
|
|
|
|
|
|
//
|
|
// RefCount should ALWAYS be 1 currently, as, the context handle code
|
|
// assumes context handle issue count never exceeds 1.
|
|
//
|
|
|
|
ASSERT( RefCount == 1 );
|
|
|
|
CallInfo = LsapGetCurrentCall();
|
|
OldRefCount = CallInfo->CallInfo.CallCount;
|
|
CallInfo->CallInfo.CallCount = RefCount;
|
|
|
|
__try
|
|
{
|
|
scRet = pspPackage->FunctionTable.DeleteContext( phContext->dwUpper );
|
|
}
|
|
__except (SP_EXCEPTION)
|
|
{
|
|
scRet = GetExceptionCode();
|
|
scRet = SPException( scRet, pspPackage->dwPackageID);
|
|
}
|
|
|
|
CallInfo->CallInfo.CallCount = OldRefCount;
|
|
EndCallToPackage( pspPackage );
|
|
|
|
#if DBG
|
|
if ( !NT_SUCCESS( scRet ) )
|
|
{
|
|
DebugLog((DEB_ERROR, "[%x] package %ws failed DeleteContext with %x\n",
|
|
Session->dwProcessID,
|
|
pspPackage->Name.Buffer,
|
|
scRet ));
|
|
|
|
}
|
|
#endif
|
|
|
|
DebugLog(( DEB_TRACE_WAPI, "[%x] return code %x\n", Session->dwProcessID,
|
|
scRet ));
|
|
|
|
|
|
SetCurrentPackageId( SPMGR_ID );
|
|
|
|
SetCurrentSession( Previous );
|
|
|
|
LsapDelPackageHandle( pspPackage, TRUE );
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: AddCredHandle
|
|
//
|
|
// Synopsis: Adds an obtained cred handle to the list for this session
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOLEAN
|
|
AddCredHandle( PSession pSession,
|
|
PCredHandle phCred,
|
|
ULONG Flags)
|
|
{
|
|
|
|
if (pSession->fSession & SESFLAG_CLONE)
|
|
{
|
|
DebugLog((DEB_ERROR, "Attempt to add a credhandle to a clone session\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
if ( pSession->fSession & SESFLAG_KERNEL )
|
|
{
|
|
pSession = pEfsSession ;
|
|
}
|
|
|
|
DebugLog(( DEB_TRACE_HANDLES, "Adding Cred %p : %p to %p\n",
|
|
phCred->dwUpper, phCred->dwLower, pSession ));
|
|
|
|
|
|
if(pSession->SharedData->CredHandlePackage->AddHandle(
|
|
pSession->SharedData->CredTable,
|
|
phCred,
|
|
pSession,
|
|
Flags))
|
|
{
|
|
|
|
LsapAddPackageHandle( phCred->dwLower, FALSE );
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AddContextHandle
|
|
//
|
|
// Synopsis: Adds a context handle to this session
|
|
//
|
|
// Arguments: [phContext] --
|
|
//
|
|
// History: 5-18-95 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOLEAN
|
|
AddContextHandle( PSession pSession,
|
|
PCtxtHandle phContext,
|
|
ULONG Flags)
|
|
{
|
|
if (pSession->fSession & SESFLAG_CLONE)
|
|
{
|
|
DebugLog((DEB_ERROR, "Attempt to add a ctxthandle to a clone session\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if ( pSession->fSession & SESFLAG_KERNEL )
|
|
{
|
|
pSession = pEfsSession ;
|
|
}
|
|
|
|
DebugLog(( DEB_TRACE_HANDLES, "Adding Context %p : %p to %p\n",
|
|
phContext->dwUpper, phContext->dwLower, pSession ));
|
|
|
|
|
|
//
|
|
// Find out where this 0:0 handle is coming from:
|
|
//
|
|
|
|
DsysAssertMsg( (phContext->dwLower | phContext->dwUpper), "Null context handle added\n");
|
|
|
|
if(pSession->SharedData->ContextHandlePackage->AddHandle(
|
|
pSession->SharedData->ContextTable,
|
|
phContext,
|
|
pSession,
|
|
Flags
|
|
))
|
|
{
|
|
LsapAddPackageHandle( phContext->dwLower, TRUE );
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ValidateContextHandle
|
|
//
|
|
// Synopsis: Validate the context handle against the session list
|
|
//
|
|
// Arguments: [pSession] --
|
|
// [phContext] --
|
|
//
|
|
// History: 5-18-95 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
ValidateContextHandle(
|
|
PSession pSession,
|
|
PCtxtHandle phContext,
|
|
PVOID * pKey
|
|
)
|
|
{
|
|
|
|
*pKey = pSession->SharedData->ContextHandlePackage->RefHandle(
|
|
pSession->SharedData->ContextTable,
|
|
phContext );
|
|
|
|
DebugLog(( DEB_TRACE_HANDLES, "Validate context (%p : %p) for %p returned %p\n",
|
|
phContext->dwUpper, phContext->dwLower,
|
|
pSession, *pKey ));
|
|
|
|
if ( *pKey )
|
|
{
|
|
return SEC_E_OK ;
|
|
}
|
|
else
|
|
{
|
|
return SEC_E_INVALID_HANDLE ;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DerefContextHandle(
|
|
PSession pSession,
|
|
PCtxtHandle phContext,
|
|
PVOID Key OPTIONAL
|
|
)
|
|
{
|
|
if ( Key )
|
|
{
|
|
#if DBG
|
|
PSEC_HANDLE_ENTRY Entry = (PSEC_HANDLE_ENTRY) Key ;
|
|
|
|
DebugLog(( DEB_TRACE_HANDLES, "Deref context handle by key ( %p : %p ) for %p \n",
|
|
Entry->Handle.dwUpper, Entry->Handle.dwLower,
|
|
pSession ));
|
|
#endif
|
|
pSession->SharedData->ContextHandlePackage->DerefHandleKey(
|
|
pSession->SharedData->ContextTable,
|
|
Key );
|
|
|
|
}
|
|
else
|
|
{
|
|
pSession->SharedData->ContextHandlePackage->DeleteHandle(
|
|
pSession->SharedData->ContextTable,
|
|
phContext,
|
|
0 );
|
|
|
|
DebugLog(( DEB_TRACE_HANDLES, "Deref context handle by handle (%p : %p) for %p\n",
|
|
phContext->dwUpper, phContext->dwLower,
|
|
pSession ));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ValidateAndDerefContextHandle(
|
|
PSession pSession,
|
|
PCtxtHandle phContext
|
|
)
|
|
{
|
|
DebugLog(( DEB_TRACE_HANDLES, "ValidateAndDeref Context (%p : %p)\n",
|
|
phContext->dwUpper, phContext->dwLower ));
|
|
|
|
if ( pSession->SharedData->ContextHandlePackage->ValidateHandle(
|
|
pSession->SharedData->ContextTable,
|
|
phContext,
|
|
TRUE ) )
|
|
{
|
|
return SEC_E_OK ;
|
|
}
|
|
|
|
return SEC_E_INVALID_HANDLE ;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ValidateCredHandle
|
|
//
|
|
// Synopsis: Validate the context handle against the session list
|
|
//
|
|
// Arguments: [pSession] --
|
|
// [phCred] --
|
|
//
|
|
// History: 5-18-95 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
ValidateCredHandle(
|
|
PSession pSession,
|
|
PCtxtHandle phCred,
|
|
PVOID * pKey
|
|
)
|
|
{
|
|
|
|
*pKey = pSession->SharedData->CredHandlePackage->RefHandle(
|
|
pSession->SharedData->CredTable,
|
|
phCred );
|
|
|
|
DebugLog(( DEB_TRACE_HANDLES, "Validate cred (%p : %p) for %p returned %p\n",
|
|
phCred->dwUpper, phCred->dwLower,
|
|
pSession, *pKey ));
|
|
|
|
if ( *pKey )
|
|
{
|
|
return SEC_E_OK ;
|
|
}
|
|
else
|
|
{
|
|
return SEC_E_INVALID_HANDLE ;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DerefCredHandle(
|
|
PSession pSession,
|
|
PCtxtHandle phCred,
|
|
PVOID Key OPTIONAL
|
|
)
|
|
{
|
|
if ( Key )
|
|
{
|
|
#if DBG
|
|
PSEC_HANDLE_ENTRY Entry = (PSEC_HANDLE_ENTRY) Key ;
|
|
|
|
DebugLog(( DEB_TRACE_HANDLES, "Deref cred ( %p : %p ) for %p \n",
|
|
Entry->Handle.dwUpper, Entry->Handle.dwLower,
|
|
pSession ));
|
|
#endif
|
|
pSession->SharedData->CredHandlePackage->DerefHandleKey(
|
|
pSession->SharedData->CredTable,
|
|
Key );
|
|
}
|
|
else
|
|
{
|
|
pSession->SharedData->CredHandlePackage->DeleteHandle(
|
|
pSession->SharedData->CredTable,
|
|
phCred,
|
|
0 );
|
|
|
|
DebugLog(( DEB_TRACE_HANDLES, "Deref cred (%p : %p) for %p\n",
|
|
phCred->dwUpper, phCred->dwLower,
|
|
pSession ));
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ValidateAndDerefCredHandle(
|
|
PSession pSession,
|
|
PCtxtHandle phCred
|
|
)
|
|
{
|
|
DebugLog(( DEB_TRACE_HANDLES, "ValidateAndDeref Cred (%p : %p)\n",
|
|
phCred->dwUpper, phCred->dwLower ));
|
|
|
|
if ( pSession->SharedData->CredHandlePackage->ValidateHandle(
|
|
pSession->SharedData->CredTable,
|
|
phCred,
|
|
TRUE ) )
|
|
{
|
|
return SEC_E_OK ;
|
|
}
|
|
|
|
return SEC_E_INVALID_HANDLE ;
|
|
}
|
|
|
|
BOOL
|
|
LsapMoveContextHandle(
|
|
PSecHandle Handle,
|
|
PSession OriginatingSession,
|
|
PSession DestinationSession
|
|
)
|
|
{
|
|
BOOL Ret ;
|
|
|
|
if ( OriginatingSession->SharedData->ContextHandlePackage->DeleteHandle(
|
|
OriginatingSession->SharedData->ContextTable,
|
|
Handle,
|
|
DELHANDLE_FORCE | DELHANDLE_NO_CALLBACK ) )
|
|
{
|
|
Ret = DestinationSession->SharedData->ContextHandlePackage->AddHandle(
|
|
DestinationSession->SharedData->ContextTable,
|
|
Handle,
|
|
DestinationSession,
|
|
0 );
|
|
|
|
|
|
} else {
|
|
Ret = FALSE ;
|
|
}
|
|
|
|
return Ret ;
|
|
}
|
|
|
|
BOOL
|
|
LsapMoveCredHandle(
|
|
PSecHandle Handle,
|
|
PSession OriginatingSession,
|
|
PSession DestinationSession
|
|
)
|
|
{
|
|
BOOL Ret ;
|
|
|
|
if ( OriginatingSession->SharedData->CredHandlePackage->DeleteHandle(
|
|
OriginatingSession->SharedData->CredTable,
|
|
Handle,
|
|
DELHANDLE_FORCE | DELHANDLE_NO_CALLBACK ) )
|
|
{
|
|
Ret = DestinationSession->SharedData->CredHandlePackage->AddHandle(
|
|
DestinationSession->SharedData->CredTable,
|
|
Handle,
|
|
DestinationSession,
|
|
0 );
|
|
|
|
|
|
} else {
|
|
Ret = FALSE ;
|
|
}
|
|
|
|
return Ret ;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
LsapValidLogonProcess(
|
|
IN PVOID Request,
|
|
IN ULONG RequestSize,
|
|
IN PCLIENT_ID ClientId,
|
|
OUT PLUID LogonId,
|
|
OUT PULONG Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function checks to see if a calling process qualifies as a logon
|
|
process. If so, a logon process context is created for the caller and
|
|
returned.
|
|
|
|
A logon process must hold the SeTcbPrivilege privilege. Since there
|
|
is no way to impersonate a connection requestor (that would be way
|
|
too easy), we have to open the client thread and then open that thread's
|
|
token.
|
|
|
|
|
|
Arguments:
|
|
|
|
ClientId - Pointer to the client Id of the sender of the logon
|
|
message. This is used to locate and open the calling thread or
|
|
process.
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Indicates the caller is a legitimate logon process
|
|
and a logon process context block is being returned.
|
|
|
|
any other value - Indicates the caller is NOT a legitimate logon
|
|
process and a logon process context block is NOT being returned.
|
|
The value returned indicates the reason why the client is not
|
|
acceptable.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS Status, TempStatus;
|
|
BOOLEAN PrivilegeHeld;
|
|
HANDLE ClientThread, ClientProcess, ClientToken;
|
|
PRIVILEGE_SET Privilege;
|
|
OBJECT_ATTRIBUTES NullAttributes;
|
|
UNICODE_STRING Unicode;
|
|
STRING Ansi;
|
|
BOOLEAN Untrusted = FALSE;
|
|
TOKEN_STATISTICS TokenStats;
|
|
PLSAP_AU_REGISTER_CONNECT_INFO_EX ConnectionRequest = (PLSAP_AU_REGISTER_CONNECT_INFO_EX) Request;
|
|
ULONG TokenStatsSize = sizeof(TokenStats);
|
|
LSAP_AU_REGISTER_CONNECT_INFO NullConnectInfo;
|
|
|
|
*Flags = 0;
|
|
|
|
|
|
RtlZeroMemory(
|
|
&NullConnectInfo,
|
|
sizeof(NullConnectInfo)
|
|
);
|
|
|
|
|
|
|
|
|
|
//
|
|
// If the connect message is all zeros, setup an untrusted connection.
|
|
//
|
|
|
|
if (RtlEqualMemory(
|
|
&NullConnectInfo,
|
|
ConnectionRequest,
|
|
sizeof(NullConnectInfo))) {
|
|
|
|
Untrusted = TRUE;
|
|
*Flags |= SESFLAG_UNTRUSTED;
|
|
}
|
|
|
|
|
|
|
|
InitializeObjectAttributes( &NullAttributes, NULL, 0, NULL, NULL );
|
|
|
|
|
|
//
|
|
// Open the client thread and that thread's token
|
|
//
|
|
|
|
|
|
Status = NtOpenThread(
|
|
&ClientThread,
|
|
THREAD_QUERY_INFORMATION,
|
|
&NullAttributes,
|
|
ClientId
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return Status;
|
|
}
|
|
|
|
Status = NtOpenThreadToken(
|
|
ClientThread,
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&ClientToken
|
|
);
|
|
|
|
TempStatus = NtClose( ClientThread );
|
|
DsysAssert( NT_SUCCESS(TempStatus) );
|
|
|
|
//
|
|
// Make sure we succeeded in opening the token
|
|
//
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
if ( Status != STATUS_NO_TOKEN ) {
|
|
return Status;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Open the client process. This is needed to:
|
|
//
|
|
// 1) Access the client's virtual memory (to copy arguments),
|
|
// 2) Duplicate token handles into the process,
|
|
// 3) Open the process's token to see if it qualifies as
|
|
// a logon process.
|
|
//
|
|
|
|
Status = NtOpenProcess(
|
|
&ClientProcess,
|
|
PROCESS_QUERY_INFORMATION | // To open primary token
|
|
PROCESS_VM_OPERATION | // To allocate memory
|
|
PROCESS_VM_READ | // To read memory
|
|
PROCESS_VM_WRITE | // To write memory
|
|
PROCESS_DUP_HANDLE, // To duplicate a handle into
|
|
&NullAttributes,
|
|
ClientId
|
|
);
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// The thread isn't impersonating...open the process's token.
|
|
//
|
|
|
|
Status = NtOpenProcessToken(
|
|
ClientProcess,
|
|
TOKEN_QUERY,
|
|
&ClientToken
|
|
);
|
|
|
|
|
|
TempStatus = NtClose( ClientProcess );
|
|
DsysAssert( NT_SUCCESS(TempStatus) );
|
|
|
|
//
|
|
// Make sure we succeeded in opening the token
|
|
//
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
return Status;
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
*Flags |= SESFLAG_IMPERSONATE;
|
|
}
|
|
|
|
//
|
|
// If the caller has the kernel flag set in the LPC message, this is
|
|
// probably a kernel session, but we can't be sure until the first
|
|
// request is made and the LPC_KERNELMODE_MESSAGE flag is set. The
|
|
// handlers will check that, but until then, set the maybe-flag.
|
|
//
|
|
|
|
if (!Untrusted &&
|
|
RequestSize == sizeof( LSAP_AU_REGISTER_CONNECT_INFO_EX) &&
|
|
((ConnectionRequest->ClientMode & LSAP_AU_KERNEL_CLIENT) != 0) )
|
|
{
|
|
*Flags |= SESFLAG_MAYBEKERNEL;
|
|
}
|
|
|
|
|
|
//
|
|
// OK, we have a token open
|
|
//
|
|
|
|
//
|
|
// Get the logon id.
|
|
//
|
|
|
|
Status = NtQueryInformationToken(
|
|
ClientToken,
|
|
TokenStatistics,
|
|
(PVOID) &TokenStats,
|
|
TokenStatsSize,
|
|
&TokenStatsSize
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
TempStatus = NtClose( ClientToken );
|
|
DsysAssert(NT_SUCCESS(TempStatus));
|
|
return(Status);
|
|
}
|
|
|
|
*LogonId = TokenStats.AuthenticationId;
|
|
|
|
Status = STATUS_SUCCESS ;
|
|
|
|
if (((*Flags) & SESFLAG_MAYBEKERNEL) == 0) {
|
|
//
|
|
// Check for the privilege to execute this service.
|
|
//
|
|
|
|
Privilege.PrivilegeCount = 1;
|
|
Privilege.Control = PRIVILEGE_SET_ALL_NECESSARY;
|
|
Privilege.Privilege[0].Luid = LsapTcbPrivilege;
|
|
Privilege.Privilege[0].Attributes = 0;
|
|
|
|
Status = NtPrivilegeCheck(
|
|
ClientToken,
|
|
&Privilege,
|
|
&PrivilegeHeld
|
|
);
|
|
DsysAssert( NT_SUCCESS(Status) );
|
|
|
|
//
|
|
// For untrusted clients who didn't really need TCB anyway don't
|
|
// bother with an audit. If they do have the privilege, by all
|
|
// means audit it.
|
|
//
|
|
|
|
if (!Untrusted || PrivilegeHeld) {
|
|
|
|
//
|
|
// Generate any necessary audits
|
|
//
|
|
|
|
TempStatus = NtPrivilegedServiceAuditAlarm (
|
|
&LsapLsaAuName,
|
|
&LsapRegisterLogonServiceName,
|
|
ClientToken,
|
|
&Privilege,
|
|
PrivilegeHeld
|
|
);
|
|
// DsysAssert( NT_SUCCESS(TempStatus) );
|
|
|
|
|
|
if ( !PrivilegeHeld ) {
|
|
|
|
TempStatus = NtClose( ClientToken );
|
|
DsysAssert( NT_SUCCESS(TempStatus) );
|
|
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
|
|
}
|
|
}
|
|
if (PrivilegeHeld)
|
|
{
|
|
*Flags |= SESFLAG_TCB_PRIV;
|
|
}
|
|
}
|
|
|
|
TempStatus = NtClose( ClientToken );
|
|
DsysAssert( NT_SUCCESS(TempStatus) );
|
|
|
|
if (!Untrusted && ((*Flags & SESFLAG_KERNEL) == 0))
|
|
{
|
|
LsapAdtAuditLogonProcessRegistration( ConnectionRequest );
|
|
}
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LsapSetSessionOptions
|
|
//
|
|
// Synopsis: Allows clients to adjust session options
|
|
//
|
|
// Arguments: [Request] --
|
|
// [Response] --
|
|
//
|
|
// History: 8-05-96 RichardW Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
LsapSetSessionOptions(
|
|
ULONG Request,
|
|
ULONG_PTR Argument,
|
|
PULONG_PTR Response
|
|
)
|
|
{
|
|
PSession pSession;
|
|
PLSAP_TASK_QUEUE pQueue;
|
|
NTSTATUS Status ;
|
|
|
|
pSession = GetCurrentSession();
|
|
|
|
DebugLog(( DEB_TRACE, "[%d] SetSession( %d )\n",
|
|
pSession->dwProcessID, Request ));
|
|
|
|
Status = STATUS_SUCCESS ;
|
|
|
|
LockSession( pSession );
|
|
|
|
switch ( Request )
|
|
{
|
|
case SETSESSION_GET_STATUS:
|
|
*Response = 0;
|
|
break;
|
|
|
|
case SETSESSION_ADD_WORKQUEUE:
|
|
if ( pSession->SharedData->pQueue == NULL )
|
|
{
|
|
if ( CreateSubordinateQueue( pSession, &GlobalQueue ) )
|
|
{
|
|
//
|
|
// If they're going to be that busy, convert the cred list
|
|
// to be a large table
|
|
//
|
|
|
|
AddRundown( pSession, LsapDeleteWorkQueue, NULL );
|
|
|
|
pSession->SharedData->CredTable = LhtConvertSmallToLarge(
|
|
pSession->SharedData->CredTable );
|
|
|
|
pSession->SharedData->CredHandlePackage = &LargeHandlePackage ;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL ;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SETSESSION_REMOVE_WORKQUEUE:
|
|
break;
|
|
|
|
case SETSESSION_GET_DISPATCH:
|
|
if ( pSession->dwProcessID == GetCurrentProcessId() )
|
|
{
|
|
Status = InitializeDirectDispatcher();
|
|
|
|
if ( NT_SUCCESS( Status ) )
|
|
{
|
|
DllCallbackHandler = (PLSA_DISPATCH_FN) Argument ;
|
|
*Response = (ULONG_PTR) DispatchAPIDirect;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_ACCESS_DENIED ;
|
|
}
|
|
break;
|
|
}
|
|
|
|
UnlockSession( pSession );
|
|
|
|
return( Status );
|
|
|
|
}
|
|
|