Module: RubySMB::Client::Negotiation

Included in:
RubySMB::Client
Defined in:
lib/ruby_smb/client/negotiation.rb

Overview

This module holds all of the methods backing the #negotiate method

Instance Method Summary collapse

Instance Method Details

#negotiatevoid

This method returns an undefined value.

Handles the entire SMB Multi-Protocol Negotiation from the Client to the Server. It sets state on the client appropriate to the protocol and capabilites negotiated during the exchange.



12
13
14
15
16
# File 'lib/ruby_smb/client/negotiation.rb', line 12

def negotiate
  raw_response    = negotiate_request
  response_packet = negotiate_response(raw_response)
  parse_negotiate_response(response_packet)
end

#negotiate_requestString

Creates and dispatches the first Negotiate Request Packet and returns the raw response data.

Returns:

  • (String)

    the raw binary string containing the response from the server



22
23
24
25
26
27
28
29
# File 'lib/ruby_smb/client/negotiation.rb', line 22

def negotiate_request
  if smb1
    request = smb1_negotiate_request
  elsif smb2
    request = smb2_negotiate_request
  end
  send_recv(request)
end

#negotiate_response(raw_data) ⇒ RubySMB::SMB1::Packet::NegotiateResponseExtended, RubySMB::SMB2::Packet::NegotiateResponse

Takes the raw response data from the server and tries parse it into a valid Response packet object. This method currently assumes that all SMB1 will use Extended Security.

Parameters:

  • raw_data (String)

    the raw binary response from the server

Returns:



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/ruby_smb/client/negotiation.rb', line 38

def negotiate_response(raw_data)
  response = nil
  if smb1
    begin
      packet = RubySMB::SMB1::Packet::NegotiateResponseExtended.read raw_data
    rescue Exception => e
      raise RubySMB::Error::InvalidPacket, "Not a Valid SMB1 Negoitate Response #{e.message}"
    end
    if packet.valid?
      response = packet
    end
  end
  if smb2 && response.nil?
    begin
      packet = RubySMB::SMB2::Packet::NegotiateResponse.read raw_data
    rescue Exception => e
      raise RubySMB::Error::InvalidPacket, "Not a Valid SMB2 Negoitate Response #{e.message}"
    end
    response = packet
  end
  if response.nil?
    raise RubySMB::Error::InvalidPacket, "No Valid Negotiate Response found"
  end
  response
end

#parse_negotiate_response(packet) ⇒ void

This method returns an undefined value.

Sets the supported SMB Protocol and whether or not Signing is enabled based on the Negotiate Response Packet.

Parameters:



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/ruby_smb/client/negotiation.rb', line 70

def parse_negotiate_response(packet)
  case packet
    when RubySMB::SMB1::Packet::NegotiateResponseExtended
      self.smb1 = true
      self.smb2 = false
      if packet.parameter_block.security_mode.security_signatures_required == 1
        self.signing_required = true
      else
        self.signing_required = false
      end
      'SMB1'
    when RubySMB::SMB2::Packet::NegotiateResponse
      self.smb1 = false
      self.smb2 = true
      if packet.security_mode.signing_required == 1
        self.signing_required = true
      else
        self.signing_required = false
      end
      'SMB2'
  end
end

#smb1_negotiate_requestRubySMB::SMB1::Packet::NegotiateRequest

Create a SMB1::Packet::NegotiateRequest packet with the dialects filled in based on the protocol options set on the Client.

Returns:



98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/ruby_smb/client/negotiation.rb', line 98

def smb1_negotiate_request
  packet = RubySMB::SMB1::Packet::NegotiateRequest.new
  # Default to always enabling Extended Security. It simplifies the Negotiation process
  # while being gauranteed to work with any modern Windows system. We can get more sophisticated
  # with switching this on and off at a later date if the need arises.
  packet.smb_header.flags2.extended_security = 1
  # There is no real good reason to ever send an SMB1 Negotiate packet
  # to Negotiate strictly SMB2, but the protocol WILL support it
  packet.add_dialect(SMB1_DIALECT_SMB1_DEFAULT) if smb1
  packet.add_dialect(SMB1_DIALECT_SMB2_DEFAULT) if smb2
  packet
end

#smb2_negotiate_requestObject

Create a SMB2::Packet::NegotiateRequest packet with the default dialect added. This will never be used when we may want to communicate over SMB1

@ return [RubySMB::SMB2::Packet::NegotiateRequest] a completed SMB2 Negotiate Request packet



116
117
118
119
120
121
122
# File 'lib/ruby_smb/client/negotiation.rb', line 116

def smb2_negotiate_request
  packet = RubySMB::SMB2::Packet::NegotiateRequest.new
  packet.security_mode.signing_enabled = 1
  packet.add_dialect(SMB2_DIALECT_DEFAULT)
  packet.client_guid = SecureRandom.random_bytes(16)
  packet
end