NTTransactHelper.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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;
  74. try
  75. {
  76. subcommand = NTTransactSubcommand.GetSubcommandRequest(subcommandName, requestSetup, requestParameters, requestData, header.UnicodeFlag);
  77. }
  78. catch
  79. {
  80. // [MS-CIFS] If the Function code is not defined, the server MUST return STATUS_INVALID_SMB.
  81. header.Status = NTStatus.STATUS_INVALID_SMB;
  82. return new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT);
  83. }
  84. state.LogToServer(Severity.Verbose, "Received complete SMB_COM_NT_TRANSACT subcommand: {0}", subcommand.SubcommandName);
  85. NTTransactSubcommand subcommandResponse = null;
  86. if (subcommand is NTTransactCreateRequest)
  87. {
  88. header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
  89. }
  90. else if (subcommand is NTTransactIOCTLRequest)
  91. {
  92. subcommandResponse = GetSubcommandResponse(header, maxDataCount, (NTTransactIOCTLRequest)subcommand, share, state);
  93. }
  94. else if (subcommand is NTTransactSetSecurityDescriptor)
  95. {
  96. header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
  97. }
  98. else if (subcommand is NTTransactNotifyChangeRequest)
  99. {
  100. NotifyChangeHelper.ProcessNTTransactNotifyChangeRequest(header, maxParameterCount, (NTTransactNotifyChangeRequest)subcommand, share, state);
  101. if (header.Status == NTStatus.STATUS_PENDING)
  102. {
  103. return new List<SMB1Command>();
  104. }
  105. }
  106. else if (subcommand is NTTransactQuerySecurityDescriptorRequest)
  107. {
  108. header.Status = NTStatus.STATUS_NOT_IMPLEMENTED;
  109. }
  110. else
  111. {
  112. // [MS-CIFS] If the Function code is defined but not implemented, the server MUST return STATUS_SMB_BAD_COMMAND.
  113. header.Status = NTStatus.STATUS_SMB_BAD_COMMAND;
  114. }
  115. if (subcommandResponse == null)
  116. {
  117. return new ErrorResponse(CommandName.SMB_COM_NT_TRANSACT);
  118. }
  119. byte[] responseSetup = subcommandResponse.GetSetup();
  120. byte[] responseParameters = subcommandResponse.GetParameters(header.UnicodeFlag);
  121. byte[] responseData = subcommandResponse.GetData();
  122. return GetNTTransactResponse(responseSetup, responseParameters, responseData, state.MaxBufferSize);
  123. }
  124. private static NTTransactIOCTLResponse GetSubcommandResponse(SMB1Header header, uint maxDataCount, NTTransactIOCTLRequest subcommand, ISMBShare share, SMB1ConnectionState state)
  125. {
  126. SMB1Session session = state.GetSession(header.UID);
  127. NTTransactIOCTLResponse response = new NTTransactIOCTLResponse();
  128. if (subcommand.IsFsctl)
  129. {
  130. OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);
  131. if (openFile == null)
  132. {
  133. header.Status = NTStatus.STATUS_INVALID_HANDLE;
  134. return null;
  135. }
  136. int maxOutputLength = (int)maxDataCount;
  137. byte[] output;
  138. header.Status = share.FileStore.DeviceIOControl(openFile.Handle, subcommand.FunctionCode, subcommand.Data, out output, maxOutputLength);
  139. if (header.Status != NTStatus.STATUS_SUCCESS && header.Status != NTStatus.STATUS_BUFFER_OVERFLOW)
  140. {
  141. return null;
  142. }
  143. response.Data = output;
  144. return response;
  145. }
  146. else
  147. {
  148. // [MS-SMB] If the IsFsctl field is set to zero, the server SHOULD fail the request with STATUS_NOT_SUPPORTED
  149. header.Status = NTStatus.STATUS_NOT_SUPPORTED;
  150. return null;
  151. }
  152. }
  153. internal static List<SMB1Command> GetNTTransactResponse(byte[] responseSetup, byte[] responseParameters, byte[] responseData, int maxBufferSize)
  154. {
  155. if (NTTransactResponse.CalculateMessageSize(responseSetup.Length, responseParameters.Length, responseData.Length) <= maxBufferSize)
  156. {
  157. NTTransactResponse response = new NTTransactResponse();
  158. response.Setup = responseSetup;
  159. response.TotalParameterCount = (ushort)responseParameters.Length;
  160. response.TotalDataCount = (ushort)responseData.Length;
  161. response.TransParameters = responseParameters;
  162. response.TransData = responseData;
  163. return response;
  164. }
  165. else
  166. {
  167. throw new NotImplementedException();
  168. }
  169. }
  170. }
  171. }