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.
874 lines
28 KiB
874 lines
28 KiB
/*++
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
|