Class: RubySMB::Server::ServerClient

Inherits:
Object
  • Object
show all
Includes:
Negotiation, SessionSetup, RubySMB::Signing
Defined in:
lib/ruby_smb/server/server_client.rb,
lib/ruby_smb/server/server_client/negotiation.rb,
lib/ruby_smb/server/server_client/session_setup.rb

Overview

This class represents a single connected client to the server. It stores and processes connection specific related information.

Defined Under Namespace

Modules: Negotiation, SessionSetup

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from SessionSetup

#do_session_setup_smb1, #do_session_setup_smb2, #handle_session_setup

Methods included from Negotiation

#do_negotiate_smb1, #do_negotiate_smb2, #handle_negotiate

Methods included from RubySMB::Signing

#smb1_sign, #smb2_sign, #smb3_sign

Constructor Details

#initialize(server, dispatcher) ⇒ ServerClient

Returns a new instance of ServerClient.

Parameters:

  • server (Server)

    the server that accepted this connection

  • dispatcher (Dispatcher::Socket)

    the connection's socket dispatcher



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/ruby_smb/server/server_client.rb', line 20

def initialize(server, dispatcher)
  @server = server
  @dispatcher = dispatcher
  @state = :negotiate
  @dialect = nil
  @session_id = nil
  @session_key = nil
  @gss_authenticator = server.gss_provider.new_authenticator(self)
  @identity = nil
  @tree_connections = {}
  @preauth_integrity_hash_algorithm = nil
  @preauth_integrity_hash_value = nil
end

Instance Attribute Details

#dialectObject (readonly)

Returns the value of attribute dialect.



16
17
18
# File 'lib/ruby_smb/server/server_client.rb', line 16

def dialect
  @dialect
end

#identityObject (readonly)

Returns the value of attribute identity.



16
17
18
# File 'lib/ruby_smb/server/server_client.rb', line 16

def identity
  @identity
end

#session_keyObject (readonly)

Returns the value of attribute session_key.



16
17
18
# File 'lib/ruby_smb/server/server_client.rb', line 16

def session_key
  @session_key
end

#stateObject (readonly)

Returns the value of attribute state.



16
17
18
# File 'lib/ruby_smb/server/server_client.rb', line 16

def state
  @state
end

Instance Method Details

#disconnect!Object

Disconnect the remote client.



114
115
116
117
# File 'lib/ruby_smb/server/server_client.rb', line 114

def disconnect!
  @state = nil
  @dispatcher.tcp_socket.close
end

#getpeernameString

The peername of the connected socket. This is a combination of the IPv4 or IPv6 address and port number.

Examples:

Parse the value into an IP address

::Socket::unpack_sockaddr_in(server_client.getpeername)

Returns:

  • (String)


49
50
51
# File 'lib/ruby_smb/server/server_client.rb', line 49

def getpeername
  @dispatcher.tcp_socket.getpeername
end

#handle_authenticated(raw_request) ⇒ Object

Handle an authenticated request. This is the main handler for all requests after the connection has been authenticated.

Parameters:

  • raw_request (String)

    the request that should be handled



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ruby_smb/server/server_client.rb', line 58

def handle_authenticated(raw_request)
  response = nil

  case raw_request[0...4].unpack1('L>')
  when RubySMB::SMB1::SMB_PROTOCOL_ID
    raise NotImplementedError
  when RubySMB::SMB2::SMB2_PROTOCOL_ID
    raise NotImplementedError
  end

  if response.nil?
    disconnect!
    return
  end

  send_packet(response)
end

#metadialectDialect::Definition

The dialects metadata definition.

Returns:



38
39
40
# File 'lib/ruby_smb/server/server_client.rb', line 38

def metadialect
  Dialect::ALL[@dialect]
end

#process_gss(buffer = nil) ⇒ Gss::Provider::Result

Process a GSS authentication buffer. If no buffer is specified, the request is assumed to be the first in the negotiation sequence.

Parameters:

  • buffer (String, nil) (defaults to: nil)

    the request GSS request buffer that should be processed

Returns:



82
83
84
# File 'lib/ruby_smb/server/server_client.rb', line 82

def process_gss(buffer=nil)
  @gss_authenticator.process(buffer)
end

#recv_packetString

Receive a single SMB packet from the dispatcher.

Returns:

  • (String)

    the raw packet



123
124
125
# File 'lib/ruby_smb/server/server_client.rb', line 123

def recv_packet
  @dispatcher.recv_packet
end

#runObject

Run the processing loop to receive and handle requests. This loop runs until an exception occurs or the dispatcher socket is closed.



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/ruby_smb/server/server_client.rb', line 90

def run
  loop do
    begin
      raw_request = recv_packet
    rescue RubySMB::Error::CommunicationError
      break
    end

    case @state
    when :negotiate
      handle_negotiate(raw_request)
    when :session_setup
      handle_session_setup(raw_request)
    when :authenticated
      handle_authenticated(raw_request)
    end

    break if @dispatcher.tcp_socket.closed?
  end
end

#send_packet(packet) ⇒ Object

Send a single SMB packet using the dispatcher. If necessary, the packet will be signed.

Parameters:



131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/ruby_smb/server/server_client.rb', line 131

def send_packet(packet)
  if @state == :authenticated && @identity != Gss::Provider::IDENTITY_ANONYMOUS && !@session_key.nil?
    case metadialect.family
    when Dialect::FAMILY_SMB2
      packet = smb2_sign(packet)
    when Dialect::FAMILY_SMB3
      packet = smb3_sign(packet)
    end
  end

  @dispatcher.send_packet(packet)
end

#update_preauth_hash(data) ⇒ Object

Update the preauth integrity hash as used by dialect 3.1.1 for various cryptographic operations. The algorithm and hash values must have been initialized prior to calling this.

Parameters:

  • data (String)

    the data with which to update the preauth integrity hash



149
150
151
152
153
154
155
156
157
158
159
# File 'lib/ruby_smb/server/server_client.rb', line 149

def update_preauth_hash(data)
  unless @preauth_integrity_hash_algorithm
    raise RubySMB::Error::EncryptionError.new(
      'Cannot compute the Preauth Integrity Hash value: Preauth Integrity Hash Algorithm is nil'
    )
  end
  @preauth_integrity_hash_value = OpenSSL::Digest.digest(
    @preauth_integrity_hash_algorithm,
    @preauth_integrity_hash_value + data.to_binary_s
  )
end