2025-04-27 07:49:33 -04:00

1037 lines
30 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
netroot.c
Abstract:
This module implements the routines for creating the SMB net root.
--*/
#include "precomp.h"
#pragma hdrstop
//
// The Bug check file id for this module
//
#define BugCheckFileId (RDBSS_BUG_CHECK_SMB_NETROOT)
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_DISPATCH)
//
// Forward declarations ...
//
extern NTSTATUS
SmbCeParseConstructNetRootResponse(
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange,
PSMB_HEADER pSmbHeader,
ULONG BytesAvailable,
ULONG BytesIndicated,
ULONG *pBytesTaken);
extern NTSTATUS
SmbConstructNetRootExchangeFinalize(
PSMB_EXCHANGE pExchange,
BOOLEAN *pPostFinalize);
NTSTATUS
MRxIfsUpdateNetRootState(
IN OUT PMRX_NET_ROOT pNetRoot)
/*++
Routine Description:
This routine updates the mini redirector state associated with a net root.
Arguments:
pNetRoot - the net root instance.
Return Value:
NTSTATUS - The return status for the operation
Notes:
By diffrentiating the mini redirector state from the net root condition it is possible
to permit a variety of reconnect strategies. It is conceivable that the RDBSS considers
a net root to be good while the underlying mini redirector might mark it as invalid
and reconnect on the fly.
--*/
{
if (pNetRoot->Context == NULL) {
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
} else {
PSMBCEDB_SERVER_ENTRY pServerEntry;
pServerEntry = SmbCeReferenceAssociatedServerEntry(pNetRoot->pSrvCall);
if (pServerEntry != NULL) {
switch (pServerEntry->Header.State) {
case SMBCEDB_ACTIVE:
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
break;
case SMBCEDB_INVALID:
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_DISCONNECTED;
break;
case SMBCEDB_CONSTRUCTION_IN_PROGRESS:
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_RECONN;
break;
default:
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
break;
}
SmbCeDereferenceServerEntry(pServerEntry);
} else {
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
}
}
return STATUS_SUCCESS;
}
ULONG
MRxSmbGetDialectFlagsFromSrvCall(
PMRX_SRV_CALL SrvCall
)
{
ULONG DialectFlags;
PSMBCEDB_SERVER_ENTRY pServerEntry;
pServerEntry = SmbCeReferenceAssociatedServerEntry(SrvCall);
ASSERT(pServerEntry != NULL);
DialectFlags = pServerEntry->Server.DialectFlags;
SmbCeDereferenceServerEntry(pServerEntry);
return(DialectFlags);
}
NTSTATUS
MRxIfsCreateVNetRoot(
IN OUT PMRX_V_NET_ROOT pVNetRoot,
IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext
)
/*++
Routine Description:
This routine patches the RDBSS created net root instance with the information required
by the mini redirector.
Arguments:
pVNetRoot - the virtual net root instance.
pCreateNetRootContext - the net root context for calling back
Return Value:
NTSTATUS - The return status for the operation
Notes:
--*/
{
NTSTATUS Status;
PRX_CONTEXT pRxContext = pCreateNetRootContext->RxContext;
PMRX_SRV_CALL pSrvCall;
PMRX_NET_ROOT pNetRoot;
PUNICODE_STRING pNetRootName,pSrvCallName;
BOOLEAN fTreeConnectOpen = TRUE; // RxContext->Create.ThisIsATreeConnectOpen;
BOOLEAN fInitializeNetRoot;
BOOLEAN fDereferenceSessionEntry = FALSE;
BOOLEAN fDereferenceNetRootEntry = FALSE;
if (pRxContext->Create.ThisIsATreeConnectOpen){
InterlockedIncrement(&MRxIfsStatistics.UseCount);
}
pNetRoot = pVNetRoot->pNetRoot;
pSrvCall = pNetRoot->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).
fInitializeNetRoot = (pNetRoot->Context == NULL);
ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) &&
(NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
Status = STATUS_SUCCESS;
// update the net root state to be good.
if (fInitializeNetRoot) {
pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
}
if (Status == STATUS_SUCCESS)
{
Status = SmbCeInitializeSessionEntry(pVNetRoot);
fDereferenceSessionEntry = (Status == STATUS_SUCCESS);
if (fInitializeNetRoot && (Status == STATUS_SUCCESS)) {
Status = SmbCeInitializeNetRootEntry(pNetRoot);
fDereferenceNetRootEntry = (Status == STATUS_SUCCESS);
RxDbgTrace( 0, Dbg, ("SmbCeOpenNetRoot %lx\n",Status));
}
if (NT_SUCCESS(Status)) {
if (fTreeConnectOpen &&
(pNetRoot->Type != NET_ROOT_MAILSLOT)) {
Status = SmbCeEstablishConnection(pVNetRoot,pCreateNetRootContext);
} else {
Status = STATUS_SUCCESS;
}
}
}
if (Status != STATUS_PENDING) {
if (!NT_SUCCESS(Status)) {
if (fInitializeNetRoot && fDereferenceNetRootEntry) {
SmbCeDereferenceNetRootEntry(SmbCeGetAssociatedNetRootEntry(pNetRoot));
pNetRoot->Context = NULL;
}
if (fDereferenceSessionEntry) {
SmbCeDereferenceSessionEntry(SmbCeGetAssociatedSessionEntry(pVNetRoot));
pVNetRoot->Context = NULL;
}
}
pCreateNetRootContext->VirtualNetRootStatus = Status;
if (fInitializeNetRoot) {
pCreateNetRootContext->NetRootStatus = Status;
} else {
pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
}
if (pRxContext->Create.ThisIsATreeConnectOpen){
InterlockedIncrement(&MRxIfsStatistics.FailedUseCount);
}
// Callback the RDBSS for resumption.
pCreateNetRootContext->Callback(pCreateNetRootContext);
// Map the error code to STATUS_PENDING since this triggers the synchronization
// mechanism in the RDBSS.
Status = STATUS_PENDING;
}
return Status;
}
NTSTATUS
MRxIfsFinalizeVNetRoot(
IN PMRX_V_NET_ROOT pVNetRoot,
IN PBOOLEAN ForceDisconnect)
/*++
Routine Description:
Arguments:
pVNetRoot - the virtual net root
ForceDisconnect - disconnect is forced
Return Value:
NTSTATUS - The return status for the operation
--*/
{
PSMBCEDB_SESSION_ENTRY pSessionEntry;
PSMBCEDB_SERVER_ENTRY pServerEntry;
PSMBCEDB_SESSION_ENTRY pDefaultSessionEntry;
RxDbgTrace( 0, Dbg, ("MRxSmbFinalizeVNetRoot %lx\n",pVNetRoot));
if (pVNetRoot->Context != NULL)
{
pSessionEntry = SmbCeGetAssociatedSessionEntry(pVNetRoot);
pServerEntry = SmbCeGetAssociatedServerEntry(pVNetRoot->pNetRoot->pSrvCall);
pDefaultSessionEntry = SmbCeGetDefaultSessionEntry(pServerEntry);
if ((pDefaultSessionEntry != NULL) && (pDefaultSessionEntry == pSessionEntry))
{
SmbCeAcquireSpinLock();
if (pDefaultSessionEntry->pRdbssVNetRoot == pVNetRoot)
{
SmbCeSetDefaultSessionEntryLite(pServerEntry,NULL);
}
SmbCeReleaseSpinLock();
DbgPrint("Resetting default session entry to NULL\n");
}
SmbCeDereferenceSessionEntry(pSessionEntry);
}
return STATUS_SUCCESS;
}
NTSTATUS
MRxIfsFinalizeNetRoot(
IN PMRX_NET_ROOT pNetRoot,
IN PBOOLEAN ForceDisconnect)
/*++
Routine Description:
Arguments:
pVirtualNetRoot - the virtual net root
ForceDisconnect - disconnect is forced
Return Value:
NTSTATUS - The return status for the operation
--*/
{
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
RxDbgTrace( 0, Dbg, ("MRxSmbFinalizeNetRoot %lx\n",pNetRoot));
if (pNetRoot->Context != NULL)
{
pNetRootEntry = SmbCeGetAssociatedNetRootEntry(pNetRoot);
SmbCeDereferenceNetRootEntry(pNetRootEntry);
}
return STATUS_SUCCESS;
}
VOID
SmbCeReconnectCallback(
PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
/*++
Routine Description:
This routine signals the completion of a reconnect attempt
Arguments:
pCreateNetRootContext - the net root context
Return Value:
NTSTATUS - The return status for the operation
--*/
{
KeSetEvent(&pCreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE );
}
NTSTATUS
SmbCeReconnect(
IN PMRX_V_NET_ROOT pVNetRoot)
/*++
Routine Description:
This routine reconnects, i.e, establishes a new session and tree connect to a previously
connected serverb share
Arguments:
pVNetRoot - the virtual net root instance.
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext;
pCreateNetRootContext = (PMRX_CREATENETROOT_CONTEXT)
RxAllocatePoolWithTag(
NonPagedPool,
sizeof(MRX_CREATENETROOT_CONTEXT),
MRXSMB_NETROOT_POOLTAG);
if (pCreateNetRootContext != NULL) {
pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
pCreateNetRootContext->VirtualNetRootStatus = STATUS_SUCCESS;
pCreateNetRootContext->Callback = SmbCeReconnectCallback;
pCreateNetRootContext->RxContext = NULL;
KeInitializeEvent( &pCreateNetRootContext->FinishEvent, SynchronizationEvent, FALSE );
Status = SmbCeEstablishConnection(pVNetRoot,pCreateNetRootContext);
if (Status == STATUS_PENDING) {
// Wait for the construction to be completed.
KeWaitForSingleObject(&pCreateNetRootContext->FinishEvent, Executive, KernelMode, FALSE, NULL);
Status = pCreateNetRootContext->VirtualNetRootStatus;
}
RxFreePool(pCreateNetRootContext);
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
return Status;
}
NTSTATUS
SmbCeEstablishConnection(
IN OUT PMRX_V_NET_ROOT pVNetRoot,
IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext
)
/*++
Routine Description:
This routine triggers off the connection attempt for initial establishment of a
connection as well as subsequent reconnect attempts.
Arguments:
pVNetRoot - the virtual net root instance.
pCreateNetRootContext - the net root context for calling back
Return Value:
NTSTATUS - The return status for the operation
Notes:
--*/
{
NTSTATUS Status;
PSMBCEDB_SERVER_ENTRY pServerEntry;
PSMBCEDB_SESSION_ENTRY pSessionEntry;
PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
pServerEntry = SmbCeReferenceAssociatedServerEntry(pVNetRoot->pNetRoot->pSrvCall);
if (pServerEntry != NULL) {
pNetRootEntry = SmbCeReferenceAssociatedNetRootEntry(pVNetRoot->pNetRoot);
if (pNetRootEntry != NULL) {
pSessionEntry = SmbCeReferenceAssociatedSessionEntry(pVNetRoot);
if (pSessionEntry != NULL) {
Status = STATUS_SUCCESS;
} else {
SmbCeDereferenceNetRootEntry(pNetRootEntry);
Status = STATUS_CONNECTION_DISCONNECTED;
}
} else {
Status = STATUS_CONNECTION_DISCONNECTED;
}
if (Status != STATUS_SUCCESS) {
SmbCeDereferenceServerEntry(pServerEntry);
}
} else {
Status = STATUS_BAD_NETWORK_PATH;
}
if (Status != STATUS_SUCCESS) {
return Status;
}
if ((Status == STATUS_SUCCESS) &&
((pNetRootEntry->Header.State != SMBCEDB_ACTIVE) ||
((pSessionEntry->Header.State != SMBCEDB_ACTIVE) &&
!(pServerEntry->Server.DialectFlags & DF_KERBEROS)))) {
// This is a tree connect open which needs to be triggered immediately.
PSMB_EXCHANGE pSmbExchange;
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
pSmbExchange = SmbMmAllocateExchange(CONSTRUCT_NETROOT_EXCHANGE,NULL);
if (pSmbExchange != NULL) {
Status = SmbCeInitializeExchange(
&pSmbExchange,
pVNetRoot,
CONSTRUCT_NETROOT_EXCHANGE,
&ConstructNetRootExchangeDispatch);
if (Status == STATUS_SUCCESS) {
pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pSmbExchange;
// Attempt to reconnect( In this case it amounts to establishing the
// connection/session)
pNetRootExchange->SmbCeFlags |= SMBCE_EXCHANGE_ATTEMPT_RECONNECTS;
// Initialize the continuation for resumption upon completion of the
// tree connetcion.
pNetRootExchange->NetRootCallback = pCreateNetRootContext->Callback;
pNetRootExchange->pCreateNetRootContext = pCreateNetRootContext;
// Initiate the exchange.
Status = SmbCeInitiateExchange(pSmbExchange);
if (Status != STATUS_PENDING) {
SmbCeDiscardExchange(pSmbExchange);
}
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
SmbCeDereferenceEntries(pServerEntry,pSessionEntry,pNetRootEntry);
return Status;
}
//
// The net roots are normally constructed as part of some other exchange, i.e., the SMB for
// Tree connect is compounded with other operations. However, there is one situation in which
// the tree connect SMB needs to be sent by itself. This case refers to the prefix claim
// situation ( net use command ). This is handled by the construct net root exchange.
//
#define CONSTRUCT_NETROOT_BUFFER_SIZE (4096)
NTSTATUS
SmbConstructNetRootExchangeStart(
PSMB_EXCHANGE pExchange)
/*++
Routine Description:
This is the start routine for net root construction exchanges. This initiates the
construction of the appropriate SMB's if required.
Arguments:
pExchange - the exchange instance
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
NTSTATUS RequestLockStatus;
NTSTATUS ResponseLockStatus;
PVOID pSmbBuffer;
UCHAR SmbCommand,LastCommandInHeader;
ULONG SmbLength;
PUCHAR pCommand;
PMDL pSmbRequestMdl,pSmbResponseMdl;
ULONG SmbMdlSize;
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
ASSERT(pNetRootExchange->Type == CONSTRUCT_NETROOT_EXCHANGE);
pSmbRequestMdl = pSmbResponseMdl = NULL;
pSmbBuffer = RxAllocatePoolWithTag(
PagedPool | POOL_COLD_ALLOCATION,
CONSTRUCT_NETROOT_BUFFER_SIZE,
MRXSMB_NETROOT_POOLTAG);
if (pSmbBuffer != NULL) {
PSMBCE_SERVER pServer = &pExchange->SmbCeContext.pServerEntry->Server;
Status = SmbCeBuildSmbHeader(
pExchange,
pSmbBuffer,
CONSTRUCT_NETROOT_BUFFER_SIZE,
&SmbLength,
&LastCommandInHeader,
&pCommand);
// Ensure that the NET_ROOT/SESSION still needs to be constructed before
// sending it. It is likely that they were costructed by an earlier exchange
if (NT_SUCCESS(Status) &&
(SmbLength > sizeof(SMB_HEADER))) {
if (LastCommandInHeader != SMB_COM_TREE_CONNECT){
*pCommand = SMB_COM_NO_ANDX_COMMAND;
}
pSmbRequestMdl = RxAllocateMdl(pSmbBuffer,CONSTRUCT_NETROOT_BUFFER_SIZE);
pSmbResponseMdl = RxAllocateMdl(pSmbBuffer,CONSTRUCT_NETROOT_BUFFER_SIZE);
if ((pSmbRequestMdl != NULL) &&
(pSmbResponseMdl != NULL)) {
RxProbeAndLockPages(pSmbRequestMdl,KernelMode,IoModifyAccess,RequestLockStatus);
RxProbeAndLockPages(pSmbResponseMdl,KernelMode,IoModifyAccess,ResponseLockStatus);
if ((Status == STATUS_SUCCESS) &&
((Status = RequestLockStatus) == STATUS_SUCCESS) &&
((Status = ResponseLockStatus) == STATUS_SUCCESS)) {
pNetRootExchange->pSmbResponseMdl = pSmbResponseMdl;
pNetRootExchange->pSmbRequestMdl = pSmbRequestMdl;
pNetRootExchange->pSmbBuffer = pSmbBuffer;
Status = SmbCeTranceive(
pExchange,
(RXCE_SEND_PARTIAL | RXCE_SEND_SYNCHRONOUS),
pNetRootExchange->pSmbRequestMdl,
SmbLength);
RxDbgTrace( 0, Dbg, ("Net Root SmbCeTranceive returned %lx\n",Status));
}
}
if ((Status != STATUS_PENDING) &&
(Status != STATUS_SUCCESS)) {
pNetRootExchange->pSmbResponseMdl = NULL;
pNetRootExchange->pSmbRequestMdl = NULL;
pNetRootExchange->pSmbBuffer = NULL;
if (pSmbResponseMdl != NULL) {
if (ResponseLockStatus == STATUS_SUCCESS) {
MmUnlockPages(pSmbResponseMdl);
}
IoFreeMdl(pSmbResponseMdl);
}
if (pSmbRequestMdl != NULL) {
if (RequestLockStatus == STATUS_SUCCESS) {
MmUnlockPages(pSmbRequestMdl);
}
IoFreeMdl(pSmbRequestMdl);
}
RxFreePool(pSmbBuffer);
}
} else {
RxFreePool(pSmbBuffer);
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
return Status;
}
NTSTATUS
SmbConstructNetRootExchangeReceive(
IN struct _SMB_EXCHANGE *pExchange, // The exchange instance
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *pBytesTaken,
IN PSMB_HEADER pSmbHeader,
OUT PMDL *pDataBufferPointer,
OUT PULONG pDataSize)
/*++
Routine Description:
This is the recieve indication handling routine for net root construction exchanges
Arguments:
pExchange - the exchange instance
BytesIndicated - the number of bytes indicated
Bytes Available - the number of bytes available
pBytesTaken - the number of bytes consumed
pSmbHeader - the byte buffer
pDataBufferPointer - the buffer into which the remaining data is to be copied.
pDataSize - the buffer size.
Return Value:
NTSTATUS - The return status for the operation
Notes:
This routine is called at DPC level.
--*/
{
NTSTATUS Status;
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated/Available %ld %ld\n",BytesIndicated,BytesAvailable));
if (BytesAvailable > BytesIndicated) {
// The SMB response was not completely returned. Post a copy data request to
// get the remainder of the response. If the response is greater than the original
// buffer size, abort this connection request and consume the bytes available.
if (BytesAvailable > CONSTRUCT_NETROOT_BUFFER_SIZE) {
ASSERT(!"not enough bytes in parsesmbheader.....sigh.............."); // To be removed soon ...
pExchange->Status = STATUS_NOT_IMPLEMENTED;
*pBytesTaken = BytesAvailable;
Status = STATUS_SUCCESS;
} else {
*pBytesTaken = 0;
*pDataBufferPointer = pNetRootExchange->pSmbResponseMdl;
*pDataSize = BytesAvailable;
Status = STATUS_MORE_PROCESSING_REQUIRED;
}
} else {
// The SMB exchange completed without an error.
pExchange->Status = SmbCeParseConstructNetRootResponse(
pNetRootExchange,
pSmbHeader,
BytesAvailable,
BytesIndicated,
pBytesTaken);
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesTaken %ld\n",*pBytesTaken));
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader Return Status %lx\n",pExchange->Status));
Status = STATUS_SUCCESS;
}
return Status;
}
NTSTATUS
SmbConstructNetRootExchangeCopyDataHandler(
IN PSMB_EXCHANGE pExchange, // The exchange instance
IN PMDL pCopyDataBuffer,
IN ULONG DataSize)
/*++
Routine Description:
This is the copy data handling routine for net root construction exchanges
Arguments:
pExchange - the exchange instance
Return Value:
NTSTATUS - The return status for the operation
--*/
{
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
PSMB_HEADER pSmbHeader;
ULONG ResponseSize = DataSize;
ULONG ResponseBytesConsumed = 0;
pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
ASSERT(pCopyDataBuffer == pNetRootExchange->pSmbResponseMdl);
pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdl(pNetRootExchange->pSmbResponseMdl);
pExchange->Status = SmbCeParseConstructNetRootResponse(
pNetRootExchange,
pSmbHeader,
ResponseSize,
ResponseSize,
&ResponseBytesConsumed);
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesTaken %ld\n",ResponseBytesConsumed));
return STATUS_SUCCESS;
}
NTSTATUS
SmbCeParseConstructNetRootResponse(
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange,
PSMB_HEADER pSmbHeader,
ULONG BytesAvailable,
ULONG BytesIndicated,
ULONG *pBytesTaken)
{
NTSTATUS Status,SmbResponseStatus;
GENERIC_ANDX CommandToProcess;
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated %ld\n",BytesIndicated));
Status = SmbCeParseSmbHeader(
(PSMB_EXCHANGE)pNetRootExchange,
pSmbHeader,
&CommandToProcess,
&SmbResponseStatus,
BytesAvailable,
BytesIndicated,
pBytesTaken);
if (Status == STATUS_SUCCESS) {
*pBytesTaken = BytesIndicated;
}
return Status;
}
NTSTATUS
SmbConstructNetRootExchangeFinalize(
PSMB_EXCHANGE pExchange,
BOOLEAN *pPostFinalize)
/*++
Routine Description:
This routine finalizes the construct net root exchange. It resumes the RDBSS by invoking
the call back and discards the exchange
Arguments:
pExchange - the exchange instance
CurrentIrql - the current interrupt request level
pPostFinalize - a pointer to a BOOLEAN if the request should be posted
Return Value:
NTSTATUS - The return status for the operation
--*/
{
PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext;
PMRX_V_NET_ROOT pVNetRoot;
PMRX_NET_ROOT pNetRoot;
if (RxShouldPostCompletion()) {
*pPostFinalize = TRUE;
return STATUS_SUCCESS;
} else {
*pPostFinalize = FALSE;
}
pVNetRoot = pExchange->SmbCeContext.pVNetRoot;
pNetRoot = pVNetRoot->pNetRoot;
ASSERT((pVNetRoot == NULL) || (pVNetRoot->pNetRoot == pNetRoot));
pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
ASSERT(pNetRootExchange->Type == CONSTRUCT_NETROOT_EXCHANGE);
pCreateNetRootContext = pNetRootExchange->pCreateNetRootContext;
pCreateNetRootContext->VirtualNetRootStatus = STATUS_SUCCESS;
pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
RxDbgTrace(0,Dbg,("SmbConstructNetRootExchangeFinalize: Net Root Exchange Status %lx\n", pExchange->Status));
if (!NT_SUCCESS(pExchange->Status)) {
if (pCreateNetRootContext->RxContext
&& pCreateNetRootContext->RxContext->Create.ThisIsATreeConnectOpen){
InterlockedIncrement(&MRxIfsStatistics.FailedUseCount);
}
if (pExchange->SmbCeContext.pSessionEntry->Header.State != SMBCEDB_ACTIVE) {
pCreateNetRootContext->VirtualNetRootStatus = pExchange->Status;
}
if (pExchange->SmbCeContext.pNetRootEntry->Header.State != SMBCEDB_ACTIVE) {
pCreateNetRootContext->NetRootStatus = pExchange->Status;
}
} else {
if (pExchange->SmbCeContext.pSessionEntry->Header.State == SMBCEDB_ACTIVE) {
PSMBCEDB_SESSION_ENTRY pSessionEntry = pExchange->SmbCeContext.pSessionEntry;
PSMBCEDB_SERVER_ENTRY pServerEntry = pSessionEntry->pServerEntry;
PMRX_V_NET_ROOT pVNetRoot = pExchange->SmbCeContext.pVNetRoot;
// Mark this session entry as the default entry if required.
if (FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_SESSION_CONSTRUCTOR) &&
((pVNetRoot->pUserName != NULL) || (pVNetRoot->pPassword != NULL))) {
SmbCeAcquireSpinLock();
if (SmbCeGetDefaultSessionEntry(pServerEntry) == NULL) {
SmbCeSetDefaultSessionEntryLite(pServerEntry,pSessionEntry);
}
SmbCeReleaseSpinLock();
}
}
//if the transaction can identify the netroottype, use it. otherwise, stay with what you have!
if (pExchange->SmbCeContext.pNetRootEntry->NetRoot.NetRootType != NET_ROOT_WILD){
pNetRoot->Type = pExchange->SmbCeContext.pNetRootEntry->NetRoot.NetRootType;
}
//
// NOTE: In this example minirdr, only remote disk access is allowed. This means
// that pipes, mailslots, printers, remote comm devices, are NOT supported.
// If the user mode caller tries to open a pipe, the open (or tree connect)
// will be sent over the wire, but we intercept the response here and
// mark it as unsuccessful (actually un-implemented). This after-the-fact
// approach allows us to keep existing error recover mechanisms in the
// code working.
switch (pNetRoot->Type) {
//
// If the remote access is for a disk, mark the device as a disk and
// go ahead.
//
case NET_ROOT_DISK:
pNetRoot->DeviceType = RxDeviceType(DISK);
break;
case NET_ROOT_PIPE:
case NET_ROOT_COMM:
case NET_ROOT_PRINT:
case NET_ROOT_MAILSLOT:
//
// The remote was NOT a disk, so mark the NetRootStatus and VNetRoot
// status as bad. Code that follows will detect this and return
// diagnostic information to the caller. The operation fails.
//
pCreateNetRootContext->VirtualNetRootStatus = STATUS_NOT_IMPLEMENTED;
pCreateNetRootContext->NetRootStatus = STATUS_NOT_IMPLEMENTED;
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("SmbConstructNetRootExchangeFinalize: Non-disk attempt forcibly denied\n"));
break;
case NET_ROOT_WILD:
break;
default:
ASSERT(!"Valid Net Root Type");
}
}
//
// Now do the callback.
//
pNetRootExchange->NetRootCallback(pCreateNetRootContext);
if (pNetRootExchange->pSmbResponseMdl != NULL) {
MmUnlockPages(pNetRootExchange->pSmbResponseMdl);
IoFreeMdl(pNetRootExchange->pSmbResponseMdl);
}
if (pNetRootExchange->pSmbRequestMdl != NULL) {
MmUnlockPages(pNetRootExchange->pSmbRequestMdl);
IoFreeMdl(pNetRootExchange->pSmbRequestMdl);
}
if (pNetRootExchange->pSmbBuffer != NULL) {
RxFreePool(pNetRootExchange->pSmbBuffer);
}
//
// Get rid of the exchange
//
SmbCeDiscardExchange(pExchange);
return STATUS_SUCCESS;
}
SMB_EXCHANGE_DISPATCH_VECTOR
ConstructNetRootExchangeDispatch = {
SmbConstructNetRootExchangeStart,
SmbConstructNetRootExchangeReceive,
SmbConstructNetRootExchangeCopyDataHandler,
NULL, // No SendCompletionHandler
SmbConstructNetRootExchangeFinalize
};
VOID
MRxIfsExtractNetRootName(
IN PUNICODE_STRING FilePathName,
IN PMRX_SRV_CALL SrvCall,
OUT PUNICODE_STRING NetRootName,
OUT PUNICODE_STRING RestOfName OPTIONAL
)
/*++
Routine Description:
This routine parses the input name into srv, netroot, and the
rest.
Arguments:
--*/
{
UNICODE_STRING xRestOfName;
ULONG length = FilePathName->Length;
PWCH w = FilePathName->Buffer;
PWCH wlimit = (PWCH)(((PCHAR)w)+length);
PWCH wlow;
w += (SrvCall->pSrvCallName->Length/sizeof(WCHAR));
NetRootName->Buffer = wlow = w;
for (;;) {
if (w>=wlimit) break;
if ( (*w == OBJ_NAME_PATH_SEPARATOR) && (w!=wlow) ){
break;
}
w++;
}
NetRootName->Length = NetRootName->MaximumLength
= (PCHAR)w - (PCHAR)wlow;
if (!RestOfName) RestOfName = &xRestOfName;
RestOfName->Buffer = w;
RestOfName->Length = RestOfName->MaximumLength
= (PCHAR)wlimit - (PCHAR)w;
RxDbgTrace( 0,Dbg,(" MRxSmbExtractNetRootName FilePath=%wZ\n",FilePathName));
RxDbgTrace(0,Dbg,(" Srv=%wZ,Root=%wZ,Rest=%wZ\n",
SrvCall->pSrvCallName,NetRootName,RestOfName));
return;
}