Source code of Windows XP (NT5)
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.

4425 lines
133 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. smbtrans.c
  5. Abstract:
  6. This module contains routines for processing the following SMBs:
  7. Transaction
  8. Transaction2
  9. Author:
  10. Chuck Lenzmeier (chuckl) 19-Feb-1990
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "smbtrans.tmh"
  15. #include <align.h> // ROUND_UP_POINTER
  16. #pragma hdrstop
  17. #define BugCheckFileId SRV_FILE_SMBTRANS
  18. //
  19. // Forward declarations
  20. //
  21. SMB_STATUS SRVFASTCALL
  22. ExecuteTransaction (
  23. IN OUT PWORK_CONTEXT WorkContext
  24. );
  25. VOID SRVFASTCALL
  26. RestartTransactionResponse (
  27. IN PWORK_CONTEXT WorkContext
  28. );
  29. VOID SRVFASTCALL
  30. RestartIpxMultipieceSend (
  31. IN OUT PWORK_CONTEXT WorkContext
  32. );
  33. VOID SRVFASTCALL
  34. RestartIpxTransactionResponse (
  35. IN OUT PWORK_CONTEXT WorkContext
  36. );
  37. SMB_TRANS_STATUS
  38. MailslotTransaction (
  39. PWORK_CONTEXT WorkContext
  40. );
  41. VOID SRVFASTCALL
  42. RestartMailslotWrite (
  43. IN OUT PWORK_CONTEXT WorkContext
  44. );
  45. #ifdef ALLOC_PRAGMA
  46. #pragma alloc_text( PAGE, ExecuteTransaction )
  47. #pragma alloc_text( PAGE, SrvCompleteExecuteTransaction )
  48. #pragma alloc_text( PAGE, SrvFindTransaction )
  49. #pragma alloc_text( PAGE, SrvInsertTransaction )
  50. #pragma alloc_text( PAGE, RestartTransactionResponse )
  51. #pragma alloc_text( PAGE, SrvSmbTransaction )
  52. #pragma alloc_text( PAGE, SrvSmbTransactionSecondary )
  53. #pragma alloc_text( PAGE, SrvSmbNtTransaction )
  54. #pragma alloc_text( PAGE, SrvSmbNtTransactionSecondary )
  55. #pragma alloc_text( PAGE, MailslotTransaction )
  56. #pragma alloc_text( PAGE, RestartMailslotWrite )
  57. #pragma alloc_text( PAGE, SrvRestartExecuteTransaction )
  58. #pragma alloc_text( PAGE, RestartIpxMultipieceSend )
  59. #pragma alloc_text( PAGE, RestartIpxTransactionResponse )
  60. #endif
  61. SMB_STATUS SRVFASTCALL
  62. ExecuteTransaction (
  63. IN OUT PWORK_CONTEXT WorkContext
  64. )
  65. /*++
  66. Routine Description:
  67. Executes a transaction and starts the process of sending the
  68. zero or more responses.
  69. Arguments:
  70. WorkContext - Supplies a pointer to a work context block. The block
  71. contains information about the last SMB received for the
  72. transaction.
  73. WorkContext->Parameters.Transaction supplies a referenced
  74. pointer to a transaction block. All block pointer fields in the
  75. block are valid. Pointers to the setup words and parameter and
  76. data bytes, and the lengths of these items, are valid. The
  77. transaction block is on the connection's pending transaction
  78. list.
  79. Return Value:
  80. SMB_STATUS - Indicates the status of SMB processing.
  81. --*/
  82. {
  83. PTRANSACTION transaction;
  84. PSMB_HEADER header;
  85. PRESP_TRANSACTION response;
  86. PRESP_NT_TRANSACTION ntResponse;
  87. SMB_TRANS_STATUS resultStatus;
  88. CLONG offset;
  89. USHORT command;
  90. PAGED_CODE( );
  91. resultStatus = SmbTransStatusErrorWithoutData;
  92. transaction = WorkContext->Parameters.Transaction;
  93. if ( (WorkContext->NextCommand == SMB_COM_TRANSACTION ||
  94. WorkContext->NextCommand == SMB_COM_TRANSACTION_SECONDARY ) &&
  95. transaction->RemoteApiRequest &&
  96. WorkContext->UsingBlockingThread == 0 ) {
  97. //
  98. // This is a downlevel API request, we must make sure we are on
  99. // a blocking thread before handling it, since it will LPC to the
  100. // srvsvc which might take some time to complete.
  101. //
  102. WorkContext->FspRestartRoutine = ExecuteTransaction;
  103. SrvQueueWorkToBlockingThread( WorkContext );
  104. return SmbStatusInProgress;
  105. }
  106. header = WorkContext->ResponseHeader;
  107. response = (PRESP_TRANSACTION)WorkContext->ResponseParameters;
  108. ntResponse = (PRESP_NT_TRANSACTION)WorkContext->ResponseParameters;
  109. //
  110. // Setup output pointers
  111. //
  112. if ( WorkContext->NextCommand == SMB_COM_NT_TRANSACT ||
  113. WorkContext->NextCommand == SMB_COM_NT_TRANSACT_SECONDARY ) {
  114. transaction->OutSetup = (PSMB_USHORT)ntResponse->Buffer;
  115. } else {
  116. transaction->OutSetup = (PSMB_USHORT)response->Buffer;
  117. }
  118. if ( transaction->OutParameters == NULL ) {
  119. //
  120. // Parameters will go into the SMB buffer. Calculate the pointer
  121. // then round it up to the next DWORD address.
  122. //
  123. transaction->OutParameters = (PCHAR)(transaction->OutSetup +
  124. transaction->MaxSetupCount);
  125. offset = (PTR_DIFF(transaction->OutParameters, header) + 3) & ~3;
  126. transaction->OutParameters = (PCHAR)header + offset;
  127. }
  128. if ( transaction->OutData == NULL ) {
  129. //
  130. // Data will go into the SMB buffer. Calculate the pointer
  131. // then round it up to the next DWORD address.
  132. //
  133. transaction->OutData = transaction->OutParameters +
  134. transaction->MaxParameterCount;
  135. offset = (PTR_DIFF(transaction->OutData, header) + 3) & ~3;
  136. transaction->OutData = (PCHAR)header + offset;
  137. }
  138. //
  139. // If this is a Transaction2 request, then we can simply index into
  140. // a table to find the right transaction processor. If it's a
  141. // Transaction request, we have to do more complicated things to
  142. // determine what to do.
  143. //
  144. if ( (WorkContext->NextCommand == SMB_COM_TRANSACTION) ||
  145. (WorkContext->NextCommand == SMB_COM_TRANSACTION_SECONDARY) ) {
  146. //
  147. // Dispatching for Transaction SMBs
  148. //
  149. if ( transaction->RemoteApiRequest ) {
  150. //
  151. // This is a down-level remote API request. Send it to
  152. // XACTSRV for processing.
  153. //
  154. ASSERT( transaction->PipeRequest );
  155. resultStatus = SrvXsRequest( WorkContext );
  156. } else if ( transaction->PipeRequest ) {
  157. //
  158. // Normal pipe function. Handle it.
  159. //
  160. command = SmbGetUshort(&transaction->InSetup[0]);
  161. //
  162. // If this operation may block, and we are running short of
  163. // free work items, fail this SMB with an out of resources error.
  164. //
  165. if ( !WorkContext->BlockingOperation &&
  166. (command == TRANS_CALL_NMPIPE ||
  167. command == TRANS_TRANSACT_NMPIPE ||
  168. command == TRANS_WAIT_NMPIPE ||
  169. command == TRANS_RAW_WRITE_NMPIPE) ) {
  170. if ( SrvReceiveBufferShortage( ) ) {
  171. SrvStatistics.BlockingSmbsRejected++;
  172. SrvSetSmbError(
  173. WorkContext,
  174. STATUS_INSUFF_SERVER_RESOURCES
  175. );
  176. resultStatus = SmbTransStatusErrorWithoutData;
  177. goto exit;
  178. } else {
  179. //
  180. // SrvBlockingOpsInProgress has already been incremented.
  181. // Flag this work item as a blocking operation.
  182. //
  183. WorkContext->BlockingOperation = TRUE;
  184. }
  185. }
  186. switch( command ) {
  187. case TRANS_TRANSACT_NMPIPE:
  188. resultStatus = SrvTransactNamedPipe( WorkContext );
  189. break;
  190. case TRANS_PEEK_NMPIPE:
  191. resultStatus = SrvPeekNamedPipe( WorkContext );
  192. break;
  193. case TRANS_CALL_NMPIPE:
  194. resultStatus = SrvCallNamedPipe( WorkContext );
  195. break;
  196. case TRANS_WAIT_NMPIPE:
  197. resultStatus = SrvWaitNamedPipe( WorkContext );
  198. break;
  199. case TRANS_QUERY_NMPIPE_STATE:
  200. resultStatus = SrvQueryStateNamedPipe( WorkContext );
  201. break;
  202. case TRANS_SET_NMPIPE_STATE:
  203. resultStatus = SrvSetStateNamedPipe( WorkContext );
  204. break;
  205. case TRANS_QUERY_NMPIPE_INFO:
  206. resultStatus = SrvQueryInformationNamedPipe( WorkContext );
  207. break;
  208. case TRANS_RAW_WRITE_NMPIPE:
  209. resultStatus = SrvRawWriteNamedPipe( WorkContext );
  210. break;
  211. case TRANS_RAW_READ_NMPIPE: // Legal command, unsupported by server
  212. SrvSetSmbError( WorkContext, STATUS_INVALID_PARAMETER );
  213. resultStatus = SmbTransStatusErrorWithoutData;
  214. break;
  215. case TRANS_WRITE_NMPIPE:
  216. resultStatus = SrvWriteNamedPipe( WorkContext );
  217. break;
  218. case TRANS_READ_NMPIPE:
  219. resultStatus = SrvReadNamedPipe( WorkContext );
  220. break;
  221. default:
  222. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  223. resultStatus = SmbTransStatusErrorWithoutData;
  224. SrvLogInvalidSmb( WorkContext );
  225. }
  226. } else if ( _wcsnicmp(
  227. transaction->TransactionName.Buffer,
  228. StrSlashMailslot,
  229. UNICODE_SMB_MAILSLOT_PREFIX_LENGTH / sizeof(WCHAR)
  230. ) == 0 ) {
  231. //
  232. // This is a mailslot transaction
  233. //
  234. resultStatus = MailslotTransaction( WorkContext );
  235. } else {
  236. //
  237. // This is not a named pipe transaction or a mailslot
  238. // transaction. The server should never see these.
  239. //
  240. SrvSetSmbError( WorkContext, STATUS_NOT_IMPLEMENTED );
  241. resultStatus = SmbTransStatusErrorWithoutData;
  242. }
  243. } else if ( (WorkContext->NextCommand == SMB_COM_NT_TRANSACT) ||
  244. (WorkContext->NextCommand == SMB_COM_NT_TRANSACT_SECONDARY) ) {
  245. command = transaction->Function;
  246. if ( command >= NT_TRANSACT_MIN_FUNCTION &&
  247. command <= NT_TRANSACT_MAX_FUNCTION ) {
  248. //
  249. // Legal function code. Call the processing routine. The
  250. // transaction processor returns TRUE if it encountered an
  251. // error and updated the response header appropriately (by
  252. // calling SrvSetSmbError). In this case, no transaction-
  253. // specific response data will be sent.
  254. //
  255. resultStatus =
  256. SrvNtTransactionDispatchTable[ command ]( WorkContext );
  257. IF_SMB_DEBUG(TRANSACTION1) {
  258. if ( resultStatus != SmbTransStatusSuccess ) {
  259. SrvPrint0( "NT Transaction processor returned error\n" );
  260. }
  261. }
  262. } else {
  263. //
  264. // Either no setup words were sent, or the function code is
  265. // out-of-range. Return an error.
  266. //
  267. IF_DEBUG(SMB_ERRORS) {
  268. SrvPrint1( "Invalid NT Transaction function code 0x%lx\n",
  269. transaction->Function );
  270. }
  271. SrvLogInvalidSmb( WorkContext );
  272. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  273. resultStatus = SmbTransStatusErrorWithoutData;
  274. }
  275. } else if ( (WorkContext->NextCommand == SMB_COM_TRANSACTION2) ||
  276. (WorkContext->NextCommand == SMB_COM_TRANSACTION2_SECONDARY) ) {
  277. USHORT command;
  278. command = SmbGetUshort( &transaction->InSetup[0] );
  279. if ( (transaction->SetupCount >= 1) &&
  280. (command <= TRANS2_MAX_FUNCTION) ) {
  281. //
  282. // Legal function code. Call the processing routine. The
  283. // transaction processor returns TRUE if it encountered an
  284. // error and updated the response header appropriately (by
  285. // calling SrvSetSmbError). In this case, no transaction-
  286. // specific response data will be sent.
  287. //
  288. resultStatus =
  289. SrvTransaction2DispatchTable[ command ]( WorkContext );
  290. IF_SMB_DEBUG(TRANSACTION1) {
  291. if ( resultStatus != SmbTransStatusSuccess ) {
  292. SrvPrint0( "Transaction processor returned error\n" );
  293. }
  294. }
  295. } else {
  296. //
  297. // Either no setup words were sent, or the function code is
  298. // out-of-range. Return an error.
  299. //
  300. IF_DEBUG(SMB_ERRORS) {
  301. if ( transaction->SetupCount <= 0 ) {
  302. SrvPrint0( "No Transaction2 setup words\n" );
  303. } else {
  304. SrvPrint1( "Invalid Transaction2 function code 0x%lx\n",
  305. (ULONG)SmbGetUshort(
  306. &transaction->InSetup[0] ) );
  307. }
  308. }
  309. SrvLogInvalidSmb( WorkContext );
  310. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  311. resultStatus = SmbTransStatusErrorWithoutData;
  312. }
  313. } else {
  314. ASSERT( FALSE );
  315. }
  316. exit:
  317. //
  318. // If the transaction call completed synchronously, generate the
  319. // response and send it.
  320. //
  321. // If the call will be completed asynchronously, then the handler
  322. // for that call will call SrvCompleteExectuteTransaction().
  323. //
  324. if ( resultStatus != SmbTransStatusInProgress ) {
  325. SrvCompleteExecuteTransaction(WorkContext, resultStatus);
  326. }
  327. return SmbStatusInProgress;
  328. } // ExecuteTransaction
  329. VOID
  330. SrvCompleteExecuteTransaction (
  331. IN OUT PWORK_CONTEXT WorkContext,
  332. IN SMB_TRANS_STATUS ResultStatus
  333. )
  334. /*++
  335. Routine Description:
  336. This function completes the execution of a transaction and sends
  337. the response
  338. Arguments:
  339. WorkContext - A pointer to the associated work context block.
  340. ResultStatus - The return code from the
  341. --*/
  342. {
  343. PTRANSACTION transaction;
  344. UCHAR transactionCommand;
  345. PSMB_HEADER header;
  346. PRESP_TRANSACTION response;
  347. PRESP_NT_TRANSACTION ntResponse;
  348. CLONG maxSize;
  349. PSMB_USHORT byteCountPtr;
  350. PCHAR paramPtr;
  351. CLONG paramLength;
  352. CLONG paramOffset;
  353. PCHAR dataPtr;
  354. CLONG dataLength;
  355. CLONG dataOffset;
  356. CLONG sendLength;
  357. BOOLEAN ntTransaction = FALSE;
  358. PAGED_CODE( );
  359. transaction = WorkContext->Parameters.Transaction;
  360. header = WorkContext->ResponseHeader;
  361. transactionCommand = (UCHAR)SmbGetUshort( &transaction->InSetup[0] );
  362. if ( ResultStatus == SmbTransStatusErrorWithoutData ) {
  363. USHORT flags = transaction->Flags;
  364. //
  365. // An error occurred, so no transaction-specific response data
  366. // will be returned. Close the transaction and arrange for a
  367. // response message indicating the error to be returned.
  368. //
  369. IF_SMB_DEBUG(TRANSACTION1) {
  370. SrvPrint1( "Error response. Closing transaction 0x%p\n",
  371. transaction );
  372. }
  373. SrvCloseTransaction( transaction );
  374. SrvDereferenceTransaction( transaction );
  375. //
  376. // If the NO_RESPONSE bit was set in the request, don't send a
  377. // response; instead, just close the transaction. (If the
  378. // transaction arrived as part of an AndX chain, we need to send a
  379. // response anyway, to respond to the preceeding commands.)
  380. //
  381. if ( (flags & SMB_TRANSACTION_NO_RESPONSE) &&
  382. (header->Command == WorkContext->NextCommand) ) {
  383. if ( WorkContext->OplockOpen ) {
  384. SrvCheckDeferredOpenOplockBreak( WorkContext );
  385. }
  386. //
  387. // The Transaction request came by itself. No response.
  388. //
  389. SrvDereferenceWorkItem( WorkContext );
  390. return;
  391. }
  392. //
  393. // Calculate the length of the response message.
  394. //
  395. sendLength = (CLONG)( (PCHAR)WorkContext->ResponseParameters -
  396. (PCHAR)WorkContext->ResponseHeader );
  397. WorkContext->ResponseBuffer->DataLength = sendLength;
  398. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  399. //
  400. // Send the response.
  401. //
  402. SRV_START_SEND_2(
  403. WorkContext,
  404. SrvFsdRestartSmbAtSendCompletion,
  405. NULL,
  406. NULL
  407. );
  408. return;
  409. }
  410. //
  411. // The transaction has been executed, and transaction-specific
  412. // response data is to be returned. The processing routine updated
  413. // the output pointers and counts appropriately.
  414. //
  415. ASSERT( transaction->SetupCount <= transaction->MaxSetupCount);
  416. ASSERT( transaction->ParameterCount <= transaction->MaxParameterCount);
  417. ASSERT( transaction->DataCount <= transaction->MaxDataCount);
  418. //
  419. // If the NO_RESPONSE bit was set in the request, don't send a
  420. // response; instead, just close the transaction. (If the
  421. // transaction arrived as part of an AndX chain, we need to send a
  422. // response anyway, to respond to the preceeding commands.)
  423. //
  424. if ( (transaction->Flags & SMB_TRANSACTION_NO_RESPONSE) &&
  425. ResultStatus != SmbTransStatusErrorWithData ) {
  426. IF_SMB_DEBUG(TRANSACTION1) {
  427. SrvPrint1( "No response. Closing transaction 0x%p\n",
  428. transaction );
  429. }
  430. SrvCloseTransaction( transaction );
  431. SrvDereferenceTransaction( transaction );
  432. if ( header->Command == WorkContext->NextCommand ) {
  433. if ( WorkContext->OplockOpen ) {
  434. SrvCheckDeferredOpenOplockBreak( WorkContext );
  435. }
  436. SrvDereferenceWorkItem( WorkContext );
  437. //
  438. // The Transaction request came by itself. No response.
  439. //
  440. return;
  441. } else {
  442. //
  443. // The Transaction request was part of an AndX chain. Find
  444. // the preceding command in the chain and update it to
  445. // indicate that it is now the end of the chain.
  446. //
  447. PGENERIC_ANDX response;
  448. IF_SMB_DEBUG(TRANSACTION1) {
  449. SrvPrint0( "AndX chain. Sending response anyway\n" );
  450. }
  451. response = (PGENERIC_ANDX)(header + 1);
  452. while( response->AndXCommand != WorkContext->NextCommand ) {
  453. response = (PGENERIC_ANDX)((PCHAR)header +
  454. SmbGetUshort( &response->AndXOffset ) );
  455. }
  456. response->AndXCommand = SMB_COM_NO_ANDX_COMMAND;
  457. SmbPutUshort( &response->AndXOffset, 0 );
  458. //
  459. // Calculate the length of the response message.
  460. //
  461. sendLength = (CLONG)( (PCHAR)WorkContext->ResponseParameters -
  462. (PCHAR)WorkContext->ResponseHeader );
  463. WorkContext->ResponseBuffer->DataLength = sendLength;
  464. //
  465. // Send the response.
  466. //
  467. SRV_START_SEND_2(
  468. WorkContext,
  469. SrvFsdRestartSmbAtSendCompletion,
  470. NULL,
  471. NULL
  472. );
  473. return;
  474. }
  475. }
  476. //
  477. // The client wants a response. Build the first (and possibly only)
  478. // response. The last received SMB of the transaction request was
  479. // retained for this purpose.
  480. //
  481. response = (PRESP_TRANSACTION)WorkContext->ResponseParameters;
  482. ntResponse = (PRESP_NT_TRANSACTION)WorkContext->ResponseParameters;
  483. //
  484. // If the transaction arrived in multiple pieces, then we have to
  485. // put the correct command code in the response header. (Note that
  486. // a multi-part transaction request cannot be sent as part of an
  487. // AndX chain, so we know it's safe to write into the header.)
  488. //
  489. if ( (WorkContext->NextCommand == SMB_COM_TRANSACTION) ||
  490. (WorkContext->NextCommand == SMB_COM_TRANSACTION2) ) {
  491. ;
  492. } else if ( WorkContext->NextCommand == SMB_COM_NT_TRANSACT ) {
  493. ntTransaction = TRUE;
  494. } else if ( WorkContext->NextCommand == SMB_COM_TRANSACTION_SECONDARY ) {
  495. header->Command = SMB_COM_TRANSACTION;
  496. } else if ( WorkContext->NextCommand == SMB_COM_TRANSACTION2_SECONDARY ) {
  497. header->Command = SMB_COM_TRANSACTION2;
  498. } else if ( WorkContext->NextCommand == SMB_COM_NT_TRANSACT_SECONDARY ) {
  499. header->Command = SMB_COM_NT_TRANSACT;
  500. ntTransaction = TRUE;
  501. }
  502. //
  503. // Is this an NT transaction? If so format an nt transaction
  504. // response. The response formats for transact and transact2
  505. // are essentially identical.
  506. //
  507. // Build the parameters portion of the response.
  508. //
  509. if ( ntTransaction ) {
  510. ntResponse->WordCount = (UCHAR)(18 + transaction->SetupCount);
  511. ntResponse->Reserved1 = 0;
  512. SmbPutUshort( &ntResponse->Reserved2, 0 );
  513. SmbPutUlong( &ntResponse->TotalParameterCount,
  514. transaction->ParameterCount
  515. );
  516. SmbPutUlong( &ntResponse->TotalDataCount,
  517. transaction->DataCount
  518. );
  519. ntResponse->SetupCount = (UCHAR)transaction->SetupCount;
  520. } else {
  521. response->WordCount = (UCHAR)(10 + transaction->SetupCount);
  522. SmbPutUshort( &response->TotalParameterCount,
  523. (USHORT)transaction->ParameterCount
  524. );
  525. SmbPutUshort( &response->TotalDataCount,
  526. (USHORT)transaction->DataCount
  527. );
  528. SmbPutUshort( &response->Reserved, 0 );
  529. response->SetupCount = (UCHAR)transaction->SetupCount;
  530. response->Reserved2 = 0;
  531. }
  532. //
  533. // Save a pointer to the byte count field.
  534. //
  535. // If the output data and parameters are not already in the SMB
  536. // buffer we must calculate how much of the parameters and data can
  537. // be sent in this response. The maximum amount we can send is
  538. // minimum of the size of our buffer and the size of the client's
  539. // buffer.
  540. //
  541. // The parameter and data byte blocks are aligned on longword
  542. // boundaries in the message.
  543. //
  544. byteCountPtr = transaction->OutSetup + transaction->SetupCount;
  545. //
  546. // Either we have a session, in which case the client's buffer sizes
  547. // are contained therein, or someone put the size in the transaction.
  548. // There is one known instance of the latter: Kerberos authentication
  549. // that requires an extra negotiation leg.
  550. //
  551. maxSize = MIN(
  552. WorkContext->ResponseBuffer->BufferLength,
  553. transaction->Session ?
  554. (CLONG)transaction->Session->MaxBufferSize :
  555. transaction->cMaxBufferSize
  556. );
  557. if ( transaction->OutputBufferCopied ) {
  558. //
  559. // The response data was not written directly in the SMB
  560. // response buffer. It must now be copied out of the transaction
  561. // block into the SMB.
  562. //
  563. paramPtr = (PCHAR)(byteCountPtr + 1); // first legal location
  564. paramOffset = PTR_DIFF(paramPtr, header);// offset from start of header
  565. paramOffset = (paramOffset + 3) & ~3; // round to next longword
  566. paramPtr = (PCHAR)header + paramOffset; // actual location
  567. paramLength = transaction->ParameterCount; // assume all parameters fit
  568. if ( (paramOffset + paramLength) > maxSize ) {
  569. //
  570. // Not all of the parameter bytes will fit. Send the maximum
  571. // number of longwords that will fit. Don't send any data bytes
  572. // in the first message.
  573. //
  574. paramLength = maxSize - paramOffset; // max that will fit
  575. paramLength = paramLength & ~3; // round down to longword
  576. dataLength = 0; // don't send data bytes
  577. dataOffset = 0;
  578. dataPtr = paramPtr + paramLength; // make calculations work
  579. } else {
  580. //
  581. // All of the parameter bytes fit. Calculate how many of the
  582. // data bytes fit.
  583. //
  584. dataPtr = paramPtr + paramLength; // first legal location
  585. dataOffset = PTR_DIFF(dataPtr, header); // offset from start of header
  586. dataOffset = (dataOffset + 3) & ~3; // round to next longword
  587. dataPtr = (PCHAR)header + dataOffset; // actual location
  588. dataLength = transaction->DataCount; // assume all data bytes fit
  589. if ( (dataOffset + dataLength) > maxSize ) {
  590. //
  591. // Not all of the data bytes will fit. Send the maximum
  592. // number of longwords that will fit.
  593. //
  594. dataLength = maxSize - dataOffset; // max that will fit
  595. dataLength = dataLength & ~3; // round down to longword
  596. }
  597. }
  598. //
  599. // Copy the appropriate parameter and data bytes into the message.
  600. //
  601. // !!! Note that it would be possible to use the chain send
  602. // capabilities of TDI to send the parameter and data bytes from
  603. // their own buffers. There is extra overhead involved in doing
  604. // this, however, because the buffers must be locked down and
  605. // mapped into system space so that the network drivers can look
  606. // at them.
  607. //
  608. if ( paramLength != 0 ) {
  609. RtlMoveMemory( paramPtr, transaction->OutParameters, paramLength );
  610. }
  611. if ( dataLength != 0 ) {
  612. RtlMoveMemory( dataPtr, transaction->OutData, dataLength );
  613. }
  614. } else {
  615. //
  616. // The data and paramter are already in the SMB buffer. The entire
  617. // response will fit in one response buffer and there is no copying
  618. // to do.
  619. //
  620. paramPtr = transaction->OutParameters;
  621. paramOffset = PTR_DIFF(paramPtr, header);
  622. paramLength = transaction->ParameterCount;
  623. dataPtr = transaction->OutData;
  624. dataOffset = PTR_DIFF(dataPtr, header);
  625. dataLength = transaction->DataCount;
  626. }
  627. //
  628. // Finish filling in the response parameters.
  629. //
  630. if ( ntTransaction ) {
  631. SmbPutUlong( &ntResponse->ParameterCount, paramLength );
  632. SmbPutUlong( &ntResponse->ParameterOffset, paramOffset );
  633. SmbPutUlong( &ntResponse->ParameterDisplacement, 0 );
  634. SmbPutUlong( &ntResponse->DataCount, dataLength );
  635. SmbPutUlong( &ntResponse->DataOffset, dataOffset );
  636. SmbPutUlong( &ntResponse->DataDisplacement, 0 );
  637. } else {
  638. SmbPutUshort( &response->ParameterCount, (USHORT)paramLength );
  639. SmbPutUshort( &response->ParameterOffset, (USHORT)paramOffset );
  640. SmbPutUshort( &response->ParameterDisplacement, 0 );
  641. SmbPutUshort( &response->DataCount, (USHORT)dataLength );
  642. SmbPutUshort( &response->DataOffset, (USHORT)dataOffset );
  643. SmbPutUshort( &response->DataDisplacement, 0 );
  644. }
  645. transaction->ParameterDisplacement = paramLength;
  646. transaction->DataDisplacement = dataLength;
  647. SmbPutUshort(
  648. byteCountPtr,
  649. (USHORT)(dataPtr - (PCHAR)(byteCountPtr + 1) + dataLength)
  650. );
  651. //
  652. // Calculate the length of the response message.
  653. //
  654. sendLength = (CLONG)( dataPtr + dataLength -
  655. (PCHAR)WorkContext->ResponseHeader );
  656. WorkContext->ResponseBuffer->DataLength = sendLength;
  657. //
  658. // Set the bit in the SMB that indicates this is a response from the
  659. // server.
  660. //
  661. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  662. //
  663. // If this isn't the last part of the response, inhibit statistics
  664. // gathering. If it is the last part of the response, restore the
  665. // start time to the work context block.
  666. //
  667. // If this isn't the last part of the response, tell TDI that we
  668. // do not expect back traffic, so that the client will immediately
  669. // ACK this packet, rather than waiting.
  670. //
  671. if ( (paramLength != transaction->ParameterCount) ||
  672. (dataLength != transaction->DataCount) ) {
  673. ASSERT( transaction->Inserted );
  674. WorkContext->StartTime = 0;
  675. //
  676. // Save the address of the transaction block in the work context
  677. // block. Send out the response. When the send completes,
  678. // RestartTransactionResponse is called to either send the next
  679. // message or close the transaction.
  680. //
  681. //
  682. // Note that the transaction block remains referenced while the
  683. // response is being sent.
  684. //
  685. WorkContext->Parameters.Transaction = transaction;
  686. WorkContext->ResponseBuffer->Mdl->ByteCount = sendLength;
  687. if ( WorkContext->Endpoint->IsConnectionless ) {
  688. WorkContext->FspRestartRoutine = RestartIpxMultipieceSend;
  689. WorkContext->FsdRestartRoutine = NULL;
  690. transaction->MultipieceIpxSend = TRUE;
  691. SrvIpxStartSend( WorkContext, SrvQueueWorkToFspAtSendCompletion );
  692. } else {
  693. SRV_START_SEND(
  694. WorkContext,
  695. WorkContext->ResponseBuffer->Mdl,
  696. TDI_SEND_NO_RESPONSE_EXPECTED,
  697. SrvQueueWorkToFspAtSendCompletion,
  698. NULL,
  699. RestartTransactionResponse
  700. );
  701. }
  702. } else {
  703. //
  704. // This is the final piece. Close the transaction.
  705. //
  706. WorkContext->StartTime = transaction->StartTime;
  707. SrvCloseTransaction( transaction );
  708. SrvDereferenceTransaction( transaction );
  709. //
  710. // Send the response.
  711. //
  712. SRV_START_SEND_2(
  713. WorkContext,
  714. SrvFsdRestartSmbAtSendCompletion,
  715. NULL,
  716. NULL
  717. );
  718. }
  719. //
  720. // The response send is in progress. The caller will assume
  721. // the we will handle send completion.
  722. //
  723. return;
  724. } // SrvCompleteExecuteTransaction
  725. PTRANSACTION
  726. SrvFindTransaction (
  727. IN PCONNECTION Connection,
  728. IN PSMB_HEADER Header,
  729. IN USHORT Fid OPTIONAL
  730. )
  731. /*++
  732. Routine Description:
  733. Searches the list of pending transactions for a connection, looking
  734. for one whose identity matches that of a received secondary
  735. Transaction(2) request. If one is found, it is referenced.
  736. Arguments:
  737. Connection - Supplies a pointer to the connection block for the
  738. connection on which the secondary request was received.
  739. Header - Supplies a pointer to the header of the received
  740. Transaction(2) Secondary SMB.
  741. Fid - The file handle for this operation. The parameter is required
  742. if operation is progress is a WriteAndX SMB.
  743. Return Value:
  744. PTRANSACTION - Returns a pointer to the matching transaction block,
  745. if one is found, else NULL.
  746. --*/
  747. {
  748. PLIST_ENTRY listEntry;
  749. PTRANSACTION thisTransaction;
  750. USHORT targetOtherInfo;
  751. PAGED_CODE( );
  752. //
  753. // If this is a multipiece transaction SMB, the MIDs of all the pieces
  754. // must match. If it is a multipiece WriteAndX protocol the pieces
  755. // using the FID.
  756. //
  757. if (Header->Command == SMB_COM_WRITE_ANDX) {
  758. targetOtherInfo = Fid;
  759. } else {
  760. targetOtherInfo = SmbGetAlignedUshort( &Header->Mid );
  761. }
  762. //
  763. // Acquire the transaction lock. This prevents the connection's
  764. // transaction list from changing while we walk it.
  765. //
  766. ACQUIRE_LOCK( &Connection->Lock );
  767. //
  768. // Walk the transaction list, looking for one with the same
  769. // identity as the new transaction.
  770. //
  771. for ( listEntry = Connection->PagedConnection->TransactionList.Flink;
  772. listEntry != &Connection->PagedConnection->TransactionList;
  773. listEntry = listEntry->Flink ) {
  774. thisTransaction = CONTAINING_RECORD(
  775. listEntry,
  776. TRANSACTION,
  777. ConnectionListEntry
  778. );
  779. if ( ( thisTransaction->Tid == SmbGetAlignedUshort( &Header->Tid ) ) &&
  780. ( thisTransaction->Pid == SmbGetAlignedUshort( &Header->Pid ) ) &&
  781. ( thisTransaction->Uid == SmbGetAlignedUshort( &Header->Uid ) ) &&
  782. ( thisTransaction->OtherInfo == targetOtherInfo ) ) {
  783. //
  784. // A transaction with the same identity has been found. If
  785. // it's still active, reference it and return its address.
  786. // Otherwise, return a NULL pointer to indicate that a valid
  787. // matching transaction was not found.
  788. //
  789. if ( GET_BLOCK_STATE(thisTransaction) == BlockStateActive ) {
  790. SrvReferenceTransaction( thisTransaction );
  791. RELEASE_LOCK( &Connection->Lock );
  792. return thisTransaction;
  793. } else {
  794. RELEASE_LOCK( &Connection->Lock );
  795. return NULL;
  796. }
  797. }
  798. } // for
  799. //
  800. // We made it all the way through the list without finding a
  801. // matching transaction. Return a NULL pointer.
  802. //
  803. RELEASE_LOCK( &Connection->Lock );
  804. return NULL;
  805. } // SrvFindTransaction
  806. BOOLEAN
  807. SrvInsertTransaction (
  808. IN PTRANSACTION Transaction
  809. )
  810. /*++
  811. Routine Description:
  812. Inserts a transaction block into the list of pending transactions
  813. for a connection. Prior to doing so, it ensures a transaction
  814. with the same identity (combination of TID, PID, UID, and MID)
  815. is not already in the list.
  816. Arguments:
  817. Transaction - Supplies a pointer to a transaction block. The
  818. Connection, Tid, Pid, Uid, and Mid fields must be valid.
  819. Return Value:
  820. BOOLEAN - Returns TRUE if the transaction block was inserted.
  821. Returns FALSE if the block was not inserted because a
  822. transaction with the same identity already exists in the list.
  823. --*/
  824. {
  825. PCONNECTION connection;
  826. PPAGED_CONNECTION pagedConnection;
  827. PLIST_ENTRY listEntry;
  828. PTRANSACTION thisTransaction;
  829. PAGED_CODE( );
  830. ASSERT( !Transaction->Inserted );
  831. //
  832. // Acquire the transaction lock. This prevents the connection's
  833. // transaction list from changing while we walk it.
  834. //
  835. connection = Transaction->Connection;
  836. pagedConnection = connection->PagedConnection;
  837. ACQUIRE_LOCK( &connection->Lock );
  838. //
  839. // Make sure the connection, session, and tree connect aren't
  840. // closing, so that we don't put the transaction on the list
  841. // after the list has been run down.
  842. //
  843. if ( (GET_BLOCK_STATE(connection) != BlockStateActive) ||
  844. ((Transaction->Session != NULL) &&
  845. (GET_BLOCK_STATE(Transaction->Session) != BlockStateActive)) ||
  846. ((Transaction->TreeConnect != NULL) &&
  847. (GET_BLOCK_STATE(Transaction->TreeConnect) != BlockStateActive)) ) {
  848. RELEASE_LOCK( &connection->Lock );
  849. return FALSE;
  850. }
  851. //
  852. // Walk the transaction list, looking for one with the same
  853. // identity as the new transaction.
  854. //
  855. for ( listEntry = pagedConnection->TransactionList.Flink;
  856. listEntry != &pagedConnection->TransactionList;
  857. listEntry = listEntry->Flink ) {
  858. thisTransaction = CONTAINING_RECORD(
  859. listEntry,
  860. TRANSACTION,
  861. ConnectionListEntry
  862. );
  863. if ( (thisTransaction->Tid == Transaction->Tid) &&
  864. (thisTransaction->Pid == Transaction->Pid) &&
  865. (thisTransaction->Uid == Transaction->Uid) &&
  866. (thisTransaction->OtherInfo == Transaction->OtherInfo) ) {
  867. //
  868. // A transaction with the same identity has been found.
  869. // Don't insert the new one in the list.
  870. //
  871. RELEASE_LOCK( &connection->Lock );
  872. return FALSE;
  873. }
  874. } // for
  875. //
  876. // We made it all the way through the list without finding a
  877. // matching transaction. Insert the new one at the tail of the
  878. // list.
  879. //
  880. SrvInsertTailList(
  881. &pagedConnection->TransactionList,
  882. &Transaction->ConnectionListEntry
  883. );
  884. Transaction->Inserted = TRUE;
  885. RELEASE_LOCK( &connection->Lock );
  886. return TRUE;
  887. } // SrvInsertTransaction
  888. VOID SRVFASTCALL
  889. RestartTransactionResponse (
  890. IN OUT PWORK_CONTEXT WorkContext
  891. )
  892. /*++
  893. Routine Description:
  894. Processes send completion for a Transaction response. If more
  895. responses are required, it builds and sends the next one. If all
  896. responses have been sent, it closes the transaction.
  897. Arguments:
  898. WorkContext - Supplies a pointer to a work context block. The
  899. block contains information about the last SMB received for
  900. the transaction.
  901. WorkContext->Parameters.Transaction supplies a referenced
  902. pointer to a transaction block. All block pointer fields in the
  903. block are valid. Pointers to the setup words and parameter and
  904. data bytes, and the lengths of these items, are valid. The
  905. transaction block is on the connection's pending transaction
  906. list.
  907. Return Value:
  908. None.
  909. --*/
  910. {
  911. PTRANSACTION transaction;
  912. PSMB_HEADER header;
  913. PRESP_TRANSACTION response;
  914. PRESP_NT_TRANSACTION ntResponse;
  915. PCONNECTION connection;
  916. CLONG maxSize;
  917. PSMB_USHORT byteCountPtr;
  918. PCHAR paramPtr;
  919. CLONG paramLength;
  920. CLONG paramOffset;
  921. CLONG paramDisp;
  922. PCHAR dataPtr;
  923. CLONG dataLength;
  924. CLONG dataOffset;
  925. CLONG dataDisp;
  926. CLONG sendLength;
  927. BOOLEAN ntTransaction;
  928. PAGED_CODE( );
  929. transaction = WorkContext->Parameters.Transaction;
  930. paramDisp = transaction->ParameterDisplacement;
  931. dataDisp = transaction->DataDisplacement;
  932. IF_DEBUG(WORKER1) SrvPrint0( " - RestartTransactionResponse\n" );
  933. //
  934. // Get the connection pointer. The connection pointer is a
  935. // referenced pointer.
  936. //
  937. connection = WorkContext->Connection;
  938. IF_DEBUG(TRACE2) {
  939. SrvPrint2( " connection 0x%p, endpoint 0x%p\n",
  940. connection, WorkContext->Endpoint );
  941. }
  942. //
  943. // If the I/O request failed or was canceled, or if the connection
  944. // is no longer active, clean up. (The connection is marked as
  945. // closing when it is disconnected or when the endpoint is closed.)
  946. //
  947. // !!! If I/O failure, should we drop the connection?
  948. //
  949. if ( WorkContext->Irp->Cancel ||
  950. !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ||
  951. (GET_BLOCK_STATE(connection) != BlockStateActive) ) {
  952. IF_DEBUG(TRACE2) {
  953. if ( WorkContext->Irp->Cancel ) {
  954. SrvPrint0( " I/O canceled\n" );
  955. } else if ( !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  956. SrvPrint1( " I/O failed: %X\n",
  957. WorkContext->Irp->IoStatus.Status );
  958. } else {
  959. SrvPrint0( " Connection no longer active\n" );
  960. }
  961. }
  962. //
  963. // Close the transaction. Indicate that SMB processing is
  964. // complete.
  965. //
  966. IF_DEBUG(ERRORS) {
  967. SrvPrint1( "I/O error. Closing transaction 0x%p\n", transaction );
  968. }
  969. SrvCloseTransaction( transaction );
  970. SrvDereferenceTransaction( transaction );
  971. if ( WorkContext->OplockOpen ) {
  972. SrvCheckDeferredOpenOplockBreak( WorkContext );
  973. }
  974. SrvEndSmbProcessing( WorkContext, SmbStatusNoResponse );
  975. IF_DEBUG(TRACE2) {
  976. SrvPrint0( "RestartTransactionResponse complete\n" );
  977. }
  978. return;
  979. }
  980. IF_SMB_DEBUG(TRANSACTION1) {
  981. SrvPrint2( "Continuing transaction response; block 0x%p, name %wZ\n",
  982. transaction, &transaction->TransactionName );
  983. SrvPrint3( "Connection 0x%p, session 0x%p, tree connect 0x%p\n",
  984. transaction->Connection, transaction->Session,
  985. transaction->TreeConnect );
  986. SrvPrint2( "Remaining: parameters %ld bytes, data %ld bytes\n",
  987. transaction->ParameterCount - paramDisp,
  988. transaction->DataCount - dataDisp );
  989. }
  990. //
  991. // Update the parameters portion of the response, reusing the last
  992. // SMB.
  993. //
  994. ASSERT( transaction->Inserted );
  995. header = WorkContext->ResponseHeader;
  996. response = (PRESP_TRANSACTION)WorkContext->ResponseParameters;
  997. ntResponse = (PRESP_NT_TRANSACTION)WorkContext->ResponseParameters;
  998. if ( WorkContext->NextCommand == SMB_COM_NT_TRANSACT ||
  999. WorkContext->NextCommand == SMB_COM_NT_TRANSACT_SECONDARY ) {
  1000. ntTransaction = TRUE;
  1001. ntResponse->WordCount = (UCHAR)18;
  1002. ntResponse->SetupCount = 0;
  1003. //
  1004. // Save a pointer to the byte count field. Calculate how much of
  1005. // the parameters and data can be sent in this response. The
  1006. // maximum amount we can send is minimum of the size of our buffer
  1007. // and the size of the client's buffer.
  1008. //
  1009. // The parameter and data byte blocks are aligned on longword
  1010. // boundaries in the message.
  1011. //
  1012. byteCountPtr = (PSMB_USHORT)ntResponse->Buffer;
  1013. } else {
  1014. ntTransaction = FALSE;
  1015. response->WordCount = (UCHAR)10;
  1016. response->SetupCount = 0;
  1017. //
  1018. // Save a pointer to the byte count field. Calculate how much of
  1019. // the parameters and data can be sent in this response. The
  1020. // maximum amount we can send is minimum of the size of our buffer
  1021. // and the size of the client's buffer.
  1022. //
  1023. // The parameter and data byte blocks are aligned on longword
  1024. // boundaries in the message.
  1025. //
  1026. byteCountPtr = (PSMB_USHORT)response->Buffer;
  1027. }
  1028. //
  1029. // Either we have a session, in which case the client's buffer sizes
  1030. // are contained therein, or someone put the size in the transaction.
  1031. // There is one known instance of the latter: Kerberos authentication
  1032. // that requires an extra negotiation leg.
  1033. //
  1034. maxSize = MIN(
  1035. WorkContext->ResponseBuffer->BufferLength,
  1036. transaction->Session ?
  1037. (CLONG)transaction->Session->MaxBufferSize :
  1038. transaction->cMaxBufferSize
  1039. );
  1040. paramPtr = (PCHAR)(byteCountPtr + 1); // first legal location
  1041. paramOffset = PTR_DIFF(paramPtr, header); // offset from start of header
  1042. paramOffset = (paramOffset + 3) & ~3; // round to next longword
  1043. paramPtr = (PCHAR)header + paramOffset; // actual location
  1044. paramLength = transaction->ParameterCount - paramDisp;
  1045. // assume all parameters fit
  1046. if ( (paramOffset + paramLength) > maxSize ) {
  1047. //
  1048. // Not all of the parameter bytes will fit. Send the maximum
  1049. // number of longwords that will fit. Don't send any data bytes
  1050. // in this message.
  1051. //
  1052. paramLength = maxSize - paramOffset; // max that will fit
  1053. paramLength = paramLength & ~3; // round down to longword
  1054. dataLength = 0; // don't send data bytes
  1055. dataOffset = 0;
  1056. dataPtr = paramPtr + paramLength; // make calculations work
  1057. } else {
  1058. //
  1059. // All of the parameter bytes fit. Calculate how many of data
  1060. // bytes fit.
  1061. //
  1062. dataPtr = paramPtr + paramLength; // first legal location
  1063. dataOffset = PTR_DIFF(dataPtr, header); // offset from start of header
  1064. dataOffset = (dataOffset + 3) & ~3; // round to next longword
  1065. dataPtr = (PCHAR)header + dataOffset; // actual location
  1066. dataLength = transaction->DataCount - dataDisp;
  1067. // assume all data bytes fit
  1068. if ( (dataOffset + dataLength) > maxSize ) {
  1069. //
  1070. // Not all of the data bytes will fit. Send the maximum
  1071. // number of longwords that will fit.
  1072. //
  1073. dataLength = maxSize - dataOffset; // max that will fit
  1074. dataLength = dataLength & ~3; // round down to longword
  1075. }
  1076. }
  1077. //
  1078. // Finish filling in the response parameters.
  1079. //
  1080. if ( ntTransaction) {
  1081. SmbPutUlong( &ntResponse->ParameterCount, paramLength );
  1082. SmbPutUlong( &ntResponse->ParameterOffset, paramOffset );
  1083. SmbPutUlong( &ntResponse->ParameterDisplacement, paramDisp );
  1084. SmbPutUlong( &ntResponse->DataCount, dataLength );
  1085. SmbPutUlong( &ntResponse->DataOffset, dataOffset );
  1086. SmbPutUlong( &ntResponse->DataDisplacement, dataDisp );
  1087. } else {
  1088. SmbPutUshort( &response->ParameterCount, (USHORT)paramLength );
  1089. SmbPutUshort( &response->ParameterOffset, (USHORT)paramOffset );
  1090. SmbPutUshort( &response->ParameterDisplacement, (USHORT)paramDisp );
  1091. SmbPutUshort( &response->DataCount, (USHORT)dataLength );
  1092. SmbPutUshort( &response->DataOffset, (USHORT)dataOffset );
  1093. SmbPutUshort( &response->DataDisplacement, (USHORT)dataDisp );
  1094. }
  1095. transaction->ParameterDisplacement = paramDisp + paramLength;
  1096. transaction->DataDisplacement = dataDisp + dataLength;
  1097. SmbPutUshort(
  1098. byteCountPtr,
  1099. (USHORT)(dataPtr - (PCHAR)(byteCountPtr + 1) + dataLength)
  1100. );
  1101. //
  1102. // Copy the appropriate parameter and data bytes into the message.
  1103. //
  1104. // !!! Note that it would be possible to use the chain send
  1105. // capabilities of TDI to send the parameter and data bytes from
  1106. // their own buffers. There is extra overhead involved in doing
  1107. // this, however, because the buffers must be locked down and
  1108. // mapped into system space so that the network drivers can look
  1109. // at them.
  1110. //
  1111. if ( paramLength != 0 ) {
  1112. RtlMoveMemory(
  1113. paramPtr,
  1114. transaction->OutParameters + paramDisp,
  1115. paramLength
  1116. );
  1117. }
  1118. if ( dataLength != 0 ) {
  1119. RtlMoveMemory(
  1120. dataPtr,
  1121. transaction->OutData + dataDisp,
  1122. dataLength
  1123. );
  1124. }
  1125. //
  1126. // Calculate the length of the response message.
  1127. //
  1128. sendLength = (CLONG)( dataPtr + dataLength -
  1129. (PCHAR)WorkContext->ResponseHeader );
  1130. WorkContext->ResponseBuffer->DataLength = sendLength;
  1131. //
  1132. // If this is the last part of the response, reenable statistics
  1133. // gathering and restore the start time to the work context block.
  1134. //
  1135. if ( ((paramLength + paramDisp) == transaction->ParameterCount) &&
  1136. ((dataLength + dataDisp) == transaction->DataCount) ) {
  1137. //
  1138. // This is the final piece. Close the transaction.
  1139. //
  1140. WorkContext->StartTime = transaction->StartTime;
  1141. SrvCloseTransaction( transaction );
  1142. SrvDereferenceTransaction( transaction );
  1143. //
  1144. // Send the response.
  1145. //
  1146. SRV_START_SEND_2(
  1147. WorkContext,
  1148. SrvFsdRestartSmbAtSendCompletion,
  1149. NULL,
  1150. NULL
  1151. );
  1152. } else {
  1153. // If this isn't the last part of the response, tell TDI that we
  1154. // do not expect back traffic, so that the client will immediately
  1155. // ACK this packet, rather than waiting.
  1156. WorkContext->ResponseBuffer->Mdl->ByteCount = sendLength;
  1157. //
  1158. // Send out the response. When the send completes,
  1159. // RestartTransactionResponse is called to either send the next
  1160. // message or close the transaction.
  1161. //
  1162. // Note that the response bit in the SMB header is already set.
  1163. //
  1164. SRV_START_SEND(
  1165. WorkContext,
  1166. WorkContext->ResponseBuffer->Mdl,
  1167. TDI_SEND_NO_RESPONSE_EXPECTED,
  1168. SrvQueueWorkToFspAtSendCompletion,
  1169. NULL,
  1170. RestartTransactionResponse
  1171. );
  1172. }
  1173. //
  1174. // The response send is in progress.
  1175. //
  1176. IF_DEBUG(TRACE2) SrvPrint0( "RestartTransactionResponse complete\n" );
  1177. return;
  1178. } // RestartTransactionResponse
  1179. SMB_PROCESSOR_RETURN_TYPE
  1180. SrvSmbTransaction (
  1181. SMB_PROCESSOR_PARAMETERS
  1182. )
  1183. /*++
  1184. Routine Description:
  1185. Processes a primary Transaction or Transaction2 SMB.
  1186. Arguments:
  1187. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  1188. of the parameters to SMB processor routines.
  1189. Return Value:
  1190. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  1191. --*/
  1192. {
  1193. NTSTATUS status = STATUS_SUCCESS;
  1194. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1195. PREQ_TRANSACTION request;
  1196. PSMB_HEADER header;
  1197. PCONNECTION connection;
  1198. PSESSION session;
  1199. PTREE_CONNECT treeConnect;
  1200. PTRANSACTION transaction;
  1201. PCHAR trailingBytes;
  1202. PCHAR startOfTrailingBytes;
  1203. PVOID name;
  1204. PVOID endOfSmb;
  1205. CLONG setupOffset;
  1206. CLONG setupCount;
  1207. CLONG maxSetupCount;
  1208. CLONG totalSetupCount;
  1209. CLONG parameterOffset;
  1210. CLONG parameterCount; // For input on this buffer
  1211. CLONG maxParameterCount; // For output
  1212. CLONG totalParameterCount; // For input
  1213. CLONG dataOffset;
  1214. CLONG dataCount; // For input on this buffer
  1215. CLONG maxDataCount; // For output
  1216. CLONG totalDataCount; // For input
  1217. CLONG smbLength;
  1218. CLONG outputBufferSize = (CLONG)-1;
  1219. CLONG inputBufferSize = (CLONG)-1;
  1220. CLONG requiredBufferSize;
  1221. USHORT command;
  1222. BOOLEAN pipeRequest;
  1223. BOOLEAN remoteApiRequest;
  1224. BOOLEAN buffersOverlap = FALSE;
  1225. BOOLEAN noResponse;
  1226. BOOLEAN singleBufferTransaction;
  1227. BOOLEAN isUnicode;
  1228. PAGED_CODE( );
  1229. request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
  1230. header = WorkContext->RequestHeader;
  1231. IF_SMB_DEBUG(TRANSACTION1) {
  1232. SrvPrint1( "Transaction%s (primary) request\n",
  1233. (WorkContext->NextCommand == SMB_COM_TRANSACTION)
  1234. ? "" : "2" );
  1235. }
  1236. //
  1237. // Make sure that the WordCount is correct to avoid any problems
  1238. // with overrunning the SMB buffer. SrvProcessSmb was unable to
  1239. // verify WordCount because it is variable, but it did verify that
  1240. // the supplied WordCount/ByteCount combination was valid.
  1241. // Verifying WordCount here ensure that what SrvProcessSmb thought
  1242. // was ByteCount really was, and that it's valid. The test here
  1243. // also implicit verifies SetupCount and that all of the setup words
  1244. // are "in range".
  1245. //
  1246. if ( (ULONG)request->WordCount != (ULONG)(14 + request->SetupCount) ) {
  1247. IF_DEBUG(SMB_ERRORS) {
  1248. SrvPrint3( "SrvSmbTransaction: Invalid WordCount: %ld, should be "
  1249. "SetupCount+14 = %ld+14 = %ld\n",
  1250. request->WordCount, request->SetupCount,
  1251. 14 + request->SetupCount );
  1252. }
  1253. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1254. status = STATUS_INVALID_SMB;
  1255. SmbStatus = SmbStatusSendResponse;
  1256. goto Cleanup;
  1257. }
  1258. //
  1259. // Even though we know that WordCount and ByteCount are valid, it's
  1260. // still possible that the offsets and lengths of the Parameter and
  1261. // Data bytes are invalid. So we check them now.
  1262. //
  1263. setupOffset = PTR_DIFF(request->Buffer, header);
  1264. setupCount = request->SetupCount * sizeof(USHORT);
  1265. maxSetupCount = request->MaxSetupCount * sizeof(USHORT);
  1266. totalSetupCount = setupCount;
  1267. parameterOffset = SmbGetUshort( &request->ParameterOffset );
  1268. parameterCount = SmbGetUshort( &request->ParameterCount );
  1269. maxParameterCount = SmbGetUshort( &request->MaxParameterCount );
  1270. totalParameterCount = SmbGetUshort( &request->TotalParameterCount );
  1271. dataOffset = SmbGetUshort( &request->DataOffset );
  1272. dataCount = SmbGetUshort( &request->DataCount );
  1273. maxDataCount = SmbGetUshort( &request->MaxDataCount );
  1274. totalDataCount = SmbGetUshort( &request->TotalDataCount );
  1275. smbLength = WorkContext->RequestBuffer->DataLength;
  1276. if ( ( (setupOffset + setupCount) > smbLength ) ||
  1277. ( (parameterOffset + parameterCount) > smbLength ) ||
  1278. ( (dataOffset + dataCount) > smbLength ) ||
  1279. ( dataCount > totalDataCount ) ||
  1280. ( parameterCount > totalParameterCount ) ) {
  1281. IF_DEBUG(SMB_ERRORS) {
  1282. SrvPrint4( "SrvSmbTransaction: Invalid setup, parameter or data "
  1283. "offset+count: sOff=%ld,sCnt=%ld;pOff=%ld,pCnt=%ld;",
  1284. setupOffset, setupCount,
  1285. parameterOffset, parameterCount );
  1286. SrvPrint2( "dOff=%ld,dCnt=%ld;", dataOffset, dataCount );
  1287. SrvPrint1( "smbLen=%ld", smbLength );
  1288. }
  1289. SrvLogInvalidSmb( WorkContext );
  1290. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1291. status = STATUS_INVALID_SMB;
  1292. SmbStatus = SmbStatusSendResponse;
  1293. goto Cleanup;
  1294. }
  1295. singleBufferTransaction = (dataCount == totalDataCount) &&
  1296. (parameterCount == totalParameterCount);
  1297. //
  1298. // Should we return a final response? If this is not a single buffer
  1299. // transaction, we need to return an interim response regardless of the
  1300. // no response flag.
  1301. //
  1302. noResponse = singleBufferTransaction &&
  1303. ((SmbGetUshort( &request->Flags ) &
  1304. SMB_TRANSACTION_NO_RESPONSE) != 0);
  1305. //
  1306. // Calculate buffer sizes.
  1307. //
  1308. // First determine whether this is a named pipe, LanMan RPC, or
  1309. // mailslot transaction. We avoid checking the transaction name
  1310. // ("\PIPE\" or "\MAILSLOT\") by recognizing that Transaction SMB
  1311. // must be one of the three, and that a mailslot write must have a
  1312. // setup count of 3 (words) and command code of
  1313. // TRANS_MAILSLOT_WRITE, and that a LanMan RPC must have a setup
  1314. // count of 0.
  1315. //
  1316. command = SmbGetUshort( (PSMB_USHORT)&request->Buffer[0] );
  1317. name = StrNull;
  1318. endOfSmb = NULL;
  1319. isUnicode = TRUE;
  1320. ASSERT( TRANS_SET_NMPIPE_STATE == TRANS_MAILSLOT_WRITE );
  1321. pipeRequest = (BOOLEAN)( (WorkContext->NextCommand == SMB_COM_TRANSACTION)
  1322. &&
  1323. ( (setupCount != 6) ||
  1324. ( (setupCount == 6) &&
  1325. (command != TRANS_MAILSLOT_WRITE) ) ) );
  1326. remoteApiRequest = (BOOLEAN)(pipeRequest && (setupCount == 0) );
  1327. if ( pipeRequest && !remoteApiRequest ) {
  1328. //
  1329. // Step 1. Have we received all of the input data and parameters?
  1330. //
  1331. // If so, we can generate the input buffers directly from the SMB
  1332. // buffer.
  1333. //
  1334. // If not, then we must copy all of the pieces to a single buffer
  1335. // which will are about to allocate. Both parameters and data
  1336. // must be dword aligned.
  1337. //
  1338. if ( singleBufferTransaction ) {
  1339. SMB_STATUS smbStatus;
  1340. //
  1341. // If this is a single buffer transact named pipe request, try
  1342. // the server fast path.
  1343. //
  1344. if ( (command == TRANS_TRANSACT_NMPIPE) &&
  1345. SrvFastTransactNamedPipe( WorkContext, &smbStatus ) ) {
  1346. SmbStatus =smbStatus;
  1347. goto Cleanup;
  1348. }
  1349. inputBufferSize = 0;
  1350. } else {
  1351. inputBufferSize = ((totalSetupCount * sizeof(UCHAR) + 3) & ~3) +
  1352. ((totalDataCount * sizeof(UCHAR) + 3) & ~3) +
  1353. ((totalParameterCount * sizeof(UCHAR) + 3) & ~3);
  1354. }
  1355. //
  1356. // If a session block has not already been assigned to the current
  1357. // work context, verify the UID. If verified, the address of the
  1358. // session block corresponding to this user is stored in the
  1359. // WorkContext block and the session block is referenced.
  1360. //
  1361. // If a tree connect block has not already been assigned to the
  1362. // current work context, find the tree connect corresponding to the
  1363. // given TID.
  1364. //
  1365. status = SrvVerifyUidAndTid(
  1366. WorkContext,
  1367. &session,
  1368. &treeConnect,
  1369. ShareTypeWild
  1370. );
  1371. if ( !NT_SUCCESS(status) ) {
  1372. IF_DEBUG(SMB_ERRORS) {
  1373. SrvPrint0( "SrvSmbTransaction: Invalid UID or TID\n" );
  1374. }
  1375. SrvSetSmbError( WorkContext, status );
  1376. SmbStatus = noResponse ? SmbStatusNoResponse
  1377. : SmbStatusSendResponse;
  1378. goto Cleanup;
  1379. }
  1380. if( session->IsSessionExpired )
  1381. {
  1382. status = SESSION_EXPIRED_STATUS_CODE;
  1383. SrvSetSmbError( WorkContext, status );
  1384. SmbStatus = SmbStatusSendResponse;
  1385. goto Cleanup;
  1386. }
  1387. //
  1388. // Step 2. Can all the output data and paramter fit in the SMB
  1389. // buffer? If so then we do not need to allocate extra space.
  1390. //
  1391. //
  1392. // Special case. If this is a PEEK_NMPIPE call, then allocate
  1393. // at least enough parameter bytes for the NT call.
  1394. //
  1395. // Since the SMB request normally asks for 6 parameter bytes,
  1396. // and NT NPFS will return 16 parameter bytes, this allows us
  1397. // to read the data and parameters directly from the NT call
  1398. // into the transaction buffer.
  1399. //
  1400. // At completion time, we will reformat the paramters, but if
  1401. // the data is read directly into the SMB buffer, there will
  1402. // be no need to recopy it.
  1403. //
  1404. if ( command == TRANS_PEEK_NMPIPE) {
  1405. maxParameterCount = MAX(
  1406. maxParameterCount,
  1407. 4 * sizeof(ULONG)
  1408. );
  1409. }
  1410. outputBufferSize = ((maxParameterCount * sizeof(CHAR) + 3) & ~3) +
  1411. ((maxDataCount * sizeof(CHAR) + 3) & ~3);
  1412. if ( sizeof(SMB_HEADER) +
  1413. sizeof (RESP_TRANSACTION) +
  1414. sizeof(USHORT) * request->SetupCount +
  1415. sizeof(USHORT) +
  1416. outputBufferSize
  1417. <= (ULONG)session->MaxBufferSize) {
  1418. outputBufferSize = 0;
  1419. }
  1420. //
  1421. // Since input and output data and parameters can overlap, just
  1422. // allocate a buffer big enough for the biggest possible buffer.
  1423. //
  1424. requiredBufferSize = MAX( inputBufferSize, outputBufferSize );
  1425. //
  1426. // If this is a call or wait named pipe operation, we need to
  1427. // keep the pipe name in the transaction block.
  1428. //
  1429. if ( (command == TRANS_CALL_NMPIPE) ||
  1430. (command == TRANS_WAIT_NMPIPE) ) {
  1431. isUnicode = SMB_IS_UNICODE( WorkContext );
  1432. name = ((PUSHORT)(&request->WordCount + 1) +
  1433. request->WordCount + 1);
  1434. if ( isUnicode ) {
  1435. name = ALIGN_SMB_WSTR( name );
  1436. }
  1437. endOfSmb = END_OF_REQUEST_SMB( WorkContext );
  1438. }
  1439. //
  1440. // This is a named pipe transaction. Input and output buffers
  1441. // can safely overlap.
  1442. //
  1443. buffersOverlap = TRUE;
  1444. } else {
  1445. //
  1446. // If a session block has not already been assigned to the current
  1447. // work context, verify the UID. If verified, the address of the
  1448. // session block corresponding to this user is stored in the
  1449. // WorkContext block and the session block is referenced.
  1450. //
  1451. // If a tree connect block has not already been assigned to the
  1452. // current work context, find the tree connect corresponding to the
  1453. // given TID.
  1454. //
  1455. status = SrvVerifyUidAndTid(
  1456. WorkContext,
  1457. &session,
  1458. &treeConnect,
  1459. ShareTypeWild
  1460. );
  1461. if ( !NT_SUCCESS(status) ) {
  1462. IF_DEBUG(SMB_ERRORS) {
  1463. SrvPrint0( "SrvSmbTransaction: Invalid UID or TID\n" );
  1464. }
  1465. SrvSetSmbError( WorkContext, status );
  1466. SmbStatus = noResponse ? SmbStatusNoResponse
  1467. : SmbStatusSendResponse;
  1468. goto Cleanup;
  1469. }
  1470. if( session->IsSessionExpired )
  1471. {
  1472. status = SESSION_EXPIRED_STATUS_CODE;
  1473. SrvSetSmbError( WorkContext, status );
  1474. SmbStatus = SmbStatusSendResponse;
  1475. goto Cleanup;
  1476. }
  1477. //
  1478. // This is a Transaction2 call or a mailslot or LanMan RPC
  1479. // Transaction call. Don't assume anything about the buffers.
  1480. //
  1481. // !!! It should be possible to be smarter about buffer space
  1482. // on Trans2 SMBs. We should be able to overlap input
  1483. // and output as well as avoiding copies to and from
  1484. // the SMB buffer.
  1485. //
  1486. requiredBufferSize =
  1487. ((totalSetupCount + 3) & ~3) + ((maxSetupCount + 3) & ~3) +
  1488. ((totalParameterCount + 3) & ~3) + ((maxParameterCount + 3) & ~3) +
  1489. ((totalDataCount + 3) & ~3) + ((maxDataCount + 3) & ~3);
  1490. //
  1491. // If this is a remote API request, check whether we have
  1492. // initialized the connection with XACTSRV.
  1493. //
  1494. if ( remoteApiRequest ) {
  1495. if ( SrvXsPortMemoryHeap == NULL ) {
  1496. //
  1497. // XACTSRV is not started. Reject the request.
  1498. //
  1499. IF_DEBUG(ERRORS) {
  1500. SrvPrint0( "SrvSmbTransaction: The XACTSRV service is not started.\n" );
  1501. }
  1502. SrvSetSmbError( WorkContext, STATUS_NOT_SUPPORTED );
  1503. status = STATUS_NOT_SUPPORTED;
  1504. SmbStatus = noResponse ? SmbStatusNoResponse
  1505. : SmbStatusSendResponse;
  1506. goto Cleanup;
  1507. }
  1508. } else if ( WorkContext->NextCommand == SMB_COM_TRANSACTION ) {
  1509. //
  1510. // We need to save the transaction name for mailslot writes.
  1511. //
  1512. isUnicode = SMB_IS_UNICODE( WorkContext );
  1513. name = ((PUSHORT)(&request->WordCount + 1) +
  1514. request->WordCount + 1);
  1515. if ( isUnicode ) {
  1516. name = ALIGN_SMB_WSTR( name );
  1517. }
  1518. endOfSmb = END_OF_REQUEST_SMB( WorkContext );
  1519. }
  1520. }
  1521. //
  1522. // If there is a transaction secondary buffer on the way, ensure
  1523. // that we have a free work item to receive it. Otherwise fail
  1524. // this SMB with an out of resources error.
  1525. //
  1526. if ( !singleBufferTransaction ) {
  1527. if ( SrvReceiveBufferShortage( ) ) {
  1528. SrvStatistics.BlockingSmbsRejected++;
  1529. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  1530. status = STATUS_INSUFF_SERVER_RESOURCES;
  1531. SmbStatus = noResponse ? SmbStatusNoResponse
  1532. : SmbStatusSendResponse;
  1533. goto Cleanup;
  1534. } else {
  1535. //
  1536. // SrvBlockingOpsInProgress has already been incremented.
  1537. // Flag this work item as a blocking operation.
  1538. //
  1539. WorkContext->BlockingOperation = TRUE;
  1540. }
  1541. }
  1542. //
  1543. // Allocate a transaction block. This block is used to retain
  1544. // information about the state of the transaction. This is
  1545. // necessary because multiple SMBs are potentially sent and
  1546. // received.
  1547. //
  1548. connection = WorkContext->Connection;
  1549. SrvAllocateTransaction(
  1550. &transaction,
  1551. (PVOID *)&trailingBytes,
  1552. connection,
  1553. requiredBufferSize,
  1554. name,
  1555. endOfSmb,
  1556. isUnicode,
  1557. remoteApiRequest
  1558. );
  1559. if ( transaction == NULL ) {
  1560. //
  1561. // Unable to allocate transaction. Return an error to the
  1562. // client. (The session and tree connect blocks are
  1563. // dereferenced automatically.)
  1564. //
  1565. IF_DEBUG(ERRORS) {
  1566. SrvPrint0( "Unable to allocate transaction\n" );
  1567. }
  1568. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  1569. status = STATUS_INSUFF_SERVER_RESOURCES;
  1570. SmbStatus = noResponse ? SmbStatusNoResponse : SmbStatusSendResponse;
  1571. goto Cleanup;
  1572. }
  1573. IF_SMB_DEBUG(TRANSACTION1) {
  1574. SrvPrint1( "Allocated transaction 0x%p\n", transaction );
  1575. }
  1576. transaction->PipeRequest = pipeRequest;
  1577. //
  1578. // Save the connection, session, and tree connect pointers in the
  1579. // transaction block. If this transaction will NOT require multiple
  1580. // SMB exchanges, the session and tree connect pointers are not
  1581. // referenced pointers, because the work context block's pointers
  1582. // will remain valid for the duration of the transaction.
  1583. //
  1584. transaction->Connection = connection;
  1585. SrvReferenceConnection( connection );
  1586. if ( session != NULL ) {
  1587. transaction->Session = session;
  1588. transaction->TreeConnect = treeConnect;
  1589. if ( requiredBufferSize != 0 ) {
  1590. SrvReferenceSession( session );
  1591. SrvReferenceTreeConnect( treeConnect );
  1592. }
  1593. } else {
  1594. IF_SMB_DEBUG(TRANSACTION1) {
  1595. SrvPrint0( "SrvSmbTransaction - Session Setup: skipping session and tree connect reference.\n" );
  1596. }
  1597. }
  1598. //
  1599. // Save the TID, PID, UID, and MID from this request in the
  1600. // transaction block. These values are used to relate secondary
  1601. // requests to the appropriate primary request.
  1602. //
  1603. transaction->Tid = SmbGetAlignedUshort( &header->Tid );
  1604. transaction->Pid = SmbGetAlignedUshort( &header->Pid );
  1605. transaction->Uid = SmbGetAlignedUshort( &header->Uid );
  1606. transaction->OtherInfo = SmbGetAlignedUshort( &header->Mid );
  1607. //
  1608. // Save the time that the initial request SMB arrived, for use in
  1609. // calculating the elapsed time for the entire transaction.
  1610. //
  1611. transaction->StartTime = WorkContext->StartTime;
  1612. //
  1613. // Save other sundry information, but don't load the ParameterCount
  1614. // and DataCount fields until after copying the data. This is to
  1615. // prevent the reception of a secondary request prior to our
  1616. // completion here from causing the transaction to be executed
  1617. // twice. (These fields are initialized to 0 during allocation.)
  1618. //
  1619. transaction->Timeout = SmbGetUlong( &request->Timeout );
  1620. transaction->Flags = SmbGetUshort( &request->Flags );
  1621. transaction->SetupCount = totalSetupCount;
  1622. transaction->MaxSetupCount = maxSetupCount;
  1623. transaction->TotalParameterCount = totalParameterCount;
  1624. transaction->MaxParameterCount = maxParameterCount;
  1625. transaction->TotalDataCount = totalDataCount;
  1626. transaction->MaxDataCount = maxDataCount;
  1627. startOfTrailingBytes = trailingBytes;
  1628. //
  1629. // Calculate the addresses of the various buffers.
  1630. //
  1631. if ( inputBufferSize != 0 ) {
  1632. //
  1633. // Input setup, parameters and data will be copied to a separate
  1634. // buffer.
  1635. //
  1636. transaction->InSetup = (PSMB_USHORT)trailingBytes;
  1637. trailingBytes += (totalSetupCount + 3) & ~3;
  1638. transaction->InParameters = (PCHAR)trailingBytes;
  1639. trailingBytes += (totalParameterCount + 3) & ~3;
  1640. transaction->InData = (PCHAR)trailingBytes;
  1641. trailingBytes += (totalDataCount + 3) & ~3;
  1642. transaction->InputBufferCopied = TRUE;
  1643. } else {
  1644. //
  1645. // Input parameters and data will be sent directly out of the
  1646. // request buffer.
  1647. //
  1648. transaction->InSetup = (PSMB_USHORT)( (PCHAR)header + setupOffset );
  1649. transaction->InParameters = (PCHAR)header + parameterOffset;
  1650. transaction->InData = (PCHAR)header + dataOffset;
  1651. transaction->InputBufferCopied = FALSE;
  1652. }
  1653. //
  1654. // Setup the output data pointers.
  1655. //
  1656. transaction->OutSetup = (PSMB_USHORT)NULL;
  1657. if ( buffersOverlap ) {
  1658. //
  1659. // The output buffer overlaps the input buffer.
  1660. //
  1661. trailingBytes = startOfTrailingBytes;
  1662. }
  1663. if ( outputBufferSize != 0 ) {
  1664. //
  1665. // The output is going into a separate buffer, to be copied
  1666. // later into the response SMB buffer.
  1667. //
  1668. transaction->OutParameters = (PCHAR)trailingBytes;
  1669. trailingBytes += (maxParameterCount + 3) & ~3;
  1670. transaction->OutData = (PCHAR)trailingBytes;
  1671. transaction->OutputBufferCopied = TRUE;
  1672. } else {
  1673. //
  1674. // The data (and parameters) will be going into the response
  1675. // SMB buffer, which may not be the one we are currently
  1676. // processing. So temporarily set these pointers to NULL. The
  1677. // correct pointers will be calculated at ExecuteTransaction time.
  1678. //
  1679. transaction->OutParameters = NULL;
  1680. transaction->OutData = NULL;
  1681. transaction->OutputBufferCopied = FALSE;
  1682. }
  1683. //
  1684. // If this transaction will require multiple SMB exchanges, link the
  1685. // transaction block into the connection's pending transaction list.
  1686. // This will fail if there is already a transaction with the same
  1687. // xID values in the list.
  1688. //
  1689. // !!! Need a way to prevent the transaction list from becoming
  1690. // clogged with pending transactions.
  1691. //
  1692. if ( (requiredBufferSize != 0) && !SrvInsertTransaction( transaction ) ) {
  1693. //
  1694. // A transaction with the same xIDs is already in progress.
  1695. // Return an error to the client.
  1696. //
  1697. // *** Note that SrvDereferenceTransaction can't be used here
  1698. // because that routine assumes that the transaction is
  1699. // queued to the transaction list.
  1700. //
  1701. IF_SMB_DEBUG(TRANSACTION1) {
  1702. SrvPrint0( "Duplicate transaction exists\n" );
  1703. }
  1704. SrvLogInvalidSmb( WorkContext );
  1705. SrvDereferenceSession( session );
  1706. DEBUG transaction->Session = NULL;
  1707. SrvDereferenceTreeConnect( treeConnect );
  1708. DEBUG transaction->TreeConnect = NULL;
  1709. SrvFreeTransaction( transaction );
  1710. SrvDereferenceConnection( connection );
  1711. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  1712. status = STATUS_INVALID_SMB;
  1713. SmbStatus = noResponse ? SmbStatusNoResponse : SmbStatusSendResponse;
  1714. goto Cleanup;
  1715. }
  1716. //
  1717. // Copy the setup, parameter and data bytes that arrived in the
  1718. // primary SMB.
  1719. //
  1720. // !!! We could allow secondary requests to start by allocating a
  1721. // separate buffer for the interim response, sending the
  1722. // response, then copying the data.
  1723. //
  1724. if ( inputBufferSize != 0 ) {
  1725. if ( setupCount != 0 ) {
  1726. RtlMoveMemory(
  1727. (PVOID)transaction->InSetup,
  1728. (PCHAR)header + setupOffset,
  1729. setupCount
  1730. );
  1731. }
  1732. //
  1733. // We can now check to see if we are doing a session setup trans2
  1734. //
  1735. if ( session == NULL ) {
  1736. IF_SMB_DEBUG(TRANSACTION1) {
  1737. SrvPrint0( "SrvSmbTransaction - Receiving a Session setup SMB\n");
  1738. }
  1739. }
  1740. if ( parameterCount != 0 ) {
  1741. RtlMoveMemory(
  1742. transaction->InParameters,
  1743. (PCHAR)header + parameterOffset,
  1744. parameterCount
  1745. );
  1746. }
  1747. if ( dataCount != 0 ) {
  1748. RtlMoveMemory(
  1749. transaction->InData,
  1750. (PCHAR)header + dataOffset,
  1751. dataCount
  1752. );
  1753. }
  1754. }
  1755. //
  1756. // Update the received parameter and data counts. If all of the
  1757. // transaction bytes have arrived, execute it. Otherwise, send
  1758. // an interim response.
  1759. //
  1760. transaction->ParameterCount = parameterCount;
  1761. transaction->DataCount = dataCount;
  1762. if ( singleBufferTransaction ) {
  1763. //
  1764. // All of the data has arrived. Execute the transaction. When
  1765. // ExecuteTransaction returns, the first (possibly only)
  1766. // response, if any, has been sent. Our work is done.
  1767. //
  1768. WorkContext->Parameters.Transaction = transaction;
  1769. SmbStatus = ExecuteTransaction( WorkContext );
  1770. goto Cleanup;
  1771. } else {
  1772. //
  1773. // Not all of the data has arrived. We have already queued the
  1774. // transaction to the connection's transaction list. We need to
  1775. // send an interim response telling the client to send the
  1776. // remaining data. We also need to dereference the transaction
  1777. // block, since we'll no longer have a pointer to it.
  1778. //
  1779. PRESP_TRANSACTION_INTERIM response;
  1780. IF_SMB_DEBUG(TRANSACTION1) {
  1781. SrvPrint0( "More transaction data expected.\n" );
  1782. }
  1783. ASSERT( transaction->Inserted );
  1784. SrvDereferenceTransaction( transaction );
  1785. response = (PRESP_TRANSACTION_INTERIM)WorkContext->ResponseParameters;
  1786. response->WordCount = 0;
  1787. SmbPutUshort( &response->ByteCount, 0 );
  1788. WorkContext->ResponseParameters = NEXT_LOCATION(
  1789. response,
  1790. RESP_TRANSACTION_INTERIM,
  1791. 0
  1792. );
  1793. //
  1794. // Inhibit statistics gathering -- this isn't the end of the
  1795. // transaction.
  1796. //
  1797. WorkContext->StartTime = 0;
  1798. SmbStatus = SmbStatusSendResponse;
  1799. }
  1800. Cleanup:
  1801. return SmbStatus;
  1802. } // SrvSmbTransaction
  1803. SMB_PROCESSOR_RETURN_TYPE
  1804. SrvSmbTransactionSecondary (
  1805. SMB_PROCESSOR_PARAMETERS
  1806. )
  1807. /*++
  1808. Routine Description:
  1809. Processes a secondary Transaction or Transaction2 SMB.
  1810. Arguments:
  1811. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  1812. of the parameters to SMB processor routines.
  1813. Return Value:
  1814. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  1815. --*/
  1816. {
  1817. PREQ_TRANSACTION_SECONDARY request;
  1818. PSMB_HEADER header;
  1819. PTRANSACTION transaction;
  1820. PCONNECTION connection;
  1821. CLONG parameterOffset;
  1822. CLONG parameterCount;
  1823. CLONG parameterDisplacement;
  1824. CLONG dataOffset;
  1825. CLONG dataCount;
  1826. CLONG dataDisplacement;
  1827. CLONG smbLength;
  1828. NTSTATUS status = STATUS_SUCCESS;
  1829. SMB_STATUS SmbStatus = SmbStatusInProgress;
  1830. PAGED_CODE( );
  1831. request = (PREQ_TRANSACTION_SECONDARY)WorkContext->RequestParameters;
  1832. header = WorkContext->RequestHeader;
  1833. IF_SMB_DEBUG(TRANSACTION1) {
  1834. SrvPrint1( "Transaction%s (secondary) request\n",
  1835. (WorkContext->NextCommand == SMB_COM_TRANSACTION_SECONDARY)
  1836. ? "" : "2" );
  1837. }
  1838. //
  1839. // Find the transaction block that matches this secondary request.
  1840. // The TID, PID, UID, and MID in the headers of all messages in
  1841. // a transaction are the same. If a match is found, it is
  1842. // referenced to prevent its deletion and its address is returned.
  1843. //
  1844. connection = WorkContext->Connection;
  1845. transaction = SrvFindTransaction( connection, header, 0 );
  1846. if ( transaction == NULL ) {
  1847. //
  1848. // Unable to find a matching transaction. Ignore this SMB.
  1849. //
  1850. // !!! Is this the right thing to do? It's what PIA does.
  1851. //
  1852. IF_DEBUG(ERRORS) {
  1853. SrvPrint0( "No matching transaction. Ignoring request.\n" );
  1854. }
  1855. SmbStatus = SmbStatusNoResponse;
  1856. goto Cleanup;
  1857. }
  1858. ASSERT( transaction->Connection == connection );
  1859. if( transaction->Session->IsSessionExpired )
  1860. {
  1861. status = SESSION_EXPIRED_STATUS_CODE;
  1862. SrvSetSmbError( WorkContext, status );
  1863. SmbStatus = SmbStatusSendResponse;
  1864. goto Cleanup;
  1865. }
  1866. //
  1867. // Ensure that the transaction isn't already complete.
  1868. // That is, that this is not a message accidentally added to a
  1869. // transaction that's already being executed.
  1870. //
  1871. #if 0
  1872. // !!! Apparently we don't get any secondary request on remote
  1873. // APIs, because this little piece of code causes an infinite
  1874. // loop because it doesn't check to see if it's already in a
  1875. // blocking thread. And it's been here for 2-1/2 years!
  1876. // Besides, we don't do primary remote APIs in blocking threads,
  1877. // so why do secondaries?
  1878. //
  1879. // If this is a remote API request, send it off to a blocking thread
  1880. // since it is possible for the operation to take a long time.
  1881. //
  1882. if ( transaction->RemoteApiRequest ) {
  1883. DEBUG WorkContext->FsdRestartRoutine = NULL;
  1884. WorkContext->FspRestartRoutine = SrvRestartSmbReceived;
  1885. SrvQueueWorkToBlockingThread( WorkContext );
  1886. SrvDereferenceTransaction( transaction );
  1887. SmbStatus = SmbStatusInProgress;
  1888. goto Cleanup;
  1889. }
  1890. #endif
  1891. //
  1892. // Unlike the Transaction[2] SMB, the Transaction[2] Secondary SMB
  1893. // has a fixed WordCount, so SrvProcessSmb has already verified it.
  1894. // But it's still possible that the offsets and lengths of the
  1895. // Parameter and Data bytes are invalid. So we check them now.
  1896. //
  1897. parameterOffset = SmbGetUshort( &request->ParameterOffset );
  1898. parameterCount = SmbGetUshort( &request->ParameterCount );
  1899. parameterDisplacement = SmbGetUshort( &request->ParameterDisplacement );
  1900. dataOffset = SmbGetUshort( &request->DataOffset );
  1901. dataCount = SmbGetUshort( &request->DataCount );
  1902. dataDisplacement = SmbGetUshort( &request->DataDisplacement );
  1903. //
  1904. // See if this is a special ack by the client to tell us to send
  1905. // the next piece of a multipiece response.
  1906. //
  1907. if ( transaction->MultipieceIpxSend ) {
  1908. ASSERT( WorkContext->Endpoint->IsConnectionless );
  1909. if ( (parameterCount == 0) && (parameterOffset == 0) &&
  1910. (dataCount == 0) && (dataOffset == 0)) {
  1911. //
  1912. // got the ACK. Make sure the displacement numbers are reasonable.
  1913. //
  1914. if ( (dataDisplacement > transaction->DataCount) ||
  1915. (parameterDisplacement > transaction->ParameterCount) ) {
  1916. IF_DEBUG(SMB_ERRORS) {
  1917. SrvPrint2( "SrvSmbTransactionSecondary: Invalid parameter or data "
  1918. "displacement: pDisp=%ld ;dDisp=%ld",
  1919. parameterDisplacement, dataDisplacement );
  1920. }
  1921. goto invalid_smb;
  1922. }
  1923. transaction->DataDisplacement = dataDisplacement;
  1924. transaction->ParameterDisplacement = parameterDisplacement;
  1925. WorkContext->Parameters.Transaction = transaction;
  1926. //
  1927. // Change the secondary command code to the primary code.
  1928. //
  1929. WorkContext->NextCommand--;
  1930. header->Command = WorkContext->NextCommand;
  1931. RestartIpxTransactionResponse( WorkContext );
  1932. SmbStatus = SmbStatusInProgress;
  1933. goto Cleanup;
  1934. } else {
  1935. IF_DEBUG(SMB_ERRORS) {
  1936. SrvPrint4( "SrvSmbTransactionSecondary: Invalid parameter or data "
  1937. "offset+count: pOff=%ld,pCnt=%ld;dOff=%ld,dCnt=%ld;",
  1938. parameterOffset, parameterCount,
  1939. dataOffset, dataCount );
  1940. SrvPrint0("Should be all zeros.\n");
  1941. }
  1942. goto invalid_smb;
  1943. }
  1944. }
  1945. smbLength = WorkContext->RequestBuffer->DataLength;
  1946. if ( ( (parameterOffset + parameterCount) > smbLength ) ||
  1947. ( (dataOffset + dataCount) > smbLength ) ||
  1948. ( (parameterCount + parameterDisplacement ) >
  1949. transaction->TotalParameterCount ) ||
  1950. ( (dataCount + dataDisplacement ) > transaction->TotalDataCount ) ) {
  1951. IF_DEBUG(SMB_ERRORS) {
  1952. SrvPrint4( "SrvSmbTransactionSecondary: Invalid parameter or data "
  1953. "offset+count: pOff=%ld,pCnt=%ld;dOff=%ld,dCnt=%ld;",
  1954. parameterOffset, parameterCount,
  1955. dataOffset, dataCount );
  1956. SrvPrint1( "smbLen=%ld", smbLength );
  1957. }
  1958. goto invalid_smb;
  1959. }
  1960. ACQUIRE_LOCK( &connection->Lock );
  1961. if( transaction->Executing == TRUE ) {
  1962. RELEASE_LOCK( &connection->Lock );
  1963. IF_DEBUG(ERRORS) {
  1964. SrvPrint0( "Transaction already executing. Ignoring request.\n" );
  1965. }
  1966. goto invalid_smb;
  1967. }
  1968. //
  1969. // Copy the parameter and data bytes that arrived in this SMB. We do
  1970. // this while we hold the resource to ensure that we don't copy memory
  1971. // into the buffer if somebody sends us an extra secondary transaction.
  1972. //
  1973. if ( parameterCount != 0 ) {
  1974. RtlMoveMemory(
  1975. transaction->InParameters + parameterDisplacement,
  1976. (PCHAR)header + parameterOffset,
  1977. parameterCount
  1978. );
  1979. }
  1980. if ( dataCount != 0 ) {
  1981. RtlMoveMemory(
  1982. transaction->InData + dataDisplacement,
  1983. (PCHAR)header + dataOffset,
  1984. dataCount
  1985. );
  1986. }
  1987. //
  1988. // Update the received parameter and data counts. If all of the
  1989. // transaction bytes have arrived, execute the transaction. We
  1990. // check for the unlikely case of the transaction having been
  1991. // aborted in the short amount of time since we verified that it was
  1992. // on the transaction list.
  1993. //
  1994. // *** This is all done under a lock in order to prevent the arrival
  1995. // of another secondary request (which could very easily happen)
  1996. // from interfering with our processing. Only one arrival can
  1997. // be allowed to actually update the counters such that they
  1998. // match the expected data size.
  1999. //
  2000. if ( GET_BLOCK_STATE(transaction) != BlockStateActive ) {
  2001. RELEASE_LOCK( &connection->Lock );
  2002. IF_SMB_DEBUG(TRANSACTION1) {
  2003. SrvPrint0( "Transaction closing. Ignoring request.\n" );
  2004. }
  2005. SrvDereferenceTransaction( transaction );
  2006. SmbStatus = SmbStatusNoResponse;
  2007. goto Cleanup;
  2008. }
  2009. transaction->ParameterCount += parameterCount;
  2010. transaction->DataCount += dataCount;
  2011. if ( (transaction->DataCount == transaction->TotalDataCount) &&
  2012. (transaction->ParameterCount == transaction->TotalParameterCount) ) {
  2013. //
  2014. // All of the data has arrived. Prepare to execute the
  2015. // transaction. Reference the tree connect and session blocks,
  2016. // saving pointers in the work context block. Note that even
  2017. // though the transaction block already references these blocks,
  2018. // we store pointers to them in the work context block so that
  2019. // common support routines only have to look there to find their
  2020. // pointers.
  2021. //
  2022. WorkContext->Session = transaction->Session;
  2023. SrvReferenceSession( transaction->Session );
  2024. WorkContext->TreeConnect = transaction->TreeConnect;
  2025. SrvReferenceTreeConnect( transaction->TreeConnect );
  2026. transaction->Executing = TRUE;
  2027. RELEASE_LOCK( &connection->Lock );
  2028. //
  2029. // Execute the transaction. When ExecuteTransaction returns,
  2030. // the first (possibly only) response, if any, has been sent.
  2031. // Our work is done.
  2032. //
  2033. WorkContext->Parameters.Transaction = transaction;
  2034. SmbStatus = ExecuteTransaction( WorkContext );
  2035. goto Cleanup;
  2036. } else {
  2037. RELEASE_LOCK( &connection->Lock );
  2038. //
  2039. // Not all of the data has arrived. Leave the transaction on
  2040. // the list, and don't send a response. Dereference the
  2041. // transaction block, since we'll no longer have a pointer to
  2042. // it.
  2043. //
  2044. IF_SMB_DEBUG(TRANSACTION1) {
  2045. SrvPrint0( "More transaction data expected.\n" );
  2046. }
  2047. SrvDereferenceTransaction( transaction );
  2048. //
  2049. // We do things differently when we are directly using ipx.
  2050. //
  2051. if ( WorkContext->Endpoint->IsConnectionless ) {
  2052. //
  2053. // Send a go-ahead response.
  2054. //
  2055. PRESP_TRANSACTION_INTERIM response;
  2056. response = (PRESP_TRANSACTION_INTERIM)WorkContext->ResponseParameters;
  2057. response->WordCount = 0;
  2058. SmbPutUshort( &response->ByteCount, 0 );
  2059. WorkContext->ResponseParameters = NEXT_LOCATION(
  2060. response,
  2061. RESP_TRANSACTION_INTERIM,
  2062. 0
  2063. );
  2064. //
  2065. // Inhibit statistics gathering -- this isn't the end of the
  2066. // transaction.
  2067. //
  2068. WorkContext->StartTime = 0;
  2069. SmbStatus = SmbStatusSendResponse;
  2070. goto Cleanup;
  2071. } else {
  2072. SmbStatus = SmbStatusNoResponse;
  2073. goto Cleanup;
  2074. }
  2075. }
  2076. invalid_smb:
  2077. SrvDereferenceTransaction( transaction );
  2078. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2079. status = STATUS_INVALID_SMB;
  2080. SmbStatus = SmbStatusSendResponse;
  2081. Cleanup:
  2082. return SmbStatus;
  2083. } // SrvSmbTransactionSecondary
  2084. SMB_PROCESSOR_RETURN_TYPE
  2085. SrvSmbNtTransaction (
  2086. SMB_PROCESSOR_PARAMETERS
  2087. )
  2088. /*++
  2089. Routine Description:
  2090. Processes a primary NT Transaction SMB.
  2091. Arguments:
  2092. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  2093. of the parameters to SMB processor routines.
  2094. Return Value:
  2095. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  2096. --*/
  2097. {
  2098. NTSTATUS status = STATUS_SUCCESS;
  2099. SMB_STATUS SmbStatus = SmbStatusInProgress;
  2100. PREQ_NT_TRANSACTION request;
  2101. PSMB_HEADER header;
  2102. PCONNECTION connection;
  2103. PSESSION session;
  2104. PTREE_CONNECT treeConnect;
  2105. PTRANSACTION transaction;
  2106. PCHAR trailingBytes;
  2107. CLONG parameterOffset;
  2108. CLONG parameterCount; // For input on this buffer
  2109. CLONG maxParameterCount; // For output
  2110. CLONG totalParameterCount; // For input
  2111. CLONG dataOffset;
  2112. CLONG dataCount; // For input on this buffer
  2113. CLONG maxDataCount; // For output
  2114. CLONG totalDataCount; // For input
  2115. CLONG smbLength;
  2116. CLONG requiredBufferSize;
  2117. CLONG parameterLength; // MAX of input and output param length
  2118. BOOLEAN singleBufferTransaction;
  2119. PAGED_CODE( );
  2120. request = (PREQ_NT_TRANSACTION)WorkContext->RequestParameters;
  2121. header = WorkContext->RequestHeader;
  2122. IF_SMB_DEBUG(TRANSACTION1) {
  2123. SrvPrint0( "NT Transaction (primary) request\n" );
  2124. }
  2125. //
  2126. // Make sure that the WordCount is correct to avoid any problems
  2127. // with overrunning the SMB buffer. SrvProcessSmb was unable to
  2128. // verify WordCount because it is variable, but it did verify that
  2129. // the supplied WordCount/ByteCount combination was valid.
  2130. // Verifying WordCount here ensure that what SrvProcessSmb thought
  2131. // was ByteCount really was, and that it's valid. The test here
  2132. // also implicit verifies SetupCount and that all of the setup words
  2133. // are "in range".
  2134. //
  2135. if ( (ULONG)request->WordCount != (ULONG)(19 + request->SetupCount) ) {
  2136. IF_DEBUG(SMB_ERRORS) {
  2137. SrvPrint3( "SrvSmbTransaction: Invalid WordCount: %ld, should be "
  2138. "SetupCount+19 = %ld+14 = %ld\n",
  2139. request->WordCount, request->SetupCount,
  2140. 19 + request->SetupCount );
  2141. }
  2142. SrvLogInvalidSmb( WorkContext );
  2143. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2144. status = STATUS_INVALID_SMB;
  2145. SmbStatus = SmbStatusSendResponse;
  2146. goto Cleanup;
  2147. }
  2148. //
  2149. // Even though we know that WordCount and ByteCount are valid, it's
  2150. // still possible that the offsets and lengths of the Parameter and
  2151. // Data bytes are invalid. So we check them now.
  2152. //
  2153. parameterOffset = request->ParameterOffset;
  2154. parameterCount = request->ParameterCount;
  2155. maxParameterCount = request->MaxParameterCount;
  2156. totalParameterCount = request->TotalParameterCount;
  2157. dataOffset = request->DataOffset;
  2158. dataCount = request->DataCount;
  2159. maxDataCount = request->MaxDataCount;
  2160. totalDataCount = request->TotalDataCount;
  2161. smbLength = WorkContext->RequestBuffer->DataLength;
  2162. if ( ( parameterOffset > smbLength ) ||
  2163. ( parameterCount > smbLength ) ||
  2164. ( (parameterOffset + parameterCount) > smbLength ) ||
  2165. ( dataOffset > smbLength ) ||
  2166. ( dataCount > smbLength ) ||
  2167. ( (dataOffset + dataCount) > smbLength ) ||
  2168. ( dataCount > totalDataCount ) ||
  2169. ( parameterCount > totalParameterCount ) ) {
  2170. IF_DEBUG(SMB_ERRORS) {
  2171. SrvPrint4( "SrvSmbTransaction: Invalid parameter or data "
  2172. "offset+count: pOff=%ld,pCnt=%ld;dOff=%ld,dCnt=%ld;",
  2173. parameterOffset, parameterCount,
  2174. dataOffset, dataCount );
  2175. SrvPrint1( "smbLen=%ld", smbLength );
  2176. }
  2177. SrvLogInvalidSmb( WorkContext );
  2178. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2179. status = STATUS_INVALID_SMB;
  2180. SmbStatus = SmbStatusSendResponse;
  2181. goto Cleanup;
  2182. }
  2183. //
  2184. // Ensure the client isn't asking for more data than we are willing
  2185. // to deal with
  2186. //
  2187. if( ( totalParameterCount > SrvMaxNtTransactionSize) ||
  2188. ( totalDataCount > SrvMaxNtTransactionSize ) ||
  2189. ( (totalParameterCount + totalDataCount) > SrvMaxNtTransactionSize) ||
  2190. ( maxParameterCount > SrvMaxNtTransactionSize ) ||
  2191. ( maxDataCount > SrvMaxNtTransactionSize ) ||
  2192. ( (maxParameterCount + maxDataCount) > SrvMaxNtTransactionSize ) ) {
  2193. SrvSetSmbError( WorkContext, STATUS_INVALID_BUFFER_SIZE );
  2194. status = STATUS_INVALID_BUFFER_SIZE;
  2195. SmbStatus = SmbStatusSendResponse;
  2196. goto Cleanup;
  2197. }
  2198. singleBufferTransaction = (dataCount == totalDataCount) &&
  2199. (parameterCount == totalParameterCount);
  2200. //
  2201. // If a session block has not already been assigned to the current
  2202. // work context, verify the UID. If verified, the address of the
  2203. // session block corresponding to this user is stored in the
  2204. // WorkContext block and the session block is referenced.
  2205. //
  2206. // If a tree connect block has not already been assigned to the
  2207. // current work context, find the tree connect corresponding to the
  2208. // given TID.
  2209. //
  2210. status = SrvVerifyUidAndTid(
  2211. WorkContext,
  2212. &session,
  2213. &treeConnect,
  2214. ShareTypeWild
  2215. );
  2216. if ( !NT_SUCCESS(status) ) {
  2217. IF_DEBUG(SMB_ERRORS) {
  2218. SrvPrint0( "SrvSmbNtTransaction: Invalid UID or TID\n" );
  2219. }
  2220. SrvSetSmbError( WorkContext, status );
  2221. SmbStatus = SmbStatusSendResponse;
  2222. goto Cleanup;
  2223. }
  2224. if( session->IsSessionExpired )
  2225. {
  2226. status = SESSION_EXPIRED_STATUS_CODE;
  2227. SrvSetSmbError( WorkContext, status );
  2228. SmbStatus = SmbStatusSendResponse;
  2229. goto Cleanup;
  2230. }
  2231. //
  2232. // If there is a transaction secondary buffer on the way, ensure
  2233. // that we have a free work item to receive it. Otherwise fail
  2234. // this SMB with an out of resources error.
  2235. //
  2236. if ( !singleBufferTransaction ) {
  2237. if ( SrvReceiveBufferShortage( ) ) {
  2238. SrvStatistics.BlockingSmbsRejected++;
  2239. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  2240. status = STATUS_INSUFF_SERVER_RESOURCES;
  2241. SmbStatus = SmbStatusSendResponse;
  2242. goto Cleanup;
  2243. } else {
  2244. //
  2245. // SrvBlockingOpsInProgress has already been incremented.
  2246. // Flag this work item as a blocking operation.
  2247. //
  2248. WorkContext->BlockingOperation = TRUE;
  2249. }
  2250. }
  2251. //
  2252. // Calculate buffer sizes.
  2253. //
  2254. // Input and output parameter buffers overlap.
  2255. // Input and output data buffers overlap.
  2256. //
  2257. //
  2258. // !!! It should be possible to be smarter about buffer space
  2259. // on NT Transaction SMBs. We should be able to avoid
  2260. // copies to and from the SMB buffer.
  2261. //
  2262. parameterLength =
  2263. MAX( ( (request->TotalParameterCount + 7) & ~7),
  2264. ( (request->MaxParameterCount + 7) & ~7));
  2265. requiredBufferSize = parameterLength +
  2266. MAX( ( (request->TotalDataCount + 7) & ~7),
  2267. ( (request->MaxDataCount + 7) & ~7) );
  2268. if( !singleBufferTransaction ) {
  2269. requiredBufferSize += (((request->SetupCount * sizeof(USHORT)) + 7 ) & ~7);
  2270. }
  2271. //
  2272. // We will later quad-word align input buffer for OFS query
  2273. // FSCTL since they are using MIDL to generate there marshalling
  2274. // (pickling). For this reason, we have to bump up our requiredBufferSize
  2275. // by 8 bytes (because the subsequent quad align might go up by as many
  2276. // as 7 bytes. 8 looks like a better number to use.
  2277. //
  2278. // While OFS is long gone, we now always quad-align the buffer for the 64-bit case,
  2279. // and for 32-bit transactions that require LARGE_INTEGER alignment.
  2280. requiredBufferSize += 8;
  2281. //
  2282. // Allocate a transaction block. This block is used to retain
  2283. // information about the state of the transaction. This is
  2284. // necessary because multiple SMBs are potentially sent and
  2285. // received.
  2286. //
  2287. connection = WorkContext->Connection;
  2288. SrvAllocateTransaction(
  2289. &transaction,
  2290. (PVOID *)&trailingBytes,
  2291. connection,
  2292. requiredBufferSize,
  2293. StrNull,
  2294. NULL,
  2295. TRUE,
  2296. FALSE // This is not a remote API
  2297. );
  2298. if ( transaction == NULL ) {
  2299. //
  2300. // Unable to allocate transaction. Return an error to the
  2301. // client. (The session and tree connect blocks are
  2302. // dereferenced automatically.)
  2303. //
  2304. IF_DEBUG(ERRORS) {
  2305. SrvPrint0( "Unable to allocate transaction\n" );
  2306. }
  2307. if( requiredBufferSize > MAX_TRANSACTION_TAIL_SIZE )
  2308. {
  2309. SrvSetSmbError( WorkContext, STATUS_INVALID_BUFFER_SIZE );
  2310. status = STATUS_INVALID_BUFFER_SIZE;
  2311. }
  2312. else
  2313. {
  2314. SrvSetSmbError( WorkContext, STATUS_INSUFF_SERVER_RESOURCES );
  2315. status = STATUS_INSUFF_SERVER_RESOURCES;
  2316. }
  2317. SmbStatus = SmbStatusSendResponse;
  2318. goto Cleanup;
  2319. }
  2320. IF_SMB_DEBUG(TRANSACTION1) {
  2321. SrvPrint1( "Allocated transaction 0x%p\n", transaction );
  2322. }
  2323. //
  2324. // Save the connection, session, and tree connect pointers in the
  2325. // transaction block. These are referenced pointers to prevent the
  2326. // blocks from being deleted while the transaction is pending.
  2327. //
  2328. SrvReferenceConnection( connection );
  2329. transaction->Connection = connection;
  2330. SrvReferenceSession( session );
  2331. transaction->Session = session;
  2332. SrvReferenceTreeConnect( treeConnect );
  2333. transaction->TreeConnect = treeConnect;
  2334. //
  2335. // Save the TID, PID, UID, and MID from this request in the
  2336. // transaction block. These values are used to relate secondary
  2337. // requests to the appropriate primary request.
  2338. //
  2339. transaction->Tid = SmbGetAlignedUshort( &header->Tid );
  2340. transaction->Pid = SmbGetAlignedUshort( &header->Pid );
  2341. transaction->Uid = SmbGetAlignedUshort( &header->Uid );
  2342. transaction->OtherInfo = SmbGetAlignedUshort( &header->Mid );
  2343. //
  2344. // Save the time that the initial request SMB arrived, for use in
  2345. // calculating the elapsed time for the entire transaction.
  2346. //
  2347. transaction->StartTime = WorkContext->StartTime;
  2348. //
  2349. // Save other sundry information, but don't load the ParameterCount
  2350. // and DataCount fields until after copying the data. This is to
  2351. // prevent the reception of a secondary request prior to our
  2352. // completion here from causing the transaction to be executed
  2353. // twice. (These fields are initialized to 0 during allocation.)
  2354. //
  2355. transaction->Flags = SmbGetUshort( &request->Flags );
  2356. transaction->Function = SmbGetUshort( &request->Function );
  2357. transaction->SetupCount = request->SetupCount;
  2358. transaction->MaxSetupCount = request->MaxSetupCount;
  2359. transaction->TotalParameterCount = totalParameterCount;
  2360. transaction->MaxParameterCount = maxParameterCount;
  2361. transaction->TotalDataCount = totalDataCount;
  2362. transaction->MaxDataCount = maxDataCount;
  2363. //
  2364. // Calculate the addresses of the various buffers.
  2365. //
  2366. if( singleBufferTransaction ) {
  2367. transaction->InSetup = (PSMB_USHORT)request->Buffer;
  2368. } else {
  2369. if( request->SetupCount ) {
  2370. transaction->InSetup = (PSMB_USHORT)trailingBytes;
  2371. RtlCopyMemory( transaction->InSetup, request->Buffer, request->SetupCount * sizeof(USHORT) );
  2372. trailingBytes += (((request->SetupCount * sizeof(USHORT)) + 7 ) & ~7);
  2373. } else {
  2374. transaction->InSetup = NULL;
  2375. }
  2376. }
  2377. //
  2378. // Input parameters and data will be copied to a separate buffer.
  2379. //
  2380. transaction->InParameters = (PCHAR)trailingBytes;
  2381. trailingBytes += parameterLength;
  2382. // We can always Quad-Align this because we padded the buffer for the OFS queries.
  2383. // This will allow all our 64-bit calls to go through fine, along with our 32-bit ones
  2384. transaction->InData = (PCHAR)ROUND_UP_POINTER(trailingBytes, 8);
  2385. transaction->InputBufferCopied = TRUE;
  2386. //
  2387. // Setup the output data pointers.
  2388. //
  2389. transaction->OutSetup = (PSMB_USHORT)NULL;
  2390. //
  2391. // The output is going into a separate buffer, to be copied
  2392. // later into the response SMB buffer.
  2393. //
  2394. transaction->OutParameters = transaction->InParameters;
  2395. transaction->OutData = transaction->InData;
  2396. transaction->OutputBufferCopied = TRUE;
  2397. //
  2398. // Link the transaction block into the connection's pending
  2399. // transaction list. This will fail if there is already a
  2400. // tranaction with the same xID values in the list.
  2401. //
  2402. // !!! Need a way to prevent the transaction list from becoming
  2403. // clogged with pending transactions.
  2404. //
  2405. // *** We can link the block into the list even though we haven't
  2406. // yet copied the data from the current message into the list
  2407. // because even if a secondary request arrives before we've done
  2408. // the copy, only one of us will be the one to find out that all
  2409. // of the data has arrived. This is because we update the
  2410. // counters while we hold a lock.
  2411. //
  2412. if ( !SrvInsertTransaction( transaction ) ) {
  2413. //
  2414. // A transaction with the same xIDs is already in progress.
  2415. // Return an error to the client.
  2416. //
  2417. // *** Note that SrvDereferenceTransaction can't be used here
  2418. // because that routine assumes that the transaction is
  2419. // queued to the transaction list.
  2420. //
  2421. IF_SMB_DEBUG(TRANSACTION1) {
  2422. SrvPrint0( "Duplicate transaction exists\n" );
  2423. }
  2424. SrvLogInvalidSmb( WorkContext );
  2425. SrvDereferenceSession( session );
  2426. DEBUG transaction->Session = NULL;
  2427. SrvDereferenceTreeConnect( treeConnect );
  2428. DEBUG transaction->TreeConnect = NULL;
  2429. SrvFreeTransaction( transaction );
  2430. SrvDereferenceConnection( connection );
  2431. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2432. status = STATUS_INVALID_SMB;
  2433. SmbStatus = SmbStatusSendResponse;
  2434. goto Cleanup;
  2435. }
  2436. //
  2437. // Copy the parameter and data bytes that arrived in the primary SMB.
  2438. // There is no need to copy the setup words as they always arrive
  2439. // completely in the primary buffer (unless we have a multipiece transaction)
  2440. //
  2441. // !!! We could allow secondary requests to start by allocating a
  2442. // separate buffer for the interim response, sending the
  2443. // response, then copying the data.
  2444. //
  2445. if ( parameterCount != 0 ) {
  2446. RtlMoveMemory(
  2447. transaction->InParameters,
  2448. (PCHAR)header + parameterOffset,
  2449. parameterCount
  2450. );
  2451. }
  2452. if ( dataCount != 0 ) {
  2453. RtlMoveMemory(
  2454. transaction->InData,
  2455. (PCHAR)header + dataOffset,
  2456. dataCount
  2457. );
  2458. }
  2459. //
  2460. // Update the received parameter and data counts. If all of the
  2461. // transaction bytes have arrived, execute it. Otherwise, send
  2462. // an interim response.
  2463. //
  2464. transaction->ParameterCount = parameterCount;
  2465. transaction->DataCount = dataCount;
  2466. if ( singleBufferTransaction ) {
  2467. //
  2468. // All of the data has arrived. Execute the transaction. When
  2469. // ExecuteTransaction returns, the first (possibly only)
  2470. // response, if any, has been sent. Our work is done.
  2471. //
  2472. WorkContext->Parameters.Transaction = transaction;
  2473. SmbStatus = ExecuteTransaction( WorkContext );
  2474. goto Cleanup;
  2475. } else {
  2476. //
  2477. // Not all of the data has arrived. We have already queued the
  2478. // transaction to the connection's transaction list. We need to
  2479. // send an interim response telling the client to send the
  2480. // remaining data. We also need to dereference the transaction
  2481. // block, since we'll no longer have a pointer to it.
  2482. //
  2483. PRESP_NT_TRANSACTION_INTERIM response;
  2484. IF_SMB_DEBUG(TRANSACTION1) {
  2485. SrvPrint0( "More transaction data expected.\n" );
  2486. }
  2487. ASSERT( transaction->Inserted );
  2488. SrvDereferenceTransaction( transaction );
  2489. response = (PRESP_NT_TRANSACTION_INTERIM)WorkContext->ResponseParameters;
  2490. response->WordCount = 0;
  2491. SmbPutUshort( &response->ByteCount, 0 );
  2492. WorkContext->ResponseParameters = NEXT_LOCATION(
  2493. response,
  2494. RESP_NT_TRANSACTION_INTERIM,
  2495. 0
  2496. );
  2497. //
  2498. // Inhibit statistics gathering -- this isn't the end of the
  2499. // transaction.
  2500. //
  2501. WorkContext->StartTime = 0;
  2502. SmbStatus = SmbStatusSendResponse;
  2503. }
  2504. Cleanup:
  2505. return SmbStatus;
  2506. } // SrvSmbNtTransaction
  2507. SMB_PROCESSOR_RETURN_TYPE
  2508. SrvSmbNtTransactionSecondary (
  2509. SMB_PROCESSOR_PARAMETERS
  2510. )
  2511. /*++
  2512. Routine Description:
  2513. Processes a secondary Nt Transaction SMB.
  2514. Arguments:
  2515. SMB_PROCESSOR_PARAMETERS - See smbtypes.h for a description
  2516. of the parameters to SMB processor routines.
  2517. Return Value:
  2518. SMB_PROCESSOR_RETURN_TYPE - See smbtypes.h
  2519. --*/
  2520. {
  2521. PREQ_NT_TRANSACTION_SECONDARY request;
  2522. PSMB_HEADER header;
  2523. PTRANSACTION transaction;
  2524. PCONNECTION connection;
  2525. CLONG parameterOffset;
  2526. CLONG parameterCount;
  2527. CLONG parameterDisplacement;
  2528. CLONG dataOffset;
  2529. CLONG dataCount;
  2530. CLONG dataDisplacement;
  2531. CLONG smbLength;
  2532. NTSTATUS status = STATUS_SUCCESS;
  2533. SMB_STATUS SmbStatus = SmbStatusInProgress;
  2534. PAGED_CODE( );
  2535. request = (PREQ_NT_TRANSACTION_SECONDARY)WorkContext->RequestParameters;
  2536. header = WorkContext->RequestHeader;
  2537. IF_SMB_DEBUG(TRANSACTION1) {
  2538. SrvPrint0( "Nt Transaction (secondary) request\n" );
  2539. }
  2540. //
  2541. // Find the transaction block that matches this secondary request.
  2542. // The TID, PID, UID, and MID in the headers of all messages in
  2543. // a transaction are the same. If a match is found, it is
  2544. // referenced to prevent its deletion and its address is returned.
  2545. //
  2546. connection = WorkContext->Connection;
  2547. transaction = SrvFindTransaction( connection, header, 0 );
  2548. if ( transaction == NULL ) {
  2549. //
  2550. // Unable to find a matching transaction. Ignore this SMB.
  2551. //
  2552. // !!! Is this the right thing to do? It's what PIA does.
  2553. //
  2554. IF_DEBUG(ERRORS) {
  2555. SrvPrint0( "No matching transaction. Ignoring request.\n" );
  2556. }
  2557. SrvLogInvalidSmb( WorkContext );
  2558. SmbStatus = SmbStatusNoResponse;
  2559. goto Cleanup;
  2560. }
  2561. ASSERT( transaction->Connection == connection );
  2562. if( transaction->Session->IsSessionExpired )
  2563. {
  2564. status = SESSION_EXPIRED_STATUS_CODE;
  2565. SrvSetSmbError( WorkContext, status );
  2566. SmbStatus = SmbStatusSendResponse;
  2567. goto Cleanup;
  2568. }
  2569. //
  2570. // !!! Should ensure that the transaction isn't already complete.
  2571. // That is, that this is not a message accidentally added to a
  2572. // transaction that's already being executed. (This is pretty
  2573. // much impossible to completely prevent, but we should do
  2574. // something to stop it.)
  2575. //
  2576. //
  2577. // Unlike the NtTransaction SMB, the NtTransaction Secondary SMB
  2578. // has a fixed WordCount, so SrvProcessSmb has already verified it.
  2579. // But it's still possible that the offsets and lengths of the
  2580. // Parameter and Data bytes are invalid. So we check them now.
  2581. //
  2582. parameterOffset = request->ParameterOffset;
  2583. parameterCount = request->ParameterCount;
  2584. parameterDisplacement = request->ParameterDisplacement;
  2585. dataOffset = request->DataOffset;
  2586. dataCount = request->DataCount;
  2587. dataDisplacement = request->DataDisplacement;
  2588. //
  2589. // See if this is a special ack by the client to tell us to send
  2590. // the next piece of a multipiece response.
  2591. //
  2592. if ( transaction->MultipieceIpxSend ) {
  2593. ASSERT( WorkContext->Endpoint->IsConnectionless );
  2594. if ( (parameterCount == 0) && (parameterOffset == 0) &&
  2595. (dataCount == 0) && (dataOffset == 0)) {
  2596. //
  2597. // got the ACK. Make sure the displacement numbers are reasonable.
  2598. //
  2599. if ( (dataDisplacement > transaction->DataCount) ||
  2600. (parameterDisplacement > transaction->ParameterCount) ) {
  2601. IF_DEBUG(SMB_ERRORS) {
  2602. SrvPrint2( "SrvSmbNtTransactionSecondary: Invalid parameter or data "
  2603. "displacement: pDisp=%ld ;dDisp=%ld",
  2604. parameterDisplacement, dataDisplacement );
  2605. }
  2606. goto invalid_smb;
  2607. }
  2608. transaction->DataDisplacement = dataDisplacement;
  2609. transaction->ParameterDisplacement = parameterDisplacement;
  2610. WorkContext->Parameters.Transaction = transaction;
  2611. //
  2612. // Change the secondary command code to the primary code.
  2613. //
  2614. WorkContext->NextCommand = SMB_COM_NT_TRANSACT;
  2615. header->Command = WorkContext->NextCommand;
  2616. RestartIpxTransactionResponse( WorkContext );
  2617. SmbStatus = SmbStatusInProgress;
  2618. goto Cleanup;
  2619. } else {
  2620. IF_DEBUG(SMB_ERRORS) {
  2621. SrvPrint4( "SrvSmbNtTransactionSecondary: Invalid parameter or data "
  2622. "offset+count: pOff=%ld,pCnt=%ld;dOff=%ld,dCnt=%ld;",
  2623. parameterOffset, parameterCount,
  2624. dataOffset, dataCount );
  2625. SrvPrint0("Should be all zeros.\n");
  2626. }
  2627. goto invalid_smb;
  2628. }
  2629. }
  2630. smbLength = WorkContext->RequestBuffer->DataLength;
  2631. if ( ( parameterOffset > smbLength ) ||
  2632. ( parameterCount > smbLength ) ||
  2633. ( (parameterOffset + parameterCount) > smbLength ) ||
  2634. ( dataOffset > smbLength ) ||
  2635. ( dataCount > smbLength ) ||
  2636. ( (dataOffset + dataCount) > smbLength ) ||
  2637. ( parameterCount > transaction->TotalParameterCount ) ||
  2638. ( parameterDisplacement > transaction->TotalParameterCount ) ||
  2639. ( (parameterCount + parameterDisplacement ) > transaction->TotalParameterCount ) ||
  2640. ( dataCount > transaction->TotalDataCount ) ||
  2641. ( dataDisplacement > transaction->TotalDataCount ) ||
  2642. ( (dataCount + dataDisplacement ) > transaction->TotalDataCount ) ) {
  2643. IF_DEBUG(SMB_ERRORS) {
  2644. SrvPrint4( "SrvSmbTransactionSecondary: Invalid parameter or data "
  2645. "offset+count: pOff=%ld,pCnt=%ld;dOff=%ld,dCnt=%ld;",
  2646. parameterOffset, parameterCount,
  2647. dataOffset, dataCount );
  2648. SrvPrint1( "smbLen=%ld", smbLength );
  2649. }
  2650. goto invalid_smb;
  2651. }
  2652. ACQUIRE_LOCK( &connection->Lock );
  2653. if( transaction->Executing == TRUE ) {
  2654. RELEASE_LOCK( &connection->Lock );
  2655. IF_DEBUG(ERRORS) {
  2656. SrvPrint0( "Transaction already executing. Ignoring request.\n" );
  2657. }
  2658. goto invalid_smb;
  2659. }
  2660. //
  2661. // Copy the parameter and data bytes that arrived in this SMB.
  2662. //
  2663. if ( parameterCount != 0 ) {
  2664. RtlMoveMemory(
  2665. transaction->InParameters + parameterDisplacement,
  2666. (PCHAR)header + parameterOffset,
  2667. parameterCount
  2668. );
  2669. }
  2670. if ( dataCount != 0 ) {
  2671. RtlMoveMemory(
  2672. transaction->InData + dataDisplacement,
  2673. (PCHAR)header + dataOffset,
  2674. dataCount
  2675. );
  2676. }
  2677. //
  2678. // Update the received parameter and data counts. If all of the
  2679. // transaction bytes have arrived, execute the transaction. We
  2680. // check for the unlikely case of the transaction having been
  2681. // aborted in the short amount of time since we verified that it was
  2682. // on the transaction list.
  2683. //
  2684. // *** This is all done under a lock in order to prevent the arrival
  2685. // of another secondary request (which could very easily happen)
  2686. // from interfering with our processing. Only one arrival can
  2687. // be allowed to actually update the counters such that they
  2688. // match the expected data size.
  2689. //
  2690. if ( GET_BLOCK_STATE(transaction) != BlockStateActive ) {
  2691. RELEASE_LOCK( &connection->Lock );
  2692. IF_SMB_DEBUG(TRANSACTION1) {
  2693. SrvPrint0( "Transaction closing. Ignoring request.\n" );
  2694. }
  2695. SrvDereferenceTransaction( transaction );
  2696. SmbStatus = SmbStatusNoResponse;
  2697. goto Cleanup;
  2698. }
  2699. transaction->ParameterCount += parameterCount;
  2700. transaction->DataCount += dataCount;
  2701. if ( (transaction->DataCount == transaction->TotalDataCount) &&
  2702. (transaction->ParameterCount == transaction->TotalParameterCount) ) {
  2703. //
  2704. // All of the data has arrived. Prepare to execute the
  2705. // transaction. Reference the tree connect and session blocks,
  2706. // saving pointers in the work context block. Note that even
  2707. // though the transaction block already references these blocks,
  2708. // we store pointers to them in the work context block so that
  2709. // common support routines only have to look there to find their
  2710. // pointers.
  2711. //
  2712. WorkContext->Session = transaction->Session;
  2713. SrvReferenceSession( transaction->Session );
  2714. WorkContext->TreeConnect = transaction->TreeConnect;
  2715. SrvReferenceTreeConnect( transaction->TreeConnect );
  2716. transaction->Executing = TRUE;
  2717. RELEASE_LOCK( &connection->Lock );
  2718. //
  2719. // Execute the transaction. When ExecuteTransaction returns,
  2720. // the first (possibly only) response, if any, has been sent.
  2721. // Our work is done.
  2722. //
  2723. WorkContext->Parameters.Transaction = transaction;
  2724. SmbStatus = ExecuteTransaction( WorkContext );
  2725. goto Cleanup;
  2726. } else {
  2727. //
  2728. // Not all of the data has arrived. Leave the transaction on
  2729. // the list, and don't send a response. Dereference the
  2730. // transaction block, since we'll no longer have a pointer to
  2731. // it.
  2732. //
  2733. RELEASE_LOCK( &connection->Lock );
  2734. SrvDereferenceTransaction( transaction );
  2735. IF_SMB_DEBUG(TRANSACTION1) SrvPrint0( "More data expected.\n" );
  2736. //
  2737. // We do things differently when we are directly using ipx.
  2738. //
  2739. if ( WorkContext->Endpoint->IsConnectionless ) {
  2740. //
  2741. // Send the go-ahead response.
  2742. //
  2743. PRESP_NT_TRANSACTION_INTERIM response;
  2744. response = (PRESP_NT_TRANSACTION_INTERIM)WorkContext->ResponseParameters;
  2745. response->WordCount = 0;
  2746. SmbPutUshort( &response->ByteCount, 0 );
  2747. WorkContext->ResponseParameters = NEXT_LOCATION(
  2748. response,
  2749. RESP_NT_TRANSACTION_INTERIM,
  2750. 0
  2751. );
  2752. //
  2753. // Inhibit statistics gathering -- this isn't the end of the
  2754. // transaction.
  2755. //
  2756. WorkContext->StartTime = 0;
  2757. SmbStatus = SmbStatusSendResponse;
  2758. goto Cleanup;
  2759. } else {
  2760. SmbStatus = SmbStatusNoResponse;
  2761. goto Cleanup;
  2762. }
  2763. }
  2764. invalid_smb:
  2765. SrvDereferenceTransaction( transaction );
  2766. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2767. status = STATUS_INVALID_SMB;
  2768. SmbStatus = SmbStatusSendResponse;
  2769. Cleanup:
  2770. return SmbStatus;
  2771. } // SrvSmbNtTransactionSecondary
  2772. SMB_TRANS_STATUS
  2773. MailslotTransaction (
  2774. PWORK_CONTEXT WorkContext
  2775. )
  2776. /*++
  2777. Routine Description:
  2778. This function processes a mailslot transaction.
  2779. Arguments:
  2780. WorkContext - Supplies a pointer to a work context block.
  2781. Return Value:
  2782. SMB_TRANS_STATUS
  2783. --*/
  2784. {
  2785. PTRANSACTION transaction;
  2786. PSMB_HEADER header;
  2787. PRESP_TRANSACTION response;
  2788. PREQ_TRANSACTION request;
  2789. USHORT command;
  2790. PCHAR name;
  2791. NTSTATUS status;
  2792. HANDLE fileHandle;
  2793. PFILE_OBJECT fileObject;
  2794. IO_STATUS_BLOCK ioStatusBlock;
  2795. OBJECT_ATTRIBUTES objectAttributes;
  2796. OBJECT_HANDLE_INFORMATION handleInformation;
  2797. UNICODE_STRING mailslotPath;
  2798. UNICODE_STRING fullName;
  2799. PAGED_CODE( );
  2800. header = WorkContext->ResponseHeader;
  2801. request = (PREQ_TRANSACTION)WorkContext->RequestParameters;
  2802. response = (PRESP_TRANSACTION)WorkContext->ResponseParameters;
  2803. transaction = WorkContext->Parameters.Transaction;
  2804. command = SmbGetUshort( &transaction->InSetup[0] );
  2805. name = (PCHAR)((PUSHORT)(&request->WordCount + 1) +
  2806. request->WordCount + 1);
  2807. //
  2808. // The only legal mailslot transaction is a mailslot write.
  2809. //
  2810. if ( command != TRANS_MAILSLOT_WRITE ) {
  2811. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2812. return SmbTransStatusErrorWithoutData;
  2813. }
  2814. //
  2815. // Strip "\MAILSLOT\" prefix from the path string. Ensure that the
  2816. // name contains more than just "\MAILSLOT\".
  2817. //
  2818. fullName.Buffer = NULL;
  2819. mailslotPath = WorkContext->Parameters.Transaction->TransactionName;
  2820. if ( mailslotPath.Length <=
  2821. (UNICODE_SMB_MAILSLOT_PREFIX_LENGTH + sizeof(WCHAR)) ) {
  2822. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  2823. return SmbTransStatusErrorWithoutData;
  2824. }
  2825. mailslotPath.Length -=
  2826. (UNICODE_SMB_MAILSLOT_PREFIX_LENGTH + sizeof(WCHAR));
  2827. mailslotPath.Buffer +=
  2828. (UNICODE_SMB_MAILSLOT_PREFIX_LENGTH + sizeof(WCHAR))/sizeof(WCHAR);
  2829. SrvAllocateAndBuildPathName(
  2830. &SrvMailslotRootDirectory,
  2831. &mailslotPath,
  2832. NULL,
  2833. &fullName
  2834. );
  2835. if ( fullName.Buffer == NULL ) {
  2836. //
  2837. // Unable to allocate heap for the full name.
  2838. //
  2839. IF_DEBUG(ERRORS) {
  2840. SrvPrint0( "MailslotTransaction: Unable to allocate heap for full path name\n" );
  2841. }
  2842. SrvSetSmbError (WorkContext, STATUS_INSUFF_SERVER_RESOURCES);
  2843. IF_DEBUG(TRACE2) SrvPrint0( "MailslotTransaction complete\n" );
  2844. return SmbTransStatusErrorWithoutData;
  2845. }
  2846. //
  2847. // Attempt to open the mailslot.
  2848. //
  2849. SrvInitializeObjectAttributes_U(
  2850. &objectAttributes,
  2851. &fullName,
  2852. OBJ_CASE_INSENSITIVE,
  2853. NULL,
  2854. NULL
  2855. );
  2856. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpenAttempts );
  2857. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TotalOpensForPathOperations );
  2858. status = SrvIoCreateFile(
  2859. WorkContext,
  2860. &fileHandle,
  2861. GENERIC_READ | GENERIC_WRITE,
  2862. &objectAttributes,
  2863. &ioStatusBlock,
  2864. NULL,
  2865. FILE_ATTRIBUTE_NORMAL,
  2866. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2867. FILE_OPEN,
  2868. 0, // Create Options
  2869. NULL, // EA Buffer
  2870. 0, // EA Length
  2871. CreateFileTypeMailslot,
  2872. (PVOID)NULL, // Create parameters
  2873. IO_FORCE_ACCESS_CHECK,
  2874. NULL
  2875. );
  2876. FREE_HEAP( fullName.Buffer );
  2877. if (!NT_SUCCESS(status)) {
  2878. //
  2879. // If the user didn't have this permission, update the
  2880. // statistics database.
  2881. //
  2882. if ( status == STATUS_ACCESS_DENIED ) {
  2883. SrvStatistics.AccessPermissionErrors++;
  2884. }
  2885. //
  2886. // The server could not open the requested mailslot
  2887. // return the error.
  2888. //
  2889. IF_SMB_DEBUG(TRANSACTION1) {
  2890. SrvPrint2( "MailslotTransaction: Failed to open %ws, err=%d\n",
  2891. WorkContext->Parameters.Transaction->TransactionName.Buffer,
  2892. status );
  2893. }
  2894. SrvSetSmbError (WorkContext, status);
  2895. IF_DEBUG(TRACE2) SrvPrint0( "MailslotTransaction complete\n" );
  2896. return SmbTransStatusErrorWithoutData;
  2897. }
  2898. SRVDBG_CLAIM_HANDLE( fileHandle, "FIL", 31, transaction );
  2899. SrvStatistics.TotalFilesOpened++;
  2900. //
  2901. // Get a pointer to the file object, so that we can directly
  2902. // build IRPs for asynchronous operations (read and write).
  2903. // Also, get the granted access mask, so that we can prevent the
  2904. // client from doing things that it isn't allowed to do.
  2905. //
  2906. status = ObReferenceObjectByHandle(
  2907. fileHandle,
  2908. 0,
  2909. NULL,
  2910. KernelMode,
  2911. (PVOID *)&fileObject,
  2912. &handleInformation
  2913. );
  2914. if ( !NT_SUCCESS(status) ) {
  2915. SrvLogServiceFailure( SRV_SVC_OB_REF_BY_HANDLE, status );
  2916. //
  2917. // This internal error bugchecks the system.
  2918. //
  2919. INTERNAL_ERROR(
  2920. ERROR_LEVEL_IMPOSSIBLE,
  2921. "MailslotTransaction: unable to reference file handle 0x%lx",
  2922. fileHandle,
  2923. NULL
  2924. );
  2925. SrvSetSmbError( WorkContext, status );
  2926. IF_DEBUG(TRACE2) SrvPrint0( "Mailslot transaction complete\n" );
  2927. return SmbTransStatusErrorWithoutData;
  2928. }
  2929. //
  2930. // Save file handle for the completion routine.
  2931. //
  2932. transaction = WorkContext->Parameters.Transaction;
  2933. transaction->FileHandle = fileHandle;
  2934. transaction->FileObject = fileObject;
  2935. //
  2936. // Set the Restart Routine addresses in the work context block.
  2937. //
  2938. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  2939. WorkContext->FspRestartRoutine = RestartMailslotWrite;
  2940. transaction = WorkContext->Parameters.Transaction;
  2941. //
  2942. // Build the IRP to start a mailslot write.
  2943. // Pass this request to MSFS.
  2944. //
  2945. SrvBuildMailslotWriteRequest(
  2946. WorkContext->Irp, // input IRP address
  2947. fileObject, // target file object address
  2948. WorkContext, // context
  2949. transaction->InData, // buffer address
  2950. transaction->TotalDataCount // buffer length
  2951. );
  2952. (VOID)IoCallDriver(
  2953. IoGetRelatedDeviceObject( fileObject ),
  2954. WorkContext->Irp
  2955. );
  2956. //
  2957. // The write was successfully started. Return the InProgress
  2958. // status to the caller, indicating that the caller should do
  2959. // nothing further with the SMB/WorkContext at the present time.
  2960. //
  2961. IF_DEBUG(TRACE2) SrvPrint0( "MailslotTransaction complete\n" );
  2962. return SmbTransStatusInProgress;
  2963. } // MailslotTransaction
  2964. VOID SRVFASTCALL
  2965. RestartMailslotWrite (
  2966. IN OUT PWORK_CONTEXT WorkContext
  2967. )
  2968. /*++
  2969. Routine Description:
  2970. This is the completion routine for MailslotTransaction
  2971. Arguments:
  2972. WorkContext - A pointer to a WORK_CONTEXT block.
  2973. Return Value:
  2974. None.
  2975. --*/
  2976. {
  2977. NTSTATUS status;
  2978. PTRANSACTION transaction;
  2979. PAGED_CODE( );
  2980. //
  2981. // If the write request failed, set an error status in the response
  2982. // header.
  2983. //
  2984. status = WorkContext->Irp->IoStatus.Status;
  2985. transaction = WorkContext->Parameters.Transaction;
  2986. //
  2987. // Close the open pipe handle.
  2988. //
  2989. SRVDBG_RELEASE_HANDLE( transaction->FileHandle, "FIL", 52, transaction );
  2990. SrvNtClose( transaction->FileHandle, TRUE );
  2991. ObDereferenceObject( transaction->FileObject );
  2992. if ( !NT_SUCCESS(status) ) {
  2993. IF_DEBUG(ERRORS) {
  2994. SrvPrint1( "RestartMailslotWrite: Mailslot write failed: %X\n",
  2995. status );
  2996. }
  2997. SrvSetSmbError( WorkContext, status );
  2998. SrvCompleteExecuteTransaction(
  2999. WorkContext,
  3000. SmbTransStatusErrorWithoutData
  3001. );
  3002. } else {
  3003. //
  3004. // Success. Prepare to generate and send the response.
  3005. //
  3006. transaction->SetupCount = 0;
  3007. transaction->ParameterCount = 2; // return 2 parameter bytes
  3008. transaction->DataCount = 0;
  3009. //
  3010. // Return an OS/2 error code in the return parameter bytes. Just copy
  3011. // the error from the header. If it is a network error the client
  3012. // will figure it out.
  3013. //
  3014. // *** If the client understands NT errors, make it look in the
  3015. // SMB header.
  3016. //
  3017. if ( !CLIENT_CAPABLE_OF(NT_STATUS,WorkContext->Connection) ) {
  3018. SmbPutUshort(
  3019. (PSMB_USHORT)transaction->OutParameters,
  3020. SmbGetUshort( &WorkContext->ResponseHeader->Error )
  3021. );
  3022. } else {
  3023. SmbPutUshort(
  3024. (PSMB_USHORT)transaction->OutParameters,
  3025. (USHORT)-1
  3026. );
  3027. }
  3028. SrvCompleteExecuteTransaction(WorkContext, SmbTransStatusSuccess);
  3029. }
  3030. IF_DEBUG(TRACE2) SrvPrint0( "RestartCallNamedPipe complete\n" );
  3031. return;
  3032. } // RestartMailslotWrite
  3033. VOID SRVFASTCALL
  3034. SrvRestartExecuteTransaction (
  3035. IN OUT PWORK_CONTEXT WorkContext
  3036. )
  3037. /*++
  3038. Routine Description:
  3039. This is the restart routine for Transaction SMBs that need to be
  3040. queued pending the completion of a raw write.
  3041. Arguments:
  3042. WorkContext - A pointer to a WORK_CONTEXT block.
  3043. Return Value:
  3044. None.
  3045. --*/
  3046. {
  3047. SMB_STATUS status;
  3048. PAGED_CODE( );
  3049. status = ExecuteTransaction( WorkContext );
  3050. ASSERT( status == SmbStatusInProgress );
  3051. return;
  3052. } // SrvRestartExecuteTransaction
  3053. VOID SRVFASTCALL
  3054. RestartIpxMultipieceSend (
  3055. IN OUT PWORK_CONTEXT WorkContext
  3056. )
  3057. /*++
  3058. Routine Description:
  3059. Processes send completion for a multipiece Transaction response over IPX.
  3060. Arguments:
  3061. WorkContext - Supplies a pointer to a work context block. The
  3062. block contains information about the last SMB received for
  3063. the transaction.
  3064. WorkContext->Parameters.Transaction supplies a referenced
  3065. pointer to a transaction block. All block pointer fields in the
  3066. block are valid. Pointers to the setup words and parameter and
  3067. data bytes, and the lengths of these items, are valid. The
  3068. transaction block is on the connection's pending transaction
  3069. list.
  3070. Return Value:
  3071. None.
  3072. --*/
  3073. {
  3074. PTRANSACTION transaction = WorkContext->Parameters.Transaction;
  3075. PAGED_CODE( );
  3076. //
  3077. // If the I/O request failed or was canceled, or if the connection
  3078. // is no longer active, clean up. (The connection is marked as
  3079. // closing when it is disconnected or when the endpoint is closed.)
  3080. //
  3081. // !!! If I/O failure, should we drop the connection?
  3082. //
  3083. if ( WorkContext->Irp->Cancel ||
  3084. !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ||
  3085. (GET_BLOCK_STATE(WorkContext->Connection) != BlockStateActive) ) {
  3086. IF_DEBUG(TRACE2) {
  3087. if ( WorkContext->Irp->Cancel ) {
  3088. SrvPrint0( " I/O canceled\n" );
  3089. } else if ( !NT_SUCCESS(WorkContext->Irp->IoStatus.Status) ) {
  3090. SrvPrint1( " I/O failed: %X\n",
  3091. WorkContext->Irp->IoStatus.Status );
  3092. } else {
  3093. SrvPrint0( " Connection no longer active\n" );
  3094. }
  3095. }
  3096. //
  3097. // Close the transaction. Indicate that SMB processing is
  3098. // complete.
  3099. //
  3100. IF_DEBUG(ERRORS) {
  3101. SrvPrint1( "I/O error. Closing transaction 0x%p\n", transaction );
  3102. }
  3103. SrvCloseTransaction( transaction );
  3104. }
  3105. //
  3106. // We had a reference to this transaction during the send. Remove it.
  3107. //
  3108. DEBUG WorkContext->Parameters.Transaction = NULL;
  3109. SrvDereferenceTransaction( transaction );
  3110. SrvRestartFsdComplete( WorkContext );
  3111. return;
  3112. } // RestartIpxMultipieceSend
  3113. VOID SRVFASTCALL
  3114. RestartIpxTransactionResponse (
  3115. IN OUT PWORK_CONTEXT WorkContext
  3116. )
  3117. /*++
  3118. Routine Description:
  3119. Processes send completion for a Transaction response. If more
  3120. responses are required, it builds and sends the next one. If all
  3121. responses have been sent, it closes the transaction.
  3122. Arguments:
  3123. WorkContext - Supplies a pointer to a work context block. The
  3124. block contains information about the last SMB received for
  3125. the transaction.
  3126. WorkContext->Parameters.Transaction supplies a referenced
  3127. pointer to a transaction block. All block pointer fields in the
  3128. block are valid. Pointers to the setup words and parameter and
  3129. data bytes, and the lengths of these items, are valid. The
  3130. transaction block is on the connection's pending transaction
  3131. list.
  3132. Return Value:
  3133. None.
  3134. --*/
  3135. {
  3136. PTRANSACTION transaction;
  3137. PSMB_HEADER header;
  3138. PRESP_TRANSACTION response;
  3139. PRESP_NT_TRANSACTION ntResponse;
  3140. PCONNECTION connection;
  3141. CLONG maxSize;
  3142. PSMB_USHORT byteCountPtr;
  3143. PCHAR paramPtr;
  3144. CLONG paramLength;
  3145. CLONG paramOffset;
  3146. CLONG paramDisp;
  3147. PCHAR dataPtr;
  3148. CLONG dataLength;
  3149. CLONG dataOffset;
  3150. CLONG dataDisp;
  3151. CLONG sendLength;
  3152. BOOLEAN ntTransaction;
  3153. PAGED_CODE( );
  3154. transaction = WorkContext->Parameters.Transaction;
  3155. paramDisp = transaction->ParameterDisplacement;
  3156. dataDisp = transaction->DataDisplacement;
  3157. IF_DEBUG(WORKER1) SrvPrint0( " - RestartIpxTransactionResponse\n" );
  3158. //
  3159. // Get the connection pointer. The connection pointer is a
  3160. // referenced pointer.
  3161. //
  3162. connection = WorkContext->Connection;
  3163. IF_DEBUG(TRACE2) {
  3164. SrvPrint2( " connection 0x%p, endpoint 0x%p\n",
  3165. connection, WorkContext->Endpoint );
  3166. }
  3167. IF_SMB_DEBUG(TRANSACTION1) {
  3168. SrvPrint2( "Continuing transaction response; block 0x%p, name %wZ\n",
  3169. transaction, &transaction->TransactionName );
  3170. SrvPrint3( "Connection 0x%p, session 0x%p, tree connect 0x%p\n",
  3171. transaction->Connection, transaction->Session,
  3172. transaction->TreeConnect );
  3173. SrvPrint2( "Remaining: parameters %ld bytes, data %ld bytes\n",
  3174. transaction->ParameterCount - paramDisp,
  3175. transaction->DataCount - dataDisp );
  3176. }
  3177. //
  3178. // Update the parameters portion of the response, reusing the last
  3179. // SMB.
  3180. //
  3181. ASSERT( transaction->Inserted );
  3182. header = WorkContext->ResponseHeader;
  3183. response = (PRESP_TRANSACTION)WorkContext->ResponseParameters;
  3184. ntResponse = (PRESP_NT_TRANSACTION)WorkContext->ResponseParameters;
  3185. if ( WorkContext->NextCommand == SMB_COM_NT_TRANSACT ) {
  3186. ntTransaction = TRUE;
  3187. ntResponse->WordCount = (UCHAR)18;
  3188. ntResponse->SetupCount = 0;
  3189. ntResponse->Reserved1 = 0;
  3190. SmbPutUshort( &ntResponse->Reserved2, 0 );
  3191. SmbPutUlong( &ntResponse->TotalParameterCount,
  3192. transaction->ParameterCount
  3193. );
  3194. SmbPutUlong( &ntResponse->TotalDataCount,
  3195. transaction->DataCount
  3196. );
  3197. //
  3198. // Save a pointer to the byte count field. Calculate how much of
  3199. // the parameters and data can be sent in this response. The
  3200. // maximum amount we can send is minimum of the size of our buffer
  3201. // and the size of the client's buffer.
  3202. //
  3203. // The parameter and data byte blocks are aligned on longword
  3204. // boundaries in the message.
  3205. //
  3206. byteCountPtr = (PSMB_USHORT)ntResponse->Buffer;
  3207. } else {
  3208. ntTransaction = FALSE;
  3209. response->WordCount = (UCHAR)10;
  3210. response->SetupCount = 0;
  3211. SmbPutUshort( &response->Reserved, 0 );
  3212. SmbPutUshort( &response->TotalParameterCount,
  3213. (USHORT)transaction->ParameterCount
  3214. );
  3215. SmbPutUshort( &response->TotalDataCount,
  3216. (USHORT)transaction->DataCount
  3217. );
  3218. //
  3219. // Save a pointer to the byte count field. Calculate how much of
  3220. // the parameters and data can be sent in this response. The
  3221. // maximum amount we can send is minimum of the size of our buffer
  3222. // and the size of the client's buffer.
  3223. //
  3224. // The parameter and data byte blocks are aligned on longword
  3225. // boundaries in the message.
  3226. //
  3227. byteCountPtr = (PSMB_USHORT)response->Buffer;
  3228. }
  3229. maxSize = MIN(
  3230. WorkContext->ResponseBuffer->BufferLength,
  3231. (CLONG)transaction->Session->MaxBufferSize
  3232. );
  3233. paramPtr = (PCHAR)(byteCountPtr + 1); // first legal location
  3234. paramOffset = PTR_DIFF(paramPtr, header); // offset from start of header
  3235. paramOffset = (paramOffset + 3) & ~3; // round to next longword
  3236. paramPtr = (PCHAR)header + paramOffset; // actual location
  3237. paramLength = transaction->ParameterCount - paramDisp;
  3238. // assume all parameters fit
  3239. if ( (paramOffset + paramLength) > maxSize ) {
  3240. //
  3241. // Not all of the parameter bytes will fit. Send the maximum
  3242. // number of longwords that will fit. Don't send any data bytes
  3243. // in this message.
  3244. //
  3245. paramLength = maxSize - paramOffset; // max that will fit
  3246. paramLength = paramLength & ~3; // round down to longword
  3247. dataLength = 0; // don't send data bytes
  3248. dataOffset = 0;
  3249. dataPtr = paramPtr + paramLength; // make calculations work
  3250. } else {
  3251. //
  3252. // All of the parameter bytes fit. Calculate how many of data
  3253. // bytes fit.
  3254. //
  3255. dataPtr = paramPtr + paramLength; // first legal location
  3256. dataOffset = PTR_DIFF(dataPtr, header); // offset from start of header
  3257. dataOffset = (dataOffset + 3) & ~3; // round to next longword
  3258. dataPtr = (PCHAR)header + dataOffset; // actual location
  3259. dataLength = transaction->DataCount - dataDisp;
  3260. // assume all data bytes fit
  3261. if ( (dataOffset + dataLength) > maxSize ) {
  3262. //
  3263. // Not all of the data bytes will fit. Send the maximum
  3264. // number of longwords that will fit.
  3265. //
  3266. dataLength = maxSize - dataOffset; // max that will fit
  3267. dataLength = dataLength & ~3; // round down to longword
  3268. }
  3269. }
  3270. //
  3271. // Finish filling in the response parameters.
  3272. //
  3273. if ( ntTransaction) {
  3274. SmbPutUlong( &ntResponse->ParameterCount, paramLength );
  3275. SmbPutUlong( &ntResponse->ParameterOffset, paramOffset );
  3276. SmbPutUlong( &ntResponse->ParameterDisplacement, paramDisp );
  3277. SmbPutUlong( &ntResponse->DataCount, dataLength );
  3278. SmbPutUlong( &ntResponse->DataOffset, dataOffset );
  3279. SmbPutUlong( &ntResponse->DataDisplacement, dataDisp );
  3280. } else {
  3281. SmbPutUshort( &response->ParameterCount, (USHORT)paramLength );
  3282. SmbPutUshort( &response->ParameterOffset, (USHORT)paramOffset );
  3283. SmbPutUshort( &response->ParameterDisplacement, (USHORT)paramDisp );
  3284. SmbPutUshort( &response->DataCount, (USHORT)dataLength );
  3285. SmbPutUshort( &response->DataOffset, (USHORT)dataOffset );
  3286. SmbPutUshort( &response->DataDisplacement, (USHORT)dataDisp );
  3287. }
  3288. transaction->ParameterDisplacement = paramDisp + paramLength;
  3289. transaction->DataDisplacement = dataDisp + dataLength;
  3290. SmbPutUshort(
  3291. byteCountPtr,
  3292. (USHORT)(dataPtr - (PCHAR)(byteCountPtr + 1) + dataLength)
  3293. );
  3294. //
  3295. // Copy the appropriate parameter and data bytes into the message.
  3296. //
  3297. // !!! Note that it would be possible to use the chain send
  3298. // capabilities of TDI to send the parameter and data bytes from
  3299. // their own buffers. There is extra overhead involved in doing
  3300. // this, however, because the buffers must be locked down and
  3301. // mapped into system space so that the network drivers can look
  3302. // at them.
  3303. //
  3304. if ( paramLength != 0 ) {
  3305. RtlMoveMemory(
  3306. paramPtr,
  3307. transaction->OutParameters + paramDisp,
  3308. paramLength
  3309. );
  3310. }
  3311. if ( dataLength != 0 ) {
  3312. RtlMoveMemory(
  3313. dataPtr,
  3314. transaction->OutData + dataDisp,
  3315. dataLength
  3316. );
  3317. }
  3318. //
  3319. // Calculate the length of the response message.
  3320. //
  3321. sendLength = (CLONG)( dataPtr + dataLength -
  3322. (PCHAR)WorkContext->ResponseHeader );
  3323. WorkContext->ResponseBuffer->DataLength = sendLength;
  3324. //
  3325. // If this is the last part of the response, reenable statistics
  3326. // gathering and restore the start time to the work context block.
  3327. //
  3328. header->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  3329. if ( ((paramLength + paramDisp) == transaction->ParameterCount) &&
  3330. ((dataLength + dataDisp) == transaction->DataCount) ) {
  3331. //
  3332. // This is the final piece. Close the transaction.
  3333. //
  3334. WorkContext->StartTime = transaction->StartTime;
  3335. SrvCloseTransaction( transaction );
  3336. SrvDereferenceTransaction( transaction );
  3337. //
  3338. // Send the response.
  3339. //
  3340. SRV_START_SEND_2(
  3341. WorkContext,
  3342. SrvFsdRestartSmbAtSendCompletion,
  3343. NULL,
  3344. NULL
  3345. );
  3346. } else {
  3347. WorkContext->ResponseBuffer->Mdl->ByteCount = sendLength;
  3348. //
  3349. // Send out the response. When the send completes,
  3350. // RestartTransactionResponse is called to either send the next
  3351. // message or close the transaction.
  3352. //
  3353. // Note that the response bit in the SMB header is already set.
  3354. //
  3355. WorkContext->FspRestartRoutine = RestartIpxMultipieceSend;
  3356. WorkContext->FsdRestartRoutine = NULL;
  3357. transaction->MultipieceIpxSend = TRUE;
  3358. SrvIpxStartSend( WorkContext, SrvQueueWorkToFspAtSendCompletion );
  3359. }
  3360. //
  3361. // The response send is in progress.
  3362. //
  3363. IF_DEBUG(TRACE2) SrvPrint0( "RestartIpxTransactionResponse complete\n" );
  3364. return;
  3365. } // RestartIpxTransactionResponse