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.

1108 lines
34 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. smbsecur.c
  5. Abstract:
  6. This module implements all functions related to enforce the SMB security signature on
  7. transmitting and recieving SMB packages.
  8. Revision History:
  9. Yun Lin [YunLin] 23-December-1997
  10. Notes:
  11. --*/
  12. #include "precomp.h"
  13. extern LONG NumOfBuffersForServerResponseInUse;
  14. extern LIST_ENTRY ExchangesWaitingForServerResponseBuffer;
  15. // this varible defines the maximum number of large buffer allowed to be pre-allocated for the
  16. // server responses that contain the security signature, which prevents it drains all system
  17. // resource under heavy network traffic situation and large read request
  18. LONG MaxNumOfLargeBuffersForServerResponse = 3;
  19. // the buffer size for most of the SMB server responses which don't contain much data
  20. ULONG MinimumBufferSizeForServerResponse = 0x100;
  21. BOOLEAN
  22. SmbCheckSecuritySignature(
  23. IN PSMB_EXCHANGE pExchange,
  24. IN PSMBCE_SERVER Server,
  25. IN ULONG MessageLength,
  26. IN PVOID pBuffer
  27. );
  28. LIST_ENTRY SmbSecurityMdlWaitingExchanges;
  29. NTSTATUS
  30. SmbCeCheckMessageLength(
  31. IN ULONG BytesIndicated,
  32. IN ULONG BytesAvailable,
  33. IN PVOID pTsdu, // pointer describing this TSDU, typically a lump of bytes
  34. OUT PULONG pMessageLength
  35. )
  36. /*++
  37. Routine Description:
  38. This routine calculates the server message length based on the SMB response command and data.
  39. Arguments:
  40. BytesIndicated - the bytes that are present in the indication.
  41. BytesAvailable - the total data available
  42. pTsdu - the data
  43. pDataBufferSize - the length of the buffer
  44. Return Value:
  45. STATUS_SUCCESS -
  46. Other Status codes correspond to error situations.
  47. --*/
  48. {
  49. NTSTATUS Status = STATUS_SUCCESS;
  50. UCHAR SmbCommand;
  51. PGENERIC_ANDX pSmbBuffer;
  52. PSMB_HEADER pSmbHeader = (PSMB_HEADER)pTsdu;
  53. ULONG ByteCount;
  54. LONG WordCount;
  55. LONG ByteLeft = BytesIndicated - sizeof(SMB_HEADER);
  56. if (ByteLeft < 0) {
  57. return STATUS_INVALID_NETWORK_RESPONSE;
  58. }
  59. *pMessageLength = sizeof(SMB_HEADER);
  60. SmbCommand = pSmbHeader->Command;
  61. pSmbBuffer = (PGENERIC_ANDX)(pSmbHeader + 1);
  62. do {
  63. switch (SmbCommand) {
  64. case SMB_COM_LOCKING_ANDX:
  65. case SMB_COM_WRITE_ANDX:
  66. case SMB_COM_SESSION_SETUP_ANDX:
  67. case SMB_COM_LOGOFF_ANDX:
  68. case SMB_COM_TREE_CONNECT_ANDX:
  69. case SMB_COM_NT_CREATE_ANDX:
  70. case SMB_COM_OPEN_ANDX:
  71. SmbCommand = pSmbBuffer->AndXCommand;
  72. *pMessageLength = pSmbBuffer->AndXOffset;
  73. pSmbBuffer = (PGENERIC_ANDX)((PUCHAR)pTsdu + pSmbBuffer->AndXOffset);
  74. break;
  75. case SMB_COM_READ_ANDX:
  76. {
  77. PRESP_READ_ANDX ReadAndX = (PRESP_READ_ANDX)pSmbBuffer;
  78. WordCount = (ULONG)pSmbBuffer->WordCount;
  79. if (ReadAndX->DataLengthHigh > 0) {
  80. ByteCount = ReadAndX->DataLengthHigh << 16;
  81. ByteCount += ReadAndX->DataLength;
  82. } else {
  83. ByteCount = *(PUSHORT)((PCHAR)pSmbBuffer + 1 + WordCount*sizeof(USHORT));
  84. }
  85. *pMessageLength += (WordCount+1)*sizeof(USHORT) + ByteCount + 1;
  86. SmbCommand = SMB_COM_NO_ANDX_COMMAND;
  87. break;
  88. }
  89. default:
  90. WordCount = (ULONG)pSmbBuffer->WordCount;
  91. if (ByteLeft > (signed)sizeof(USHORT)*WordCount) {
  92. ByteCount = *(PUSHORT)((PCHAR)pSmbBuffer + 1 + WordCount*sizeof(USHORT));
  93. } else {
  94. ByteCount = 0;
  95. }
  96. *pMessageLength += (WordCount+1)*sizeof(USHORT) + ByteCount + 1;
  97. SmbCommand = SMB_COM_NO_ANDX_COMMAND;
  98. }
  99. ByteLeft = BytesIndicated - *pMessageLength;
  100. if (ByteLeft < 0) {
  101. Status = STATUS_MORE_PROCESSING_REQUIRED;
  102. break;
  103. }
  104. } while (SmbCommand != SMB_COM_NO_ANDX_COMMAND);
  105. return Status;
  106. }
  107. NTSTATUS
  108. SmbCeReceiveIndWithSecuritySignature(
  109. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  110. IN ULONG BytesIndicated,
  111. IN ULONG BytesAvailable,
  112. OUT ULONG *pBytesTaken,
  113. IN PVOID pTsdu,
  114. OUT PMDL *pDataBufferPointer,
  115. OUT PULONG pDataBufferSize,
  116. IN ULONG ReceiveFlags
  117. )
  118. /*++
  119. Routine Description:
  120. This routine handles the SMB server response that contains the security signature. There are 3
  121. scenaorios handled in this routine.
  122. 1. TDI indicates the entire SMB message, and SmbCeReceiveInd returns STATUS_SUCCESS;
  123. 2. TDI indicates the entire SMB message, and SmbceReceiveInd returns STATUS_MORE_PROCESSING_REQUIRED;
  124. 3. TDI indicates partial SMB message.
  125. For corresponding solution are:
  126. 1. Check the security signature and calls SmbCeReceiveInd
  127. 2. Check the security signature and calls SmbCeReceiveInd, then call SmbCeDataReadyInd for the
  128. rest of the message
  129. 3. Use the pre-allocated buffer for the entir SMB message and return to TDI
  130. In case of bad security signatre, an error status is set on the SMB header and the receive exchange
  131. routine will drop the message.
  132. Arguments:
  133. pServerEntry - the server entry
  134. BytesIndicated - the bytes that are present in the indication.
  135. BytesAvailable - the total data available
  136. pTsdu - pointer describing this TSDU, typically a lump of bytes
  137. pDataBufferPointer - the buffer for copying the data not indicated.
  138. pDataBufferSize - the length of the buffer
  139. Return Value:
  140. STATUS_SUCCESS -
  141. Other Status codes correspond to error situations.
  142. --*/
  143. {
  144. NTSTATUS Status;
  145. PSMB_HEADER pSmbHeader = (PSMB_HEADER)pTsdu;
  146. PSMB_EXCHANGE pExchange;
  147. ULONG MessageLength;
  148. // Perform the quick tests by which ill formed SMB's, mangled SMB's can be rejected.
  149. // e.g., any indication which is of non zero length whihc is less then the length of
  150. // a SMB_HEADER cannot be a valid SMB.
  151. if ((BytesAvailable < sizeof(SMB_HEADER) + 3) ||
  152. (SmbGetUlong(((PULONG )pSmbHeader->Protocol)) != (ULONG)SMB_HEADER_PROTOCOL) ||
  153. (pSmbHeader->Command == SMB_COM_NO_ANDX_COMMAND) ) {
  154. RxLog(("SmbCeReceiveInd: Invalid Response for %lx\n",pServerEntry));
  155. SmbLogError(STATUS_UNSUCCESSFUL,
  156. LOG,
  157. SmbCeReceiveInd,
  158. LOGPTR(pServerEntry)
  159. LOGUSTR(pServerEntry->Name));
  160. *pBytesTaken = BytesIndicated;
  161. return STATUS_SUCCESS;
  162. }
  163. ASSERT(pServerEntry->Header.ObjectType == SMBCEDB_OT_SERVER);
  164. if (pSmbHeader->Command == SMB_COM_ECHO) {
  165. Status = SmbCeReceiveInd(
  166. pServerEntry,
  167. BytesIndicated,
  168. BytesAvailable,
  169. pBytesTaken,
  170. pTsdu,
  171. pDataBufferPointer,
  172. pDataBufferSize,
  173. ReceiveFlags);
  174. return Status;
  175. }
  176. //RxLog(("Smb (Rece) %lx %lx %lx\n",pServerEntry,pSmbHeader->Command,pSmbHeader->Mid));
  177. // Perform the tests for detecting oplock break SMB's. These are SMB's with the
  178. // command SMB_COM_LOCKING_ANDX with the LOCKING_ANDX_OPLOCK_RELEASE bit set.
  179. // These SMB's are transformed into buffering state change requests which are
  180. // processed by the RDBSS.
  181. // CODE.IMPROVEMENT -- raw mode handling needs to be incorporated
  182. //
  183. if (pSmbHeader->Command == SMB_COM_LOCKING_ANDX) {
  184. if (BytesIndicated == LOCK_BROKEN_SIZE) {
  185. PREQ_LOCKING_ANDX pOplockBreakRequest = (PREQ_LOCKING_ANDX)(pSmbHeader + 1);
  186. if (SmbGetUshort(&pOplockBreakRequest->LockType) & LOCKING_ANDX_OPLOCK_RELEASE) {
  187. Status = SmbCeReceiveInd(
  188. pServerEntry,
  189. BytesIndicated,
  190. BytesAvailable,
  191. pBytesTaken,
  192. pTsdu,
  193. pDataBufferPointer,
  194. pDataBufferSize,
  195. ReceiveFlags);
  196. return Status;
  197. }
  198. }
  199. }
  200. // Handle the cases when the server responds to the oplock break response.
  201. if ((pSmbHeader->Mid == SMBCE_MAILSLOT_OPERATION_MID) ||
  202. (pSmbHeader->Mid == SMBCE_OPLOCK_RESPONSE_MID)) {
  203. Status = SmbCeReceiveInd(
  204. pServerEntry,
  205. BytesIndicated,
  206. BytesAvailable,
  207. pBytesTaken,
  208. pTsdu,
  209. pDataBufferPointer,
  210. pDataBufferSize,
  211. ReceiveFlags);
  212. return Status;
  213. }
  214. pExchange = SmbCeMapMidToExchange(pServerEntry,pSmbHeader->Mid);
  215. // some exchange might have been initiated before the security signature is enabled.
  216. // In this case, we should avoid security signature check.
  217. if (pExchange != NULL && pExchange->IsSecuritySignatureEnabled) {
  218. if (BytesAvailable > BytesIndicated ||
  219. !FlagOn(ReceiveFlags,TDI_RECEIVE_ENTIRE_MESSAGE)) {
  220. ASSERT(pExchange->MdlForServerResponse != NULL &&
  221. pExchange->MdlForServerResponse->ByteCount >= BytesAvailable);
  222. *pBytesTaken = 0;
  223. *pDataBufferPointer = pExchange->MdlForServerResponse;
  224. *pDataBufferSize = pExchange->MdlForServerResponse->ByteCount;
  225. Status = SmbCeAssociateBufferWithExchange(pServerEntry,pExchange,*pDataBufferPointer);
  226. if (Status == STATUS_SUCCESS) {
  227. SmbCeIncrementPendingCopyDataOperations(pExchange);
  228. Status = STATUS_MORE_PROCESSING_REQUIRED;
  229. } else {
  230. DbgPrint("MRxSmb:Fail to associate MDL witn exchange. %lx\n",Status);
  231. pExchange->Status = Status;
  232. *pBytesTaken = BytesIndicated;
  233. Status = STATUS_SUCCESS;
  234. }
  235. } else {
  236. if (!SmbCheckSecuritySignature(pExchange,
  237. &pServerEntry->Server,
  238. BytesIndicated,
  239. pTsdu)) {
  240. pSmbHeader->ErrorClass = SMB_ERR_CLASS_SERVER;
  241. SmbPutUshort(&pSmbHeader->Error, ERROR_UNEXP_NET_ERR);
  242. RxLog(("SmbCeReceiveInd: Invalid Security Signature\n"));
  243. SmbLogError(STATUS_UNSUCCESSFUL,
  244. LOG,
  245. SmbCeReceiveIndWithSecuritySignature,
  246. LOGPTR(pServerEntry)
  247. LOGUSTR(pServerEntry->Name));
  248. }
  249. Status = SmbCeReceiveInd(
  250. pServerEntry,
  251. BytesIndicated,
  252. BytesAvailable,
  253. pBytesTaken,
  254. pTsdu,
  255. pDataBufferPointer,
  256. pDataBufferSize,
  257. ReceiveFlags);
  258. if (Status==STATUS_MORE_PROCESSING_REQUIRED) {
  259. ULONG BytesCopied;
  260. Status = TdiCopyBufferToMdl(
  261. pTsdu,
  262. *pBytesTaken,
  263. BytesIndicated,
  264. *pDataBufferPointer,
  265. 0,
  266. &BytesCopied);
  267. SmbCeDataReadyInd(pServerEntry,
  268. *pDataBufferPointer,
  269. BytesCopied,
  270. Status);
  271. }
  272. Status = STATUS_SUCCESS;
  273. *pBytesTaken = BytesIndicated;
  274. }
  275. } else {
  276. if (pExchange != NULL) {
  277. Status = SmbCeReceiveInd(
  278. pServerEntry,
  279. BytesIndicated,
  280. BytesAvailable,
  281. pBytesTaken,
  282. pTsdu,
  283. pDataBufferPointer,
  284. pDataBufferSize,
  285. ReceiveFlags);
  286. } else {
  287. RxLog(("SmbCeReceiveInd:No resumption context %lx\n",pServerEntry));
  288. Status = STATUS_SUCCESS;
  289. *pBytesTaken = BytesIndicated;
  290. }
  291. }
  292. return Status;
  293. }
  294. NTSTATUS
  295. SmbCeDataReadyIndWithSecuritySignature(
  296. IN PSMBCEDB_SERVER_ENTRY pServerEntry,
  297. IN PMDL pBuffer,
  298. IN ULONG DataSize,
  299. IN NTSTATUS CopyDataStatus
  300. )
  301. /*++
  302. Routine Description:
  303. This routine handles the indication when the requested data has been copied which contains security
  304. signature. In case of bad security signature, an error is set on SMB message header and the receive
  305. exchange routine will drop the message.
  306. Arguments:
  307. pServerEntry - the server instance
  308. pBuffer - the buffer being returned
  309. DataSize - the amount of data copied in bytes
  310. Return Value:
  311. STATUS_SUCCESS - the server call construction has been finalized.
  312. Other Status codes correspond to error situations.
  313. --*/
  314. {
  315. NTSTATUS Status;
  316. ULONG BytesTaken;
  317. PMDL pDataBufferPointer;
  318. ULONG DataBufferSize;
  319. PSMB_EXCHANGE pExchange = SmbCeGetExchangeAssociatedWithBuffer(pServerEntry,pBuffer);
  320. // some exchange might have been initiated before the security signature is enabled.
  321. // In this case, we should avoid security signature check.
  322. if (pExchange != NULL && pExchange->IsSecuritySignatureEnabled) {
  323. if (CopyDataStatus == STATUS_SUCCESS) {
  324. PSMB_HEADER pSmbHeader = (PSMB_HEADER)pExchange->BufferForServerResponse;
  325. if (!SmbCheckSecuritySignature(pExchange,
  326. &pServerEntry->Server,
  327. DataSize,
  328. pExchange->BufferForServerResponse)) {
  329. pSmbHeader->ErrorClass = SMB_ERR_CLASS_SERVER;
  330. SmbPutUshort(&pSmbHeader->Error, ERROR_UNEXP_NET_ERR);
  331. RxLog(("SmbCeDataReadyInd: Invalid Security Signature\n"));
  332. SmbLogError(STATUS_UNSUCCESSFUL,
  333. LOG,
  334. SmbCeDataReadyIndWithSecuritySignature,
  335. LOGPTR(pServerEntry)
  336. LOGUSTR(pServerEntry->Name));
  337. }
  338. Status = SmbCeReceiveInd(
  339. pServerEntry,
  340. DataSize,
  341. DataSize,
  342. &BytesTaken,
  343. pExchange->BufferForServerResponse,
  344. &pDataBufferPointer,
  345. &DataBufferSize,
  346. TDI_RECEIVE_ENTIRE_MESSAGE);
  347. if (Status==STATUS_MORE_PROCESSING_REQUIRED) {
  348. ULONG BytesCopied;
  349. ASSERT(DataBufferSize >= DataSize - BytesTaken);
  350. Status = TdiCopyBufferToMdl(
  351. pExchange->BufferForServerResponse,
  352. BytesTaken,
  353. DataSize,
  354. pDataBufferPointer,
  355. 0,
  356. &BytesCopied);
  357. SmbCeDataReadyInd(pServerEntry,
  358. pDataBufferPointer,
  359. BytesCopied,
  360. Status);
  361. }
  362. } else {
  363. // Resume the exchange that was waiting for the receive.
  364. pExchange->Status = STATUS_CONNECTION_DISCONNECTED;
  365. pExchange->SmbStatus = STATUS_CONNECTION_DISCONNECTED;
  366. SmbCeDecrementPendingReceiveOperationsAndFinalize(pExchange);
  367. }
  368. // Resume the exchange that was waiting for the data.
  369. SmbCeDecrementPendingCopyDataOperationsAndFinalize(pExchange);
  370. } else {
  371. if (pExchange != NULL) {
  372. if (CopyDataStatus == STATUS_SUCCESS) {
  373. // Notify the exchange of the completion
  374. //ExInterlockedAddLargeStatistic(&MRxSmbStatistics.SmbsReceived,1);
  375. ExInterlockedAddLargeStatistic(&MRxSmbStatistics.BytesReceived,DataSize);
  376. SMB_EXCHANGE_DISPATCH(
  377. pExchange,
  378. CopyDataHandler,
  379. (pExchange,pBuffer,DataSize));
  380. } else {
  381. pExchange->Status = CopyDataStatus;
  382. pExchange->SmbStatus = CopyDataStatus;
  383. }
  384. // Resume the exchange that was waiting for the data.
  385. SmbCeDecrementPendingCopyDataOperationsAndFinalize(pExchange);
  386. } else {
  387. // The data MDL is part of the exchange, which should be freed with the exchange.
  388. ASSERT(FALSE);
  389. }
  390. }
  391. return STATUS_SUCCESS;
  392. }
  393. NTSTATUS
  394. SmbCeSyncExchangeForSecuritySignature(
  395. PSMB_EXCHANGE pExchange
  396. )
  397. /*++
  398. Routine Description:
  399. This routines puts the exchange on the list waiting for the previous extended session
  400. setup to finish in order to serialize the requests sent to the server with security
  401. signature enabled.
  402. Arguments:
  403. pExchange - the smb exchange
  404. Return Value:
  405. STATUS_SUCCESS - the exchange can be initiated.
  406. STATUS_PENDING - the exchange can be resumed after the extended session setup finishes
  407. Other Status codes correspond to error situations.
  408. --*/
  409. {
  410. NTSTATUS Status = STATUS_SUCCESS;
  411. PSMBCEDB_SERVER_ENTRY pServerEntry;
  412. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  413. KEVENT SmbCeSynchronizationEvent;
  414. PSMBCEDB_REQUEST_ENTRY pRequestEntry = NULL;
  415. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  416. pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange);
  417. if (!pSessionEntry->SessionRecoverInProgress) {
  418. if (!pServerEntry->ExtSessionSetupInProgress) {
  419. if (pExchange->Type == EXTENDED_SESSION_SETUP_EXCHANGE) {
  420. // if this is the first extended session setup, let it proceed
  421. pServerEntry->ExtSessionSetupInProgress = TRUE;
  422. }
  423. return Status;
  424. }
  425. } else {
  426. if (pExchange->Type == EXTENDED_SESSION_SETUP_EXCHANGE) {
  427. // if this is the extended session setup, let it proceed
  428. return Status;
  429. }
  430. }
  431. // We are performing an operation that does not attempt reconnects, so it will
  432. // not recover from the disconnect/lack of session. We should simply abort here.
  433. if( !(pExchange->SmbCeFlags & SMBCE_EXCHANGE_ATTEMPT_RECONNECTS) )
  434. {
  435. return STATUS_CONNECTION_DISCONNECTED;
  436. }
  437. pRequestEntry = (PSMBCEDB_REQUEST_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_REQUEST);
  438. if (pRequestEntry != NULL) {
  439. pRequestEntry->Request.pExchange = pExchange;
  440. SmbCeIncrementPendingLocalOperations(pExchange);
  441. SmbCeAddRequestEntry(&pServerEntry->SecuritySignatureSyncRequests,pRequestEntry);
  442. if (pExchange->pSmbCeSynchronizationEvent != NULL) {
  443. Status = STATUS_PENDING;
  444. } else {
  445. KeInitializeEvent(
  446. &SmbCeSynchronizationEvent,
  447. SynchronizationEvent,
  448. FALSE);
  449. pExchange->pSmbCeSynchronizationEvent = &SmbCeSynchronizationEvent;
  450. SmbCeReleaseResource();
  451. KeWaitForSingleObject(
  452. &SmbCeSynchronizationEvent,
  453. Executive,
  454. KernelMode,
  455. FALSE,
  456. NULL);
  457. SmbCeAcquireResource();
  458. pExchange->pSmbCeSynchronizationEvent = NULL;
  459. }
  460. } else {
  461. Status = STATUS_INSUFFICIENT_RESOURCES;
  462. }
  463. return Status;
  464. }
  465. NTSTATUS
  466. SmbCeAllocateBufferForServerResponse(
  467. PSMB_EXCHANGE pExchange
  468. )
  469. /*++
  470. Routine Description:
  471. This routine allocates the buffer for server response in case that the TDI doesn't indicates the
  472. entire message once. The security siganture cannot be checked until entire message is indicated.
  473. Normally, we allocate 0x100 for the short message from the server. In case of read and transact
  474. exchanges, we allocate the buffer large enough to handle the message that server might return.
  475. Since the large buffer will consum a lot of system memory, we only allow a certain amount of this
  476. kind pre-allocated buffers outstanding, which cannot exceed the MaxNumOfLargeBuffersForServerResponse
  477. defined at beginning of this module. If the request exceeds the limitation, the exchange acquiring
  478. the buffer is put onto sleep until and existing large buffer is freed by another exchange.
  479. Arguments:
  480. pExchange - the smb exchange
  481. Return Value:
  482. STATUS_SUCCESS - the server call construction has been finalized.
  483. Other Status codes correspond to error situations.
  484. --*/
  485. {
  486. NTSTATUS Status = STATUS_SUCCESS;
  487. ULONG BufferSize = MinimumBufferSizeForServerResponse;
  488. PVOID Buffer = NULL;
  489. PMDL Mdl = NULL;
  490. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  491. PSMBCE_SERVER pServer = &pServerEntry->Server;
  492. switch (pExchange->Type) {
  493. case ORDINARY_EXCHANGE:
  494. {
  495. PLOWIO_CONTEXT LowIoContext = &pExchange->RxContext->LowIoContext;
  496. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)pExchange;
  497. PSMBCE_NET_ROOT pNetRoot = SmbCeGetExchangeNetRoot(OrdinaryExchange);
  498. switch(OrdinaryExchange->EntryPoint) {
  499. case SMBPSE_OE_FROM_READ:
  500. BufferSize += min(LowIoContext->ParamsFor.ReadWrite.ByteCount,
  501. pNetRoot->MaximumReadBufferSize);
  502. break;
  503. case SMBPSE_OE_FROM_QUERYDIRECTORY:
  504. case SMBPSE_OE_FROM_QUERYFILEINFO:
  505. case SMBPSE_OE_FROM_QUERYVOLUMEINFO:
  506. BufferSize += min(LowIoContext->ParamsFor.FsCtl.OutputBufferLength,
  507. pNetRoot->MaximumReadBufferSize);
  508. break;
  509. }
  510. }
  511. break;
  512. case TRANSACT_EXCHANGE:
  513. {
  514. PSMB_TRANSACT_EXCHANGE TransactExchange = (PSMB_TRANSACT_EXCHANGE)pExchange;
  515. BufferSize += TransactExchange->ReceiveDataBufferSize +
  516. TransactExchange->ReceiveParamBufferSize +
  517. TransactExchange->ReceiveSetupBufferSize;
  518. }
  519. break;
  520. case CONSTRUCT_NETROOT_EXCHANGE:
  521. case EXTENDED_SESSION_SETUP_EXCHANGE:
  522. // for netroot and session setup request, we cannot predict how many bytes
  523. // the server is going to return. For doscore, the MaximumBufferSize is 0.
  524. BufferSize = max(pServer->MaximumBufferSize,MinimumBufferSizeForServerResponse);
  525. break;
  526. case ADMIN_EXCHANGE:
  527. break;
  528. default:
  529. break;
  530. }
  531. if ((BufferSize > MinimumBufferSizeForServerResponse) &&
  532. (pExchange->Type != EXTENDED_SESSION_SETUP_EXCHANGE) &&
  533. FlagOn(pExchange->SmbCeFlags,SMBCE_EXCHANGE_TIMED_RECEIVE_OPERATION)) {
  534. LONG NumOfBuffers;
  535. SmbCeAcquireResource();
  536. NumOfBuffers = InterlockedIncrement(&NumOfBuffersForServerResponseInUse);
  537. if (NumOfBuffers > MaxNumOfLargeBuffersForServerResponse) {
  538. if (!IsListEmpty(&pExchange->ExchangeList)) {
  539. RemoveEntryList(&pExchange->ExchangeList);
  540. }
  541. InsertTailList(
  542. &ExchangesWaitingForServerResponseBuffer,
  543. &pExchange->ExchangeList);
  544. SmbCeIncrementPendingLocalOperations(pExchange);
  545. InterlockedDecrement(&NumOfBuffersForServerResponseInUse);
  546. Status = STATUS_PENDING;
  547. }
  548. else
  549. {
  550. // We incremented the NumOfBuffers counter, mark it
  551. pExchange->SmbCeFlags |= SMBCE_EXCHANGE_SIGNATURE_BUFFER_ALLOCATED;
  552. }
  553. SmbCeReleaseResource();
  554. }
  555. if (Status == STATUS_SUCCESS) {
  556. Buffer = RxAllocatePoolWithTag(PagedPool,BufferSize,MRXSMB_MISC_POOLTAG);
  557. if (Buffer != NULL) {
  558. Mdl = RxAllocateMdl(Buffer, BufferSize);
  559. if (Mdl != NULL) {
  560. RxProbeAndLockPages(Mdl,KernelMode,IoModifyAccess,Status);
  561. if (Status == STATUS_SUCCESS) {
  562. if (MmGetSystemAddressForMdlSafe(Mdl,LowPagePriority) == NULL) {
  563. Status = STATUS_INSUFFICIENT_RESOURCES;
  564. }
  565. }
  566. } else {
  567. Status = STATUS_INSUFFICIENT_RESOURCES;
  568. }
  569. } else {
  570. Status = STATUS_INSUFFICIENT_RESOURCES;
  571. }
  572. if (Status != STATUS_SUCCESS &&
  573. FlagOn( pExchange->SmbCeFlags, SMBCE_EXCHANGE_SIGNATURE_BUFFER_ALLOCATED) ) {
  574. InterlockedDecrement(&NumOfBuffersForServerResponseInUse);
  575. }
  576. }
  577. ASSERT(pExchange->MdlForServerResponse == NULL);
  578. ASSERT(pExchange->BufferForServerResponse == NULL);
  579. if (Status == STATUS_SUCCESS) {
  580. pExchange->BufferForServerResponse = Buffer;
  581. pExchange->MdlForServerResponse = Mdl;
  582. pExchange->SmbCeState = SMBCE_EXCHANGE_SECURITYBUFFER_INITIALIZED;
  583. } else {
  584. if (Buffer != NULL) {
  585. RxFreePool(Buffer);
  586. }
  587. if (Mdl != NULL) {
  588. IoFreeMdl(Mdl);
  589. }
  590. // We did not succeed, so make sure its not marked as having incremented the counter
  591. pExchange->SmbCeFlags &= ~SMBCE_EXCHANGE_SIGNATURE_BUFFER_ALLOCATED;
  592. }
  593. return Status;
  594. }
  595. VOID
  596. SmbCeFreeBufferForServerResponse(
  597. PSMB_EXCHANGE pExchange
  598. )
  599. /*++
  600. Routine Description:
  601. This routine frees the buffer for server response and resume one exchange, if exists,
  602. that is waiting for allocating the large buffer.
  603. Arguments:
  604. pExchange - the smb exchange
  605. Return Value:
  606. none
  607. --*/
  608. {
  609. PSMB_EXCHANGE pWaitingExchange = NULL;
  610. if (pExchange->MdlForServerResponse != NULL) {
  611. if ( FlagOn(pExchange->SmbCeFlags, SMBCE_EXCHANGE_SIGNATURE_BUFFER_ALLOCATED) ) {
  612. PLIST_ENTRY pListHead = &ExchangesWaitingForServerResponseBuffer;
  613. SmbCeAcquireResource();
  614. InterlockedDecrement(&NumOfBuffersForServerResponseInUse);
  615. ClearFlag( pExchange->SmbCeFlags, SMBCE_EXCHANGE_SIGNATURE_BUFFER_ALLOCATED );
  616. if (!IsListEmpty(pListHead)) {
  617. PLIST_ENTRY pListEntry;
  618. pListEntry = pListHead->Flink;
  619. RemoveHeadList(pListHead);
  620. pWaitingExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  621. }
  622. SmbCeReleaseResource();
  623. }
  624. RxUnlockHeaderPages(pExchange->MdlForServerResponse);
  625. IoFreeMdl(pExchange->MdlForServerResponse);
  626. pExchange->MdlForServerResponse = NULL;
  627. }
  628. if (pExchange->BufferForServerResponse != NULL) {
  629. RxFreePool(pExchange->BufferForServerResponse);
  630. pExchange->BufferForServerResponse = NULL;
  631. }
  632. if (pWaitingExchange != NULL) {
  633. NTSTATUS Status = STATUS_SUCCESS;
  634. InitializeListHead(&pWaitingExchange->ExchangeList);
  635. if (pWaitingExchange->pSmbCeSynchronizationEvent == NULL) {
  636. SmbCeResumeExchange(pWaitingExchange);
  637. SmbCeDecrementPendingLocalOperationsAndFinalize(pWaitingExchange);
  638. } else {
  639. SmbCeDecrementPendingLocalOperations(pWaitingExchange);
  640. KeSetEvent(
  641. pWaitingExchange->pSmbCeSynchronizationEvent,
  642. 0,
  643. FALSE);
  644. }
  645. }
  646. }
  647. VOID
  648. SmbInitializeSmbSecuritySignature(
  649. IN OUT PSMBCE_SERVER Server,
  650. IN PUCHAR SessionKey,
  651. IN PUCHAR ChallengeResponse,
  652. IN ULONG ChallengeResponseLength
  653. )
  654. /*++
  655. Routine Description:
  656. Initializes the security signature generator for a session by calling MD5Update
  657. on the session key, challenge response
  658. Arguments:
  659. SessionKey - Either the LM or NT session key, depending on which
  660. password was used for authentication, must be at least 16 bytes
  661. ChallengeResponse - The challenge response used for authentication, must
  662. be at least 24 bytes
  663. --*/
  664. {
  665. //DbgPrint( "MRxSmb: Initialize Security Signature Intermediate Contex\n");
  666. RtlZeroMemory(&Server->SmbSecuritySignatureIntermediateContext, sizeof(MD5_CTX));
  667. MD5Init(&Server->SmbSecuritySignatureIntermediateContext);
  668. if (SessionKey != NULL) {
  669. MD5Update(&Server->SmbSecuritySignatureIntermediateContext,
  670. (PCHAR)SessionKey,
  671. MSV1_0_USER_SESSION_KEY_LENGTH);
  672. }
  673. MD5Update(&Server->SmbSecuritySignatureIntermediateContext,
  674. (PCHAR)ChallengeResponse,
  675. ChallengeResponseLength);
  676. Server->SmbSecuritySignatureIndex = 0;
  677. }
  678. BOOLEAN DumpSecuritySignature = FALSE;
  679. NTSTATUS
  680. SmbAddSmbSecuritySignature(
  681. IN PSMBCE_SERVER Server,
  682. IN OUT PMDL Mdl,
  683. IN OUT ULONG *ServerIndex,
  684. IN ULONG SendLength
  685. )
  686. /*++
  687. Routine Description:
  688. Generates the next security signature
  689. Arguments:
  690. WorkContext - the context to sign
  691. Return Value:
  692. none.
  693. --*/
  694. {
  695. NTSTATUS Status = STATUS_SUCCESS;
  696. MD5_CTX Context;
  697. PSMB_HEADER Smb;
  698. PCHAR SysAddress;
  699. ULONG MessageLength = 0;
  700. Smb = MmGetSystemAddressForMdlSafe(Mdl,LowPagePriority);
  701. if (Smb == NULL) {
  702. return STATUS_INSUFFICIENT_RESOURCES;
  703. }
  704. //SmbPutUshort(&Smb->Gid,(USHORT)Server->SmbSecuritySignatureIndex+1);
  705. SmbPutUlong(Smb->SecuritySignature,Server->SmbSecuritySignatureIndex);
  706. *ServerIndex = Server->SmbSecuritySignatureIndex+1; //Index of server response
  707. RtlZeroMemory(Smb->SecuritySignature + sizeof(ULONG),
  708. SMB_SECURITY_SIGNATURE_LENGTH-sizeof(ULONG));
  709. //
  710. // Start out with our initial context
  711. //
  712. RtlCopyMemory( &Context, &Server->SmbSecuritySignatureIntermediateContext, sizeof( Context ) );
  713. //
  714. // Compute the signature for the SMB we're about to send
  715. //
  716. do {
  717. SysAddress = MmGetSystemAddressForMdlSafe(Mdl,LowPagePriority);
  718. if (SysAddress == NULL) {
  719. return STATUS_INSUFFICIENT_RESOURCES;
  720. }
  721. if (Mdl->ByteCount >= SendLength) {
  722. MD5Update(&Context, SysAddress, SendLength);
  723. MessageLength += SendLength;
  724. SendLength = 0;
  725. ASSERT(Mdl->Next == NULL);
  726. break;
  727. } else {
  728. MD5Update(&Context, SysAddress, Mdl->ByteCount);
  729. SendLength -= Mdl->ByteCount;
  730. MessageLength += Mdl->ByteCount;
  731. ASSERT(Mdl->Next != NULL);
  732. }
  733. } while( (Mdl = Mdl->Next) != NULL );
  734. MD5Final( &Context );
  735. // Put the signature into the SMB
  736. RtlCopyMemory(
  737. Smb->SecuritySignature,
  738. Context.digest,
  739. SMB_SECURITY_SIGNATURE_LENGTH
  740. );
  741. if (DumpSecuritySignature) {
  742. DbgPrint("Add Signature: index %u length %u\n", *ServerIndex-1,MessageLength);
  743. }
  744. return STATUS_SUCCESS;
  745. }
  746. VOID
  747. SmbDumpSignatureError(
  748. IN PSMB_EXCHANGE pExchange,
  749. IN PUCHAR ExpectedSignature,
  750. IN PUCHAR ActualSignature,
  751. IN ULONG Length
  752. )
  753. /*++
  754. Routine Description:
  755. Print the mismatched signature information to the debugger
  756. Arguments:
  757. Return Value:
  758. none.
  759. --*/
  760. {
  761. PWCHAR p;
  762. DWORD i;
  763. PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)SmbCeGetExchangeServerEntry(pExchange);
  764. //
  765. // Security Signature Mismatch!
  766. //
  767. //DbgPrint("MRXSMB: Bad security signature from %wZ ", &pServerEntry->Name);
  768. DbgPrint("\n\t Wanted: ");
  769. for( i = 0; i < SMB_SECURITY_SIGNATURE_LENGTH; i++ ) {
  770. DbgPrint( "%X ", ExpectedSignature[i] & 0xff );
  771. }
  772. DbgPrint("\n\tReceived: ");
  773. for( i = 0; i < SMB_SECURITY_SIGNATURE_LENGTH; i++ ) {
  774. DbgPrint( "%X ", ActualSignature[i] & 0xff );
  775. }
  776. DbgPrint("\n\tLength %u, Expected Index Number %X\n", Length, pExchange->SmbSecuritySignatureIndex);
  777. }
  778. BOOLEAN
  779. SmbCheckSecuritySignature(
  780. IN PSMB_EXCHANGE pExchange,
  781. IN PSMBCE_SERVER Server,
  782. IN ULONG MessageLength,
  783. IN PVOID pBuffer
  784. )
  785. /*++
  786. Routine Description:
  787. This routine checks whether the security signature on the server response matches the one that is
  788. calculated on the client machine.
  789. Arguments:
  790. Return Value:
  791. A BOOLEAN value is returned to indicated whether the security signature matches.
  792. --*/
  793. {
  794. MD5_CTX Context;
  795. CHAR SavedSignature[ SMB_SECURITY_SIGNATURE_LENGTH ];
  796. PSMB_HEADER Smb = (PSMB_HEADER)pBuffer;
  797. ULONG ServerIndex;
  798. BOOLEAN Correct;
  799. //
  800. // Initialize the Context
  801. //
  802. RtlCopyMemory(&Context, &Server->SmbSecuritySignatureIntermediateContext, sizeof(Context));
  803. //
  804. // Save the signature that's presently in the SMB
  805. //
  806. RtlCopyMemory( SavedSignature, Smb->SecuritySignature, sizeof( SavedSignature ));
  807. //
  808. // Put the correct (expected) signature index into the buffer
  809. //
  810. SmbPutUlong( Smb->SecuritySignature, pExchange->SmbSecuritySignatureIndex );
  811. RtlZeroMemory( Smb->SecuritySignature + sizeof(ULONG),
  812. SMB_SECURITY_SIGNATURE_LENGTH-sizeof(ULONG));
  813. //
  814. // Compute what the signature should be
  815. //
  816. MD5Update(&Context, (PUCHAR)pBuffer, (UINT)MessageLength);
  817. MD5Final(&Context);
  818. //
  819. // Put the signature back
  820. //
  821. //RtlCopyMemory( Smb->SecuritySignature, SavedSignature, sizeof( Smb->SecuritySignature ));
  822. //
  823. // Now compare them!
  824. //
  825. if( RtlCompareMemory( Context.digest, SavedSignature, sizeof( SavedSignature ) ) !=
  826. sizeof( SavedSignature ) ) {
  827. //SmbDumpSignatureError(pExchange,
  828. // Context.digest,
  829. // SavedSignature,
  830. // MessageLength);
  831. DbgPrint("MRXSMB: SS mismatch command %X, Length %X, Expected Index Number %X\n",
  832. Smb->Command, MessageLength, pExchange->SmbSecuritySignatureIndex);
  833. DbgPrint(" server send length %X, mdl length %X index %X\n",
  834. SmbGetUshort(&Smb->PidHigh), SmbGetUshort(&Smb->Pid), SmbGetUshort(&Smb->Gid));
  835. //DbgBreakPoint();
  836. SmbCeTransportDisconnectIndicated(pExchange->SmbCeContext.pServerEntry);
  837. RxLogFailure(
  838. MRxSmbDeviceObject,
  839. NULL,
  840. EVENT_RDR_SECURITY_SIGNATURE_MISMATCH,
  841. STATUS_UNSUCCESSFUL);
  842. return FALSE;
  843. }
  844. return TRUE;
  845. }