123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- /* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
- *
- * You can redistribute this program and/or modify it under the terms of
- * the GNU Lesser Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- */
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Net;
- using System.Net.Sockets;
- using System.Threading;
- using SMBLibrary.NetBios;
- using SMBLibrary.SMB1;
- using Utilities;
- namespace SMBLibrary.Client
- {
- public class SMB1Client
- {
- public const int NetBiosOverTCPPort = 139;
- public const int DirectTCPPort = 445;
- public const string NTLanManagerDialect = "NT LM 0.12";
- private SMBTransportType m_transport;
- private bool m_isConnected;
- private Socket m_clientSocket;
- private IAsyncResult m_currentAsyncResult;
- private object m_incomingQueueLock = new object();
- private List<SMB1Message> m_incomingQueue = new List<SMB1Message>();
- private EventWaitHandle m_incomingQueueEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
- public SMB1Client()
- {
- }
- public bool Connect(IPAddress serverAddress, SMBTransportType transport)
- {
- m_transport = transport;
- if (!m_isConnected)
- {
- m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- int port;
- if (transport == SMBTransportType.DirectTCPTransport)
- {
- port = DirectTCPPort;
- }
- else
- {
- port = NetBiosOverTCPPort;
- }
- try
- {
- m_clientSocket.Connect(serverAddress, port);
- }
- catch (SocketException)
- {
- return false;
- }
- ConnectionState state = new ConnectionState();
- NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
- m_currentAsyncResult = m_clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnServerSocketReceive), state);
- bool supportsCIFS = NegotiateNTLanManagerDialect();
- if (!supportsCIFS)
- {
- m_clientSocket.Close();
- }
- else
- {
- m_isConnected = true;
- }
- }
- return m_isConnected;
- }
- public void Disconnect()
- {
- if (m_isConnected)
- {
- m_clientSocket.Disconnect(false);
- m_isConnected = false;
- }
- }
- private bool NegotiateNTLanManagerDialect()
- {
- if (m_transport == SMBTransportType.NetBiosOverTCP)
- {
- SessionRequestPacket sessionRequest = new SessionRequestPacket();
- sessionRequest.CalledName = NetBiosUtils.GetMSNetBiosName("*SMBSERVER", NetBiosSuffix.FileServiceService); ;
- sessionRequest.CallingName = NetBiosUtils.GetMSNetBiosName(Environment.MachineName, NetBiosSuffix.WorkstationService);
- TrySendPacket(m_clientSocket, sessionRequest);
- }
- NegotiateRequest request = new NegotiateRequest();
- request.Dialects.Add(NTLanManagerDialect);
- TrySendMessage(m_clientSocket, request);
- SMB1Message reply = WaitForMessage(CommandName.SMB_COM_NEGOTIATE);
- if (reply == null)
- {
- return false;
- }
- if (reply.Commands[0] is NegotiateResponse)
- {
- NegotiateResponse response = (NegotiateResponse)reply.Commands[0];
- return true;
- }
- else if (reply.Commands[0] is NegotiateResponseExtended)
- {
- NegotiateResponseExtended response = (NegotiateResponseExtended)reply.Commands[0];
- return true;
- }
- else
- {
- return false;
- }
- }
- private void OnServerSocketReceive(IAsyncResult ar)
- {
- if (ar != m_currentAsyncResult)
- {
- // We ignore calls for old sockets which we no longer use
- // See: http://rajputyh.blogspot.co.il/2010/04/solve-exception-message-iasyncresult.html
- return;
- }
- ConnectionState state = (ConnectionState)ar.AsyncState;
- if (!m_clientSocket.Connected)
- {
- return;
- }
- int numberOfBytesReceived = 0;
- try
- {
- numberOfBytesReceived = m_clientSocket.EndReceive(ar);
- }
- catch (ObjectDisposedException)
- {
- Log("[ReceiveCallback] EndReceive ObjectDisposedException");
- return;
- }
- catch (SocketException ex)
- {
- Log("[ReceiveCallback] EndReceive SocketException: " + ex.Message);
- return;
- }
- if (numberOfBytesReceived == 0)
- {
- m_isConnected = false;
- }
- else
- {
- NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
- buffer.SetNumberOfBytesReceived(numberOfBytesReceived);
- ProcessConnectionBuffer(state);
- try
- {
- m_currentAsyncResult = m_clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnServerSocketReceive), state);
- }
- catch (ObjectDisposedException)
- {
- m_isConnected = false;
- Log("[ReceiveCallback] BeginReceive ObjectDisposedException");
- }
- catch (SocketException ex)
- {
- m_isConnected = false;
- Log("[ReceiveCallback] BeginReceive SocketException: " + ex.Message);
- }
- }
- }
- private void ProcessConnectionBuffer(ConnectionState state)
- {
- NBTConnectionReceiveBuffer receiveBuffer = state.ReceiveBuffer;
- while (receiveBuffer.HasCompletePacket())
- {
- SessionPacket packet = null;
- try
- {
- packet = receiveBuffer.DequeuePacket();
- }
- catch (Exception)
- {
- m_clientSocket.Close();
- break;
- }
- if (packet != null)
- {
- ProcessPacket(packet, state);
- }
- }
- }
- private void ProcessPacket(SessionPacket packet, ConnectionState state)
- {
- if (packet is SessionKeepAlivePacket && m_transport == SMBTransportType.NetBiosOverTCP)
- {
- // [RFC 1001] NetBIOS session keep alives do not require a response from the NetBIOS peer
- }
- else if (packet is PositiveSessionResponsePacket && m_transport == SMBTransportType.NetBiosOverTCP)
- {
- }
- else if (packet is NegativeSessionResponsePacket && m_transport == SMBTransportType.NetBiosOverTCP)
- {
- m_clientSocket.Close();
- m_isConnected = false;
- }
- else if (packet is SessionMessagePacket)
- {
- SMB1Message message;
- try
- {
- message = SMB1Message.GetSMB1Message(packet.Trailer);
- }
- catch (Exception ex)
- {
- Log("Invalid SMB1 message: " + ex.Message);
- m_clientSocket.Close();
- m_isConnected = false;
- return;
- }
- lock (m_incomingQueueLock)
- {
- m_incomingQueue.Add(message);
- m_incomingQueueEventHandle.Set();
- }
- }
- }
- public SMB1Message WaitForMessage(CommandName commandName)
- {
- const int TimeOut = 5000;
- Stopwatch stopwatch = new Stopwatch();
- stopwatch.Start();
- while (stopwatch.ElapsedMilliseconds < TimeOut)
- {
- lock (m_incomingQueueLock)
- {
- for (int index = 0; index < m_incomingQueue.Count; index++)
- {
- SMB1Message message = m_incomingQueue[index];
- if (message.Commands[0].CommandName == commandName)
- {
- m_incomingQueue.RemoveAt(index);
- return message;
- }
- }
- }
- m_incomingQueueEventHandle.WaitOne(100);
- }
- return null;
- }
- public void Log(string message)
- {
- System.Diagnostics.Debug.Print(message);
- }
- public static void TrySendMessage(Socket serverSocket, SMB1Command request)
- {
- SMB1Message message = new SMB1Message();
- message.Commands.Add(request);
- TrySendMessage(serverSocket, message);
- }
- public static void TrySendMessage(Socket serverSocket, SMB1Message message)
- {
- SessionMessagePacket packet = new SessionMessagePacket();
- packet.Trailer = message.GetBytes();
- TrySendPacket(serverSocket, packet);
- }
- public static void TrySendPacket(Socket serverSocket, SessionPacket response)
- {
- try
- {
- serverSocket.Send(response.GetBytes());
- }
- catch (SocketException)
- {
- }
- catch (ObjectDisposedException)
- {
- }
- }
- }
- }
|