NTTransactHelper.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Text;
  10. using SMBLibrary.SMB1;
  11. using Utilities;
  12. namespace SMBLibrary.Server.SMB1
  13. {
  14. internal class NTTransactHelper
  15. {
  16. /// <summary>
  17. /// The client MUST send as many secondary requests as are needed to complete the transfer of the transaction request.
  18. /// </summary>
  19. internal static List<SMB1Command> GetNTTransactResponse(SMB1Header header, NTTransactRequest request, ISMBShare share, SMB1ConnectionState state)
  20. {
  21. if (request.TransParameters.Length < request.TotalParameterCount ||
  22. request.TransData.Length < request.TotalDataCount)
  23. {
  24. // A secondary transaction request is pending
  25. ProcessStateObject processState = state.CreateProcessState(header.PID);
  26. processState.SubcommandID = (ushort)request.Function;
  27. processState.MaxParameterCount = request.MaxParameterCount;
  28. processState.MaxDataCount = request.MaxDataCount;
  29. processState.TransactionSetup = request.Setup;
  30. processState.TransactionParameters = new byte[request.TotalParameterCount];
  31. processState.TransactionData = new byte[request.TotalDataCount];
  32. ByteWriter.WriteBytes(processState.TransactionParameters, 0, request.TransParameters);
  33. ByteWriter.WriteBytes(processState.TransactionData, 0, request.TransData);
  34. processState.TransactionParametersReceived += request.TransParameters.Length;
  35. processState.TransactionDataReceived += request.TransData.Length;
  36. return new NTTransactInterimResponse();
  37. }
  38. else
  39. {
  40. // We have a complete command
  41. return GetCompleteNTTransactResponse(header, request.MaxParameterCount, request.MaxDataCount, request.Function, request.Setup, request.TransParameters, request.TransData, share, state);
  42. }
  43. }
  44. /// <summary>
  45. /// There are no secondary response messages.
  46. /// The client MUST send as many secondary requests as are needed to complete the transfer of the transaction request.
  47. /// </summary>
  48. internal static List<SMB1Command> GetNTTransactResponse(SMB1Header header, NTTransactSecondaryRequest request, ISMBShare share, SMB1ConnectionState state)
  49. {
  50. ProcessStateObject processState = state.GetProcessState(header.PID);
  51. if (processState == null)
  52. {
  53. throw new InvalidRequestException();
  54. }
  55. ByteWriter.WriteBytes(processState.TransactionParameters, (int)request.ParameterDisplacement, request.TransParameters);
  56. ByteWriter.WriteBytes(processState.TransactionData, (int)request.DataDisplacement, request.TransData);
  57. processState.TransactionParametersReceived += request.TransParameters.Length;
  58. processState.TransactionDataReceived += request.TransData.Length;
  59. if (processState.TransactionParametersReceived < processState.TransactionParameters.Length ||
  60. processState.TransactionDataReceived < processState.TransactionData.Length)
  61. {
  62. return new List<SMB1Command>();
  63. }
  64. else
  65. {
  66. // We have a complete command
  67. state.RemoveProcessState(header.PID);
  68. return GetCompleteNTTransactResponse(header, processState.MaxParameterCount, processState.MaxDataCount, (NTTransactSubcommandName)processState.SubcommandID, processState.TransactionSetup, processState.TransactionParameters, processState.TransactionData, share, state);
  69. }
  70. }
  71. internal static List<SMB1Command> GetCompleteNTTransactResponse(SMB1Header header, uint maxParameterCount, uint maxDataCount, NTTransactSubcommandName subcommandName, byte[] requestSetup, byte[] requestParameters, byte[] requestData, ISMBShare share, SMB1ConnectionState state)
  72. {
  73. NTTransactSubcommand subcommand = NTTransactSubcommand.GetSubcommandRequest(subcommandName, requestSetup, requestParameters, requestData, header.UnicodeFlag);
  74. NTTransactSubcommand subcommandResponse = null;
  75. if (subcommand is NTTransactCreateRequest)
  76. {
  77. header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
  78. }
  79. else if (subcommand is NTTransactIOCTLRequest)
  80. {
  81. subcommandResponse = GetSubcommandResponse(header, maxDataCount, (NTTransactIOCTLRequest)subcommand, share, state);
  82. }
  83. else if (subcommand is NTTransactSetSecurityDescriptor)
  84. {
  85. header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
  86. }
  87. else if (subcommand is NTTransactNotifyChangeRequest)
  88. {
  89. // [MS-CIFS] If the server does not support the NT_TRANSACT_NOTIFY_CHANGE subcommand, it can return an
  90. // error response with STATUS_NOT_IMPLEMENTED [..] in response to an NT_TRANSACT_NOTIFY_CHANGE Request.
  91. header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
  92. }
  93. else if (subcommand is NTTransactQuerySecurityDescriptorRequest)
  94. {
  95. header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
  96. }
  97. else
  98. {
  99. header.Status = NTStatus.STATUS_SMB_BAD_COMMAND;
  100. }
  101. if (subcommandResponse == null)
  102. {
  103. return new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT);
  104. }
  105. byte[] responseSetup = subcommandResponse.GetSetup();
  106. byte[] responseParameters = subcommandResponse.GetParameters(header.UnicodeFlag);
  107. byte[] responseData = subcommandResponse.GetData();
  108. return GetNTTransactResponse(responseSetup, responseParameters, responseData, state.MaxBufferSize);
  109. }
  110. private static NTTransactIOCTLResponse GetSubcommandResponse(SMB1Header header, uint maxDataCount, NTTransactIOCTLRequest subcommand, ISMBShare share, SMB1ConnectionState state)
  111. {
  112. SMB1Session session = state.GetSession(header.UID);
  113. NTTransactIOCTLResponse response = new NTTransactIOCTLResponse();
  114. if (subcommand.IsFsctl)
  115. {
  116. OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);
  117. if (openFile == null)
  118. {
  119. header.Status = NTStatus.STATUS_INVALID_HANDLE;
  120. return null;
  121. }
  122. int maxOutputLength = (int)maxDataCount;
  123. byte[] output;
  124. header.Status = share.FileStore.DeviceIOControl(openFile.Handle, subcommand.FunctionCode, subcommand.Data, out output, maxOutputLength);
  125. if (header.Status != NTStatus.STATUS_SUCCESS && header.Status != NTStatus.STATUS_BUFFER_OVERFLOW)
  126. {
  127. return null;
  128. }
  129. response.Data = output;
  130. return response;
  131. }
  132. else
  133. {
  134. // [MS-SMB] If the IsFsctl field is set to zero, the server SHOULD fail the request with STATUS_NOT_SUPPORTED
  135. header.Status = NTStatus.STATUS_NOT_SUPPORTED;
  136. return null;
  137. }
  138. }
  139. private static List<SMB1Command> GetNTTransactResponse(byte[] responseSetup, byte[] responseParameters, byte[] responseData, int maxBufferSize)
  140. {
  141. if (NTTransactResponse.CalculateMessageSize(responseSetup.Length, responseParameters.Length, responseData.Length) <= maxBufferSize)
  142. {
  143. NTTransactResponse response = new NTTransactResponse();
  144. response.Setup = responseSetup;
  145. response.TotalParameterCount = (ushort)responseParameters.Length;
  146. response.TotalDataCount = (ushort)responseData.Length;
  147. response.TransParameters = responseParameters;
  148. response.TransData = responseData;
  149. return response;
  150. }
  151. else
  152. {
  153. throw new NotImplementedException();
  154. }
  155. }
  156. }
  157. }