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.

1239 lines
43 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. sndrcv.c
  5. Abstract:
  6. This module implements all functions related to transmitting and recieving SMB's on
  7. all transports. The functionality common to all transports are handled in this
  8. module while transport specific functionality are handled in the appropriate
  9. ??sndrcv.c modules.
  10. mssndrcv.c -- mailslot related send/receive functionality
  11. vcsndrcv.c -- virtual circuit(connection) related send/receive functionality
  12. Revision History:
  13. Balan Sethu Raman [SethuR] 6-March-1995
  14. Notes:
  15. --*/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, SmbCeSend)
  20. #pragma alloc_text(PAGE, SmbCeSendToServer)
  21. #endif
  22. RXDT_DefineCategory(SMBSNDRCV);
  23. #define Dbg (DEBUG_TRACE_SMBSNDRCV)
  24. extern ERESOURCE s_SmbSecuritySignatureResource;
  25. #define MIN(A,B) ((A<B)?A:B)
  26. NTSTATUS
  27. SmbAddSmbSecuritySignature(
  28. IN PSMBCE_SERVER Server,
  29. IN OUT PMDL Mdl,
  30. IN OUT ULONG *ServerIndex,
  31. IN ULONG SendLength);
  32. char MRxSmbMiniSniff_SurrogateFormat[] = "%S%S%N%N%N%N%N%N%N";
  33. //// 2 3 4 5 6 7 8 9
  34. char MRxSmbMiniSniff_ActualFormat[] = "Minisniff (%s) srv %lx cmd/mid %lx status %lx len %04lx flg %06lx xc %08lx rx %08lx";
  35. char MRxSmbMiniSniffTranceive[] = "Tranceive";
  36. char MRxSmbMiniSniffReceive[] = "Receive";
  37. char MRxSmbMiniSniffReceiveEcho[] = "RcvEcho";
  38. char MRxSmbMiniSniffReceiveDiscard[] = "RcvDiscard";
  39. char MRxSmbMiniSniffReceiveDiscardOplock[] = "RcvDiscardOplock";
  40. char MRxSmbMiniSniffReceiveIndicateOplock[] = "RcvIndicateOplock";
  41. char MRxSmbMiniSniffSend[] = "Send";
  42. char MRxSmbMiniSniffSendSrv[] = "SendToServer";
  43. VOID
  44. RxMiniSniffer(
  45. IN PSZ TagString,
  46. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  47. IN ULONG Length,
  48. IN PSMB_EXCHANGE pExchange,
  49. IN PSMB_HEADER pSmbHeader
  50. )
  51. {
  52. PRX_CONTEXT RxContext = NULL;
  53. USHORT Mid = SmbGetUshort(&pSmbHeader->Mid);
  54. ULONG Status = SmbGetUlong(&((PNT_SMB_HEADER)pSmbHeader)->Status.NtStatus);
  55. USHORT Flags2 = SmbGetUshort(&pSmbHeader->Flags2);
  56. if (pExchange!=NULL) {
  57. RxContext = pExchange->RxContext;
  58. }
  59. RxLog((MRxSmbMiniSniff_SurrogateFormat, MRxSmbMiniSniff_ActualFormat,
  60. TagString,
  61. pServerEntry,
  62. (ULONG)(pSmbHeader->Command<<24) | Mid,
  63. Status,
  64. Length,
  65. (pSmbHeader->Flags<<16)|Flags2,
  66. pExchange,RxContext));
  67. SmbLog(LOG,
  68. RxMiniSniffer,
  69. LOGPTR(pServerEntry)
  70. LOGUCHAR(pSmbHeader->Command)
  71. LOGXSHORT(Mid)
  72. LOGULONG(Status)
  73. LOGULONG(Length)
  74. LOGUCHAR(pSmbHeader->Flags)
  75. LOGXSHORT(Flags2)
  76. LOGPTR(pExchange)
  77. LOGPTR(RxContext)
  78. LOGARSTR(TagString));
  79. }
  80. NTSTATUS
  81. SmbCopySendBufferForSecuritySignatures(
  82. IN PMDL pSrcMdl,
  83. IN ULONG SendLength,
  84. OUT PMDL *ppDestMdl,
  85. OUT PCHAR *ppDest
  86. )
  87. /*++
  88. Routine Description:
  89. This routine allocates a new buffer, and copies the contents of the exchange buffer
  90. into the new buffer. The new buffer is returned using the ppDestMdl & ppDest arguments.
  91. We require this double buffering so that we can ensure that nobody changes the contents
  92. of the buffer while the signature is being calculated.
  93. Arguments:
  94. pSrcMdl : MDL describing the souce buffer
  95. SendLength : Length in bytes of source buffer
  96. ppDestMdl : Address of a PMDL to return the newly allocated MDL
  97. ppDest : Address of a PCHAR to return the newly allocated buffer.
  98. Note:
  99. *ppDestMdl and *ppDest are updated only on success.
  100. Return Value:
  101. STATUS_SUCCESS - Success
  102. STATUS_INSUFFICIENT_RESOURCES if memory cannot be allocated.
  103. --*/
  104. {
  105. NTSTATUS Status;
  106. PBYTE pDest, pOriginalDest;
  107. PMDL pDestMdl;
  108. ULONG copylen;
  109. pOriginalDest = pDest = ExAllocatePoolWithTag( NonPagedPool, SendLength, MRXSMB_SECSIG_POOLTAG );
  110. if( pDest == NULL )
  111. {
  112. return STATUS_INSUFFICIENT_RESOURCES;
  113. }
  114. pDestMdl = RxAllocateMdl( pDest, SendLength );
  115. if( pDestMdl == NULL )
  116. {
  117. ExFreePool( pDest );
  118. return STATUS_INSUFFICIENT_RESOURCES;
  119. }
  120. MmBuildMdlForNonPagedPool( pDestMdl );
  121. while( pSrcMdl && (SendLength > 0) )
  122. {
  123. copylen = MIN(pSrcMdl->ByteCount, SendLength );
  124. RtlCopyMemory( pDest, pSrcMdl->MappedSystemVa, copylen );
  125. SendLength -= copylen;
  126. pDest += copylen;
  127. pSrcMdl = pSrcMdl->Next;
  128. }
  129. *ppDestMdl = pDestMdl;
  130. *ppDest = pOriginalDest;
  131. return STATUS_SUCCESS;
  132. }
  133. NTSTATUS
  134. SmbCeTranceive(
  135. PSMB_EXCHANGE pExchange,
  136. ULONG SendOptions,
  137. PMDL pSmbMdl,
  138. ULONG SendLength)
  139. /*++
  140. Routine Description:
  141. This routine transmits/receives a SMB for a give exchange
  142. Arguments:
  143. pServerEntry - the server entry
  144. pExchange - the exchange instance issuing this SMB.
  145. SendOptions - options for send
  146. pSmbMdl - the SMB that needs to be sent.
  147. SendLength - length of data to be transmitted
  148. Return Value:
  149. STATUS_PENDING - the transmit/receive request has been passed on successfully to the underlying
  150. connection engine.
  151. Other Status codes correspond to error situations.
  152. --*/
  153. {
  154. NTSTATUS Status = STATUS_SUCCESS;
  155. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  156. PSMB_HEADER pSmbHeader = MmGetSystemAddressForMdlSafe(pSmbMdl,LowPagePriority);
  157. USHORT Mid;
  158. PVOID pSendCompletionContext = NULL;
  159. PMDL pSendMdl = pSmbMdl;
  160. if (pSmbHeader == NULL) {
  161. Status = STATUS_INSUFFICIENT_RESOURCES;
  162. } else {
  163. Status = SmbCeIncrementPendingOperations(
  164. pExchange,
  165. (SMBCE_LOCAL_OPERATION | SMBCE_SEND_COMPLETE_OPERATION | SMBCE_RECEIVE_OPERATION),
  166. __FILE__,
  167. __LINE__);
  168. }
  169. if (Status == STATUS_SUCCESS) {
  170. PSMBCE_SERVER_TRANSPORT pTransport;
  171. // Ensure that the transport associated with the exchange is valid.
  172. // It is not always possible to make decisions w.r.t changing
  173. // transports since it is a function of the protocol choosen at the
  174. // higher level. Therefore no attempts to reconnect are made at this
  175. // level.
  176. if (FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_MAILSLOT_OPERATION)) {
  177. pTransport = pServerEntry->pMailSlotTransport;
  178. } else {
  179. pTransport = pServerEntry->pTransport;
  180. }
  181. if (pTransport == NULL) {
  182. Status = STATUS_CONNECTION_DISCONNECTED;
  183. }
  184. if (Status == STATUS_SUCCESS &&
  185. !(pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID)) {
  186. // Associate the exchange with a mid
  187. Status = SmbCeAssociateExchangeWithMid(pServerEntry,pExchange);
  188. }
  189. if (Status == STATUS_SUCCESS) {
  190. if (pExchange->pDispatchVector->SendCompletionHandler != NULL) {
  191. Status = SmbCeAssociateBufferWithExchange(pServerEntry,pExchange,pSmbMdl);
  192. if (Status == STATUS_SUCCESS) {
  193. pSendCompletionContext = pSmbMdl;
  194. }
  195. }
  196. // If there is no send completion handling associated with this tranceive
  197. // decrement the count.
  198. if (pSendCompletionContext == NULL) {
  199. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  200. }
  201. if (Status == STATUS_SUCCESS) {
  202. // Stamp the MID allocated for the request and send the SMB.
  203. pSmbHeader->Mid = pExchange->Mid;
  204. RxMiniSniffer(MRxSmbMiniSniffTranceive,pServerEntry,SendLength,pExchange,pSmbHeader);
  205. // Update the expiry time on the exchange if required.
  206. SmbCeSetExpiryTime(pExchange);
  207. if ( InterlockedCompareExchange(
  208. &pExchange->CancellationStatus,
  209. SMBCE_EXCHANGE_NOT_CANCELLED,
  210. SMBCE_EXCHANGE_NOT_CANCELLED) == SMBCE_EXCHANGE_NOT_CANCELLED ) {
  211. BOOLEAN ResourceAcquired = FALSE;
  212. if ( pServerEntry->SecuritySignaturesActive &&
  213. !FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_MAILSLOT_OPERATION)) {
  214. PSMBCE_SERVER Server = SmbCeGetExchangeServer(pExchange);
  215. if( !FlagOn( SendOptions, SMBCE_NO_DOUBLE_BUFFERING ) ) {
  216. ASSERT( pExchange->pBufSecSigData == NULL );
  217. Status = SmbCopySendBufferForSecuritySignatures( pSmbMdl,
  218. SendLength,
  219. &pExchange->pBufSecSigMdl,
  220. &pExchange->pBufSecSigData);
  221. pSendMdl = pExchange->pBufSecSigMdl;
  222. }
  223. if(Status == STATUS_SUCCESS) {
  224. //
  225. // The resource should be released after return from TDI to ensure serialization
  226. // of sending SMB message with security signature.
  227. //
  228. SmbCeAcquireSecuritySignatureResource();
  229. ResourceAcquired = TRUE;
  230. Status = SmbAddSmbSecuritySignature(
  231. Server,
  232. pSendMdl,
  233. &pExchange->SmbSecuritySignatureIndex,
  234. SendLength);
  235. pExchange->IsSecuritySignatureEnabled = TRUE;
  236. // the index for next request. Notice index+1 is reserved for the response
  237. Server->SmbSecuritySignatureIndex += 2;
  238. }
  239. if( !NT_SUCCESS( Status ) && ( pSendCompletionContext != NULL ) ) {
  240. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  241. }
  242. }
  243. if (Status == STATUS_SUCCESS) {
  244. pExchange->SmbCommand = pSmbHeader->Command;
  245. // Update the operation counts for the exchange instance.
  246. // Refer to Header for detailed explanation
  247. Status = (pTransport->pDispatchVector->Tranceive)(
  248. pTransport,
  249. pServerEntry,
  250. pExchange,
  251. SendOptions & (~SMBCE_NO_DOUBLE_BUFFERING),
  252. pSendMdl,
  253. SendLength,
  254. pSendCompletionContext);
  255. }
  256. if (ResourceAcquired == TRUE) {
  257. SmbCeReleaseSecuritySignatureResource();
  258. }
  259. } else {
  260. if (pSendCompletionContext != NULL) {
  261. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  262. }
  263. Status = STATUS_CANCELLED;
  264. }
  265. if ((Status != STATUS_PENDING) &&
  266. (Status != STATUS_SUCCESS)) {
  267. pExchange->Status = Status;
  268. SmbCeDecrementPendingReceiveOperations(pExchange);
  269. InterlockedIncrement(&MRxSmbStatistics.InitiallyFailedOperations);
  270. } else {
  271. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsTransmitted,1);
  272. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesTransmitted,SendLength);
  273. }
  274. } else {
  275. pExchange->Status = Status;
  276. SmbCeDecrementPendingReceiveOperations(pExchange);
  277. InterlockedIncrement(&MRxSmbStatistics.InitiallyFailedOperations);
  278. }
  279. } else {
  280. SmbCeDecrementPendingReceiveOperations(pExchange);
  281. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  282. }
  283. if ((Status != STATUS_SUCCESS) && (Status != STATUS_PENDING)) {
  284. pExchange->SmbStatus = Status;
  285. }
  286. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  287. Status = STATUS_PENDING;
  288. }
  289. return Status;
  290. }
  291. NTSTATUS
  292. SmbCeReceive(
  293. PSMB_EXCHANGE pExchange)
  294. /*++
  295. Routine Description:
  296. This routine receives a SMB for a give exchange
  297. Arguments:
  298. pExchange - the exchange instance issuing this SMB.
  299. Return Value:
  300. STATUS_SUCCESS - the exchange has been setup for receiving an SMB
  301. Other Status codes correspond to error situations.
  302. --*/
  303. {
  304. NTSTATUS Status = STATUS_SUCCESS;
  305. ASSERT(pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID);
  306. Status = SmbCeIncrementPendingOperations(pExchange, (SMBCE_RECEIVE_OPERATION),__FILE__,__LINE__);
  307. if (Status == STATUS_SUCCESS) {
  308. // Update the expiry time on the exchange if required.
  309. SmbCeSetExpiryTime(pExchange);
  310. }
  311. return Status;
  312. }
  313. NTSTATUS
  314. SmbCeSend(
  315. PSMB_EXCHANGE pExchange,
  316. ULONG SendOptions,
  317. PMDL pSmbMdl,
  318. ULONG SendLength)
  319. /*++
  320. Routine Description:
  321. This routine transmits a SMB for a give exchange
  322. Arguments:
  323. pServerEntry - the server entry
  324. pExchange - the exchange instance issuing this SMB.
  325. SendOptions - options for send
  326. pSmbMdl - the SMB that needs to be sent.
  327. SendLength - length of data to be transmitted
  328. Return Value:
  329. For asynchronous sends ....
  330. STATUS_PENDING - the request was passed onto the underlying transport and
  331. the quiescent state routine will be called in the future.
  332. any other status code -- indicates an error in passing the request and the
  333. quiescent state routine will never be called in the future.
  334. For synchronous sends
  335. the appropriate status but will never return STATUS_PENDING.
  336. Notes:
  337. This routine always expects an exchange with the appropriate SendCompletionHandler.
  338. --*/
  339. {
  340. NTSTATUS Status = STATUS_SUCCESS;
  341. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  342. PSMB_HEADER pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdlSafe(pSmbMdl,LowPagePriority);
  343. PVOID pSendCompletionContext = NULL;
  344. PMDL pSendMdl = pSmbMdl;
  345. PAGED_CODE();
  346. ASSERT(pExchange != NULL);
  347. if (pSmbHeader == NULL) {
  348. Status = STATUS_INSUFFICIENT_RESOURCES;
  349. } else {
  350. Status = SmbCeIncrementPendingOperations(
  351. pExchange,
  352. (SMBCE_LOCAL_OPERATION | SMBCE_SEND_COMPLETE_OPERATION),
  353. __FILE__,
  354. __LINE__);
  355. }
  356. if (Status == STATUS_SUCCESS) {
  357. PSMBCE_SERVER_TRANSPORT pTransport;
  358. // Ensure that the transport associated with the exchange is valid.
  359. // It is not always possible to make decisions w.r.t changing
  360. // transports since it is a function of the protocol choosen at the
  361. // higher level. Therefore no attempts to reconnect are made at this
  362. // level.
  363. if (FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_MAILSLOT_OPERATION)) {
  364. pTransport = pServerEntry->pMailSlotTransport;
  365. } else {
  366. pTransport = pServerEntry->pTransport;
  367. }
  368. ASSERT(pTransport != NULL);
  369. if (SmbCeGetServerType(pServerEntry) == SMBCEDB_FILE_SERVER) {
  370. if (!(pExchange->SmbCeFlags & SMBCE_EXCHANGE_MID_VALID)) {
  371. // Associate the exchange with a mid if it does not already have a valid mid.
  372. Status = SmbCeAssociateExchangeWithMid(pServerEntry,pExchange);
  373. }
  374. if (Status == STATUS_SUCCESS) {
  375. // if the MID association was successful copy the MID onto the SMB and setup
  376. // a send completion context if required
  377. pSmbHeader->Mid = pExchange->Mid;
  378. if (!(SendOptions & RXCE_SEND_SYNCHRONOUS)) {
  379. ASSERT(pExchange->pDispatchVector->SendCompletionHandler != NULL);
  380. Status = SmbCeAssociateBufferWithExchange(pServerEntry,pExchange,pSmbMdl);
  381. if (Status == STATUS_SUCCESS) {
  382. pSendCompletionContext = pSmbMdl;
  383. }
  384. }
  385. }
  386. }
  387. if ((pSendCompletionContext == NULL) ||
  388. (Status != STATUS_SUCCESS)) {
  389. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  390. }
  391. if (Status == STATUS_SUCCESS) {
  392. // Update the expiry time on the exchange if required.
  393. SmbCeSetExpiryTime(pExchange);
  394. if (InterlockedCompareExchange(
  395. &pExchange->CancellationStatus,
  396. SMBCE_EXCHANGE_NOT_CANCELLED,
  397. SMBCE_EXCHANGE_NOT_CANCELLED) == SMBCE_EXCHANGE_NOT_CANCELLED) {
  398. BOOLEAN ResourceAcquired = FALSE;
  399. if (pServerEntry->SecuritySignaturesActive &&
  400. !FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_MAILSLOT_OPERATION)) {
  401. PSMBCE_SERVER Server = SmbCeGetExchangeServer(pExchange);
  402. if (Server != NULL) {
  403. if( !FlagOn( SendOptions, SMBCE_NO_DOUBLE_BUFFERING ) ) {
  404. ASSERT( pExchange->pBufSecSigData == NULL );
  405. Status = SmbCopySendBufferForSecuritySignatures( pSmbMdl,
  406. SendLength,
  407. &pExchange->pBufSecSigMdl,
  408. &pExchange->pBufSecSigData);
  409. pSendMdl = pExchange->pBufSecSigMdl;
  410. }
  411. if(Status == STATUS_SUCCESS) {
  412. // The resource should be released after return from TDI to ensure serialization
  413. // of sending SMB message with security signature.
  414. SmbCeAcquireSecuritySignatureResource();
  415. ResourceAcquired = TRUE;
  416. Status = SmbAddSmbSecuritySignature(
  417. Server,
  418. pSendMdl,
  419. &pExchange->SmbSecuritySignatureIndex,
  420. SendLength);
  421. pExchange->IsSecuritySignatureEnabled = TRUE;
  422. // the index for next request
  423. Server->SmbSecuritySignatureIndex += 2;
  424. }
  425. }
  426. if( !NT_SUCCESS( Status ) && ( pSendCompletionContext != NULL ) ) {
  427. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  428. }
  429. }
  430. if (Status == STATUS_SUCCESS) {
  431. pExchange->SmbCommand = pSmbHeader->Command;
  432. Status = (pTransport->pDispatchVector->Send)(
  433. pTransport,
  434. pServerEntry,
  435. SendOptions & (~SMBCE_NO_DOUBLE_BUFFERING),
  436. pSendMdl,
  437. SendLength,
  438. pSendCompletionContext);
  439. }
  440. if (ResourceAcquired == TRUE) {
  441. SmbCeReleaseSecuritySignatureResource();
  442. }
  443. } else {
  444. if (pSendCompletionContext != NULL) {
  445. SmbCeDecrementPendingSendCompleteOperations(pExchange);
  446. }
  447. Status = STATUS_CANCELLED;
  448. }
  449. }
  450. RxMiniSniffer(MRxSmbMiniSniffSend,pServerEntry,SendLength,pExchange,pSmbHeader);
  451. if ((Status != STATUS_SUCCESS) && (Status != STATUS_PENDING)) {
  452. pExchange->SmbStatus = Status;
  453. InterlockedIncrement(&MRxSmbStatistics.InitiallyFailedOperations);
  454. } else {
  455. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsTransmitted,1);
  456. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesTransmitted,SendLength);
  457. }
  458. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  459. if (!(SendOptions & RXCE_SEND_SYNCHRONOUS)) {
  460. Status = STATUS_PENDING;
  461. } else {
  462. ASSERT(Status != STATUS_PENDING);
  463. }
  464. }
  465. return Status;
  466. }
  467. NTSTATUS
  468. SmbCeSendToServer(
  469. PSMBCEDB_SERVER_ENTRY pServerEntry,
  470. ULONG SendOptions,
  471. PMDL pSmbMdl,
  472. ULONG SendLength)
  473. /*++
  474. Routine Description:
  475. This routine transmits a SMB to a given server synchronously.
  476. Arguments:
  477. pServerEntry - the server entry
  478. SendOptions - options for send
  479. pSmbMdl - the SMB that needs to be sent.
  480. SendLength - length of data to be transmitted
  481. Return Value:
  482. STATUS_SUCCESS if successful
  483. otherwise appropriate error code
  484. --*/
  485. {
  486. NTSTATUS Status = STATUS_SUCCESS;
  487. PSMB_HEADER pSmbHeader = (PSMB_HEADER)MmGetSystemAddressForMdlSafe(pSmbMdl,LowPagePriority);
  488. PVOID pSendCompletionContext = NULL;
  489. PMDL pSendMdl = pSmbMdl;
  490. PCHAR pDest = NULL;
  491. PAGED_CODE();
  492. if (pSmbHeader == NULL) {
  493. Status = STATUS_INSUFFICIENT_RESOURCES;
  494. } else {
  495. if (pServerEntry->pTransport != NULL) {
  496. BOOLEAN ResourceAcquired = FALSE;
  497. if (pServerEntry->SecuritySignaturesActive) {
  498. PSMBCE_SERVER Server = &pServerEntry->Server;
  499. ULONG Index;
  500. if (Server != NULL) {
  501. Status = SmbCopySendBufferForSecuritySignatures(pSmbMdl,SendLength, &pSendMdl, &pDest);
  502. if(Status == STATUS_SUCCESS) {
  503. // The resource should be released after return from TDI to ensure serialization
  504. // of sending SMB message with security signature.
  505. SmbCeAcquireSecuritySignatureResource();
  506. ResourceAcquired = TRUE;
  507. Status = SmbAddSmbSecuritySignature(
  508. Server,
  509. pSendMdl,
  510. &Index,
  511. SendLength);
  512. // the index for next request
  513. Server->SmbSecuritySignatureIndex ++;
  514. }
  515. }
  516. }
  517. Status = (pServerEntry->pTransport->pDispatchVector->Send)(
  518. pServerEntry->pTransport,
  519. pServerEntry,
  520. (SendOptions | RXCE_SEND_SYNCHRONOUS),
  521. pSendMdl,
  522. SendLength,
  523. pSendCompletionContext);
  524. if (ResourceAcquired == TRUE) {
  525. SmbCeReleaseSecuritySignatureResource();
  526. }
  527. if( pDest )
  528. {
  529. ExFreePool( pDest );
  530. IoFreeMdl( pSendMdl );
  531. }
  532. if (!NT_SUCCESS(Status)) {
  533. InterlockedIncrement(&MRxSmbStatistics.InitiallyFailedOperations);
  534. } else {
  535. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsTransmitted,1);
  536. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesTransmitted,SendLength);
  537. RxMiniSniffer(MRxSmbMiniSniffSendSrv,pServerEntry,SendLength,NULL,pSmbHeader);
  538. }
  539. } else {
  540. Status = RX_MAP_STATUS(CONNECTION_DISCONNECTED);
  541. }
  542. }
  543. ASSERT(Status != STATUS_PENDING);
  544. return Status;
  545. }
  546. NTSTATUS
  547. SmbCeReceiveInd(
  548. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  549. IN ULONG BytesIndicated,
  550. IN ULONG BytesAvailable,
  551. OUT ULONG *pBytesTaken,
  552. IN PVOID pTsdu, // pointer describing this TSDU, typically a lump of bytes
  553. OUT PMDL *pDataBufferPointer, // the buffer in which data is to be copied.
  554. OUT PULONG pDataBufferSize, // amount of data to copy
  555. IN ULONG ReceiveFlags
  556. )
  557. /*++
  558. Routine Description:
  559. This routine handles the receive indication for SMB's along all vcs in a connection to a
  560. server.
  561. Arguments:
  562. pServerEntry - the server entry
  563. BytesIndicated - the bytes that are present in the indication.
  564. BytesAvailable - the total data available
  565. pTsdu - the data
  566. pDataBufferPointer - the buffer for copying the data not indicated.
  567. pDataBufferSize - the length of the buffer
  568. Return Value:
  569. STATUS_SUCCESS -
  570. Other Status codes correspond to error situations.
  571. --*/
  572. {
  573. NTSTATUS Status;
  574. BYTE *pSmbCommand;
  575. PSMB_EXCHANGE pExchange;
  576. PSMB_HEADER pSmbHeader = (PSMB_HEADER)pTsdu;
  577. // Perform the quick tests by which ill formed SMB's, mangled SMB's can be rejected.
  578. // e.g., any indication which is of non zero length which is less then the length of
  579. // a SMB_HEADER plus the minimum SMB message body length of 3 bytes cannot be a valid
  580. // SMB.
  581. if ((BytesAvailable < sizeof(SMB_HEADER) + 2) ||
  582. (SmbGetUlong(((PULONG )pSmbHeader->Protocol)) != (ULONG)SMB_HEADER_PROTOCOL) ||
  583. (pSmbHeader->Command == SMB_COM_NO_ANDX_COMMAND) ) {
  584. RxLog(("SmbCeReceiveInd: Invalid Response for %lx\n",pServerEntry));
  585. SmbLogError(STATUS_UNSUCCESSFUL,
  586. LOG,
  587. SmbCeReceiveInd,
  588. LOGPTR(pServerEntry)
  589. LOGUSTR(pServerEntry->Name));
  590. *pBytesTaken = BytesIndicated;
  591. return STATUS_SUCCESS;
  592. }
  593. ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
  594. if (pSmbHeader->Command == SMB_COM_ECHO) {
  595. PSMBCE_RESUMPTION_CONTEXT pResumptionContext = NULL;
  596. InterlockedExchange(
  597. &pServerEntry->Server.EchoProbeState,
  598. ECHO_PROBE_IDLE);
  599. pServerEntry->Server.EchoExpiryTime.QuadPart = 0;
  600. *pBytesTaken = BytesIndicated;
  601. RxMiniSniffer(MRxSmbMiniSniffReceiveEcho,pServerEntry,BytesIndicated,NULL,pSmbHeader);
  602. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  603. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,BytesIndicated);
  604. return STATUS_SUCCESS;
  605. }
  606. // Perform the tests for detecting oplock break SMB's. These are SMB's with the
  607. // command SMB_COM_LOCKING_ANDX with the LOCKING_ANDX_OPLOCK_RELEASE bit set.
  608. // These SMB's are transformed into buffering state change requests which are
  609. // processed by the RDBSS.
  610. // CODE.IMPROVEMENT -- raw mode handling needs to be incorporated
  611. //
  612. if (pSmbHeader->Command == SMB_COM_LOCKING_ANDX) {
  613. if (BytesIndicated == LOCK_BROKEN_SIZE) {
  614. PREQ_LOCKING_ANDX pOplockBreakRequest = (PREQ_LOCKING_ANDX)(pSmbHeader + 1);
  615. if (SmbGetUshort(&pOplockBreakRequest->LockType) & LOCKING_ANDX_OPLOCK_RELEASE) {
  616. ULONG NewOplockLevel;
  617. switch (pOplockBreakRequest->OplockLevel) {
  618. case OPLOCK_BROKEN_TO_II:
  619. NewOplockLevel = SMB_OPLOCK_LEVEL_II;
  620. break;
  621. case OPLOCK_BROKEN_TO_NONE:
  622. default:
  623. NewOplockLevel = SMB_OPLOCK_LEVEL_NONE;
  624. }
  625. RxMiniSniffer(MRxSmbMiniSniffReceiveIndicateOplock,pServerEntry,BytesIndicated,NULL,pSmbHeader);
  626. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  627. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,BytesIndicated);
  628. if (pServerEntry->pRdbssSrvCall != NULL) {
  629. RxIndicateChangeOfBufferingState(
  630. pServerEntry->pRdbssSrvCall,
  631. MRxSmbMakeSrvOpenKey(pSmbHeader->Tid,pOplockBreakRequest->Fid),
  632. ULongToPtr(NewOplockLevel));
  633. }
  634. RxDbgTrace(0,Dbg,("SmbCeReceiveInd: OPLOCK Break Request TID(%lx) FID(%lx)\n",
  635. pSmbHeader->Tid,pOplockBreakRequest->Fid));
  636. RxLog(("OPLOCK Break: FID %lx Level %x\n",pOplockBreakRequest->Fid,pOplockBreakRequest->OplockLevel));
  637. SmbLog(LOG,
  638. SmbCeReceiveInd_2,
  639. LOGXSHORT(pOplockBreakRequest->Fid)
  640. LOGUCHAR(pOplockBreakRequest->OplockLevel)
  641. LOGPTR(pServerEntry)
  642. LOGUSTR(pServerEntry->Name));
  643. //DbgPrint("OPLOCK Break: FID %lx Level %x\n",pOplockBreakRequest->Fid,pOplockBreakRequest->OplockLevel);
  644. *pBytesTaken = BytesIndicated;
  645. return STATUS_SUCCESS;
  646. }
  647. }
  648. }
  649. // Handle the cases when the server responds to the oplock break response.
  650. if ((pSmbHeader->Mid == SMBCE_MAILSLOT_OPERATION_MID) ||
  651. (pSmbHeader->Mid == SMBCE_OPLOCK_RESPONSE_MID)) {
  652. *pBytesTaken = BytesIndicated;
  653. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  654. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,BytesIndicated);
  655. RxMiniSniffer(MRxSmbMiniSniffReceiveDiscardOplock,pServerEntry,BytesIndicated,NULL,pSmbHeader);
  656. return STATUS_SUCCESS;
  657. }
  658. InterlockedIncrement(&pServerEntry->Server.SmbsReceivedSinceLastStrobe);
  659. // Initialize the copy data buffer and size to begin with.
  660. *pDataBufferPointer = NULL;
  661. *pDataBufferSize = 0;
  662. // Map the MID to the associated exchange.
  663. if (pSmbHeader->Command == SMB_COM_NEGOTIATE) {
  664. pExchange = SmbResetServerEntryNegotiateExchange(pServerEntry);
  665. if (pExchange != NULL) {
  666. SmbCeDecrementPendingLocalOperations(pExchange);
  667. }
  668. } else {
  669. pExchange = SmbCeMapMidToExchange(pServerEntry,pSmbHeader->Mid);
  670. }
  671. RxMiniSniffer(MRxSmbMiniSniffReceive,pServerEntry,BytesIndicated,pExchange,pSmbHeader);
  672. // check if the return command matches the send command, or command+1 on secondary transact case
  673. if ((pExchange != NULL) &&
  674. (pSmbHeader->Command != SMB_COM_NT_CANCEL) &&
  675. (pExchange->SmbCommand != pSmbHeader->Command) &&
  676. (pExchange->SmbCommand != pSmbHeader->Command + 1)) {
  677. ASSERT(FALSE);
  678. RxLog(("SmbCeReceiveInd: Invalid Response for %lx\n",pServerEntry));
  679. SmbLogError(STATUS_UNSUCCESSFUL,
  680. LOG,
  681. SmbCeReceiveInd,
  682. LOGPTR(pServerEntry)
  683. LOGUSTR(pServerEntry->Name));
  684. *pBytesTaken = BytesIndicated;
  685. return STATUS_SUCCESS;
  686. }
  687. // Note that the absence of a request entry cannot be asserted. It is conceivable that
  688. // requests could have been cancelled.
  689. if ((pExchange != NULL) &&
  690. (SmbCeIncrementPendingOperations(
  691. pExchange,
  692. (SMBCE_LOCAL_OPERATION | SMBCE_COPY_DATA_OPERATION),
  693. __FILE__,
  694. __LINE__) == STATUS_SUCCESS)) {
  695. if (pServerEntry->SecuritySignaturesActive && (BytesIndicated == BytesAvailable)) {
  696. SmbCheckSecuritySignature(pExchange,
  697. &pServerEntry->Server,
  698. BytesIndicated,
  699. pTsdu);
  700. MD5Final(&pExchange->MD5Context);
  701. if( RtlCompareMemory(&pExchange->MD5Context.digest,pExchange->ResponseSignature,SMB_SECURITY_SIGNATURE_LENGTH*sizeof(CHAR)) !=
  702. SMB_SECURITY_SIGNATURE_LENGTH*sizeof(CHAR)) {
  703. #if DBG
  704. DbgPrint("MRXSMB: SS mismatch command %X, Length %X, Expected Index Number %X\n",
  705. pSmbHeader->Command, BytesIndicated, pExchange->SmbSecuritySignatureIndex);
  706. DbgPrint(" server send length %X, mdl length %X index %X\n",
  707. SmbGetUshort(&pSmbHeader->PidHigh), SmbGetUshort(&pSmbHeader->Pid), SmbGetUshort(&pSmbHeader->Gid));
  708. // DbgBreakPoint();
  709. #endif
  710. DbgPrint("SS mismatch on receive ind, tear down connection\n");
  711. RxLog(("SmbCeReceiveInd: Invalid Security Signature\n"));
  712. pSmbHeader->ErrorClass = SMB_ERR_CLASS_SERVER;
  713. SmbPutUshort(&pSmbHeader->Error, ERROR_UNEXP_NET_ERR);
  714. SmbCeTransportDisconnectIndicated(pExchange->SmbCeContext.pServerEntry);
  715. }
  716. }
  717. // Invoke the receive indication handler
  718. Status = SMB_EXCHANGE_DISPATCH(pExchange,
  719. Receive,
  720. (pExchange,
  721. BytesIndicated,
  722. BytesAvailable,
  723. pBytesTaken,
  724. pTsdu,
  725. pDataBufferPointer,
  726. pDataBufferSize,
  727. ReceiveFlags));
  728. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  729. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,*pBytesTaken);
  730. RxDbgTrace(0, Dbg, ("SmbCeReceiveInd: SMB_EXCHANGE_DISPATCH returned %lx,taken/mdl=%08lx/%08lx\n",
  731. Status,*pBytesTaken,*pDataBufferPointer));
  732. ASSERT ( (Status==RX_MAP_STATUS(MORE_PROCESSING_REQUIRED))==((*pDataBufferPointer)!=NULL));
  733. if (Status == RX_MAP_STATUS(MORE_PROCESSING_REQUIRED)) {
  734. Status = SmbCeAssociateBufferWithExchange(pServerEntry,pExchange,*pDataBufferPointer);
  735. if (Status != STATUS_SUCCESS) {
  736. DbgPrint("VctIndReceive:Error handling copy data request %lx\n",Status);
  737. pExchange->Status = Status;
  738. *pBytesTaken = BytesAvailable;
  739. Status = STATUS_SUCCESS;
  740. } else {
  741. Status = RX_MAP_STATUS(MORE_PROCESSING_REQUIRED);
  742. }
  743. }
  744. if (pServerEntry->SecuritySignaturesActive &&
  745. (Status == RX_MAP_STATUS(MORE_PROCESSING_REQUIRED)) &&
  746. (*pBytesTaken > 0)) {
  747. ASSERT(*pBytesTaken >= sizeof(SMB_HEADER));
  748. SmbCheckSecuritySignature(pExchange,
  749. &pServerEntry->Server,
  750. *pBytesTaken,
  751. pTsdu);
  752. pExchange->MD5ContextInitialized = TRUE;
  753. }
  754. if (Status != RX_MAP_STATUS(MORE_PROCESSING_REQUIRED)) {
  755. SmbCeDecrementPendingCopyDataOperations(pExchange);
  756. } else {
  757. // Update the expiry time on the exchange if required.
  758. SmbCeSetExpiryTime(pExchange);
  759. }
  760. SmbCeDecrementPendingReceiveOperations(pExchange);
  761. SmbCeDecrementPendingLocalOperationsAndFinalize(pExchange);
  762. if (((*pBytesTaken + *pDataBufferSize) < BytesAvailable) &&
  763. (Status != RX_MAP_STATUS(MORE_PROCESSING_REQUIRED))) {
  764. RxDbgTrace(0,Dbg,("SmbCeReceiveInd:Not consuming all indicated data\n"));
  765. *pBytesTaken = BytesAvailable;
  766. }
  767. } else {
  768. // Should we change over to a strategy in which the transport pipeline is kept
  769. // open by consuming all indicated data
  770. // DbgBreakPoint();
  771. RxLog(("SmbCeReceiveInd:No resumption context %lx\n",pServerEntry));
  772. SmbLogError(STATUS_UNSUCCESSFUL,
  773. LOG,
  774. SmbCeReceiveInd_3,
  775. LOGXSHORT(pSmbHeader->Mid)
  776. LOGPTR(pServerEntry)
  777. LOGUSTR(pServerEntry->Name));
  778. Status = STATUS_SUCCESS;
  779. *pBytesTaken = BytesAvailable;
  780. }
  781. ASSERT((*pBytesTaken + *pDataBufferSize) >= BytesAvailable);
  782. //ASSERT(*pBytesTaken <= BytesIndicated);
  783. ASSERT(Status == STATUS_SUCCESS ||
  784. Status == STATUS_DATA_NOT_ACCEPTED ||
  785. Status == STATUS_MORE_PROCESSING_REQUIRED);
  786. return Status;
  787. }
  788. NTSTATUS
  789. SmbCeDataReadyInd(
  790. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  791. IN PMDL pBuffer,
  792. IN ULONG DataSize,
  793. IN NTSTATUS CopyDataStatus
  794. )
  795. /*++
  796. Routine Description:
  797. This routine handles the indication when the requested data has been copied
  798. Arguments:
  799. pServerEntry - the server instance
  800. pBuffer - the buffer being returned
  801. DataSize - the amount of data copied in bytes
  802. Return Value:
  803. STATUS_SUCCESS - the server call construction has been finalized.
  804. Other Status codes correspond to error situations.
  805. --*/
  806. {
  807. NTSTATUS Status;
  808. PSMB_EXCHANGE pExchange;
  809. // Map the buffer to the exchange
  810. pExchange = SmbCeGetExchangeAssociatedWithBuffer(pServerEntry,pBuffer);
  811. RxDbgTrace(0, Dbg, ("VctIndDataReady: Processing Exchange %lx\n",pExchange));
  812. if (pExchange != NULL) {
  813. if (CopyDataStatus == STATUS_SUCCESS && pServerEntry->SecuritySignaturesActive) {
  814. BOOLEAN Secure;
  815. if (pExchange->MD5ContextInitialized) {
  816. Secure = SmbCheckSecuritySignaturePartial(pExchange,
  817. &pServerEntry->Server,
  818. DataSize,
  819. pBuffer);
  820. } else {
  821. Secure = SmbCheckSecuritySignatureWithMdl(pExchange,
  822. &pServerEntry->Server,
  823. DataSize,
  824. pBuffer);
  825. }
  826. if (!Secure) {
  827. DbgPrint("SS mismatch on data ready ind, tear down connection\n");
  828. RxLog(("SmbCeDataReadyInd: Invalid Security Signature\n"));
  829. CopyDataStatus = STATUS_INVALID_NETWORK_RESPONSE;
  830. SmbCeTransportDisconnectIndicated(pExchange->SmbCeContext.pServerEntry);
  831. }
  832. }
  833. if (CopyDataStatus == STATUS_SUCCESS) {
  834. // Notify the exchange of the completion
  835. //ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  836. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,DataSize);
  837. SMB_EXCHANGE_DISPATCH(
  838. pExchange,
  839. CopyDataHandler,
  840. (pExchange,pBuffer,DataSize));
  841. } else {
  842. pExchange->Status = CopyDataStatus;
  843. pExchange->SmbStatus = CopyDataStatus;
  844. }
  845. // Resume the exchange that was waiting for the data.
  846. SmbCeDecrementPendingCopyDataOperationsAndFinalize(pExchange);
  847. } else {
  848. // The data MDL is part of the exchange, which should be freed with the exchange.
  849. ASSERT(FALSE);
  850. }
  851. return STATUS_SUCCESS;
  852. }
  853. NTSTATUS
  854. SmbCeErrorInd(
  855. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  856. IN NTSTATUS IndicatedStatus
  857. )
  858. /*++
  859. Routine Description:
  860. This routine handles the error indication
  861. Arguments:
  862. pEventContext - the server instance
  863. Status - the error
  864. Return Value:
  865. STATUS_SUCCESS
  866. --*/
  867. {
  868. NTSTATUS Status;
  869. PSMB_EXCHANGE pExchange;
  870. DbgPrint("@@@@@@ Error Indication for %lx @@@@@\n",pServerEntry);
  871. SmbLogError(IndicatedStatus,
  872. LOG,
  873. SmbCeErrorInd,
  874. LOGULONG(IndicatedStatus)
  875. LOGPTR(pServerEntry)
  876. LOGUSTR(pServerEntry->Name));
  877. InterlockedIncrement(&MRxSmbStatistics.NetworkErrors);
  878. // Post to the worker queue to resume all the outstanding requests
  879. pServerEntry->ServerStatus = IndicatedStatus;
  880. SmbCeReferenceServerEntry(pServerEntry);
  881. Status = RxDispatchToWorkerThread(
  882. MRxSmbDeviceObject,
  883. CriticalWorkQueue,
  884. SmbCeResumeAllOutstandingRequestsOnError,
  885. pServerEntry);
  886. if (Status != STATUS_SUCCESS) {
  887. DbgPrint("Error Indication not dispatched\n");
  888. RxLog(("SmbCeErrorInd(SE) %lx\n", pServerEntry));
  889. }
  890. return STATUS_SUCCESS;
  891. }
  892. NTSTATUS
  893. SmbCeSendCompleteInd(
  894. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  895. IN PVOID pCompletionContext,
  896. IN NTSTATUS SendCompletionStatus
  897. )
  898. /*++
  899. Routine Description:
  900. This routine handles the send complete indication for asynchronous sends
  901. Arguments:
  902. pServerEntry - the server instance
  903. pCompletionContext - the context for identifying the send request
  904. SendCompletionStatus - the send completion status
  905. Return Value:
  906. STATUS_SUCCESS always ..
  907. --*/
  908. {
  909. NTSTATUS Status;
  910. PSMB_EXCHANGE pExchange;
  911. PVOID pSendBuffer = pCompletionContext;
  912. if (pCompletionContext != NULL) {
  913. // Map the MID to the associated exchange
  914. pExchange = SmbCeGetExchangeAssociatedWithBuffer(
  915. pServerEntry,
  916. pSendBuffer);
  917. if (pExchange != NULL) {
  918. // Resume the exchange which was waiting for this response
  919. RxDbgTrace(0, Dbg, ("SmbCeSendCompleteInd: Send Completion Status %lx\n",SendCompletionStatus));
  920. //
  921. // Free the security signature copy buffer if any.
  922. //
  923. if( pExchange->pBufSecSigData )
  924. {
  925. IoFreeMdl( pExchange->pBufSecSigMdl );
  926. pExchange->pBufSecSigMdl = NULL;
  927. ExFreePool( pExchange->pBufSecSigData );
  928. pExchange->pBufSecSigData = NULL;
  929. }
  930. if (pExchange->pDispatchVector->SendCompletionHandler != NULL) {
  931. Status = SMB_EXCHANGE_DISPATCH(pExchange,
  932. SendCompletionHandler,
  933. (pExchange,
  934. pSendBuffer,
  935. SendCompletionStatus));
  936. }
  937. RxDbgTrace(0, Dbg, ("SmbCeSendCompleteInd: SMB_EXCHANGE_DISPATCH returned %lx\n",Status));
  938. SmbCeDecrementPendingSendCompleteOperationsAndFinalize(pExchange);
  939. }
  940. }
  941. return STATUS_SUCCESS;
  942. }
  943.