SMB2Command.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /* Copyright (C) 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 Utilities;
  10. namespace SMBLibrary.SMB2
  11. {
  12. public abstract class SMB2Command
  13. {
  14. public SMB2Header Header;
  15. public SMB2Command(SMB2CommandName commandName)
  16. {
  17. Header = new SMB2Header(commandName);
  18. }
  19. public SMB2Command(byte[] buffer, int offset)
  20. {
  21. Header = new SMB2Header(buffer, offset);
  22. }
  23. public void WriteBytes(byte[] buffer, int offset)
  24. {
  25. Header.WriteBytes(buffer, offset);
  26. WriteCommandBytes(buffer, offset + SMB2Header.Length);
  27. }
  28. public abstract void WriteCommandBytes(byte[] buffer, int offset);
  29. public byte[] GetBytes()
  30. {
  31. byte[] buffer = new byte[this.Length];
  32. WriteBytes(buffer, 0);
  33. return buffer;
  34. }
  35. public SMB2CommandName CommandName
  36. {
  37. get
  38. {
  39. return Header.Command;
  40. }
  41. }
  42. public int Length
  43. {
  44. get
  45. {
  46. return SMB2Header.Length + CommandLength;
  47. }
  48. }
  49. public abstract int CommandLength
  50. {
  51. get;
  52. }
  53. public static SMB2Command ReadRequest(byte[] buffer, int offset)
  54. {
  55. SMB2CommandName Command = (SMB2CommandName)LittleEndianConverter.ToUInt16(buffer, offset + 12);
  56. switch (Command)
  57. {
  58. case SMB2CommandName.Negotiate:
  59. return new NegotiateRequest(buffer, offset);
  60. case SMB2CommandName.SessionSetup:
  61. return new SessionSetupRequest(buffer, offset);
  62. case SMB2CommandName.Logoff:
  63. return new LogoffRequest(buffer, offset);
  64. case SMB2CommandName.TreeConnect:
  65. return new TreeConnectRequest(buffer, offset);
  66. case SMB2CommandName.TreeDisconnect:
  67. return new TreeDisconnectRequest(buffer, offset);
  68. case SMB2CommandName.Create:
  69. return new CreateRequest(buffer, offset);
  70. case SMB2CommandName.Close:
  71. return new CloseRequest(buffer, offset);
  72. case SMB2CommandName.Flush:
  73. return new FlushRequest(buffer, offset);
  74. case SMB2CommandName.Read:
  75. return new ReadRequest(buffer, offset);
  76. case SMB2CommandName.Write:
  77. return new WriteRequest(buffer, offset);
  78. case SMB2CommandName.Lock:
  79. return new LockRequest(buffer, offset);
  80. case SMB2CommandName.IOCtl:
  81. return new IOCtlRequest(buffer, offset);
  82. case SMB2CommandName.Cancel:
  83. return new CancelRequest(buffer, offset);
  84. case SMB2CommandName.Echo:
  85. return new EchoRequest(buffer, offset);
  86. case SMB2CommandName.QueryDirectory:
  87. return new QueryDirectoryRequest(buffer, offset);
  88. case SMB2CommandName.ChangeNotify:
  89. return new ChangeNotifyRequest(buffer, offset);
  90. case SMB2CommandName.QueryInfo:
  91. return new QueryInfoRequest(buffer, offset);
  92. case SMB2CommandName.SetInfo:
  93. return new SetInfoRequest(buffer, offset);
  94. default:
  95. throw new System.IO.InvalidDataException("Invalid SMB2 command in buffer");
  96. }
  97. }
  98. public static List<SMB2Command> ReadRequestChain(byte[] buffer, int offset)
  99. {
  100. List<SMB2Command> result = new List<SMB2Command>();
  101. SMB2Command command;
  102. do
  103. {
  104. command = ReadRequest(buffer, offset);
  105. result.Add(command);
  106. offset += (int)command.Header.NextCommand;
  107. }
  108. while (command.Header.NextCommand != 0);
  109. return result;
  110. }
  111. public static byte[] GetCommandChainBytes(List<SMB2Command> commands)
  112. {
  113. int totalLength = 0;
  114. for (int index = 0; index < commands.Count; index++)
  115. {
  116. // Any subsequent SMB2 header MUST be 8-byte aligned
  117. int length = commands[index].Length;
  118. if (index < commands.Count - 1)
  119. {
  120. int paddedLength = (int)Math.Ceiling((double)length / 8) * 8;
  121. totalLength += paddedLength;
  122. }
  123. else
  124. {
  125. totalLength += length;
  126. }
  127. }
  128. byte[] buffer = new byte[totalLength];
  129. int offset = 0;
  130. for (int index = 0; index < commands.Count; index++)
  131. {
  132. SMB2Command command = commands[index];
  133. int commandLength = command.Length;
  134. int paddedLength = (int)Math.Ceiling((double)commandLength / 8) * 8;
  135. if (index < commands.Count - 1)
  136. {
  137. command.Header.NextCommand = (uint)paddedLength;
  138. }
  139. command.WriteBytes(buffer, offset);
  140. offset += paddedLength;
  141. }
  142. return buffer;
  143. }
  144. }
  145. }