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.

646 lines
18 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. LIST_ENTRY SmbSecurityMdlWaitingExchanges;
  16. NTSTATUS
  17. SmbCeCheckMessageLength(
  18. IN ULONG BytesIndicated,
  19. IN ULONG BytesAvailable,
  20. IN PVOID pTsdu, // pointer describing this TSDU, typically a lump of bytes
  21. OUT PULONG pMessageLength
  22. )
  23. /*++
  24. Routine Description:
  25. This routine calculates the server message length based on the SMB response command and data.
  26. Arguments:
  27. BytesIndicated - the bytes that are present in the indication.
  28. BytesAvailable - the total data available
  29. pTsdu - the data
  30. pDataBufferSize - the length of the buffer
  31. Return Value:
  32. STATUS_SUCCESS -
  33. Other Status codes correspond to error situations.
  34. --*/
  35. {
  36. NTSTATUS Status = STATUS_SUCCESS;
  37. UCHAR SmbCommand;
  38. PGENERIC_ANDX pSmbBuffer;
  39. PSMB_HEADER pSmbHeader = (PSMB_HEADER)pTsdu;
  40. ULONG ByteCount;
  41. LONG WordCount;
  42. LONG ByteLeft = BytesIndicated - sizeof(SMB_HEADER);
  43. if (ByteLeft < 0) {
  44. return STATUS_INVALID_NETWORK_RESPONSE;
  45. }
  46. *pMessageLength = sizeof(SMB_HEADER);
  47. SmbCommand = pSmbHeader->Command;
  48. pSmbBuffer = (PGENERIC_ANDX)(pSmbHeader + 1);
  49. do {
  50. switch (SmbCommand) {
  51. case SMB_COM_LOCKING_ANDX:
  52. case SMB_COM_WRITE_ANDX:
  53. case SMB_COM_SESSION_SETUP_ANDX:
  54. case SMB_COM_LOGOFF_ANDX:
  55. case SMB_COM_TREE_CONNECT_ANDX:
  56. case SMB_COM_NT_CREATE_ANDX:
  57. case SMB_COM_OPEN_ANDX:
  58. SmbCommand = pSmbBuffer->AndXCommand;
  59. *pMessageLength = pSmbBuffer->AndXOffset;
  60. pSmbBuffer = (PGENERIC_ANDX)((PUCHAR)pTsdu + pSmbBuffer->AndXOffset);
  61. break;
  62. case SMB_COM_READ_ANDX:
  63. {
  64. PRESP_READ_ANDX ReadAndX = (PRESP_READ_ANDX)pSmbBuffer;
  65. WordCount = (ULONG)pSmbBuffer->WordCount;
  66. if (ReadAndX->DataLengthHigh > 0) {
  67. ByteCount = ReadAndX->DataLengthHigh << 16;
  68. ByteCount += ReadAndX->DataLength;
  69. } else {
  70. ByteCount = *(PUSHORT)((PCHAR)pSmbBuffer + 1 + WordCount*sizeof(USHORT));
  71. }
  72. *pMessageLength += (WordCount+1)*sizeof(USHORT) + ByteCount + 1;
  73. SmbCommand = SMB_COM_NO_ANDX_COMMAND;
  74. break;
  75. }
  76. default:
  77. WordCount = (ULONG)pSmbBuffer->WordCount;
  78. if (ByteLeft > (signed)sizeof(USHORT)*WordCount) {
  79. ByteCount = *(PUSHORT)((PCHAR)pSmbBuffer + 1 + WordCount*sizeof(USHORT));
  80. } else {
  81. ByteCount = 0;
  82. }
  83. *pMessageLength += (WordCount+1)*sizeof(USHORT) + ByteCount + 1;
  84. SmbCommand = SMB_COM_NO_ANDX_COMMAND;
  85. }
  86. ByteLeft = BytesIndicated - *pMessageLength;
  87. if (ByteLeft < 0) {
  88. Status = STATUS_MORE_PROCESSING_REQUIRED;
  89. break;
  90. }
  91. } while (SmbCommand != SMB_COM_NO_ANDX_COMMAND);
  92. return Status;
  93. }
  94. NTSTATUS
  95. SmbCeSyncExchangeForSecuritySignature(
  96. PSMB_EXCHANGE pExchange
  97. )
  98. /*++
  99. Routine Description:
  100. This routines puts the exchange on the list waiting for the previous extended session
  101. setup to finish in order to serialize the requests sent to the server with security
  102. signature enabled.
  103. Arguments:
  104. pExchange - the smb exchange
  105. Return Value:
  106. STATUS_SUCCESS - the exchange can be initiated.
  107. STATUS_PENDING - the exchange can be resumed after the extended session setup finishes
  108. Other Status codes correspond to error situations.
  109. --*/
  110. {
  111. NTSTATUS Status = STATUS_SUCCESS;
  112. PSMBCEDB_SERVER_ENTRY pServerEntry;
  113. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  114. KEVENT SmbCeSynchronizationEvent;
  115. PSMBCEDB_REQUEST_ENTRY pRequestEntry = NULL;
  116. pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  117. pSessionEntry = SmbCeGetExchangeSessionEntry(pExchange);
  118. if (pSessionEntry->SessionRecoverInProgress ||
  119. pServerEntry->SecuritySignaturesEnabled &&
  120. !pServerEntry->SecuritySignaturesActive) {
  121. //
  122. // if security signature is enabled and not yet turned on, exchange should wait for
  123. // outstanding extended session setup to finish before resume in order to avoid index mismatch.
  124. //
  125. RxLog(("** Syncing xchg %lx for sess recovery.\n",pExchange));
  126. if (!pSessionEntry->SessionRecoverInProgress) {
  127. if (!pServerEntry->ExtSessionSetupInProgress) {
  128. if (pExchange->Type == EXTENDED_SESSION_SETUP_EXCHANGE) {
  129. // if this is the first extended session setup, let it proceed
  130. pServerEntry->ExtSessionSetupInProgress = TRUE;
  131. }
  132. return Status;
  133. }
  134. } else {
  135. if (pExchange->Type == EXTENDED_SESSION_SETUP_EXCHANGE) {
  136. // if this is the extended session setup, let it proceed
  137. return Status;
  138. }
  139. }
  140. //
  141. // If we are performing an operation that does not attempt reconnects, it will
  142. // not recover from the disconnect/lack of session. We should simply abort here.
  143. // However, if we are retrying because of a session expiry (indicated by a RECOVER
  144. // flag on the session entry.), then we retry regardless of the exchange flag.
  145. //
  146. if( ! ( pSessionEntry->Header.State == SMBCEDB_RECOVER ||
  147. pSessionEntry->SessionRecoverInProgress ) ) {
  148. if( ( pExchange->SmbCeFlags & SMBCE_EXCHANGE_ATTEMPT_RECONNECTS ) == 0 ) {
  149. return STATUS_CONNECTION_DISCONNECTED;
  150. }
  151. }
  152. pRequestEntry = (PSMBCEDB_REQUEST_ENTRY)SmbMmAllocateObject(SMBCEDB_OT_REQUEST);
  153. if (pRequestEntry != NULL) {
  154. pRequestEntry->Request.pExchange = pExchange;
  155. SmbCeIncrementPendingLocalOperations(pExchange);
  156. SmbCeAddRequestEntry(&pServerEntry->SecuritySignatureSyncRequests,pRequestEntry);
  157. if (pExchange->pSmbCeSynchronizationEvent != NULL) {
  158. Status = STATUS_PENDING;
  159. } else {
  160. KeInitializeEvent(
  161. &SmbCeSynchronizationEvent,
  162. SynchronizationEvent,
  163. FALSE);
  164. pExchange->pSmbCeSynchronizationEvent = &SmbCeSynchronizationEvent;
  165. SmbCeReleaseResource();
  166. KeWaitForSingleObject(
  167. &SmbCeSynchronizationEvent,
  168. Executive,
  169. KernelMode,
  170. FALSE,
  171. NULL);
  172. SmbCeAcquireResource();
  173. pExchange->pSmbCeSynchronizationEvent = NULL;
  174. }
  175. } else {
  176. Status = STATUS_INSUFFICIENT_RESOURCES;
  177. }
  178. RxLog(("** Recovered Sess for xchg %lx\n",pExchange));
  179. }
  180. return Status;
  181. }
  182. VOID
  183. SmbInitializeSmbSecuritySignature(
  184. IN OUT PSMBCE_SERVER Server,
  185. IN PUCHAR SessionKey,
  186. IN PUCHAR ChallengeResponse,
  187. IN ULONG ChallengeResponseLength
  188. )
  189. /*++
  190. Routine Description:
  191. Initializes the security signature generator for a session by calling MD5Update
  192. on the session key, challenge response
  193. Arguments:
  194. SessionKey - Either the LM or NT session key, depending on which
  195. password was used for authentication, must be at least 16 bytes
  196. ChallengeResponse - The challenge response used for authentication, must
  197. be at least 24 bytes
  198. --*/
  199. {
  200. //DbgPrint( "MRxSmb: Initialize Security Signature Intermediate Contex\n");
  201. RtlZeroMemory(&Server->SmbSecuritySignatureIntermediateContext, sizeof(MD5_CTX));
  202. MD5Init(&Server->SmbSecuritySignatureIntermediateContext);
  203. if (SessionKey != NULL) {
  204. MD5Update(&Server->SmbSecuritySignatureIntermediateContext,
  205. (PCHAR)SessionKey,
  206. MSV1_0_USER_SESSION_KEY_LENGTH);
  207. }
  208. MD5Update(&Server->SmbSecuritySignatureIntermediateContext,
  209. (PCHAR)ChallengeResponse,
  210. ChallengeResponseLength);
  211. Server->SmbSecuritySignatureIndex = 0;
  212. }
  213. BOOLEAN DumpSecuritySignature = FALSE;
  214. NTSTATUS
  215. SmbAddSmbSecuritySignature(
  216. IN PSMBCE_SERVER Server,
  217. IN OUT PMDL Mdl,
  218. IN OUT ULONG *ServerIndex,
  219. IN ULONG SendLength
  220. )
  221. /*++
  222. Routine Description:
  223. Generates the next security signature
  224. Arguments:
  225. WorkContext - the context to sign
  226. Return Value:
  227. none.
  228. --*/
  229. {
  230. NTSTATUS Status = STATUS_SUCCESS;
  231. MD5_CTX Context;
  232. PSMB_HEADER Smb;
  233. PCHAR SysAddress;
  234. ULONG MessageLength = 0;
  235. Smb = MmGetSystemAddressForMdlSafe(Mdl,LowPagePriority);
  236. if (Smb == NULL) {
  237. return STATUS_INSUFFICIENT_RESOURCES;
  238. }
  239. //SmbPutUshort(&Smb->Gid,(USHORT)Server->SmbSecuritySignatureIndex+1);
  240. SmbPutUlong(Smb->SecuritySignature,Server->SmbSecuritySignatureIndex);
  241. *ServerIndex = Server->SmbSecuritySignatureIndex+1; //Index of server response
  242. RtlZeroMemory(Smb->SecuritySignature + sizeof(ULONG),
  243. SMB_SECURITY_SIGNATURE_LENGTH-sizeof(ULONG));
  244. //
  245. // Start out with our initial context
  246. //
  247. RtlCopyMemory( &Context, &Server->SmbSecuritySignatureIntermediateContext, sizeof( Context ) );
  248. //
  249. // Compute the signature for the SMB we're about to send
  250. //
  251. do {
  252. SysAddress = MmGetSystemAddressForMdlSafe(Mdl,LowPagePriority);
  253. if (SysAddress == NULL) {
  254. return STATUS_INSUFFICIENT_RESOURCES;
  255. }
  256. if (Mdl->ByteCount >= SendLength) {
  257. MD5Update(&Context, SysAddress, SendLength);
  258. MessageLength += SendLength;
  259. SendLength = 0;
  260. ASSERT(Mdl->Next == NULL);
  261. break;
  262. } else {
  263. MD5Update(&Context, SysAddress, Mdl->ByteCount);
  264. SendLength -= Mdl->ByteCount;
  265. MessageLength += Mdl->ByteCount;
  266. ASSERT(Mdl->Next != NULL);
  267. }
  268. } while( (Mdl = Mdl->Next) != NULL );
  269. MD5Final( &Context );
  270. // Put the signature into the SMB
  271. RtlCopyMemory(
  272. Smb->SecuritySignature,
  273. Context.digest,
  274. SMB_SECURITY_SIGNATURE_LENGTH
  275. );
  276. if (DumpSecuritySignature) {
  277. DbgPrint("Add Signature: index %u length %u\n", *ServerIndex-1,MessageLength);
  278. }
  279. return STATUS_SUCCESS;
  280. }
  281. VOID
  282. SmbDumpSignatureError(
  283. IN PSMB_EXCHANGE pExchange,
  284. IN PUCHAR ExpectedSignature,
  285. IN PUCHAR ActualSignature,
  286. IN ULONG Length
  287. )
  288. /*++
  289. Routine Description:
  290. Print the mismatched signature information to the debugger
  291. Arguments:
  292. Return Value:
  293. none.
  294. --*/
  295. {
  296. PWCHAR p;
  297. DWORD i;
  298. PSMBCEDB_SERVER_ENTRY pServerEntry = (PSMBCEDB_SERVER_ENTRY)SmbCeGetExchangeServerEntry(pExchange);
  299. //
  300. // Security Signature Mismatch!
  301. //
  302. //DbgPrint("MRXSMB: Bad security signature from %wZ ", &pServerEntry->Name);
  303. DbgPrint("\n\t Wanted: ");
  304. for( i = 0; i < SMB_SECURITY_SIGNATURE_LENGTH; i++ ) {
  305. DbgPrint( "%X ", ExpectedSignature[i] & 0xff );
  306. }
  307. DbgPrint("\n\tReceived: ");
  308. for( i = 0; i < SMB_SECURITY_SIGNATURE_LENGTH; i++ ) {
  309. DbgPrint( "%X ", ActualSignature[i] & 0xff );
  310. }
  311. DbgPrint("\n\tLength %u, Expected Index Number %X\n", Length, pExchange->SmbSecuritySignatureIndex);
  312. }
  313. VOID
  314. SmbCheckSecuritySignature(
  315. IN PSMB_EXCHANGE pExchange,
  316. IN PSMBCE_SERVER Server,
  317. IN ULONG MessageLength,
  318. IN PVOID pBuffer
  319. )
  320. /*++
  321. Routine Description:
  322. This routine checks whether the security signature on the server response matches the one that is
  323. calculated on the client machine.
  324. Arguments:
  325. Return Value:
  326. A BOOLEAN value is returned to indicated whether the security signature matches.
  327. --*/
  328. {
  329. MD5_CTX *Context = &pExchange->MD5Context;
  330. PCHAR SavedSignature = pExchange->ResponseSignature;
  331. PSMB_HEADER Smb = (PSMB_HEADER)pBuffer;
  332. ULONG ServerIndex;
  333. BOOLEAN Correct;
  334. //
  335. // Initialize the Context
  336. //
  337. RtlCopyMemory(Context, &Server->SmbSecuritySignatureIntermediateContext, sizeof(MD5_CTX));
  338. //
  339. // Save the signature that's presently in the SMB
  340. //
  341. RtlCopyMemory( SavedSignature, Smb->SecuritySignature, sizeof(CHAR) * SMB_SECURITY_SIGNATURE_LENGTH);
  342. //
  343. // Put the correct (expected) signature index into the buffer
  344. //
  345. SmbPutUlong( Smb->SecuritySignature, pExchange->SmbSecuritySignatureIndex );
  346. RtlZeroMemory( Smb->SecuritySignature + sizeof(ULONG),
  347. SMB_SECURITY_SIGNATURE_LENGTH-sizeof(ULONG));
  348. //
  349. // Compute what the signature should be
  350. //
  351. MD5Update(Context, (PUCHAR)pBuffer, (UINT)MessageLength);
  352. //
  353. // Restore the signature that's presently in the SMB Header
  354. //
  355. RtlCopyMemory( Smb->SecuritySignature, SavedSignature, sizeof(CHAR)*SMB_SECURITY_SIGNATURE_LENGTH);
  356. }
  357. BOOLEAN
  358. SmbCheckSecuritySignaturePartial(
  359. IN PSMB_EXCHANGE pExchange,
  360. IN PSMBCE_SERVER Server,
  361. IN ULONG DataLength,
  362. IN PMDL Mdl
  363. )
  364. /*++
  365. Routine Description:
  366. This routine checks whether the security signature on the server response matches the one that is
  367. calculated on the client machine.
  368. Arguments:
  369. Return Value:
  370. A BOOLEAN value is returned to indicated whether the security signature matches.
  371. --*/
  372. {
  373. MD5_CTX *Context = &pExchange->MD5Context;
  374. PCHAR SavedSignature = pExchange->ResponseSignature;
  375. ULONG ServerIndex;
  376. BOOLEAN Correct;
  377. PCHAR SysAddress;
  378. ULONG MessageLength = 0;
  379. do {
  380. SysAddress = MmGetSystemAddressForMdlSafe(Mdl,LowPagePriority);
  381. if (SysAddress == NULL) {
  382. return FALSE;
  383. }
  384. if (Mdl->ByteCount >= DataLength) {
  385. MD5Update(Context, SysAddress, DataLength);
  386. MessageLength += DataLength;
  387. ASSERT(Mdl->Next == NULL);
  388. break;
  389. } else {
  390. MD5Update(Context, SysAddress, Mdl->ByteCount);
  391. MessageLength += Mdl->ByteCount;
  392. ASSERT(Mdl->Next != NULL);
  393. }
  394. } while( (Mdl = Mdl->Next) != NULL );
  395. MD5Final(Context);
  396. //
  397. // Now compare them!
  398. //
  399. if( RtlCompareMemory( Context->digest, SavedSignature, sizeof( SavedSignature ) ) !=
  400. sizeof( SavedSignature ) ) {
  401. //SmbDumpSignatureError(pExchange,
  402. // Context.digest,
  403. // SavedSignature,
  404. // MessageLength);
  405. //DbgPrint("MRXSMB: SS mismatch command %X, Length %X, Expected Index Number %X\n",
  406. // Smb->Command, MessageLength, pExchange->SmbSecuritySignatureIndex);
  407. //DbgPrint(" server send length %X, mdl length %X index %X\n",
  408. // SmbGetUshort(&Smb->PidHigh), SmbGetUshort(&Smb->Pid), SmbGetUshort(&Smb->Gid));
  409. //DbgBreakPoint();
  410. //SmbCeTransportDisconnectIndicated(pExchange->SmbCeContext.pServerEntry);
  411. //RxLogFailure(
  412. // MRxSmbDeviceObject,
  413. // NULL,
  414. // EVENT_RDR_SECURITY_SIGNATURE_MISMATCH,
  415. // STATUS_UNSUCCESSFUL);
  416. return FALSE;
  417. } else {
  418. return TRUE;
  419. }
  420. }
  421. BOOLEAN
  422. SmbCheckSecuritySignatureWithMdl(
  423. IN PSMB_EXCHANGE pExchange,
  424. IN PSMBCE_SERVER Server,
  425. IN ULONG DataLength,
  426. IN PMDL Mdl
  427. )
  428. /*++
  429. Routine Description:
  430. This routine checks whether the security signature on the server response matches the one that is
  431. calculated on the client machine.
  432. Arguments:
  433. Return Value:
  434. A BOOLEAN value is returned to indicated whether the security signature matches.
  435. --*/
  436. {
  437. MD5_CTX *Context = &pExchange->MD5Context;
  438. PCHAR SavedSignature = pExchange->ResponseSignature;
  439. ULONG ServerIndex;
  440. BOOLEAN Correct;
  441. PCHAR SysAddress;
  442. ULONG MessageLength = 0;
  443. ASSERT(Mdl->Next == NULL);
  444. SysAddress = MmGetSystemAddressForMdlSafe(Mdl,LowPagePriority);
  445. if (SysAddress == NULL) {
  446. return FALSE;
  447. }
  448. SmbCheckSecuritySignature(pExchange,
  449. Server,
  450. DataLength,
  451. SysAddress);
  452. MD5Final(&pExchange->MD5Context);
  453. if (RtlCompareMemory( Context->digest, pExchange->ResponseSignature, SMB_SECURITY_SIGNATURE_LENGTH*sizeof(CHAR)) !=
  454. SMB_SECURITY_SIGNATURE_LENGTH*sizeof(CHAR)) {
  455. PSMB_HEADER Smb = (PSMB_HEADER)SysAddress;
  456. //SmbDumpSignatureError(pExchange,
  457. // Context.digest,
  458. // SavedSignature,
  459. // MessageLength);
  460. #if DBG
  461. DbgPrint("MRXSMB: SS mismatch command %X, Length %X, Expected Index Number %X\n",
  462. Smb->Command, MessageLength, pExchange->SmbSecuritySignatureIndex);
  463. DbgPrint(" server send length %X, mdl length %X index %X\n",
  464. SmbGetUshort(&Smb->PidHigh), SmbGetUshort(&Smb->Pid), SmbGetUshort(&Smb->Gid));
  465. #endif
  466. //DbgBreakPoint();
  467. //SmbCeTransportDisconnectIndicated(pExchange->SmbCeContext.pServerEntry);
  468. //RxLogFailure(
  469. // MRxSmbDeviceObject,
  470. // NULL,
  471. // EVENT_RDR_SECURITY_SIGNATURE_MISMATCH,
  472. // STATUS_UNSUCCESSFUL);
  473. return FALSE;
  474. } else {
  475. return TRUE;
  476. }
  477. }