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.
602 lines
14 KiB
602 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
blksess.c
|
|
|
|
Abstract:
|
|
|
|
This module implements routines for managing session blocks.
|
|
|
|
Author:
|
|
|
|
Chuck Lenzmeier (chuckl) 4-Oct-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "blksess.tmh"
|
|
#pragma hdrstop
|
|
|
|
#define BugCheckFileId SRV_FILE_BLKSESS
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, SrvAllocateSession )
|
|
#pragma alloc_text( PAGE, SrvCheckAndReferenceSession )
|
|
#pragma alloc_text( PAGE, SrvCloseSession )
|
|
#pragma alloc_text( PAGE, SrvCloseSessionsOnConnection )
|
|
#pragma alloc_text( PAGE, SrvDereferenceSession )
|
|
#pragma alloc_text( PAGE, SrvFreeSession )
|
|
#endif
|
|
|
|
|
|
VOID
|
|
SrvAllocateSession (
|
|
OUT PSESSION *Session,
|
|
IN PUNICODE_STRING UserName OPTIONAL,
|
|
IN PUNICODE_STRING Domain OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates a Session Block from the FSP heap.
|
|
|
|
Arguments:
|
|
|
|
Session - Returns a pointer to the session block, or NULL if
|
|
no heap space was available.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG blockLength;
|
|
PNONPAGED_HEADER header;
|
|
PSESSION session;
|
|
PWCH buffer;
|
|
|
|
PAGED_CODE( );
|
|
|
|
blockLength = sizeof(SESSION);
|
|
if( ARGUMENT_PRESENT( UserName ) ) {
|
|
blockLength += UserName->Length;
|
|
}
|
|
|
|
if( ARGUMENT_PRESENT( Domain ) ) {
|
|
blockLength += Domain->Length;
|
|
}
|
|
|
|
//
|
|
// Attempt to allocate from the heap.
|
|
//
|
|
|
|
session = ALLOCATE_HEAP( blockLength, BlockTypeSession );
|
|
*Session = session;
|
|
|
|
if ( session == NULL ) {
|
|
INTERNAL_ERROR(
|
|
ERROR_LEVEL_EXPECTED,
|
|
"SrvAllocateSession: Unable to allocate %d bytes from heap",
|
|
blockLength,
|
|
NULL
|
|
);
|
|
return;
|
|
}
|
|
|
|
|
|
IF_DEBUG(HEAP) {
|
|
SrvPrint1( "SrvAllocateSession: Allocated session at %p\n", session );
|
|
}
|
|
|
|
//
|
|
// Allocate the nonpaged header.
|
|
//
|
|
|
|
header = ALLOCATE_NONPAGED_POOL(
|
|
sizeof(NONPAGED_HEADER),
|
|
BlockTypeNonpagedHeader
|
|
);
|
|
if ( header == NULL ) {
|
|
INTERNAL_ERROR(
|
|
ERROR_LEVEL_EXPECTED,
|
|
"SrvAllocateSession: Unable to allocate %d bytes from pool.",
|
|
sizeof( NONPAGED_HEADER ),
|
|
NULL
|
|
);
|
|
FREE_HEAP( session );
|
|
*Session = NULL;
|
|
return;
|
|
}
|
|
|
|
header->Type = BlockTypeSession;
|
|
header->PagedBlock = session;
|
|
|
|
RtlZeroMemory( session, blockLength );
|
|
|
|
session->NonpagedHeader = header;
|
|
SET_BLOCK_TYPE_STATE_SIZE( session, BlockTypeSession, BlockStateActive, blockLength );
|
|
|
|
session->SecurityContext = NULL;
|
|
|
|
header->ReferenceCount = 2; // allow for Active status and caller's pointer
|
|
|
|
//
|
|
// Initialize times for autologoff.
|
|
//
|
|
|
|
KeQuerySystemTime( &session->StartTime );
|
|
session->LastUseTime.QuadPart = session->StartTime.QuadPart;
|
|
|
|
buffer = (PWCH)( session + 1 );
|
|
|
|
//
|
|
// Initialize the user name.
|
|
//
|
|
if( ARGUMENT_PRESENT( UserName ) ) {
|
|
session->NtUserName.Length = UserName->Length;
|
|
session->NtUserName.MaximumLength = UserName->Length;
|
|
session->NtUserName.Buffer = buffer;
|
|
buffer += UserName->Length / sizeof( WCHAR );
|
|
|
|
if( UserName->Length != 0 ) {
|
|
RtlCopyUnicodeString( &session->NtUserName, UserName );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Initialize the domain name.
|
|
//
|
|
if( ARGUMENT_PRESENT( Domain ) ) {
|
|
session->NtUserDomain.Length = Domain->Length;
|
|
session->NtUserDomain.MaximumLength = Domain->Length;
|
|
session->NtUserDomain.Buffer = buffer;
|
|
|
|
if( Domain->Buffer != NULL ) {
|
|
RtlCopyUnicodeString( &session->NtUserDomain, Domain );
|
|
}
|
|
}
|
|
|
|
#if SRVDBG2
|
|
session->BlockHeader.ReferenceCount = 2; // for INITIALIZE_REFERENCE_HISTORY
|
|
#endif
|
|
INITIALIZE_REFERENCE_HISTORY( session );
|
|
|
|
INCREMENT_DEBUG_STAT( SrvDbgStatistics.SessionInfo.Allocations );
|
|
|
|
return;
|
|
|
|
} // SrvAllocateSession
|
|
|
|
|
|
BOOLEAN SRVFASTCALL
|
|
SrvCheckAndReferenceSession (
|
|
PSESSION Session
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function atomically verifies that a session is active and
|
|
increments the reference count on the session if it is.
|
|
|
|
Arguments:
|
|
|
|
Session - Address of session
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - Returns TRUE if the session is active, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
if( Session->LogonSequenceInProgress == FALSE ) {
|
|
//
|
|
// Acquire the lock that guards the session's state field.
|
|
//
|
|
|
|
ACQUIRE_LOCK( &Session->Connection->Lock );
|
|
|
|
//
|
|
// If the session is active, reference it and return TRUE.
|
|
//
|
|
|
|
if ( GET_BLOCK_STATE(Session) == BlockStateActive ) {
|
|
|
|
SrvReferenceSession( Session );
|
|
|
|
RELEASE_LOCK( &Session->Connection->Lock );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// The session isn't active. Return FALSE.
|
|
//
|
|
|
|
RELEASE_LOCK( &Session->Connection->Lock );
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
} // SrvCheckAndReferenceSession
|
|
|
|
|
|
VOID
|
|
SrvCloseSession (
|
|
PSESSION Session
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does the core of a logoff (disconnect session). It
|
|
sets the state of the session to Closing, closes open files and
|
|
pending transactions, and dereferences the session block.
|
|
|
|
Arguments:
|
|
|
|
Session - Supplies a pointer to the session block that is to be
|
|
closed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONNECTION connection = Session->Connection;
|
|
PPAGED_CONNECTION pagedConnection = connection->PagedConnection;
|
|
PAGED_CODE( );
|
|
|
|
ACQUIRE_LOCK( &connection->Lock );
|
|
|
|
if ( GET_BLOCK_STATE(Session) == BlockStateActive ) {
|
|
|
|
IF_DEBUG(BLOCK1) SrvPrint1( "Closing session at %p\n", Session );
|
|
|
|
SET_BLOCK_STATE( Session, BlockStateClosing );
|
|
|
|
//
|
|
// Free the session table entry.
|
|
//
|
|
// *** This must be done here, not in SrvDereferenceSession!
|
|
// This routine can be called from SrvSmbSessionSetupAndX
|
|
// when it needs to free up session table entry 0 for
|
|
// IMMEDIATE reuse.
|
|
//
|
|
|
|
SrvRemoveEntryTable(
|
|
&pagedConnection->SessionTable,
|
|
UID_INDEX( Session->Uid )
|
|
);
|
|
|
|
connection->CurrentNumberOfSessions--;
|
|
|
|
RELEASE_LOCK( &connection->Lock );
|
|
|
|
//
|
|
// Disconnect the tree connects from this session
|
|
//
|
|
SrvDisconnectTreeConnectsFromSession( connection, Session );
|
|
|
|
//
|
|
// Close all open files.
|
|
//
|
|
|
|
SrvCloseRfcbsOnSessionOrPid( Session, NULL );
|
|
|
|
//
|
|
// Close all pending transactions.
|
|
//
|
|
|
|
SrvCloseTransactionsOnSession( Session );
|
|
|
|
//
|
|
// Close all DOS searches on this session.
|
|
//
|
|
|
|
SrvCloseSearches(
|
|
connection,
|
|
(PSEARCH_FILTER_ROUTINE)SrvSearchOnSession,
|
|
(PVOID) Session,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Close all cached directories on this session.
|
|
//
|
|
SrvCloseCachedDirectoryEntries( connection );
|
|
|
|
//
|
|
// Dereference the session (to indicate that it's no longer
|
|
// open).
|
|
//
|
|
|
|
SrvDereferenceSession( Session );
|
|
|
|
INCREMENT_DEBUG_STAT( SrvDbgStatistics.SessionInfo.Closes );
|
|
|
|
} else {
|
|
|
|
RELEASE_LOCK( &connection->Lock );
|
|
}
|
|
|
|
return;
|
|
|
|
} // SrvCloseSession
|
|
|
|
|
|
VOID
|
|
SrvCloseSessionsOnConnection (
|
|
IN PCONNECTION Connection,
|
|
IN PUNICODE_STRING UserName OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function closes sessions on a connection. It walks the
|
|
connection's list of sessions, calling SrvCloseSession as
|
|
appropriate.
|
|
|
|
Arguments:
|
|
|
|
Connection - Supplies a pointer to a Connection Block
|
|
|
|
UserName - if specified, only sessions with the given user name
|
|
are closed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTABLE_HEADER tableHeader;
|
|
PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
|
|
LONG i;
|
|
UNICODE_STRING userName;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Close all active sessions. (This also causes all open files
|
|
// and pending transactions to be closed.)
|
|
//
|
|
// *** In order to prevent the session from being deallocated
|
|
// between when we find it in the table and the call to
|
|
// SrvCloseSession, we reference the session. It is not
|
|
// legal to hold the connection lock while calling
|
|
// SrvCloseSession, so simply holding the lock while we walk
|
|
// the list is not legal.
|
|
|
|
tableHeader = &pagedConnection->SessionTable;
|
|
|
|
ACQUIRE_LOCK( &Connection->Lock );
|
|
|
|
for ( i = 0; i < tableHeader->TableSize; i++ ) {
|
|
|
|
PSESSION session = (PSESSION)tableHeader->Table[i].Owner;
|
|
|
|
if( session == NULL || GET_BLOCK_STATE( session ) != BlockStateActive ) {
|
|
//
|
|
// This session either doesn't exist, or is already going away
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if( UserName != NULL ) {
|
|
//
|
|
// Get the user name for this session. We don't care about the
|
|
// domain name.
|
|
//
|
|
status = SrvGetUserAndDomainName( session, &userName, NULL );
|
|
|
|
if( !NT_SUCCESS( status ) ) {
|
|
//
|
|
// We can't figure out the name for the user for this session.
|
|
// We probably shouldn't just blow it away, so let's just keep
|
|
// going.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if( RtlCompareUnicodeString( &userName, UserName, TRUE ) != 0 ) {
|
|
//
|
|
// This is not the user we're interested in. Skip it.
|
|
//
|
|
SrvReleaseUserAndDomainName( session, &userName, NULL );
|
|
continue;
|
|
}
|
|
|
|
SrvReleaseUserAndDomainName( session, &userName, NULL );
|
|
}
|
|
|
|
SrvReferenceSession( session );
|
|
RELEASE_LOCK( &Connection->Lock );
|
|
|
|
SrvStatistics.SessionsErroredOut++;
|
|
SrvCloseSession( session );
|
|
|
|
SrvDereferenceSession( session );
|
|
ACQUIRE_LOCK( &Connection->Lock );
|
|
}
|
|
|
|
RELEASE_LOCK( &Connection->Lock );
|
|
|
|
} // SrvCloseSessionsOnConnection
|
|
|
|
|
|
VOID SRVFASTCALL
|
|
SrvDereferenceSession (
|
|
IN PSESSION Session
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function decrements the reference count on a session. If the
|
|
reference count goes to zero, the session block is deleted.
|
|
|
|
Since this routine may call SrvDereferenceConnection, the caller
|
|
must be careful if he holds the connection lock that he also
|
|
holds a referenced pointer to the connection.
|
|
|
|
Arguments:
|
|
|
|
Session - Address of session
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONNECTION connection;
|
|
LONG result;
|
|
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Enter a critical section and decrement the reference count on the
|
|
// block.
|
|
//
|
|
|
|
connection = Session->Connection;
|
|
|
|
IF_DEBUG(REFCNT) {
|
|
SrvPrint2( "Dereferencing session %p; old refcnt %lx\n",
|
|
Session, Session->NonpagedHeader->ReferenceCount );
|
|
}
|
|
|
|
ASSERT( GET_BLOCK_TYPE( Session ) == BlockTypeSession );
|
|
ASSERT( Session->NonpagedHeader->ReferenceCount > 0 );
|
|
UPDATE_REFERENCE_HISTORY( Session, TRUE );
|
|
|
|
result = InterlockedDecrement(
|
|
&Session->NonpagedHeader->ReferenceCount
|
|
);
|
|
|
|
if ( result == 0 ) {
|
|
|
|
//
|
|
// The new reference count is 0, meaning that it's time to
|
|
// delete this block.
|
|
//
|
|
// Remove the session from the global list of sessions.
|
|
//
|
|
|
|
SrvRemoveEntryOrderedList( &SrvSessionList, Session );
|
|
|
|
//
|
|
// Dereference the connection.
|
|
//
|
|
|
|
SrvDereferenceConnection( connection );
|
|
DEBUG Session->Connection = NULL;
|
|
|
|
//
|
|
// Free the session block.
|
|
//
|
|
|
|
SrvFreeSession( Session );
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} // SrvDereferenceSession
|
|
|
|
|
|
VOID
|
|
SrvFreeSession (
|
|
IN PSESSION Session
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns a Session Block to the FSP heap.
|
|
|
|
Arguments:
|
|
|
|
Session - Address of session
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
KAPC_STATE ApcState;
|
|
PEPROCESS process;
|
|
|
|
PAGED_CODE( );
|
|
|
|
DEBUG SET_BLOCK_TYPE_STATE_SIZE( Session, BlockTypeGarbage, BlockStateDead, -1 );
|
|
DEBUG Session->NonpagedHeader->ReferenceCount = -1;
|
|
TERMINATE_REFERENCE_HISTORY( Session );
|
|
|
|
//
|
|
// Ensure we are in the system process
|
|
//
|
|
process = IoGetCurrentProcess();
|
|
if ( process != SrvServerProcess ) {
|
|
KeStackAttachProcess( SrvServerProcess, &ApcState );
|
|
}
|
|
|
|
//
|
|
// Tell the License Server
|
|
//
|
|
SrvXsLSOperation( Session, XACTSRV_MESSAGE_LSRELEASE );
|
|
|
|
//
|
|
// Close the logon token
|
|
//
|
|
SrvFreeSecurityContexts( Session );
|
|
|
|
//
|
|
// Get back to where we were
|
|
//
|
|
if( process != SrvServerProcess ) {
|
|
KeUnstackDetachProcess( &ApcState );
|
|
}
|
|
|
|
//
|
|
// Deallocate the session's memory.
|
|
//
|
|
|
|
DEALLOCATE_NONPAGED_POOL( Session->NonpagedHeader );
|
|
FREE_HEAP( Session );
|
|
IF_DEBUG(HEAP) {
|
|
SrvPrint1( "SrvFreeSession: Freed session block at %p\n", Session );
|
|
}
|
|
|
|
INCREMENT_DEBUG_STAT( SrvDbgStatistics.SessionInfo.Frees );
|
|
|
|
return;
|
|
|
|
} // SrvFreeSession
|