119 lines
3.1 KiB
Ruby
119 lines
3.1 KiB
Ruby
module RubyQA
|
|
class CommandRunner
|
|
# Handles creating an interface for running arbitrary commands on a host/target
|
|
#
|
|
# To basically provide a unified interface to run commands via different methods (ssh, telnet, etc)
|
|
# Params:
|
|
# - ip
|
|
# - hostname (optional)
|
|
def initialize (data)
|
|
@data = data
|
|
verify_data
|
|
initialize_runner
|
|
end
|
|
|
|
def verify_data
|
|
if @data[:ip].empty?
|
|
if not @data[:hostname].empty?
|
|
begin
|
|
@data[:ip] = Resolv.getaddress(@data[:hostname])
|
|
rescue Resolv::ResolvError => error
|
|
raise "Host: Hostname provided, but did not resolve to IP"
|
|
end
|
|
else
|
|
raise "Host: No hostname or IP provided"
|
|
end
|
|
end
|
|
client_validations
|
|
end
|
|
|
|
def client_validations
|
|
# Handles client specific validations (port-connect test, etc)
|
|
end
|
|
|
|
def exec (command)
|
|
run_command(command)
|
|
end
|
|
|
|
def exec_sudo(command)
|
|
if @data[:password].empty?
|
|
raise "Password was not provided for host"
|
|
end
|
|
sudo_command = <<EOT
|
|
if [[ $UID -ne 0 ]]; then
|
|
command_file=/tmp/sudo-command-$(date +%Y-%m-%d_%H-%M)
|
|
cat >$command_file <<EOF
|
|
#{command}
|
|
EOF
|
|
echo "#{@data[:password]}" | sudo -S /bin/bash $command_file 2>/dev/null
|
|
rm $command_file
|
|
else
|
|
#{command}
|
|
fi > sudo-output
|
|
EOT
|
|
run_command(sudo_command)
|
|
run_command('cat sudo-output')
|
|
end
|
|
end
|
|
|
|
|
|
require 'net/ssh'
|
|
class SSH_Runner < CommandRunner
|
|
def initialize_runner
|
|
begin
|
|
if @data[:password]
|
|
@client = Net::SSH.start(@data[:ip], @data[:user], password: @data[:password])
|
|
else
|
|
@client = Net::SSH.start(@data[:ip], @data[:user])
|
|
end
|
|
|
|
rescue SocketError
|
|
raise "Failed to make ssh client for #{@data[:hostname]}"
|
|
end
|
|
end
|
|
|
|
def run_command(command)
|
|
@client.exec!(command).strip
|
|
end
|
|
|
|
end
|
|
|
|
|
|
class Telnet_Runner < CommandRunner
|
|
require 'net/ssh/telnet'
|
|
LOGIN_HANDLER=nil
|
|
TELNET_OPTS={
|
|
"Timeout" => 10,
|
|
"Prompt" => /[$:#]/
|
|
}
|
|
def initialize_runner
|
|
begin
|
|
@client = Net::SSH::Telnet.new( "Host" => @data[:ip], "Username" => @data[:user], "Password" => @data[:password])
|
|
# Since this is telnet, it doesn't filter out command sequences, so we have to set the PS1/prompt to something
|
|
# that is easily matched for filtering purposes
|
|
@client.cmd({"String" => "PS1='<filter_line>'; PROMPT_COMMANDS='';", "Match" => /filter_line/})
|
|
rescue SocketError
|
|
raise "Failed to make ssh client for #{@data[:hostname]}"
|
|
end
|
|
end
|
|
|
|
def run_command(command)
|
|
output = ""
|
|
|
|
## Doing intitial command (doesn't send white-space/newline)
|
|
lines = Array.new
|
|
filter_regex=/(^|#{command}|^\n$)/
|
|
|
|
output = @client.cmd({"String" => command, "Waittime" => 100, "Match" => /filter_line/})
|
|
|
|
# Have to clean output since telnet session will return all output, both stdin & stdout.
|
|
output = output.split(/\n/).reject do |line|
|
|
line.match?(/filter_line/) || line.match(/#{command}/)
|
|
end.join("\n")
|
|
|
|
output
|
|
end
|
|
end
|
|
|
|
end
|