Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

698 lines
19 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbproc.c
  5. Abstract:
  6. This module contains the high-level routines for processing SMBs.
  7. Current contents:
  8. SrvEndSmbProcessing
  9. SrvProcessSmb
  10. SrvRestartFsdComplete
  11. SrvRestartSmbReceived
  12. SrvSmbIllegalCommand
  13. SrvSmbNotImplemented
  14. SrvTransactionNotImplemented
  15. Author:
  16. David Treadwell (davidtr) 25-Sept-1989
  17. Chuck Lenzmeier
  18. Revision History:
  19. --*/
  20. #include "precomp.h"
  21. #include "smbproc.tmh"
  22. #pragma hdrstop
  23. #define BugCheckFileId SRV_FILE_SMBPROC
  24. #ifdef ALLOC_PRAGMA
  25. //#pragma alloc_text( PAGE, SrvEndSmbProcessing )
  26. //#pragma alloc_text( PAGE, SrvProcessSmb )
  27. #pragma alloc_text( PAGE, SrvRestartFsdComplete )
  28. //#pragma alloc_text( PAGE, SrvRestartReceive )
  29. #pragma alloc_text( PAGE, SrvRestartSmbReceived )
  30. #pragma alloc_text( PAGE, SrvSmbIllegalCommand )
  31. #pragma alloc_text( PAGE, SrvSmbNotImplemented )
  32. #pragma alloc_text( PAGE, SrvTransactionNotImplemented )
  33. #endif
  34. USHORT SessionInvalidateCommand = 0xFFFF;
  35. USHORT SessionInvalidateIndex = 0;
  36. USHORT SessionInvalidateMod = 100;
  37. VOID
  38. SrvEndSmbProcessing (
  39. IN OUT PWORK_CONTEXT WorkContext,
  40. IN SMB_STATUS SmbStatus
  41. )
  42. /*++
  43. Routine Description:
  44. This routine is called when all request processing on an SMB is
  45. complete. If no response is to be sent, this routine simply cleans
  46. up and requeues the request buffer to the receive queue. If a
  47. response is to be sent, this routine starts the sending of that
  48. response; in this case SrvFsdRestartSmbComplete will do the rest of
  49. the cleanup after the send completes.
  50. Arguments:
  51. WorkContext - Supplies a pointer to the work context block
  52. containing information about the SMB.
  53. SmbStatus - Either SmbStatusSendResponse or SmbStatusNoResponse.
  54. Return Value:
  55. None.
  56. --*/
  57. {
  58. CLONG sendLength;
  59. PAGED_CODE( );
  60. IF_DEBUG(WORKER2) SrvPrint0( "SrvEndSmbProcessing entered\n" );
  61. if ( SmbStatus == SmbStatusSendResponse ) {
  62. //
  63. // A response is to be sent. The response starts at
  64. // WorkContext->ResponseHeader, and its length is calculated
  65. // using WorkContext->ResponseParameters, which the SMB
  66. // processor set to point to the next location *after* the end
  67. // of the response.
  68. //
  69. sendLength = (CLONG)( (PCHAR)WorkContext->ResponseParameters -
  70. (PCHAR)WorkContext->ResponseHeader );
  71. WorkContext->ResponseBuffer->DataLength = sendLength;
  72. //
  73. // Set the bit in the SMB that indicates this is a response from
  74. // the server.
  75. //
  76. WorkContext->ResponseHeader->Flags |= SMB_FLAGS_SERVER_TO_REDIR;
  77. //
  78. // Send out the response. When the send completes,
  79. // SrvFsdRestartSmbComplete is called. We then put the original
  80. // buffer back on the receive queue.
  81. //
  82. SRV_START_SEND_2(
  83. WorkContext,
  84. SrvFsdRestartSmbAtSendCompletion,
  85. NULL,
  86. NULL
  87. );
  88. //
  89. // The send has been started. Our work is done.
  90. //
  91. IF_DEBUG(WORKER2) SrvPrint0( "SrvEndSmbProcessing complete\n" );
  92. return;
  93. }
  94. //
  95. // There was no response to send. Dereference the work item.
  96. //
  97. SrvDereferenceWorkItem( WorkContext );
  98. IF_DEBUG(WORKER2) SrvPrint0( "SrvEndSmbProcessing complete\n" );
  99. return;
  100. } // SrvEndSmbProcessing
  101. VOID SRVFASTCALL
  102. SrvProcessSmb (
  103. IN OUT PWORK_CONTEXT WorkContext
  104. )
  105. /*++
  106. Routine Description:
  107. This routine dispatches the command(s) in an SMB to the appropriate
  108. processing routines. Based on the current command code, it calls
  109. indirectly through the dispatch table (SrvFspSmbDispatchTable). The
  110. SMB processor executes the command, updates pointers into the SMB,
  111. and returns with an indication of whether there is another command
  112. to be processed. If yes, this routine dispatches the next command.
  113. If no, this routine sends a response, if any. Alternatively, if the
  114. SMB processor starts an asynchronous operation, it can indicate so,
  115. and this routine will simply return to its caller.
  116. This routine is called initially from SrvRestartSmbReceived, which
  117. is the FSP routine that gains control after a TdiReceive completion
  118. work item is queued to the FSP. It is also called from other
  119. restart routines when asynchronous operations, such as a file read,
  120. complete and there are chained (AndX) commands to process.
  121. SrvRestartSmbReceive loads SMB pointers and such into the work
  122. context block calling this routine. Notably, it copies the first
  123. command code in the SMB into WorkContext->NextCommand. When an AndX
  124. command is processed, the SMB processor must load the chained
  125. command code into NextCommand before calling this routine to process
  126. that command.
  127. Arguments:
  128. WorkContext - Supplies a pointer to the work context block
  129. containing information about the SMB to process. This block
  130. is updated during the processing of the SMB.
  131. Return Value:
  132. None.
  133. --*/
  134. {
  135. SMB_STATUS smbStatus;
  136. LONG commandIndex;
  137. PAGED_CODE( );
  138. IF_DEBUG(WORKER2) SrvPrint0( "SrvProcessSmb entered\n" );
  139. //
  140. // Loop dispatching SMB processors until a status other than
  141. // SmbStatusMoreCommands is returned. When an SMB processor returns
  142. // this command code, it also sets the next command code in
  143. // WorkContext->NextCommand, so that we can dispatch the next
  144. // command.
  145. //
  146. if( WorkContext->ProcessingCount == 1 &&
  147. WorkContext->Connection->SmbSecuritySignatureActive &&
  148. SrvCheckSmbSecuritySignature( WorkContext ) == FALSE ) {
  149. //
  150. // We've received an SMB with an invalid security signature!
  151. //
  152. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  153. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  154. return;
  155. }
  156. while ( TRUE ) {
  157. if( ( (WorkContext->NextCommand == SessionInvalidateCommand) ||
  158. (SessionInvalidateCommand == 0xFF00)
  159. ) &&
  160. !((SessionInvalidateIndex++)%SessionInvalidateMod)
  161. )
  162. {
  163. SrvVerifyUid( WorkContext, SmbGetAlignedUshort( &WorkContext->RequestHeader->Uid ) );
  164. if( WorkContext->Session )
  165. {
  166. WorkContext->Session->IsSessionExpired = TRUE;
  167. KdPrint(( "-=- Expiring Session %p -=-\n", WorkContext->Session ));
  168. }
  169. }
  170. //
  171. // The first SMB has been validated in the FSD. It is safe to
  172. // execute it now.
  173. //
  174. commandIndex = SrvSmbIndexTable[WorkContext->NextCommand];
  175. #if DBG
  176. IF_SMB_DEBUG( TRACE ) {
  177. KdPrint(( "%s @%p, Blocking %d, Count %d\n",
  178. SrvSmbDispatchTable[ commandIndex ].Name,
  179. WorkContext,
  180. WorkContext->UsingBlockingThread,
  181. WorkContext->ProcessingCount ));
  182. }
  183. #endif
  184. smbStatus = SrvSmbDispatchTable[commandIndex].Func( WorkContext );
  185. //
  186. // If the SMB processor returned SmbStatusInProgress, it started
  187. // an asynchronous operation and will restart SMB processing
  188. // when that operation completes.
  189. //
  190. if ( smbStatus == SmbStatusInProgress ) {
  191. IF_DEBUG(WORKER2) SrvPrint0( "SrvProcessSmb complete\n" );
  192. return;
  193. }
  194. //
  195. // If the SMB processor didn't return SmbStatusMoreCommands,
  196. // processing of the SMB is done. Call SrvEndSmbProcessing to
  197. // send the response, if any, and rundown the WorkContext.
  198. //
  199. // *** SrvEndSmbProcessing is a separate function so that
  200. // asynchronous restart routines have something to call when
  201. // they are done processing the SMB.
  202. //
  203. if ( smbStatus != SmbStatusMoreCommands ) {
  204. SrvEndSmbProcessing( WorkContext, smbStatus );
  205. IF_DEBUG(WORKER2) SrvPrint0( "SrvProcessSmb complete\n" );
  206. return;
  207. }
  208. //
  209. // There are more commands in the SMB. Verify the SMB to make
  210. // sure that it has a valid header, and that the word count and
  211. // byte counts are within range.
  212. //
  213. if ( !SrvValidateSmb( WorkContext ) ) {
  214. IF_DEBUG(SMB_ERRORS) {
  215. SrvPrint0( "SrvProcessSmb: Invalid SMB.\n" );
  216. SrvPrint1( " SMB received from %z\n",
  217. (PCSTRING)&WorkContext->Connection->OemClientMachineNameString );
  218. }
  219. SrvEndSmbProcessing( WorkContext, SmbStatusSendResponse );
  220. IF_DEBUG(WORKER2) SrvPrint0( "SrvProcessSmb complete\n" );
  221. return;
  222. }
  223. }
  224. // can't get here.
  225. } // SrvProcessSmb
  226. VOID SRVFASTCALL
  227. SrvRestartFsdComplete (
  228. IN OUT PWORK_CONTEXT WorkContext
  229. )
  230. /*++
  231. Routine Description:
  232. This is the restart routine invoked when SMB processing by the FSD
  233. is complete. It's necessary to get back into the FSP in order to
  234. dereference objects that were used during the processing of the SMB.
  235. This is true because dereferencing an object may cause it to be
  236. deleted, which cannot happen in the FSD.
  237. This routine first dereferences control blocks. Then, if a response
  238. SMB was sent, it checks for and processes send errors. Finally, it
  239. requeues the work context block as a receive work item.
  240. Arguments:
  241. WorkContext - Supplies a pointer to the work context block
  242. describing server-specific context for the request
  243. Return Value:
  244. None.
  245. --*/
  246. {
  247. PAGED_CODE( );
  248. IF_DEBUG(WORKER1) SrvPrint0( " - SrvRestartFsdComplete\n" );
  249. if ( WorkContext->OplockOpen ) {
  250. SrvCheckDeferredOpenOplockBreak( WorkContext );
  251. }
  252. //
  253. // Dereference the work item.
  254. //
  255. SrvDereferenceWorkItem( WorkContext );
  256. IF_DEBUG(TRACE2) SrvPrint0( "SrvRestartFsdComplete complete\n" );
  257. return;
  258. } // SrvRestartFsdComplete
  259. VOID SRVFASTCALL
  260. SrvRestartReceive (
  261. IN OUT PWORK_CONTEXT WorkContext
  262. )
  263. /*++
  264. Routine Description:
  265. This is the restart routine for TDI Receive completion. It validates
  266. the smb and setups header and parameter pointers in the work context
  267. block and before forwarding the request to SmbProcessSmb.
  268. Arguments:
  269. WorkContext - Supplies a pointer to the work context block
  270. describing server-specific context for the request.
  271. Return Value:
  272. None.
  273. --*/
  274. {
  275. PCONNECTION connection;
  276. PIRP irp;
  277. PSMB_HEADER header;
  278. ULONG length;
  279. PAGED_CODE( );
  280. IF_DEBUG(WORKER1) SrvPrint0( " - SrvRestartReceive\n" );
  281. connection = WorkContext->Connection;
  282. irp = WorkContext->Irp;
  283. //
  284. // Save the length of the received message. Store the length
  285. // in the work context block for statistics gathering.
  286. //
  287. length = (ULONG)irp->IoStatus.Information;
  288. WorkContext->RequestBuffer->DataLength = length;
  289. WorkContext->CurrentWorkQueue->stats.BytesReceived += length;
  290. //
  291. // Store in the work context block the time at which processing
  292. // of the request began. Use the time that the work item was
  293. // queued to the FSP for this purpose.
  294. //
  295. WorkContext->StartTime = WorkContext->Timestamp;
  296. //
  297. // Update the server network error count. If the TDI receive
  298. // failed or was canceled, don't try to process an SMB.
  299. //
  300. if ( !irp->Cancel &&
  301. NT_SUCCESS(irp->IoStatus.Status) ||
  302. irp->IoStatus.Status == STATUS_BUFFER_OVERFLOW ) {
  303. SrvUpdateErrorCount( &SrvNetworkErrorRecord, FALSE );
  304. if( irp->IoStatus.Status == STATUS_BUFFER_OVERFLOW ) {
  305. WorkContext->LargeIndication = TRUE;
  306. }
  307. //
  308. // We (should) have received an SMB.
  309. //
  310. SMBTRACE_SRV2(
  311. WorkContext->ResponseBuffer->Buffer,
  312. WorkContext->ResponseBuffer->DataLength
  313. );
  314. //
  315. // Initialize the error class and code fields in the header to
  316. // indicate success.
  317. //
  318. header = WorkContext->ResponseHeader;
  319. SmbPutUlong( &header->ErrorClass, STATUS_SUCCESS );
  320. //
  321. // If the connection is closing or the server is shutting down,
  322. // ignore this SMB.
  323. //
  324. if ( (GET_BLOCK_STATE(connection) == BlockStateActive) &&
  325. !SrvFspTransitioning ) {
  326. //
  327. // Verify the SMB to make sure that it has a valid header,
  328. // and that the word count and byte counts are within range.
  329. //
  330. WorkContext->NextCommand = header->Command;
  331. if ( SrvValidateSmb( WorkContext ) ) {
  332. //
  333. // If this is NOT a raw read request, clear the flag
  334. // that indicates the we just sent an oplock break II to
  335. // none. This allows subsequent raw reads to be
  336. // processed.
  337. //
  338. if ( header->Command != SMB_COM_READ_RAW ) {
  339. connection->BreakIIToNoneJustSent = FALSE;
  340. }
  341. //
  342. // Process the received SMB. The called routine is
  343. // responsible for sending any response(s) that are
  344. // needed and for getting the receive buffer back onto
  345. // the receive queue as soon as possible.
  346. //
  347. SrvProcessSmb( WorkContext );
  348. IF_DEBUG(TRACE2) SrvPrint0( "SrvRestartReceive complete\n" );
  349. return;
  350. } else {
  351. IF_DEBUG(SMB_ERRORS) {
  352. SrvPrint0( "SrvProcessSmb: Invalid SMB.\n" );
  353. SrvPrint1( " SMB received from %z\n",
  354. (PCSTRING)&WorkContext->Connection->OemClientMachineNameString );
  355. }
  356. //
  357. // The SMB is invalid. We send back an INVALID_SMB
  358. // status, unless this looks like a Read Block Raw
  359. // request, in which case we send back a zero-byte
  360. // response, so as not to confuse the redirector.
  361. //
  362. if ( header->Command != SMB_COM_READ_RAW ) {
  363. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  364. } else {
  365. WorkContext->ResponseParameters = header;
  366. }
  367. if( WorkContext->LargeIndication ) {
  368. //
  369. // We need to consume the rest of the messaage!
  370. //
  371. SrvConsumeSmbData( WorkContext );
  372. return;
  373. }
  374. SrvFsdSendResponse( WorkContext );
  375. return;
  376. }
  377. } else {
  378. SrvDereferenceWorkItem( WorkContext );
  379. return;
  380. }
  381. } else if( irp->Cancel || (irp->IoStatus.Status == STATUS_CANCELLED) ) {
  382. // The Cancel routine was called while we were receiving. Let us consume
  383. // any data left on the transport and return cancelled as the user wishes.
  384. // We don't bother to return anything if the connection is going down.
  385. if( (GET_BLOCK_STATE(connection) == BlockStateActive) &&
  386. !SrvFspTransitioning )
  387. {
  388. SrvSetSmbError( WorkContext, STATUS_CANCELLED );
  389. if( WorkContext->LargeIndication ) {
  390. //
  391. // We need to consume the rest of the messaage!
  392. //
  393. SrvConsumeSmbData( WorkContext );
  394. return;
  395. }
  396. SrvFsdSendResponse( WorkContext );
  397. return;
  398. }
  399. else
  400. {
  401. SrvDereferenceWorkItem( WorkContext );
  402. return;
  403. }
  404. } else {
  405. IF_DEBUG(NETWORK_ERRORS) {
  406. SrvPrint2( "SrvRestartReceive: status = %X for IRP %p\n",
  407. irp->IoStatus.Status, irp );
  408. }
  409. SrvUpdateErrorCount( &SrvNetworkErrorRecord, TRUE );
  410. SrvDereferenceWorkItem( WorkContext );
  411. return;
  412. }
  413. } // SrvRestartReceive
  414. VOID SRVFASTCALL
  415. SrvRestartSmbReceived (
  416. IN OUT PWORK_CONTEXT WorkContext
  417. )
  418. /*++
  419. Routine Description:
  420. This function is the worker thread restart routine for received
  421. SMBs. It calls SrvProcessSmb to start processing of the first
  422. command in the SMB.
  423. Arguments:
  424. WorkContext - Supplies a pointer to the work context block
  425. describing server-specific context for the request.
  426. Return Value:
  427. None.
  428. --*/
  429. {
  430. PAGED_CODE( );
  431. IF_DEBUG(WORKER1) SrvPrint0( " - SrvRestartSmbReceived\n" );
  432. if ( (GET_BLOCK_STATE(WorkContext->Connection) != BlockStateActive) ||
  433. SrvFspTransitioning ) {
  434. //
  435. // The connection must be disconnecting. Simply ignore this SMB.
  436. //
  437. SrvDereferenceWorkItem( WorkContext );
  438. } else {
  439. //
  440. // Process the received SMB. The called routine is responsible
  441. // for sending any response(s) that are needed and for getting
  442. // the receive buffer back onto the receive queue as soon as
  443. // possible.
  444. //
  445. SrvProcessSmb( WorkContext );
  446. }
  447. IF_DEBUG(TRACE2) SrvPrint0( "SrvRestartSmbReceived complete\n" );
  448. return;
  449. } // SrvRestartSmbReceived
  450. SMB_PROCESSOR_RETURN_TYPE SRVFASTCALL
  451. SrvSmbIllegalCommand (
  452. SMB_PROCESSOR_PARAMETERS
  453. )
  454. /*++
  455. Routine Description:
  456. This routine is called to process SMBs that have an illegal
  457. (unassigned) command code. It builds an error response.
  458. Arguments:
  459. SMB_PROCESSOR_PARAMETERS - See smbprocs.h for a description
  460. of the parameters to SMB processor routines.
  461. Return Value:
  462. SMB_PROCESSOR_RETURN_TYPE - See smbprocs.h
  463. --*/
  464. {
  465. PAGED_CODE( );
  466. IF_DEBUG(SMB_ERRORS) {
  467. SrvPrint1( "SrvSmbIllegalCommand: command code 0x%lx\n",
  468. (ULONG)WorkContext->NextCommand );
  469. }
  470. SrvLogInvalidSmb( WorkContext );
  471. SrvSetSmbError( WorkContext, STATUS_SMB_BAD_COMMAND );
  472. return SmbStatusSendResponse;
  473. } // SrvSmbIllegalCommand
  474. SMB_PROCESSOR_RETURN_TYPE
  475. SrvSmbNotImplemented (
  476. SMB_PROCESSOR_PARAMETERS
  477. )
  478. {
  479. PAGED_CODE( );
  480. INTERNAL_ERROR(
  481. ERROR_LEVEL_UNEXPECTED,
  482. "SrvSmbNotImplemented: command code 0x%lx",
  483. (ULONG)WorkContext->NextCommand,
  484. NULL
  485. );
  486. SrvSetSmbError( WorkContext, STATUS_NOT_IMPLEMENTED );
  487. return SmbStatusSendResponse;
  488. } // SrvSmbNotImplemented
  489. SMB_TRANS_STATUS
  490. SrvTransactionNotImplemented (
  491. IN OUT PWORK_CONTEXT WorkContext
  492. )
  493. {
  494. PTRANSACTION transaction = WorkContext->Parameters.Transaction;
  495. PAGED_CODE( );
  496. DEBUG SrvPrint1( "SrvTransactionNotImplemented: function code %lx\n",
  497. SmbGetUlong( (PULONG)&transaction->InSetup[0] ) );
  498. SrvSetSmbError( WorkContext, STATUS_NOT_IMPLEMENTED );
  499. return SmbTransStatusErrorWithoutData;
  500. } // SrvTransactionNotImplemented