/*++ Copyright (c) 1989 Microsoft Corporation Module Name: smbcedb.c Abstract: This module implements all functions related to accessing the SMB connection engine database Revision History: Balan Sethu Raman [SethuR] 6-March-1995 Notes: The mapping between MRX_V_NET_ROOT and a mini rdr data structure is a many to one relationship, i.e., more than one MRX_V_NET_ROOT instance can be associated with the same mini rdr data structure. --*/ #include "precomp.h" #pragma hdrstop #include "exsessup.h" #include "secext.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, SmbCeCompleteVNetRootContextInitialization) #pragma alloc_text(PAGE, SmbCeDestroyAssociatedVNetRootContext) #pragma alloc_text(PAGE, SmbCeTearDownVNetRootContext) #endif RXDT_Extern(SMBCEDB); #define Dbg (DEBUG_TRACE_SMBCEDB) extern BOOLEAN Win9xSessionRestriction; PSMBCE_V_NET_ROOT_CONTEXT SmbCeFindVNetRootContext( PSMBCE_V_NET_ROOT_CONTEXTS pVNetRootContexts, PSMBCEDB_SERVER_ENTRY pServerEntry, PSMBCEDB_SESSION_ENTRY pSessionEntry, PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry, BOOLEAN fCscAgentOpen) /*++ Routine Description: This routine finds a SMBCE_V_NET_ROOT_CONTEXT instance Arguments: pVNetRootContexts - list of VNetRootContexts for searching PServerEntry - the ServerEntry should be the same as the one on found VNetRootContext PSessionEntry - the SessionEntry should be the same as the one on found VNetRootContext pNetRootEntry - the NetRootEntry should be the same as the one on found VNetRootContext fCscAgentOpen - this V_NET_ROOT_CONTEXT instance is being created for the CSC agent Return Value: VNetRootContext if found Notes: --*/ { PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL; pVNetRootContext = SmbCeGetFirstVNetRootContext( pVNetRootContexts); while (pVNetRootContext != NULL) { if ((pVNetRootContext->pServerEntry == pServerEntry) && (pVNetRootContext->pSessionEntry == pSessionEntry) && (pVNetRootContext->pNetRootEntry == pNetRootEntry) && (BooleanFlagOn(pVNetRootContext->Flags, SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE) == fCscAgentOpen)) { SmbCeRemoveVNetRootContext( pVNetRootContexts, pVNetRootContext); SmbCeAddVNetRootContext( &pServerEntry->VNetRootContexts, pVNetRootContext); InterlockedDecrement(&pServerEntry->Server.NumberOfVNetRootContextsForScavenging); SmbCeLog(("CachedVNRContext(S) %lx\n",pVNetRootContext)); SmbLog(LOG, SmbCeFindVNetRootContext, LOGPTR(pVNetRootContext)); break; } else { pVNetRootContext = SmbCeGetNextVNetRootContext( pVNetRootContexts, pVNetRootContext); } } return pVNetRootContext; } NTSTATUS SmbCeFindOrConstructVNetRootContext( PMRX_V_NET_ROOT pVNetRoot, BOOLEAN fDeferNetworkInitialization, BOOLEAN fCscAgentOpen) /*++ Routine Description: This routine finds or constructs a SMBCE_V_NET_ROOT_CONTEXT instance Arguments: pVNetRoot - the MRX_V_NET_ROOT instance fDeferNetworkInitialization - a directive to delay network initialization for new instances. fCscAgentOpen - this V_NET_ROOT_CONTEXT instance is being created for the CSC agent Return Value: STATUS_SUCCESS if the MRX_V_NET_ROOT instance was successfully initialized Notes: The algorithm that has been implemented tries to delay the construction of a new instance as much as possible. It does this be either reusing a context that has already been active or a context instance that has been marked for scavenging but has not been scavenged. --*/ { NTSTATUS Status; PMRX_SRV_CALL pSrvCall; PMRX_NET_ROOT pNetRoot; PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL; PSMBCEDB_SERVER_ENTRY pServerEntry = NULL; PSMBCEDB_SESSION_ENTRY pSessionEntry = NULL; PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = NULL; BOOLEAN fInitializeNetRoot; BOOLEAN fDereferenceSessionEntry = FALSE; BOOLEAN fDereferenceNetRootEntry = FALSE; pNetRoot = pVNetRoot->pNetRoot; pSrvCall = pNetRoot->pSrvCall; SmbCeAcquireResource(); pServerEntry = SmbCeGetAssociatedServerEntry(pSrvCall); // The V_NET_ROOT is associated with a NET_ROOT. The two cases of interest are as // follows // 1) the V_NET_ROOT and the associated NET_ROOT are being newly created. // 2) a new V_NET_ROOT associated with an existing NET_ROOT is being created. // // These two cases can be distinguished by checking if the context associated with // NET_ROOT is NULL. Since the construction of NET_ROOT's/V_NET_ROOT's are serialized // by the wrapper this is a safe check. // ( The wrapper cannot have more then one thread tryingto initialize the same // NET_ROOT). pNetRootEntry = (PSMBCEDB_NET_ROOT_ENTRY)pNetRoot->Context; fInitializeNetRoot = (pNetRootEntry == NULL); pVNetRoot->Context = NULL; // Find or construct the session entry that will be associated with the context. The // one error that deserves special consideration is STATUS_NETWORK_CREDENTIAL_CONFLICT. // This error signifies that the credentials presented with the MRX_V_NET_ROOT instance // conflicted with an existing session. This conflict could be either becuase there // exists an active session or because a previously active session is awaiting // scavenging. In the former case the error needs to be propagated back but in the // later case the contexts must be selectively scavenged. // // The scavenging should be limited only to those contexts to the appropriate server. Status = SmbCeFindOrConstructSessionEntry( pVNetRoot, &pSessionEntry); if (Status == STATUS_NETWORK_CREDENTIAL_CONFLICT) { NTSTATUS ScavengingStatus; SmbCeReleaseResource(); ScavengingStatus = SmbCeScavengeRelatedContexts(pServerEntry); if (ScavengingStatus == STATUS_SUCCESS) { SmbCeAcquireResource(); Status = SmbCeFindOrConstructSessionEntry( pVNetRoot, &pSessionEntry); } else { return Status; } } fDereferenceSessionEntry = (Status == STATUS_SUCCESS); if (Status == STATUS_SUCCESS) { if (fInitializeNetRoot) { pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD; // Initialize the device type and state for a new MRX_NET_ROOT instance switch (pNetRoot->Type) { case NET_ROOT_DISK: { pNetRoot->DeviceType = RxDeviceType(DISK); RxInitializeNetRootThrottlingParameters( &pNetRoot->DiskParameters.LockThrottlingParameters, MRxSmbConfiguration.LockIncrement, MRxSmbConfiguration.MaximumLock ); } break; case NET_ROOT_PIPE: { pNetRoot->DeviceType = RxDeviceType(NAMED_PIPE); RxInitializeNetRootThrottlingParameters( &pNetRoot->NamedPipeParameters.PipeReadThrottlingParameters, MRxSmbConfiguration.PipeIncrement, MRxSmbConfiguration.PipeMaximum ); } break; case NET_ROOT_COMM: pNetRoot->DeviceType = RxDeviceType(SERIAL_PORT); break; case NET_ROOT_PRINT: pNetRoot->DeviceType = RxDeviceType(PRINTER); break; case NET_ROOT_MAILSLOT: pNetRoot->DeviceType = RxDeviceType(MAILSLOT); break; case NET_ROOT_WILD: break; default: ASSERT(!"Valid Net Root Type"); } Status = SmbCeFindOrConstructNetRootEntry( pNetRoot, &pNetRootEntry); RxDbgTrace( 0, Dbg, ("SmbCeOpenNetRoot %lx\n",Status)); } else { SmbCeLog(("ReuseNREntry %lx\n",pNetRootEntry)); SmbLog(LOG, SmbCeFindOrConstructVNetRootContext_1, LOGPTR(pNetRootEntry)); SmbCeReferenceNetRootEntry(pNetRootEntry); } fDereferenceNetRootEntry = (Status == STATUS_SUCCESS); } if (Status == STATUS_SUCCESS) { pVNetRootContext = SmbCeFindVNetRootContext( &pServerEntry->VNetRootContexts, pServerEntry, pSessionEntry, pNetRootEntry, fCscAgentOpen); if (pVNetRootContext == NULL) { pVNetRootContext = SmbCeFindVNetRootContext( &MRxSmbScavengerServiceContext.VNetRootContexts, pServerEntry, pSessionEntry, pNetRootEntry, fCscAgentOpen); } if (pVNetRootContext != NULL) { // An existing instance can be reused. No more work to be done SmbCeReferenceVNetRootContext(pVNetRootContext); } else { // None of the existing instances can be reused. A new instance needs to be // constructed. pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT) RxAllocatePoolWithTag( NonPagedPool, sizeof(SMBCE_V_NET_ROOT_CONTEXT), MRXSMB_VNETROOT_POOLTAG); if (pVNetRootContext != NULL) { // Initialize the new instance RtlZeroMemory( pVNetRootContext, sizeof(SMBCE_V_NET_ROOT_CONTEXT)); // Transfer the references made during the construction of the session and // the net root entries to the new context. Disable the dereferencing at // the end of this routine. fDereferenceSessionEntry = FALSE; fDereferenceNetRootEntry = FALSE; SmbCeReferenceServerEntry(pServerEntry); pVNetRootContext->Header.NodeType = SMB_CONNECTION_ENGINE_NTC( SMBCEDB_OT_VNETROOTCONTEXT); if (pNetRootEntry->NetRoot.NetRootType == NET_ROOT_MAILSLOT) { pVNetRootContext->Header.State = SMBCEDB_ACTIVE; } else { pVNetRootContext->Header.State = SMBCEDB_INVALID; } pVNetRootContext->Flags = 0; if (fCscAgentOpen) { pVNetRootContext->Flags |= SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE; } InitializeListHead(&pVNetRootContext->Requests.ListHead); pVNetRootContext->pServerEntry = pServerEntry; pVNetRootContext->pSessionEntry = pSessionEntry; pVNetRootContext->pNetRootEntry = pNetRootEntry; SmbCeReferenceVNetRootContext(pVNetRootContext); // Add it to the list of active contexts SmbCeAddVNetRootContext( &pServerEntry->VNetRootContexts, pVNetRootContext); SmbCeLog(("NewVNetRootContext %lx\n",pVNetRootContext)); SmbLog(LOG, SmbCeFindOrConstructVNetRootContext_2, LOGPTR(pVNetRootContext)); } else { Status = STATUS_INSUFFICIENT_RESOURCES; } } } if (Status == STATUS_SUCCESS) { // If everything was successful set up the MRX_V_NET_ROOT and MRX_NET_ROOT // instances pVNetRoot->Context = pVNetRootContext; pVNetRootContext->pRdbssVNetRoot = pVNetRoot; if (fInitializeNetRoot) { ASSERT(pNetRootEntry->pRdbssNetRoot == NULL); InterlockedExchangePointer( &pNetRootEntry->pRdbssNetRoot, pNetRoot); SmbCeUpdateNetRoot(pNetRootEntry,pNetRoot); SmbCeReferenceNetRootEntry(pNetRootEntry); pNetRoot->Context = pNetRootEntry; } else { if (FlagOn(pNetRoot->Flags,NETROOT_FLAG_FINALIZE_INVOKED)) { ClearFlag(pNetRoot->Flags,NETROOT_FLAG_FINALIZE_INVOKED); SmbCeReferenceNetRootEntry(pNetRootEntry); } } InterlockedIncrement(&pSessionEntry->Session.NumberOfActiveVNetRoot); } else { pVNetRoot->Context = NULL; if (fInitializeNetRoot) { pNetRoot->Context = NULL; } } SmbCeReleaseResource(); if (fDereferenceSessionEntry) { SmbCeDereferenceSessionEntry(pSessionEntry); } if (fDereferenceNetRootEntry) { SmbCeDereferenceNetRootEntry(pNetRootEntry); } if (!fDeferNetworkInitialization && (Status == STATUS_SUCCESS)) { Status = STATUS_MORE_PROCESSING_REQUIRED; } if (SmbCeGetServerType(pServerEntry) == SMBCEDB_FILE_SERVER) { ASSERT((Status != STATUS_SUCCESS) || (pVNetRoot->Context != NULL)); } return Status; } VOID SmbCeCompleteVNetRootContextInitialization( PVOID pContext) /*++ Routine Description: This routine is invoked in the context of a worker thread to finalize the construction of a SMBCE_V_NET_ROOT_CONTEXT instance Arguments: pContext - the SMBCE_V_NET_ROOT_CONTEXT instance Notes: PRE_CONDITION: The VNetRootContext must have been referenced to ensure that even it has been finalized it will not be deleted. --*/ { NTSTATUS Status; PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext; PSMBCEDB_REQUEST_ENTRY pRequestEntry; SMBCEDB_REQUESTS Requests; PAGED_CODE(); RxDbgTrace( 0, Dbg, ("Net Root Entry Finalization\n")); pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)pContext; ASSERT(pVNetRootContext->Header.ObjectType == SMBCEDB_OT_VNETROOTCONTEXT); SmbCeAcquireResource(); pVNetRootContext->pExchange = NULL; SmbCeTransferRequests(&Requests,&pVNetRootContext->Requests); if (pVNetRootContext->Header.State == SMBCEDB_ACTIVE) { Status = STATUS_SUCCESS; } else { Status = STATUS_INVALID_CONNECTION; SmbCeUpdateVNetRootContextState( pVNetRootContext, SMBCEDB_INVALID); } SmbCeReleaseResource(); // Iterate over the list of pending requests and resume all of them SmbCeResumeOutstandingRequests(&Requests,Status); SmbCeDereferenceVNetRootContext(pVNetRootContext); } VOID SmbCepDereferenceVNetRootContext( PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext) /*++ Routine Description: This routine dereferences a SMBCE_V_NET_ROOT_CONTEXT instance Arguments: pVNetRootContext - the SMBCE_V_NET_ROOT_CONTEXT instance Notes: There are two intersting points to note. A mini redirector can avoid potential network traffic by delaying the scavenging of the SMBCE_V_NET_ROOT_CONTEXT instance since it contains all the relevant network setup to satisfy requests. This is a policy that is implemented in the mini redirector and is different from the wrapper policies. Once the decision to delay scavenging has been made, there are two options. The successful and unsuccessful instances can be delayed or only the successful instances. The current algorithm is to delay the scavenging of the successful SMBCE_V_NET_ROOT_CONTEXT instances only. Also there are three components to a VNetRootContext that can be scavenged independently. If the server exists and a session setup to the server fails because of wrong credentials there is no point in throwing away the server entry eagerly. This routine selectively gathers the failed fields for eager scavenging and retains the VNetRootContext skeleton alongwith the other structures that can be deferred. --*/ { if (pVNetRootContext != NULL) { LONG FinalRefCount; FinalRefCount = InterlockedDecrement( &pVNetRootContext->Header.SwizzleCount); if (FinalRefCount == 0) { LARGE_INTEGER CurrentTime; BOOLEAN TearDownVNetRootContext = FALSE; PSMBCE_SERVER pServer = &pVNetRootContext->pServerEntry->Server; PSMBCE_SESSION pSession = &pVNetRootContext->pSessionEntry->Session; SmbCeAcquireResource(); if (pVNetRootContext->Header.SwizzleCount == 0) { // Remove the instance from the active list of contexts to the server. SmbCeRemoveVNetRootContext( &pVNetRootContext->pSessionEntry->pServerEntry->VNetRootContexts, pVNetRootContext); // if it was a successful instance mark it for scavenging, otherwise // tear it down immediately if ((pVNetRootContext->pSessionEntry != NULL) && (pVNetRootContext->pSessionEntry->Header.State != SMBCEDB_ACTIVE || pSession->pUserName != NULL || pSession->pPassword != NULL || pSession->pUserDomainName != NULL)) { TearDownVNetRootContext = TRUE; } if ((pVNetRootContext->pNetRootEntry != NULL) && (pVNetRootContext->pNetRootEntry->Header.State != SMBCEDB_ACTIVE || TearDownVNetRootContext)) { TearDownVNetRootContext = TRUE; } if (Win9xSessionRestriction && (pVNetRootContext->pServerEntry != NULL) && FlagOn(pVNetRootContext->pServerEntry->Server.DialectFlags,DF_W95)) { TearDownVNetRootContext = TRUE; } InterlockedIncrement(&pServer->NumberOfVNetRootContextsForScavenging); if (!TearDownVNetRootContext && (pVNetRootContext->pNetRootEntry != NULL) && (pVNetRootContext->pSessionEntry != NULL) && pServer->NumberOfVNetRootContextsForScavenging < MaximumNumberOfVNetRootContextsForScavenging) { ClearFlag(pVNetRootContext->Flags, SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE); KeQueryTickCount( &CurrentTime ); pVNetRootContext->ExpireTime.QuadPart = CurrentTime.QuadPart + (LONGLONG) ((MRXSMB_V_NETROOT_CONTEXT_SCAVENGER_INTERVAL * 10 * 1000 * 1000) / KeQueryTimeIncrement()); SmbCeAddVNetRootContext( &MRxSmbScavengerServiceContext.VNetRootContexts, pVNetRootContext); MRxSmbActivateRecurrentService( (PRECURRENT_SERVICE_CONTEXT)&MRxSmbScavengerServiceContext); SmbCeLog(("ScavngVNetRootCntxt %lx\n",pVNetRootContext)); SmbLog(LOG, SmbCepDereferenceVNetRootContext, LOGPTR(pVNetRootContext)); } else { TearDownVNetRootContext = TRUE; } } SmbCeReleaseResource(); if (TearDownVNetRootContext) { pVNetRootContext->Header.State = SMBCEDB_MARKED_FOR_DELETION; SmbCeTearDownVNetRootContext(pVNetRootContext); } } } } NTSTATUS SmbCeDestroyAssociatedVNetRootContext( PMRX_V_NET_ROOT pVNetRoot) /*++ Routine Description: This routine derferences a SMBCE_V_NET_ROOT_CONTEXT instance Arguments: pVNetRootContext - the SMBCE_V_NET_ROOT_CONTEXT instance to be dereferenced --*/ { PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext; PAGED_CODE(); pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)pVNetRoot->Context; if (pVNetRootContext != NULL) { pVNetRootContext->pRdbssVNetRoot = NULL; SmbCeDecrementNumberOfActiveVNetRootOnSession(pVNetRootContext); SmbCeDereferenceVNetRootContext(pVNetRootContext); } pVNetRoot->Context = NULL; return STATUS_SUCCESS; } VOID SmbCeTearDownVNetRootContext( PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext) /*++ Routine Description: This routine tears down a SMBCE_V_NET_ROOT_CONTEXT instance Arguments: pVNetRootContext - the SMBCE_V_NET_ROOT_CONTEXT instance to be torn down --*/ { PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry; PAGED_CODE(); SmbCeLog(("TearVNetRootContext %lx\n",pVNetRootContext)); SmbLog(LOG, SmbCeTearDownVNetRootContext, LOGPTR(pVNetRootContext)); pNetRootEntry = pVNetRootContext->pNetRootEntry; if ((pNetRootEntry != NULL) && BooleanFlagOn(pVNetRootContext->Flags,SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID) && (SmbCeGetServerType(pVNetRootContext->pServerEntry) == SMBCEDB_FILE_SERVER)) { SmbCeDisconnect(pVNetRootContext); } if (pNetRootEntry != NULL) { pVNetRootContext->pNetRootEntry = NULL; SmbCeDereferenceNetRootEntry(pNetRootEntry); } if (pVNetRootContext->pSessionEntry != NULL) { SmbCeDereferenceSessionEntry(pVNetRootContext->pSessionEntry); } InterlockedDecrement(&pVNetRootContext->pServerEntry->Server.NumberOfVNetRootContextsForScavenging); SmbCeDereferenceServerEntry(pVNetRootContext->pServerEntry); RxFreePool(pVNetRootContext); } NTSTATUS SmbCeScavenger( PVOID pContext) /*++ Routine Description: This routine scavenges SMBCE_V_NET_ROOT_CONTEXT instances Arguments: pContext - the scavenger service context Notes: Since the contexts for scavenging are threaded together in an entry that is managed in a FIFO fashion, if the first entry fails the time interval test ( expiry time has not elapsed ) all the other entries in the list are guaranteed to fail the test. This is an important property that eases the implementation of scavenging. --*/ { NTSTATUS Status = STATUS_SUCCESS; PMRXSMB_SCAVENGER_SERVICE_CONTEXT pScavengerServiceContext; LARGE_INTEGER CurrentTime; PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext; BOOLEAN fTerminateScavenging = FALSE; pScavengerServiceContext = (PMRXSMB_SCAVENGER_SERVICE_CONTEXT)pContext; do { SmbCeAcquireResource(); KeQueryTickCount( &CurrentTime ); pVNetRootContext = SmbCeGetFirstVNetRootContext( &pScavengerServiceContext->VNetRootContexts); fTerminateScavenging = (pVNetRootContext == NULL); if (!fTerminateScavenging) { if ((CurrentTime.QuadPart >= pVNetRootContext->ExpireTime.QuadPart) || (pScavengerServiceContext->RecurrentServiceContext.State == RECURRENT_SERVICE_SHUTDOWN)) { SmbCeRemoveVNetRootContext( &pScavengerServiceContext->VNetRootContexts, pVNetRootContext); } else { fTerminateScavenging = TRUE; } } SmbCeReleaseResource(); if (!fTerminateScavenging && (pVNetRootContext != NULL)) { SmbCeTearDownVNetRootContext(pVNetRootContext); } } while (!fTerminateScavenging); return Status; } NTSTATUS SmbCeScavengeRelatedContexts( PSMBCEDB_SERVER_ENTRY pServerEntry) /*++ Routine Description: This routine scavenges SMBCE_V_NET_ROOT_CONTEXT instances for a given server entry Arguments: pServerEntry - the server entry Notes: --*/ { NTSTATUS Status; SMBCE_V_NET_ROOT_CONTEXTS VNetRootContexts; PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext; InitializeListHead(&VNetRootContexts.ListHead); SmbCeAcquireResource(); pVNetRootContext = SmbCeGetFirstVNetRootContext( &MRxSmbScavengerServiceContext.VNetRootContexts); while (pVNetRootContext != NULL) { PSMBCE_V_NET_ROOT_CONTEXT pNextVNetRootContext; pNextVNetRootContext = SmbCeGetNextVNetRootContext( &MRxSmbScavengerServiceContext.VNetRootContexts, pVNetRootContext); if (pVNetRootContext->pServerEntry == pServerEntry) { SmbCeRemoveVNetRootContext( &MRxScavengerServiceContext.VNetRootContexts, pVNetRootContext); SmbCeAddVNetRootContext( &VNetRootContexts, pVNetRootContext); } pVNetRootContext = pNextVNetRootContext; } SmbCeReleaseResource(); pVNetRootContext = SmbCeGetFirstVNetRootContext( &VNetRootContexts); if (pVNetRootContext != NULL) { do { SmbCeRemoveVNetRootContext( &VNetRootContexts, pVNetRootContext); SmbCeTearDownVNetRootContext(pVNetRootContext); pVNetRootContext = SmbCeGetFirstVNetRootContext( &VNetRootContexts); } while ( pVNetRootContext != NULL ); Status = STATUS_SUCCESS; } else { Status = STATUS_UNSUCCESSFUL; } SmbCeLog(("Scavctxts Srv %lx Status %lx\n",pServerEntry,Status)); SmbLog(LOG, SmbCeScavengeRelatedContexts, LOGULONG(Status) LOGPTR(pServerEntry) LOGUSTR(pServerEntry->Name)); return Status; } VOID SmbCeDecrementNumberOfActiveVNetRootOnSession( PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext ) { ULONG NumberOfVNetRoot; BOOLEAN fLogOffRequired = FALSE; PSMBCEDB_SERVER_ENTRY pServerEntry = NULL; PSMBCEDB_SESSION_ENTRY pSessionEntry = NULL; SmbCeAcquireResource(); NumberOfVNetRoot = InterlockedDecrement(&pVNetRootContext->pSessionEntry->Session.NumberOfActiveVNetRoot); if (NumberOfVNetRoot == 0) { pSessionEntry = pVNetRootContext->pSessionEntry; pServerEntry = pVNetRootContext->pServerEntry; if (!FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_LOGGED_OFF)) { SmbCeRemoveSessionEntry(pServerEntry,pSessionEntry); SmbCeRemoveDefaultSessionEntry(pSessionEntry); } if ((pSessionEntry->Session.UserId != (SMB_USER_ID)(SMBCE_SHARE_LEVEL_SERVER_USERID)) && (pSessionEntry->Session.UserId != 0) && (pSessionEntry->Header.State == SMBCEDB_ACTIVE) && !FlagOn(pSessionEntry->Session.Flags,SMBCE_SESSION_FLAGS_LOGGED_OFF)) { SmbCeReferenceServerEntry(pServerEntry); SmbCeReferenceSessionEntry(pSessionEntry); fLogOffRequired = TRUE; } // all the consequent requests on this session should fail pSessionEntry->Header.State = SMBCEDB_MARKED_FOR_DELETION; pSessionEntry->Session.Flags |= SMBCE_SESSION_FLAGS_LOGGED_OFF; pSessionEntry->Session.Flags |= SMBCE_SESSION_FLAGS_MARKED_FOR_DELETION; } SmbCeReleaseResource(); if (fLogOffRequired) { SmbCeLogOff(pServerEntry,pSessionEntry); SmbCeDereferenceServerEntry(pServerEntry); } }