Esempio n. 1
0
        private static void UpdateSMB2Header(SMB2Command response, SMB2Command request, ConnectionState state)
        {
            response.Header.MessageID           = request.Header.MessageID;
            response.Header.CreditCharge        = request.Header.CreditCharge;
            response.Header.Credits             = Math.Max((ushort)1, request.Header.Credits);
            response.Header.IsRelatedOperations = request.Header.IsRelatedOperations;
            response.Header.Reserved            = request.Header.Reserved;
            if (response.Header.SessionID == 0)
            {
                response.Header.SessionID = request.Header.SessionID;
            }
            if (response.Header.TreeID == 0)
            {
                response.Header.TreeID = request.Header.TreeID;
            }
            bool signingRequired = false;

            if (state is SMB2ConnectionState)
            {
                SMB2Session session = ((SMB2ConnectionState)state).GetSession(response.Header.SessionID);
                if (session != null && session.SigningRequired)
                {
                    signingRequired = true;
                }
            }
            // [MS-SMB2] The server SHOULD sign the message [..] if the request was signed by the client,
            // and the response is not an interim response to an asynchronously processed request.
            bool isInterimResponse = (response.Header.IsAsync && response.Header.Status == NTStatus.STATUS_PENDING);

            response.Header.IsSigned = (request.Header.IsSigned || signingRequired) && !isInterimResponse;
        }
Esempio n. 2
0
 internal static void EnqueueResponse(ConnectionState state, SMB2Command response)
 {
     List<SMB2Command> responseChain = new List<SMB2Command>();
     responseChain.Add(response);
     EnqueueResponseChain(state, responseChain);
 }
Esempio n. 3
0
 public SMB1ConnectionState(ConnectionState state) : base(state)
 {
 }
Esempio n. 4
0
        private void ProcessPacket(SessionPacket packet, ref ConnectionState state)
        {
            if (packet is SessionRequestPacket && m_transport == SMBTransportType.NetBiosOverTCP)
            {
                PositiveSessionResponsePacket response = new PositiveSessionResponsePacket();
                state.SendQueue.Enqueue(response);
            }
            else 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 SessionMessagePacket)
            {
                // Note: To be compatible with SMB2 specifications, we must accept SMB_COM_NEGOTIATE.
                // We will disconnect the connection if m_enableSMB1 == false and the client does not support SMB2.
                bool acceptSMB1 = (state.Dialect == SMBDialect.NotSet || state.Dialect == SMBDialect.NTLM012);
                bool acceptSMB2 = (m_enableSMB2 && (state.Dialect == SMBDialect.NotSet || state.Dialect == SMBDialect.SMB202 || state.Dialect == SMBDialect.SMB210));

                if (SMB1Header.IsValidSMB1Header(packet.Trailer))
                {
                    if (!acceptSMB1)
                    {
                        state.LogToServer(Severity.Verbose, "Rejected SMB1 message");
                        state.ClientSocket.Dispose();
                        return;
                    }

                    SMB1Message message = null;
                    try
                    {
                        message = SMB1Message.GetSMB1Message(packet.Trailer);
                    }
                    catch (Exception ex)
                    {
                        state.LogToServer(Severity.Warning, "Invalid SMB1 message: " + ex.Message);
                        state.ClientSocket.Dispose();
                        return;
                    }
                    state.LogToServer(Severity.Verbose, "SMB1 message received: {0} requests, First request: {1}, Packet length: {2}", message.Commands.Count, message.Commands[0].CommandName.ToString(), packet.Length);
                    if (state.Dialect == SMBDialect.NotSet && m_enableSMB2)
                    {
                        // Check if the client supports SMB 2
                        List <string> smb2Dialects = SMB2.NegotiateHelper.FindSMB2Dialects(message);
                        if (smb2Dialects.Count > 0)
                        {
                            SMB2Command response = SMB2.NegotiateHelper.GetNegotiateResponse(smb2Dialects, m_securityProvider, state, m_serverGuid, m_serverStartTime);
                            if (state.Dialect != SMBDialect.NotSet)
                            {
                                state = new SMB2ConnectionState(state);
                                m_connectionManager.AddConnection(state);
                            }
                            EnqueueResponse(state, response);
                            return;
                        }
                    }

                    if (m_enableSMB1)
                    {
                        ProcessSMB1Message(message, ref state);
                    }
                    else
                    {
                        // [MS-SMB2] 3.3.5.3.2 If the string is not present in the dialect list and the server does not implement SMB,
                        // the server MUST disconnect the connection [..] without sending a response.
                        state.LogToServer(Severity.Verbose, "Rejected SMB1 message");
                        state.ClientSocket.Dispose();
                    }
                }
                else if (SMB2Header.IsValidSMB2Header(packet.Trailer))
                {
                    if (!acceptSMB2)
                    {
                        state.LogToServer(Severity.Verbose, "Rejected SMB2 message");
                        state.ClientSocket.Dispose();
                        return;
                    }

                    List <SMB2Command> requestChain;
                    try
                    {
                        requestChain = SMB2Command.ReadRequestChain(packet.Trailer, 0);
                    }
                    catch (Exception ex)
                    {
                        state.LogToServer(Severity.Warning, "Invalid SMB2 request chain: " + ex.Message);
                        state.ClientSocket.Dispose();
                        return;
                    }
                    state.LogToServer(Severity.Verbose, "SMB2 request chain received: {0} requests, First request: {1}, Packet length: {2}", requestChain.Count, requestChain[0].CommandName.ToString(), packet.Length);
                    ProcessSMB2RequestChain(requestChain, ref state);
                }
                else
                {
                    state.LogToServer(Severity.Warning, "Invalid SMB message");
                    state.ClientSocket.Dispose();
                }
            }
            else
            {
                state.LogToServer(Severity.Warning, "Invalid NetBIOS packet");
                state.ClientSocket.Dispose();
                return;
            }
        }
Esempio n. 5
0
        private void ReceiveCallback(object sender, SocketAsyncEventArgs result)
        {
            ConnectionState state        = (ConnectionState)result.UserToken;
            Socket          clientSocket = state.ClientSocket;

            if (!m_listening)
            {
                clientSocket.Dispose();
                return;
            }

            int numberOfBytesReceived;

            try
            {
                numberOfBytesReceived = result.BytesTransferred;
            }
            catch (ObjectDisposedException)
            {
                state.LogToServer(Severity.Debug, "The connection was terminated");
                m_connectionManager.ReleaseConnection(state);
                return;
            }
            catch (SocketException ex)
            {
                ///const int WSAECONNRESET = 10054;
                if (ex.SocketErrorCode == SocketError.ConnectionReset)
                {
                    state.LogToServer(Severity.Debug, "The connection was forcibly closed by the remote host");
                }
                else
                {
                    state.LogToServer(Severity.Debug, "The connection was terminated, Socket error code: {0}", ex.SocketErrorCode);
                }
                m_connectionManager.ReleaseConnection(state);
                return;
            }

            if (numberOfBytesReceived == 0)
            {
                state.LogToServer(Severity.Debug, "The client closed the connection");
                m_connectionManager.ReleaseConnection(state);
                return;
            }

            state.UpdateLastReceiveDT();
            NBTConnectionReceiveBuffer receiveBuffer = state.ReceiveBuffer;

            receiveBuffer.SetNumberOfBytesReceived(numberOfBytesReceived);
            ProcessConnectionBuffer(ref state);

            if (clientSocket.Connected)
            {
                try
                {
                    SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                    args.SetBuffer(state.ReceiveBuffer.Buffer, state.ReceiveBuffer.WriteOffset, state.ReceiveBuffer.AvailableLength);
                    args.Completed += ReceiveCallback;
                    args.UserToken  = state;
                    //m_currentAsyncResult =
                    if (!clientSocket.ReceiveAsync(args))
                    {
                        ReceiveCallback(sender, args);
                    }
                }
                catch (ObjectDisposedException)
                {
                    m_connectionManager.ReleaseConnection(state);
                }
                catch (SocketException)
                {
                    m_connectionManager.ReleaseConnection(state);
                }
            }
        }
Esempio n. 6
0
        // This method accepts new connections
        private void ConnectRequestCallback(object sender, SocketAsyncEventArgs ar)
        {
            Socket listenerSocket = (Socket)ar.UserToken;

            Socket clientSocket = ar.AcceptSocket;

            // Windows will set the TCP keepalive timeout to 120 seconds for an SMB connection
            SocketUtils.SetKeepAlive(clientSocket, TimeSpan.FromMinutes(2));
            // Disable the Nagle Algorithm for this tcp socket:
            clientSocket.NoDelay = true;
            IPEndPoint clientEndPoint = (IPEndPoint)clientSocket.RemoteEndPoint;
            EventHandler <ConnectionRequestEventArgs> handler = ConnectionRequested;
            bool acceptConnection = true;

            if (handler != null)
            {
                ConnectionRequestEventArgs connectionRequestArgs = new ConnectionRequestEventArgs(clientEndPoint);
                handler(this, connectionRequestArgs);
                acceptConnection = connectionRequestArgs.Accept;
            }

            if (acceptConnection)
            {
                ConnectionState state = new ConnectionState(clientSocket, clientEndPoint, Log);
                state.LogToServer(Severity.Verbose, "New connection request accepted");
                Thread senderThread = new Thread(delegate()
                {
                    ProcessSendQueue(state);
                });
                senderThread.IsBackground = true;
                senderThread.Start();

                try
                {
                    // Direct TCP transport packet is actually an NBT Session Message Packet,
                    // So in either case (NetBios over TCP or Direct TCP Transport) we will receive an NBT packet.
                    SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                    args.SetBuffer(state.ReceiveBuffer.Buffer, state.ReceiveBuffer.WriteOffset, state.ReceiveBuffer.AvailableLength);
                    args.Completed += ReceiveCallback;
                    args.UserToken  = state;
                    if (!clientSocket.ReceiveAsync(args))
                    {
                        ReceiveCallback(clientSocket, args);
                    }
                }
                catch (ObjectDisposedException)
                {
                }
                catch (SocketException)
                {
                }
            }
            else
            {
                Log(Severity.Verbose, "[{0}:{1}] New connection request rejected", clientEndPoint.Address, clientEndPoint.Port);
                clientSocket.Dispose();
            }

acceptConnection:
            try
            {
                ar.AcceptSocket = null;
                ar.UserToken    = listenerSocket;
                if (listenerSocket.AcceptAsync(ar) == false)
                {
                    ConnectRequestCallback(sender, ar);
                }
            }
            catch (ObjectDisposedException)
            {
                return;
            }
            catch (SocketException ex)
            {
                ///const int WSAECONNRESET = 10054; // The client may have closed the connection before we start to process the connection request.
                ///const int WSAETIMEDOUT = 10060; // The client did not properly respond after a period of time.
                // When we get WSAECONNRESET or WSAETIMEDOUT, we have to continue to accept other connection requests.
                // See http://stackoverflow.com/questions/7704417/socket-endaccept-error-10054
                if (ex.SocketErrorCode == SocketError.ConnectionReset || ex.SocketErrorCode == SocketError.TimedOut)
                {
                    goto acceptConnection;
                }
                Log(Severity.Debug, "Connection request error {0}", ex.SocketErrorCode);
                return;
            }
        }
Esempio n. 7
0
        private void ReceiveCallback(IAsyncResult result)
        {
            ConnectionState state        = (ConnectionState)result.AsyncState;
            Socket          clientSocket = state.ClientSocket;

            if (!m_listening)
            {
                clientSocket.Close();
                return;
            }

            int numberOfBytesReceived;

            try
            {
                numberOfBytesReceived = clientSocket.EndReceive(result);
            }
            catch (ObjectDisposedException)
            {
                state.LogToServer(Severity.Debug, "The connection was terminated");
                m_connectionManager.ReleaseConnection(state);
                return;
            }
            catch (SocketException ex)
            {
                const int WSAECONNRESET = 10054;
                if (ex.ErrorCode == WSAECONNRESET)
                {
                    state.LogToServer(Severity.Debug, "The connection was forcibly closed by the remote host");
                }
                else
                {
                    state.LogToServer(Severity.Debug, "The connection was terminated, Socket error code: {0}", ex.ErrorCode);
                }
                m_connectionManager.ReleaseConnection(state);
                return;
            }

            if (numberOfBytesReceived == 0)
            {
                state.LogToServer(Severity.Debug, "The client closed the connection");
                m_connectionManager.ReleaseConnection(state);
                return;
            }

            state.UpdateLastReceiveDT();
            NBTConnectionReceiveBuffer receiveBuffer = state.ReceiveBuffer;

            receiveBuffer.SetNumberOfBytesReceived(numberOfBytesReceived);
            ProcessConnectionBuffer(ref state);

            if (clientSocket.Connected)
            {
                try
                {
                    clientSocket.BeginReceive(state.ReceiveBuffer.Buffer, state.ReceiveBuffer.WriteOffset, state.ReceiveBuffer.AvailableLength, 0, ReceiveCallback, state);
                }
                catch (ObjectDisposedException)
                {
                    m_connectionManager.ReleaseConnection(state);
                }
                catch (SocketException)
                {
                    m_connectionManager.ReleaseConnection(state);
                }
            }
        }
Esempio n. 8
0
 /// <summary>
 /// May return an empty list
 /// </summary>
 private List <SMB1Command> ProcessSMB1Command(SMB1Header header, SMB1Command command, ref ConnectionState state)
 {
     if (state.Dialect == SMBDialect.NotSet)
     {
         if (command is NegotiateRequest)
         {
             NegotiateRequest request = (NegotiateRequest)command;
             if (request.Dialects.Contains(SMBServer.NTLanManagerDialect))
             {
                 state         = new SMB1ConnectionState(state);
                 state.Dialect = SMBDialect.NTLM012;
                 m_connectionManager.AddConnection(state);
                 if (EnableExtendedSecurity && header.ExtendedSecurityFlag)
                 {
                     return(NegotiateHelper.GetNegotiateResponseExtended(request, m_serverGuid));
                 }
                 else
                 {
                     return(NegotiateHelper.GetNegotiateResponse(header, request, m_securityProvider, state));
                 }
             }
             else
             {
                 return(new NegotiateResponseNotSupported());
             }
         }
         else
         {
             // [MS-CIFS] An SMB_COM_NEGOTIATE exchange MUST be completed before any other SMB messages are sent to the server
             header.Status = NTStatus.STATUS_INVALID_SMB;
             return(new ErrorResponse(command.CommandName));
         }
     }
     else if (command is NegotiateRequest)
     {
         // There MUST be only one SMB_COM_NEGOTIATE exchange per SMB connection.
         // Subsequent SMB_COM_NEGOTIATE requests received by the server MUST be rejected with error responses.
         header.Status = NTStatus.STATUS_INVALID_SMB;
         return(new ErrorResponse(command.CommandName));
     }
     else
     {
         return(ProcessSMB1Command(header, command, (SMB1ConnectionState)state));
     }
 }