Leaked source code of windows server 2003
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.

1126 lines
34 KiB

  1. /*++
  2. Copyright (c) 1989 - 1999 Microsoft Corporation
  3. Module Name:
  4. netroot.c
  5. Abstract:
  6. This module implements the routines for creating the SMB net root.
  7. --*/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. //
  11. // The Bug check file id for this module
  12. //
  13. #define BugCheckFileId (RDBSS_BUG_CHECK_SMB_NETROOT)
  14. //
  15. // The local debug trace level
  16. //
  17. #define Dbg (DEBUG_TRACE_DISPATCH)
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, MRxSmbUpdateNetRootState)
  20. #pragma alloc_text(PAGE, MRxSmbGetDialectFlagsFromSrvCall)
  21. #pragma alloc_text(PAGE, MRxSmbCreateVNetRoot)
  22. #pragma alloc_text(PAGE, MRxSmbFinalizeNetRoot)
  23. #pragma alloc_text(PAGE, SmbCeReconnect)
  24. #pragma alloc_text(PAGE, SmbCeEstablishConnection)
  25. #pragma alloc_text(PAGE, SmbConstructNetRootExchangeStart)
  26. #pragma alloc_text(PAGE, MRxSmbExtractNetRootName)
  27. #endif
  28. //
  29. // Forward declarations ...
  30. //
  31. extern NTSTATUS
  32. SmbCeParseConstructNetRootResponse(
  33. PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange,
  34. PSMB_HEADER pSmbHeader,
  35. ULONG BytesAvailable,
  36. ULONG BytesIndicated,
  37. ULONG *pBytesTaken);
  38. extern NTSTATUS
  39. SmbConstructNetRootExchangeFinalize(
  40. PSMB_EXCHANGE pExchange,
  41. BOOLEAN *pPostFinalize);
  42. typedef struct _SMBCE_NETROOT_CONSTRUCTION_CONTEXT {
  43. NTSTATUS Status;
  44. PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext;
  45. PMRX_V_NET_ROOT pVNetRoot;
  46. RX_WORK_QUEUE_ITEM WorkQueueItem;
  47. } SMBCE_NETROOT_CONSTRUCTION_CONTEXT,
  48. *PSMBCE_NETROOT_CONSTRUCTION_CONTEXT;
  49. NTSTATUS
  50. MRxSmbUpdateNetRootState(
  51. IN OUT PMRX_NET_ROOT pNetRoot)
  52. /*++
  53. Routine Description:
  54. This routine update the mini redirector state associated with a net root.
  55. Arguments:
  56. pNetRoot - the net root instance.
  57. Return Value:
  58. RXSTATUS - The return status for the operation
  59. Notes:
  60. By diffrentiating the mini redirewctor state from the net rot condition it is possible
  61. to permit a variety of reconnect strategies. It is conceivable that the RDBSS considers
  62. a net root to be good while the underlying mini redirector might mark it as invalid
  63. and reconnect on the fly.
  64. --*/
  65. {
  66. if (pNetRoot->MRxNetRootState == MRX_NET_ROOT_STATE_GOOD) {
  67. if (pNetRoot->Context == NULL) {
  68. pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
  69. } else {
  70. PSMBCEDB_SERVER_ENTRY pServerEntry;
  71. pServerEntry = SmbCeReferenceAssociatedServerEntry(pNetRoot->pSrvCall);
  72. if (pServerEntry != NULL) {
  73. switch (pServerEntry->Header.State) {
  74. case SMBCEDB_ACTIVE:
  75. pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_GOOD;
  76. break;
  77. case SMBCEDB_INVALID:
  78. pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_DISCONNECTED;
  79. break;
  80. case SMBCEDB_CONSTRUCTION_IN_PROGRESS:
  81. pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_RECONN;
  82. break;
  83. default:
  84. pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
  85. break;
  86. }
  87. SmbCeDereferenceServerEntry(pServerEntry);
  88. } else {
  89. pNetRoot->MRxNetRootState = MRX_NET_ROOT_STATE_ERROR;
  90. }
  91. }
  92. }
  93. return STATUS_SUCCESS;
  94. }
  95. ULONG
  96. MRxSmbGetDialectFlagsFromSrvCall(
  97. PMRX_SRV_CALL SrvCall
  98. )
  99. {
  100. ULONG DialectFlags;
  101. PSMBCEDB_SERVER_ENTRY pServerEntry;
  102. PAGED_CODE();
  103. pServerEntry = SmbCeReferenceAssociatedServerEntry(SrvCall);
  104. ASSERT(pServerEntry != NULL);
  105. DialectFlags = pServerEntry->Server.DialectFlags;
  106. SmbCeDereferenceServerEntry(pServerEntry);
  107. return(DialectFlags);
  108. }
  109. NTSTATUS
  110. MRxSmbCreateVNetRoot(
  111. IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext
  112. )
  113. /*++
  114. Routine Description:
  115. This routine patches the RDBSS created net root instance with the information required
  116. by the mini redirector.
  117. In case the connection cannot be established, the mini redirector tries to transition
  118. the VNetRoot into disconnected mode and establishes the connection off-line. If the
  119. connection failes to establish in the synchronouse way, this routine will do the transition;
  120. Otherwise, SmbConstructNetRootExchangeFinalize routine will try the transition. In both
  121. cases, MRxSmbCreateVNetRoot will be called again to establish the connection in disconnected
  122. mode.
  123. Arguments:
  124. pVNetRoot - the virtual net root instance.
  125. pCreateNetRootContext - the net root context for calling back
  126. Return Value:
  127. RXSTATUS - The return status for the operation
  128. --*/
  129. {
  130. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  131. PRX_CONTEXT pRxContext = pCreateNetRootContext->RxContext;
  132. PMRX_V_NET_ROOT pVNetRoot = (PMRX_V_NET_ROOT)pCreateNetRootContext->pVNetRoot;
  133. PMRX_SRV_CALL pSrvCall;
  134. PMRX_NET_ROOT pNetRoot;
  135. PSMBCEDB_SERVER_ENTRY pServerEntry;
  136. PUNICODE_STRING pNetRootName,pSrvCallName;
  137. BOOLEAN fInitializeNetRoot;
  138. BOOLEAN fDeferNetworkInitialization;
  139. BOOLEAN CallBack = FALSE;
  140. extern DWORD hShareReint;
  141. PAGED_CODE();
  142. pNetRoot = pVNetRoot->pNetRoot;
  143. pSrvCall = pNetRoot->pSrvCall;
  144. pServerEntry = SmbCeGetAssociatedServerEntry(pSrvCall);
  145. if (pRxContext->Create.ThisIsATreeConnectOpen){
  146. InterlockedIncrement(&MRxSmbStatistics.UseCount);
  147. }
  148. SmbCeLog(("Vnetroot %wZ \n", pNetRoot->pNetRootName));
  149. fInitializeNetRoot = (pNetRoot->Context == NULL);
  150. fDeferNetworkInitialization = pRxContext->Create.TreeConnectOpenDeferred;
  151. ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) &&
  152. (NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
  153. if (pNetRoot->Type == NET_ROOT_MAILSLOT) {
  154. pVNetRoot->Context = NULL;
  155. Status = STATUS_NOT_SUPPORTED;
  156. RxDbgTrace( 0, Dbg, ("Mailslot open\n"));
  157. } else if (pNetRoot->Type == NET_ROOT_PIPE) {
  158. pVNetRoot->Context = NULL;
  159. Status = STATUS_NOT_SUPPORTED;
  160. RxDbgTrace( 0, Dbg, ("pipe open to core server\n"));
  161. }
  162. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  163. Status = SmbCeFindOrConstructVNetRootContext(
  164. pVNetRoot,
  165. fDeferNetworkInitialization);
  166. }
  167. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  168. // Update the flags on the VNetRootContext to indicate if this is a
  169. // agent open
  170. Status = SmbCeEstablishConnection(
  171. pVNetRoot,
  172. pCreateNetRootContext,
  173. fInitializeNetRoot);
  174. }
  175. if (Status != STATUS_PENDING) {
  176. if (!NT_SUCCESS(Status)) {
  177. if (fInitializeNetRoot &&
  178. (pNetRoot->Context != NULL)) {
  179. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  180. SmbCeAcquireResource();
  181. pNetRootEntry = SmbCeGetAssociatedNetRootEntry(pNetRoot);
  182. if (pNetRootEntry != NULL) {
  183. pNetRootEntry->pRdbssNetRoot = NULL;
  184. SmbCeDereferenceNetRootEntry(pNetRootEntry);
  185. }
  186. pNetRoot->Context = NULL;
  187. SmbCeReleaseResource();
  188. }
  189. SmbCeDestroyAssociatedVNetRootContext(pVNetRoot);
  190. if (pRxContext->Create.ThisIsATreeConnectOpen){
  191. InterlockedIncrement(&MRxSmbStatistics.FailedUseCount);
  192. }
  193. }
  194. pCreateNetRootContext->VirtualNetRootStatus = Status;
  195. if (fInitializeNetRoot) {
  196. pCreateNetRootContext->NetRootStatus = Status;
  197. } else {
  198. pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
  199. }
  200. CallBack = TRUE;
  201. // Map the error code to STATUS_PENDING since this triggers the synchronization
  202. // mechanism in the RDBSS.
  203. Status = STATUS_PENDING;
  204. }
  205. if (CallBack) {
  206. // Callback the RDBSS for resumption.
  207. pCreateNetRootContext->Callback(pCreateNetRootContext);
  208. }
  209. return Status;
  210. }
  211. NTSTATUS
  212. MRxSmbFinalizeVNetRoot(
  213. IN PMRX_V_NET_ROOT pVNetRoot,
  214. IN PBOOLEAN ForceDisconnect)
  215. /*++
  216. Routine Description:
  217. Arguments:
  218. pVNetRoot - the virtual net root
  219. ForceDisconnect - disconnect is forced
  220. Return Value:
  221. RXSTATUS - The return status for the operation
  222. --*/
  223. {
  224. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  225. PSMBCEDB_SESSION_ENTRY pDefaultSessionEntry;
  226. // This cannot be paged code since we meed to protect the default session list with the lock
  227. RxDbgTrace( 0, Dbg, ("MRxSmbFinalizeVNetRoot %lx\n",pVNetRoot));
  228. if (pVNetRoot->Context != NULL) {
  229. SmbCeDestroyAssociatedVNetRootContext(pVNetRoot);
  230. }
  231. return STATUS_SUCCESS;
  232. }
  233. NTSTATUS
  234. MRxSmbFinalizeNetRoot(
  235. IN PMRX_NET_ROOT pNetRoot,
  236. IN PBOOLEAN ForceDisconnect)
  237. /*++
  238. Routine Description:
  239. Arguments:
  240. pVirtualNetRoot - the virtual net root
  241. ForceDisconnect - disconnect is forced
  242. Return Value:
  243. RXSTATUS - The return status for the operation
  244. --*/
  245. {
  246. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  247. PAGED_CODE();
  248. RxDbgTrace( 0, Dbg, ("MRxSmbFinalizeNetRoot %lx\n",pNetRoot));
  249. if (pNetRoot->Context != NULL) {
  250. SmbCeAcquireResource();
  251. pNetRootEntry = SmbCeGetAssociatedNetRootEntry(pNetRoot);
  252. InterlockedCompareExchangePointer(
  253. &pNetRootEntry->pRdbssNetRoot,
  254. NULL,
  255. pNetRoot);
  256. SmbCeDereferenceNetRootEntry(pNetRootEntry);
  257. ASSERT(!FlagOn(pNetRoot->Flags,NETROOT_FLAG_FINALIZE_INVOKED));
  258. SetFlag(pNetRoot->Flags,NETROOT_FLAG_FINALIZE_INVOKED);
  259. SmbCeReleaseResource();
  260. }
  261. return STATUS_SUCCESS;
  262. }
  263. VOID
  264. SmbCeReconnectCallback(
  265. PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
  266. /*++
  267. Routine Description:
  268. This routine signals the completion of a reconnect attempt
  269. Arguments:
  270. pCreateNetRootContext - the net root context
  271. Return Value:
  272. RXSTATUS - The return status for the operation
  273. --*/
  274. {
  275. KeSetEvent(&pCreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE );
  276. }
  277. NTSTATUS
  278. SmbCeReconnect(
  279. IN PMRX_V_NET_ROOT pVNetRoot)
  280. /*++
  281. Routine Description:
  282. This routine reconnects, i.e, establishes a new session and tree connect to a previously
  283. connected serverb share
  284. Arguments:
  285. pVNetRoot - the virtual net root instance.
  286. Return Value:
  287. RXSTATUS - The return status for the operation
  288. --*/
  289. {
  290. NTSTATUS Status;
  291. PSMBCEDB_SERVER_ENTRY pServerEntry;
  292. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  293. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  294. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)pVNetRoot->Context;
  295. PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext;
  296. PAGED_CODE();
  297. if ((pVNetRootContext != NULL) &&
  298. (pVNetRootContext->Header.State == SMBCEDB_ACTIVE)) {
  299. pServerEntry = pVNetRootContext->pServerEntry;
  300. pSessionEntry = pVNetRootContext->pSessionEntry;
  301. pNetRootEntry = pVNetRootContext->pNetRootEntry;
  302. if ((pServerEntry->Header.State == SMBCEDB_ACTIVE) &&
  303. (pSessionEntry->Header.State == SMBCEDB_ACTIVE) &&
  304. (pNetRootEntry->Header.State == SMBCEDB_ACTIVE)) {
  305. return STATUS_SUCCESS;
  306. }
  307. }
  308. pCreateNetRootContext = (PMRX_CREATENETROOT_CONTEXT)
  309. RxAllocatePoolWithTag(
  310. NonPagedPool,
  311. sizeof(MRX_CREATENETROOT_CONTEXT),
  312. MRXSMB_NETROOT_POOLTAG);
  313. if (pCreateNetRootContext != NULL) {
  314. for (;;) {
  315. pCreateNetRootContext->pVNetRoot = (PV_NET_ROOT)pVNetRoot;
  316. pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
  317. pCreateNetRootContext->VirtualNetRootStatus = STATUS_SUCCESS;
  318. pCreateNetRootContext->Callback = SmbCeReconnectCallback;
  319. pCreateNetRootContext->RxContext = NULL;
  320. KeInitializeEvent(
  321. &pCreateNetRootContext->FinishEvent,
  322. SynchronizationEvent,
  323. FALSE );
  324. // Since this is a reconnect instance the net root initialization is not required
  325. Status = SmbCeEstablishConnection(
  326. pVNetRoot,
  327. pCreateNetRootContext,
  328. FALSE);
  329. if (Status == STATUS_PENDING) {
  330. // Wait for the construction to be completed.
  331. KeWaitForSingleObject(
  332. &pCreateNetRootContext->FinishEvent,
  333. Executive,
  334. KernelMode,
  335. FALSE,
  336. NULL);
  337. Status = pCreateNetRootContext->VirtualNetRootStatus;
  338. }
  339. if (Status != STATUS_LINK_FAILED) {
  340. break;
  341. }
  342. }
  343. RxFreePool(pCreateNetRootContext);
  344. } else {
  345. Status = STATUS_INSUFFICIENT_RESOURCES;
  346. }
  347. return Status;
  348. }
  349. NTSTATUS
  350. SmbCeEstablishConnection(
  351. IN OUT PMRX_V_NET_ROOT pVNetRoot,
  352. IN PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext,
  353. IN BOOLEAN fInitializeNetRoot
  354. )
  355. /*++
  356. Routine Description:
  357. This routine triggers off the connection attempt for initial establishment of a
  358. connection as well as subsequent reconnect attempts.
  359. Arguments:
  360. pVNetRoot - the virtual net root instance.
  361. pCreateNetRootContext - the net root context for calling back
  362. Return Value:
  363. RXSTATUS - The return status for the operation
  364. --*/
  365. {
  366. NTSTATUS Status;
  367. PSMBCEDB_SERVER_ENTRY pServerEntry;
  368. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  369. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  370. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  371. PAGED_CODE();
  372. pVNetRootContext = SmbCeGetAssociatedVNetRootContext(pVNetRoot);
  373. if (pVNetRootContext == NULL) {
  374. Status = STATUS_BAD_NETWORK_PATH;
  375. } else {
  376. pServerEntry = pVNetRootContext->pServerEntry;
  377. pSessionEntry = pVNetRootContext->pSessionEntry;
  378. pNetRootEntry = pVNetRootContext->pNetRootEntry;
  379. Status = STATUS_SUCCESS;
  380. }
  381. if (Status == STATUS_SUCCESS) {
  382. //
  383. // The following code initializes the NetRootEntry, VNetRootContext and
  384. // the session entry under certain cases.
  385. //
  386. // The session entry to a doenlevel server needs to be initialized. This
  387. // is not handled by the previous code since the session entry and the
  388. // net root entry initialization can be combined into one exchange.
  389. //
  390. // The net root entry has not been initialized, i.e., this corresponds to
  391. // the construction of the first SMBCE_V_NET_ROOT_CONTEXT instance for a
  392. // given NetRootEntry.
  393. //
  394. // Subsequent SMBCE_V_NET_ROOT context constructions. In these cases the
  395. // construction of each context must obtain a new TID
  396. //
  397. BOOLEAN fNetRootExchangeRequired;
  398. fNetRootExchangeRequired = (
  399. (pSessionEntry->Header.State != SMBCEDB_ACTIVE) ||
  400. !BooleanFlagOn(
  401. pVNetRootContext->Flags,
  402. SMBCE_V_NET_ROOT_CONTEXT_FLAG_VALID_TID)
  403. );
  404. if (fNetRootExchangeRequired) {
  405. // This is a tree connect open which needs to be triggered immediately.
  406. PSMB_EXCHANGE pSmbExchange;
  407. PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
  408. pSmbExchange = SmbMmAllocateExchange(CONSTRUCT_NETROOT_EXCHANGE,NULL);
  409. if (pSmbExchange != NULL) {
  410. Status = SmbCeInitializeExchange(
  411. &pSmbExchange,
  412. NULL,
  413. pVNetRoot,
  414. CONSTRUCT_NETROOT_EXCHANGE,
  415. &ConstructNetRootExchangeDispatch);
  416. if (Status == STATUS_SUCCESS) {
  417. pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pSmbExchange;
  418. // Attempt to reconnect( In this case it amounts to establishing the
  419. // connection/session)
  420. pNetRootExchange->SmbCeFlags |= (SMBCE_EXCHANGE_ATTEMPT_RECONNECTS |
  421. SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION);
  422. // Initialize the continuation for resumption upon completion of the
  423. // tree connetcion.
  424. pNetRootExchange->NetRootCallback = pCreateNetRootContext->Callback;
  425. pNetRootExchange->pCreateNetRootContext = pCreateNetRootContext;
  426. pNetRootExchange->fInitializeNetRoot = fInitializeNetRoot;
  427. // Initiate the exchange.
  428. Status = SmbCeInitiateExchange(pSmbExchange);
  429. if (Status != STATUS_PENDING) {
  430. SmbCeDiscardExchangeWorkerThreadRoutine(pSmbExchange);
  431. }
  432. }
  433. } else {
  434. Status = STATUS_INSUFFICIENT_RESOURCES;
  435. }
  436. }
  437. }
  438. return Status;
  439. }
  440. //
  441. // The net roots are normally constructed as part of some other exchange, i.e., the SMB for
  442. // Tree connect is compounded with other operations. However, there is one situation in which
  443. // the tree connect SMB needs to be sent by itself. This case refers to the prefix claim
  444. // situation ( net use command ). This is handled by the construct net root exchange.
  445. //
  446. #define CONSTRUCT_NETROOT_BUFFER_SIZE (4096)
  447. NTSTATUS
  448. SmbConstructNetRootExchangeStart(
  449. PSMB_EXCHANGE pExchange)
  450. /*++
  451. Routine Description:
  452. This is the start routine for net root construction exchanges. This initiates the
  453. construction of the appropriate SMB's if required.
  454. Arguments:
  455. pExchange - the exchange instance
  456. Return Value:
  457. RXSTATUS - The return status for the operation
  458. --*/
  459. {
  460. NTSTATUS Status;
  461. NTSTATUS RequestLockStatus = STATUS_UNSUCCESSFUL;
  462. NTSTATUS ResponseLockStatus = STATUS_UNSUCCESSFUL;
  463. PVOID pSmbActualBuffer;
  464. PVOID pSmbBuffer;
  465. UCHAR SmbCommand,LastCommandInHeader;
  466. ULONG SmbLength;
  467. PUCHAR pCommand;
  468. PMDL pSmbRequestMdl,pSmbResponseMdl;
  469. ULONG SmbMdlSize;
  470. PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
  471. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  472. PMRX_NET_ROOT pNetRoot = pExchange->SmbCeContext.pVNetRoot->pNetRoot;
  473. PAGED_CODE();
  474. pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
  475. ASSERT(pNetRootExchange->Type == CONSTRUCT_NETROOT_EXCHANGE);
  476. if (pNetRoot->Type == NET_ROOT_PIPE) {
  477. RxDbgTrace( 0, Dbg, ("pipe open to core server\n"));
  478. return STATUS_NOT_SUPPORTED;
  479. }
  480. pSmbRequestMdl = pSmbResponseMdl = NULL;
  481. pSmbActualBuffer = RxAllocatePoolWithTag(
  482. PagedPool,
  483. (CONSTRUCT_NETROOT_BUFFER_SIZE + TRANSPORT_HEADER_SIZE),
  484. MRXSMB_NETROOT_POOLTAG);
  485. if (pSmbActualBuffer != NULL) {
  486. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(pExchange);
  487. (PCHAR) pSmbBuffer = (PCHAR) pSmbActualBuffer + TRANSPORT_HEADER_SIZE;
  488. Status = SmbCeBuildSmbHeader(
  489. pExchange,
  490. pSmbBuffer,
  491. CONSTRUCT_NETROOT_BUFFER_SIZE,
  492. &SmbLength,
  493. &LastCommandInHeader,
  494. &pCommand);
  495. // Ensure that the NET_ROOT/SESSION still needs to be constructed before
  496. // sending it. It is likely that they were costructed by an earlier exchange
  497. if (NT_SUCCESS(Status) &&
  498. (SmbLength > sizeof(SMB_HEADER))) {
  499. if (LastCommandInHeader != SMB_COM_TREE_CONNECT){
  500. *pCommand = SMB_COM_NO_ANDX_COMMAND;
  501. }
  502. RxAllocateHeaderMdl(
  503. pSmbBuffer,
  504. SmbLength,
  505. pSmbRequestMdl
  506. );
  507. pSmbResponseMdl = RxAllocateMdl(pSmbBuffer,CONSTRUCT_NETROOT_BUFFER_SIZE);
  508. if ((pSmbRequestMdl != NULL) &&
  509. (pSmbResponseMdl != NULL)) {
  510. RxProbeAndLockHeaderPages(
  511. pSmbRequestMdl,
  512. KernelMode,
  513. IoModifyAccess,
  514. RequestLockStatus);
  515. RxProbeAndLockPages(
  516. pSmbResponseMdl,
  517. KernelMode,
  518. IoModifyAccess,
  519. ResponseLockStatus);
  520. if ((Status == STATUS_SUCCESS) &&
  521. ((Status = RequestLockStatus) == STATUS_SUCCESS) &&
  522. ((Status = ResponseLockStatus) == STATUS_SUCCESS)) {
  523. pNetRootExchange->pSmbResponseMdl = pSmbResponseMdl;
  524. pNetRootExchange->pSmbRequestMdl = pSmbRequestMdl;
  525. pNetRootExchange->pSmbActualBuffer = pSmbActualBuffer;
  526. pNetRootExchange->pSmbBuffer = pSmbBuffer;
  527. Status = SmbCeTranceive(
  528. pExchange,
  529. (RXCE_SEND_PARTIAL | RXCE_SEND_SYNCHRONOUS),
  530. pNetRootExchange->pSmbRequestMdl,
  531. SmbLength);
  532. RxDbgTrace( 0, Dbg, ("Net Root SmbCeTranceive returned %lx\n",Status));
  533. }
  534. } else {
  535. Status = STATUS_INSUFFICIENT_RESOURCES;
  536. }
  537. if ((Status != STATUS_PENDING) &&
  538. (Status != STATUS_SUCCESS)) {
  539. pNetRootExchange->pSmbResponseMdl = NULL;
  540. pNetRootExchange->pSmbRequestMdl = NULL;
  541. pNetRootExchange->pSmbActualBuffer = NULL;
  542. pNetRootExchange->pSmbBuffer = NULL;
  543. if (pSmbResponseMdl != NULL) {
  544. if (ResponseLockStatus == STATUS_SUCCESS) {
  545. MmUnlockPages(pSmbResponseMdl);
  546. }
  547. IoFreeMdl(pSmbResponseMdl);
  548. }
  549. if (pSmbRequestMdl != NULL) {
  550. if (RequestLockStatus == STATUS_SUCCESS) {
  551. RxUnlockHeaderPages(pSmbRequestMdl);
  552. }
  553. IoFreeMdl(pSmbRequestMdl);
  554. }
  555. RxFreePool(pSmbActualBuffer);
  556. }
  557. } else {
  558. RxFreePool(pSmbActualBuffer);
  559. }
  560. } else {
  561. Status = STATUS_INSUFFICIENT_RESOURCES;
  562. }
  563. return Status;
  564. }
  565. NTSTATUS
  566. SmbConstructNetRootExchangeReceive(
  567. IN struct _SMB_EXCHANGE *pExchange,
  568. IN ULONG BytesIndicated,
  569. IN ULONG BytesAvailable,
  570. OUT ULONG *pBytesTaken,
  571. IN PSMB_HEADER pSmbHeader,
  572. OUT PMDL *pDataBufferPointer,
  573. OUT PULONG pDataSize,
  574. IN ULONG ReceiveFlags)
  575. /*++
  576. Routine Description:
  577. This is the recieve indication handling routine for net root construction exchanges
  578. Arguments:
  579. pExchange - the exchange instance
  580. BytesIndicated - the number of bytes indicated
  581. Bytes Available - the number of bytes available
  582. pBytesTaken - the number of bytes consumed
  583. pSmbHeader - the byte buffer
  584. pDataBufferPointer - the buffer into which the remaining data is to be copied.
  585. pDataSize - the buffer size.
  586. Return Value:
  587. NTSTATUS - The return status for the operation
  588. Notes:
  589. This routine is called at DPC level.
  590. --*/
  591. {
  592. NTSTATUS Status;
  593. PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
  594. pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
  595. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated/Available %ld %ld\n",BytesIndicated,BytesAvailable));
  596. if (BytesAvailable > BytesIndicated ||
  597. !FlagOn(ReceiveFlags,TDI_RECEIVE_ENTIRE_MESSAGE)) {
  598. // The SMB response was not completely returned. Post a copy data request to
  599. // get the remainder of the response. If the response is greater than the original
  600. // buffer size, abort this connection request and consume the bytes available.
  601. if (BytesAvailable > CONSTRUCT_NETROOT_BUFFER_SIZE) {
  602. ASSERT(!"not enough bytes in parsesmbheader.....sigh.............."); // To be removed soon ...
  603. pExchange->Status = STATUS_NOT_IMPLEMENTED;
  604. *pBytesTaken = BytesAvailable;
  605. Status = STATUS_SUCCESS;
  606. } else {
  607. *pBytesTaken = 0;
  608. *pDataBufferPointer = pNetRootExchange->pSmbResponseMdl;
  609. *pDataSize = CONSTRUCT_NETROOT_BUFFER_SIZE;
  610. Status = STATUS_MORE_PROCESSING_REQUIRED;
  611. }
  612. } else {
  613. // The SMB exchange completed without an error.
  614. pExchange->Status = SmbCeParseConstructNetRootResponse(
  615. pNetRootExchange,
  616. pSmbHeader,
  617. BytesAvailable,
  618. BytesIndicated,
  619. pBytesTaken);
  620. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesTaken %ld\n",*pBytesTaken));
  621. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader Return Status %lx\n",pExchange->Status));
  622. Status = STATUS_SUCCESS;
  623. }
  624. return Status;
  625. }
  626. NTSTATUS
  627. SmbConstructNetRootExchangeCopyDataHandler(
  628. IN PSMB_EXCHANGE pExchange,
  629. IN PMDL pCopyDataBuffer,
  630. IN ULONG DataSize)
  631. /*++
  632. Routine Description:
  633. This is the copy data handling routine for net root construction exchanges
  634. Arguments:
  635. pExchange - the exchange instance
  636. Return Value:
  637. NTSTATUS - The return status for the operation
  638. --*/
  639. {
  640. PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
  641. PSMB_HEADER pSmbHeader;
  642. ULONG ResponseSize = DataSize;
  643. ULONG ResponseBytesConsumed = 0;
  644. NTSTATUS Status = STATUS_SUCCESS;
  645. pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
  646. ASSERT(pCopyDataBuffer == pNetRootExchange->pSmbResponseMdl);
  647. pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdlSafe(pNetRootExchange->pSmbResponseMdl,LowPagePriority);
  648. if (pSmbHeader != NULL) {
  649. pExchange->Status = SmbCeParseConstructNetRootResponse(
  650. pNetRootExchange,
  651. pSmbHeader,
  652. ResponseSize,
  653. ResponseSize,
  654. &ResponseBytesConsumed);
  655. } else {
  656. Status = STATUS_INSUFFICIENT_RESOURCES;
  657. }
  658. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesTaken %ld\n",ResponseBytesConsumed));
  659. return Status;
  660. }
  661. NTSTATUS
  662. SmbCeParseConstructNetRootResponse(
  663. PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange,
  664. PSMB_HEADER pSmbHeader,
  665. ULONG BytesAvailable,
  666. ULONG BytesIndicated,
  667. ULONG *pBytesTaken)
  668. {
  669. NTSTATUS Status,SmbResponseStatus;
  670. GENERIC_ANDX CommandToProcess;
  671. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("ParseSmbHeader BytesIndicated %ld\n",BytesIndicated));
  672. Status = SmbCeParseSmbHeader(
  673. (PSMB_EXCHANGE)pNetRootExchange,
  674. pSmbHeader,
  675. &CommandToProcess,
  676. &SmbResponseStatus,
  677. BytesAvailable,
  678. BytesIndicated,
  679. pBytesTaken);
  680. if (Status == STATUS_SUCCESS) {
  681. *pBytesTaken = BytesIndicated;
  682. }
  683. return Status;
  684. }
  685. NTSTATUS
  686. SmbConstructNetRootExchangeFinalize(
  687. PSMB_EXCHANGE pExchange,
  688. BOOLEAN *pPostFinalize)
  689. /*++
  690. Routine Description:
  691. This routine finalizes the construct net root exchange. It resumes the RDBSS by invoking
  692. the call back and discards the exchange
  693. Arguments:
  694. pExchange - the exchange instance
  695. CurrentIrql - the current interrupt request level
  696. pPostFinalize - a pointer to a BOOLEAN if the request should be posted
  697. Return Value:
  698. RXSTATUS - The return status for the operation
  699. --*/
  700. {
  701. PSMB_CONSTRUCT_NETROOT_EXCHANGE pNetRootExchange;
  702. PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext;
  703. PMRX_NETROOT_CALLBACK pNetRootCallback;
  704. PMRX_V_NET_ROOT pVNetRoot;
  705. PMRX_NET_ROOT pNetRoot;
  706. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  707. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  708. NTSTATUS Status = pExchange->Status;
  709. if (RxShouldPostCompletion()) {
  710. *pPostFinalize = TRUE;
  711. return STATUS_SUCCESS;
  712. } else {
  713. *pPostFinalize = FALSE;
  714. }
  715. pVNetRoot = SmbCeGetExchangeVNetRoot(pExchange);
  716. pNetRoot = pVNetRoot->pNetRoot;
  717. pVNetRootContext = SmbCeGetAssociatedVNetRootContext(pVNetRoot);
  718. ASSERT((pVNetRoot == NULL) || (pVNetRoot->pNetRoot == pNetRoot));
  719. pNetRootExchange = (PSMB_CONSTRUCT_NETROOT_EXCHANGE)pExchange;
  720. pNetRootCallback = pNetRootExchange->NetRootCallback;
  721. ASSERT(pNetRootExchange->Type == CONSTRUCT_NETROOT_EXCHANGE);
  722. pCreateNetRootContext = pNetRootExchange->pCreateNetRootContext;
  723. pCreateNetRootContext->VirtualNetRootStatus = STATUS_SUCCESS;
  724. pCreateNetRootContext->NetRootStatus = STATUS_SUCCESS;
  725. RxDbgTrace(0,Dbg,("SmbConstructNetRootExchangeFinalize: Net Root Exchange Status %lx\n", pExchange->Status));
  726. if (!NT_SUCCESS(pExchange->Status)) {
  727. if (pCreateNetRootContext->RxContext &&
  728. pCreateNetRootContext->RxContext->Create.ThisIsATreeConnectOpen){
  729. InterlockedIncrement(&MRxSmbStatistics.FailedUseCount);
  730. }
  731. pCreateNetRootContext->VirtualNetRootStatus = Status;
  732. if (pCreateNetRootContext->VirtualNetRootStatus == STATUS_INVALID_HANDLE) {
  733. pCreateNetRootContext->VirtualNetRootStatus = STATUS_UNEXPECTED_NETWORK_ERROR;
  734. }
  735. if (pNetRootExchange->fInitializeNetRoot) {
  736. pCreateNetRootContext->NetRootStatus = Status;
  737. if (pCreateNetRootContext->NetRootStatus == STATUS_INVALID_HANDLE) {
  738. pCreateNetRootContext->NetRootStatus = STATUS_UNEXPECTED_NETWORK_ERROR;
  739. }
  740. }
  741. SmbCeUpdateVNetRootContextState(
  742. pVNetRootContext,
  743. SMBCEDB_MARKED_FOR_DELETION);
  744. } else {
  745. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  746. pNetRootEntry = SmbCeGetExchangeNetRootEntry(pExchange);
  747. // Update the associated wrapper data structures.
  748. SmbCeUpdateNetRoot(pNetRootEntry,pNetRoot);
  749. }
  750. SmbCeReferenceVNetRootContext(pVNetRootContext);
  751. SmbCeCompleteVNetRootContextInitialization(pVNetRootContext);
  752. pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_NETROOT_CONSTRUCTOR;
  753. ASSERT((pCreateNetRootContext->VirtualNetRootStatus != STATUS_SUCCESS) || (pVNetRoot->Context != NULL));
  754. if ((pCreateNetRootContext->NetRootStatus == STATUS_CONNECTION_RESET)||(pCreateNetRootContext->NetRootStatus == STATUS_IO_TIMEOUT))
  755. {
  756. SmbCeLog(("!!Remote Reset Status=%x\n", pCreateNetRootContext->NetRootStatus));
  757. }
  758. if (pNetRootExchange->pSmbResponseMdl != NULL) {
  759. MmUnlockPages(pNetRootExchange->pSmbResponseMdl);
  760. IoFreeMdl(pNetRootExchange->pSmbResponseMdl);
  761. }
  762. if (pNetRootExchange->pSmbRequestMdl != NULL) {
  763. RxUnlockHeaderPages(pNetRootExchange->pSmbRequestMdl);
  764. IoFreeMdl(pNetRootExchange->pSmbRequestMdl);
  765. }
  766. if (pNetRootExchange->pSmbActualBuffer != NULL) {
  767. RxFreePool(pNetRootExchange->pSmbActualBuffer);
  768. }
  769. // Tear down the exchange instance ...
  770. SmbCeDiscardExchange(pExchange);
  771. // Callback the RDBSS for resumption
  772. pNetRootCallback(pCreateNetRootContext);
  773. return STATUS_SUCCESS;
  774. }
  775. SMB_EXCHANGE_DISPATCH_VECTOR
  776. ConstructNetRootExchangeDispatch = {
  777. SmbConstructNetRootExchangeStart,
  778. SmbConstructNetRootExchangeReceive,
  779. SmbConstructNetRootExchangeCopyDataHandler,
  780. NULL, // No SendCompletionHandler
  781. SmbConstructNetRootExchangeFinalize,
  782. NULL
  783. };
  784. VOID
  785. MRxSmbExtractNetRootName(
  786. IN PUNICODE_STRING FilePathName,
  787. IN PMRX_SRV_CALL SrvCall,
  788. OUT PUNICODE_STRING NetRootName,
  789. OUT PUNICODE_STRING RestOfName OPTIONAL
  790. )
  791. /*++
  792. Routine Description:
  793. This routine parses the input name into srv, netroot, and the
  794. rest.
  795. Arguments:
  796. --*/
  797. {
  798. UNICODE_STRING xRestOfName;
  799. ULONG length = FilePathName->Length;
  800. PWCH w = FilePathName->Buffer;
  801. PWCH wlimit = (PWCH)(((PCHAR)w)+length);
  802. PWCH wlow;
  803. PAGED_CODE();
  804. w += (SrvCall->pSrvCallName->Length/sizeof(WCHAR));
  805. NetRootName->Buffer = wlow = w;
  806. for (;;) {
  807. if (w>=wlimit) break;
  808. if ( (*w == OBJ_NAME_PATH_SEPARATOR) && (w!=wlow) ){
  809. break;
  810. }
  811. w++;
  812. }
  813. NetRootName->Length = NetRootName->MaximumLength
  814. = (USHORT)((PCHAR)w - (PCHAR)wlow);
  815. if (!RestOfName) RestOfName = &xRestOfName;
  816. RestOfName->Buffer = w;
  817. RestOfName->Length = RestOfName->MaximumLength
  818. = (USHORT)((PCHAR)wlimit - (PCHAR)w);
  819. RxDbgTrace( 0,Dbg,(" MRxSmbExtractNetRootName FilePath=%wZ\n",FilePathName));
  820. RxDbgTrace(0,Dbg,(" Srv=%wZ,Root=%wZ,Rest=%wZ\n",
  821. SrvCall->pSrvCallName,NetRootName,RestOfName));
  822. return;
  823. }