SMBServer.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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.Net;
  10. using System.Net.Sockets;
  11. using SMBLibrary.NetBios;
  12. using SMBLibrary.Services;
  13. using SMBLibrary.SMB1;
  14. using Utilities;
  15. namespace SMBLibrary.Server
  16. {
  17. public partial class SMBServer
  18. {
  19. public const int NetBiosOverTCPPort = 139;
  20. public const int DirectTCPPort = 445;
  21. public const string NTLanManagerDialect = "NT LM 0.12";
  22. public const bool EnableExtendedSecurity = true;
  23. private ShareCollection m_shares; // e.g. Shared folders
  24. private INTLMAuthenticationProvider m_users;
  25. private NamedPipeShare m_services; // Named pipes
  26. private IPAddress m_serverAddress;
  27. private SMBTransportType m_transport;
  28. private Socket m_listenerSocket;
  29. private bool m_listening;
  30. private Guid m_serverGuid;
  31. public SMBServer(ShareCollection shares, INTLMAuthenticationProvider users, IPAddress serverAddress, SMBTransportType transport)
  32. {
  33. m_shares = shares;
  34. m_users = users;
  35. m_serverAddress = serverAddress;
  36. m_serverGuid = Guid.NewGuid();
  37. m_transport = transport;
  38. m_services = new NamedPipeShare(shares.ListShares());
  39. }
  40. public void Start()
  41. {
  42. if (!m_listening)
  43. {
  44. m_listening = true;
  45. m_listenerSocket = new Socket(m_serverAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  46. int port = (m_transport == SMBTransportType.DirectTCPTransport ? DirectTCPPort : NetBiosOverTCPPort);
  47. m_listenerSocket.Bind(new IPEndPoint(m_serverAddress, port));
  48. m_listenerSocket.Listen((int)SocketOptionName.MaxConnections);
  49. m_listenerSocket.BeginAccept(ConnectRequestCallback, m_listenerSocket);
  50. }
  51. }
  52. public void Stop()
  53. {
  54. m_listening = false;
  55. SocketUtils.ReleaseSocket(m_listenerSocket);
  56. }
  57. // This method Accepts new connections
  58. private void ConnectRequestCallback(IAsyncResult ar)
  59. {
  60. System.Diagnostics.Debug.Print("[{0}] New connection request", DateTime.Now.ToString("HH:mm:ss:ffff"));
  61. Socket listenerSocket = (Socket)ar.AsyncState;
  62. Socket clientSocket;
  63. try
  64. {
  65. clientSocket = listenerSocket.EndAccept(ar);
  66. }
  67. catch (ObjectDisposedException)
  68. {
  69. return;
  70. }
  71. catch (SocketException ex)
  72. {
  73. const int WSAECONNRESET = 10054;
  74. // Client may have closed the connection before we start to process the connection request.
  75. // When we get this error, we have to continue to accept other requests.
  76. // See http://stackoverflow.com/questions/7704417/socket-endaccept-error-10054
  77. if (ex.ErrorCode == WSAECONNRESET)
  78. {
  79. m_listenerSocket.BeginAccept(ConnectRequestCallback, m_listenerSocket);
  80. }
  81. System.Diagnostics.Debug.Print("[{0}] Connection request error {1}", DateTime.Now.ToString("HH:mm:ss:ffff"), ex.ErrorCode);
  82. return;
  83. }
  84. SMB1ConnectionState state = new SMB1ConnectionState();
  85. // Disable the Nagle Algorithm for this tcp socket:
  86. clientSocket.NoDelay = true;
  87. state.ClientSocket = clientSocket;
  88. try
  89. {
  90. // Direct TCP transport packet is actually an NBT Session Message Packet,
  91. // So in either case (NetBios over TCP or Direct TCP Transport) we will receive an NBT packet.
  92. clientSocket.BeginReceive(state.ReceiveBuffer.Buffer, state.ReceiveBuffer.WriteOffset, state.ReceiveBuffer.AvailableLength, 0, ReceiveCallback, state);
  93. }
  94. catch (ObjectDisposedException)
  95. {
  96. }
  97. catch (SocketException)
  98. {
  99. }
  100. m_listenerSocket.BeginAccept(ConnectRequestCallback, m_listenerSocket);
  101. }
  102. private void ReceiveCallback(IAsyncResult result)
  103. {
  104. SMB1ConnectionState state = (SMB1ConnectionState)result.AsyncState;
  105. Socket clientSocket = state.ClientSocket;
  106. if (!m_listening)
  107. {
  108. clientSocket.Close();
  109. return;
  110. }
  111. int numberOfBytesReceived;
  112. try
  113. {
  114. numberOfBytesReceived = clientSocket.EndReceive(result);
  115. }
  116. catch (ObjectDisposedException)
  117. {
  118. return;
  119. }
  120. catch (SocketException)
  121. {
  122. return;
  123. }
  124. if (numberOfBytesReceived == 0)
  125. {
  126. // The other side has closed the connection
  127. System.Diagnostics.Debug.Print("[{0}] The other side closed the connection", DateTime.Now.ToString("HH:mm:ss:ffff"));
  128. clientSocket.Close();
  129. return;
  130. }
  131. NBTConnectionReceiveBuffer receiveBuffer = state.ReceiveBuffer;
  132. receiveBuffer.SetNumberOfBytesReceived(numberOfBytesReceived);
  133. ProcessConnectionBuffer(state);
  134. if (clientSocket.Connected)
  135. {
  136. try
  137. {
  138. clientSocket.BeginReceive(state.ReceiveBuffer.Buffer, state.ReceiveBuffer.WriteOffset, state.ReceiveBuffer.AvailableLength, 0, ReceiveCallback, state);
  139. }
  140. catch (ObjectDisposedException)
  141. {
  142. }
  143. catch (SocketException)
  144. {
  145. }
  146. }
  147. }
  148. public void ProcessConnectionBuffer(SMB1ConnectionState state)
  149. {
  150. Socket clientSocket = state.ClientSocket;
  151. NBTConnectionReceiveBuffer receiveBuffer = state.ReceiveBuffer;
  152. while (receiveBuffer.HasCompletePacket())
  153. {
  154. SessionPacket packet = null;
  155. try
  156. {
  157. packet = receiveBuffer.DequeuePacket();
  158. }
  159. catch (Exception)
  160. {
  161. state.ClientSocket.Close();
  162. }
  163. if (packet != null)
  164. {
  165. ProcessPacket(packet, state);
  166. }
  167. }
  168. }
  169. public void ProcessPacket(SessionPacket packet, SMB1ConnectionState state)
  170. {
  171. if (packet is SessionRequestPacket && m_transport == SMBTransportType.NetBiosOverTCP)
  172. {
  173. PositiveSessionResponsePacket response = new PositiveSessionResponsePacket();
  174. TrySendPacket(state, response);
  175. }
  176. else if (packet is SessionKeepAlivePacket && m_transport == SMBTransportType.NetBiosOverTCP)
  177. {
  178. // [RFC 1001] NetBIOS session keep alives do not require a response from the NetBIOS peer
  179. }
  180. else if (packet is SessionMessagePacket)
  181. {
  182. SMB1Message message = null;
  183. #if DEBUG
  184. message = SMB1Message.GetSMB1Message(packet.Trailer);
  185. System.Diagnostics.Debug.Print("[{0}] Message Received: {1} Commands, First Command: {2}, Packet length: {3}", DateTime.Now.ToString("HH:mm:ss:ffff"), message.Commands.Count, message.Commands[0].CommandName.ToString(), packet.Length);
  186. #else
  187. try
  188. {
  189. message = SMB1Message.GetSMB1Message(packet.Trailer);
  190. }
  191. catch (Exception)
  192. {
  193. state.ClientSocket.Close();
  194. return;
  195. }
  196. #endif
  197. ProcessSMB1Message(message, state);
  198. }
  199. else
  200. {
  201. System.Diagnostics.Debug.Print("[{0}] Invalid NetBIOS packet", DateTime.Now.ToString("HH:mm:ss:ffff"));
  202. state.ClientSocket.Close();
  203. return;
  204. }
  205. }
  206. public static void TrySendPacket(SMB1ConnectionState state, SessionPacket response)
  207. {
  208. Socket clientSocket = state.ClientSocket;
  209. try
  210. {
  211. clientSocket.Send(response.GetBytes());
  212. }
  213. catch (SocketException)
  214. {
  215. }
  216. catch (ObjectDisposedException)
  217. {
  218. }
  219. }
  220. }
  221. }