//+----------------------------------------------------------------------- // // 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 extern "C" { #include } 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 ); }