Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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