/*++ 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; }