class SMB::Client
Low-level interface to smbclient executable
Constants
- VERSION
Attributes
executable[RW]
pid[RW]
Public Class Methods
new(options = {})
click to toggle source
Creates a new instance and connects to server @param [Hash] options Hash with connection options
# File lib/smb/client/client.rb, line 19 def initialize(options = {}) @executable = ENV.fetch('SMBCLIENT_EXECUTABLE') { 'smbclient' } @options = { user: options[:user], share: options[:share], password: options[:password], version: options[:version] || 2, host: options[:host] || 'localhost', workgroup: options[:workgroup] || 'WORKGROUP' } Thread.abort_on_exception = true connect # Pipe used to pass commands to pty @read1, @write1 = IO.pipe # Pipe used to pass responses from pty @read2, @write2 = IO.pipe # Indicates if first output should be ignored @first_message = true @connection_established = false @shutdown_in_progress = false end
Public Instance Methods
close()
click to toggle source
Closes the connection to the server end terminates all running threads
# File lib/smb/client/client.rb, line 47 def close @shutdown_in_progress = true Process.kill('QUIT', @pid) == 1 end
exec(cmd)
click to toggle source
Execute a smbclient command @param [String] cmd The command to be executed
# File lib/smb/client/client.rb, line 54 def exec(cmd) # Send command @write1.puts cmd # Wait for response text = @read2.read # Close previous pipe @read2.close # Create new pipe @read2, @write2 = IO.pipe # Raise at the end to support continuing raise Client::RuntimeError, text if text.start_with? 'NT_STATUS_' text end
Private Instance Methods
connect()
click to toggle source
Connect to the server using separate threads and pipe for communications
# File lib/smb/client/client.rb, line 76 def connect # Run +@executable+ in a separate thread to talk to hin asynchronously Thread.start do # Spawn the actual +@executable+ pty with +input+ and +output+ handle begin PTY.spawn(@executable + ' ' + params) do |output, input, pid| @pid = pid output.sync = true input.sync = true # Write inputs to pty from +exec+ method Thread.start do while (line = @read1.readline) input.puts line end end # Wait for responses ending with input prompt loop do output.expect(/smb: \\>$/) { |text| handle_response text } end end rescue Errno::EIO => e unless @shutdown_in_progress if @connection_established raise StandardError, "Unexpected error: [#{e.message}]" else raise Client::ConnectionError, 'Cannot connect to SMB server' end end end end end
handle_response(text)
click to toggle source
Handles a response from smbclient
# File lib/smb/client/client.rb, line 121 def handle_response(text) # Write to second pipe so the origin command invocation thread can # receive this if @first_message @first_message = false # TODO: Filter for server information? => Domain, OS and Server @connection_established = true return end # Format responses # Ignore command sent (the first returned line) and the last returned # which is the smb prompt ("smb: \>") @write2.write text[0].lines[1..-2].join @write2.close end
params()
click to toggle source
Returns the parameters for the smbclient
command @return [String] The parameters
# File lib/smb/client/client.rb, line 112 def params @options.map do |k, v| v.nil? && raise(Client::RuntimeError, "Missing option [:#{k}]") end "//#{@options[:host]}/#{@options[:share]} #{@options[:password]} \ -U #{@options[:user]} -W #{@options[:workgroup]} -m SMB#{@options[:version]}" end